/[projects]/dao/DelphiScanner/Components/tpsystools_4.04/source/StStrZ.pas
ViewVC logotype

Annotation of /dao/DelphiScanner/Components/tpsystools_4.04/source/StStrZ.pas

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2671 - (hide annotations) (download)
Tue Aug 25 18:15:15 2015 UTC (8 years, 10 months ago) by torben
File size: 122842 byte(s)
Added tpsystools component
1 torben 2671 (* ***** BEGIN LICENSE BLOCK *****
2     * Version: MPL 1.1
3     *
4     * The contents of this file are subject to the Mozilla Public License Version
5     * 1.1 (the "License"); you may not use this file except in compliance with
6     * the License. You may obtain a copy of the License at
7     * http://www.mozilla.org/MPL/
8     *
9     * Software distributed under the License is distributed on an "AS IS" basis,
10     * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11     * for the specific language governing rights and limitations under the
12     * License.
13     *
14     * The Original Code is TurboPower SysTools
15     *
16     * The Initial Developer of the Original Code is
17     * TurboPower Software
18     *
19     * Portions created by the Initial Developer are Copyright (C) 1996-2002
20     * the Initial Developer. All Rights Reserved.
21     *
22     * Contributor(s):
23     *
24     * ***** END LICENSE BLOCK ***** *)
25    
26     {*********************************************************}
27     {* SysTools: StStrZ.pas 4.04 *}
28     {*********************************************************}
29     {* SysTools: Null terminated string routines *}
30     {*********************************************************}
31    
32     {$I StDefine.inc}
33    
34     unit StStrZ;
35    
36     interface
37    
38     uses
39     Windows,
40     Classes, SysUtils, StConst, StBase;
41    
42     {-------- Numeric conversion -----------}
43    
44     function HexBZ(Dest : PAnsiChar; B : Byte) : PAnsiChar; overload;
45     function HexBZ(Dest : PWideChar; B : Byte) : PWideChar; overload;
46     {-Return the hex string for a byte.}
47    
48     function HexWZ(Dest : PAnsiChar; W : Word) : PAnsiChar;
49     {-Return the hex string for a word.}
50    
51     function HexLZ(Dest : PAnsiChar; L : LongInt) : PAnsiChar;
52     {-Return the hex string for a long integer.}
53    
54     function HexPtrZ(Dest : PAnsiChar; P : Pointer) : PAnsiChar;
55     {-Return the hex string for a pointer.}
56    
57     function BinaryBZ(Dest : PAnsiChar; B : Byte) : PAnsiChar;
58     {-Return a binary string for a byte.}
59    
60     function BinaryWZ(Dest : PAnsiChar; W : Word) : PAnsiChar;
61     {-Return the binary string for a word.}
62    
63     function BinaryLZ(Dest : PAnsiChar; L : LongInt) : PAnsiChar;
64     {-Return the binary string for a long integer.}
65    
66     function OctalBZ(Dest : PAnsiChar; B : Byte) : PAnsiChar;
67     {-Return an octal string for a byte.}
68    
69     function OctalWZ(Dest : PAnsiChar; W : Word) : PAnsiChar;
70     {-Return an octal string for a word.}
71    
72     function OctalLZ(Dest : PAnsiChar; L : LongInt) : PAnsiChar;
73     {-Return an octal string for a long integer.}
74    
75     function Str2Int16Z(S : PAnsiChar; var I : SmallInt) : Boolean;
76     {-Convert a string to an SmallInt.}
77    
78     function Str2WordZ(S : PAnsiChar; var I : Word) : Boolean;
79     {-Convert a string to a word.}
80    
81     function Str2LongZ(S : PAnsiChar; var I : LongInt) : Boolean;
82     {-Convert a string to a long integer.}
83    
84     {$IFDEF VER93}
85     function Str2RealZ(S : PAnsiChar; var R : Double) : Boolean;
86     {$ELSE}
87     function Str2RealZ(S : PChar; var R : Real) : Boolean;
88     {$ENDIF}
89     {-Convert a string to a real.}
90    
91     function Str2ExtZ(S : PAnsiChar; var R : Extended) : Boolean;
92     {-Convert a string to an extended.}
93    
94     function Long2StrZ(Dest : PAnsiChar; L : LongInt) : PAnsiChar;
95     {-Convert an integer type to a string.}
96    
97     function Real2StrZ(Dest : PAnsiChar; R : Double; Width : Byte;
98     Places : ShortInt) : PAnsiChar;
99     {-Convert a real to a string.}
100    
101     function Ext2StrZ(Dest : PAnsiChar; R : Extended; Width : Byte;
102     Places : ShortInt) : PAnsiChar;
103     {-Convert an extended to a string.}
104    
105     function ValPrepZ(S : PAnsiChar) : PAnsiChar; overload;
106     {$IFDEF UNICODE}
107     function ValPrepZ(S : PWideChar) : PWideChar; overload;
108     {$ENDIF}
109     {-Prepares a string for calling Val.}
110    
111    
112     {-------- General purpose string manipulation --------}
113    
114     function CharStrZ(Dest : PAnsiChar; C : AnsiChar; Len : Cardinal) : PAnsiChar;
115     {-Return a string filled with the specified character.}
116    
117     function PadChZ(Dest, S : PAnsiChar; C : AnsiChar; Len : Cardinal) : PAnsiChar;
118     {-Pad a string on the right with a specified character.}
119    
120     function PadZ(Dest, S : PAnsiChar; Len : Cardinal) : PAnsiChar;
121     {-Pad a string on the right with spaces.}
122    
123     function LeftPadChZ(Dest, S : PAnsiChar; C : AnsiChar; Len : Cardinal) : PAnsiChar;
124     {-Pad a string on the left with a specified character.}
125    
126     function LeftPadZ(Dest, S : PAnsiChar; Len : Cardinal) : PAnsiChar;
127     {-Pad a string on the left with spaces.}
128    
129     function PadChPrimZ(S : PAnsiChar; C : AnsiChar; Len : Cardinal) : PAnsiChar;
130     {-Pad a string on the right with a specified character.
131     This primitive version modifies the source string directly.}
132    
133     function PadPrimZ(S : PAnsiChar; Len : Cardinal) : PAnsiChar;
134     {-Pad a string on the right with spaces. This primitive version modifies the
135     source string directly.}
136    
137     function LeftPadChPrimZ(S : PAnsiChar; C : AnsiChar; Len : Cardinal) : PAnsiChar;
138     {-Pad a string on the left with a specified character. This primitive
139     version modifies the source string directly.}
140    
141     function LeftPadPrimZ(S : PAnsiChar; Len : Cardinal) : PAnsiChar;
142     {-Pad a string on the left with spaces. This primitive version modifies the
143     source string directly.}
144    
145     function TrimLeadZ(Dest, S : PAnsiChar) : PAnsiChar;
146     {-Return a string with leading white space removed.}
147    
148     function TrimTrailZ(Dest, S : PAnsiChar) : PAnsiChar;
149     {-Return a string with trailing white space removed.}
150    
151     function TrimZ(Dest, S : PAnsiChar) : PAnsiChar;
152     {-Return a string with leading and trailing white space removed.}
153    
154     function TrimSpacesZ(Dest, S : PAnsiChar) : PAnsiChar;
155     {-Return a string with leading and trailing spaces removed.}
156    
157     function TrimLeadPrimZ(S : PAnsiChar) : PAnsiChar;
158     {-Return a string with leading white space removed. This primitive version
159     modifies the source string directly.}
160    
161     function TrimTrailPrimZ(S : PAnsiChar) : PAnsiChar; overload;
162     function TrimTrailPrimZ(S : PWideChar) : PWideChar; overload;
163     {-Return a string with trailing white space removed. This primitive version
164     modifies the source string directly.}
165    
166     function TrimPrimZ(S : PAnsiChar) : PAnsiChar;
167     {-Return a string with leading and trailing white space removed. This
168     primitive version modifies the source string directly.}
169    
170     function TrimSpacesPrimZ(S : PAnsiChar) : PAnsiChar; overload;
171     {$IFDEF UNICODE}
172     function TrimSpacesPrimZ(S : PWideChar) : PWideChar; overload;
173     {$ENDIF}
174     {-Return a string with leading and trailing spaces removed. This primitive
175     version modifies the source string directly.}
176    
177     function CenterChPrimZ(S : PAnsiChar; C : AnsiChar; Len : Cardinal) : PAnsiChar;
178     {-Pad a string on the left and right with a specified character. This
179     primitive version modifies the source string directly.}
180    
181     function CenterPrimZ(S : PAnsiChar; Len : Cardinal) : PAnsiChar;
182     {-Pad a string on the left and right with spaces. This primitive version
183     modifies the source string directly.}
184    
185     function CenterChZ(Dest, S : PAnsiChar; C : AnsiChar; Len : Cardinal) : PAnsiChar;
186     {-Pad a string on the left and right with a specified character.}
187    
188     function CenterZ(Dest, S : PAnsiChar; Len : Cardinal) : PAnsiChar;
189     {-Pad a string on the left and right with spaces.}
190    
191     function EntabZ(Dest, Src : PAnsiChar; TabSize : Byte) : PAnsiChar;
192     {-Convert blanks in a string to tabs.}
193    
194     function DetabZ(Dest, Src : PAnsiChar; TabSize : Byte) : PAnsiChar;
195     {-Expand tabs in a string to blanks.}
196    
197     function ScramblePrimZ(S, Key : PAnsiChar) : PAnsiChar;
198     {-Encrypt / Decrypt string with enhanced XOR encryption. This
199     primitive version modifies the source string directly.}
200    
201     function ScrambleZ(Dest, S, Key : PAnsiChar) : PAnsiChar;
202     {-Encrypt / Decrypt string with enhanced XOR encryption.}
203    
204     function SubstituteZ(Dest, Src, FromStr, ToStr : PAnsiChar) : PAnsiChar;
205     {-Map the characters found in FromStr to the corresponding ones in ToStr.}
206    
207     function FilterZ(Dest, Src, Filters : PAnsiChar) : PAnsiChar;
208     {-Remove characters from a string. The characters to remove are specified in
209     ChSet.}
210    
211     {--------------- Word / Char manipulation -------------------------}
212    
213     function CharExistsZ(S : PAnsiChar; C : AnsiChar) : Boolean; overload;
214     function CharExistsZ(S : PWideChar; C : Char) : Boolean; overload;
215     {-Determine whether the given character exists in a string. }
216    
217     function CharCountZ(S : PAnsiChar; C : AnsiChar) : Cardinal;
218     {-Count the number of a given character in a string. }
219    
220     function WordCountZ(S : PAnsiChar; WordDelims : PAnsiChar) : Cardinal;
221     {-Given an array of word delimiters, return the number of words in a string.}
222    
223     function WordPositionZ(N : Cardinal; S : PAnsiChar; WordDelims : PAnsiChar;
224     var Pos : Cardinal) : Boolean;
225     {-Given an array of word delimiters, set Pos to the start position of the
226     N'th word in a string. Result indicates success/failure.}
227    
228     function ExtractWordZ(Dest : PAnsiChar; N : Cardinal; Src : PAnsiChar;
229     WordDelims : PAnsiChar) : PAnsiChar;
230     {-Given an array of word delimiters, return the N'th word in a string.}
231    
232     function AsciiCountZ(S : PAnsiChar; WordDelims : PAnsiChar; Quote : AnsiChar) : Cardinal;
233     {-Return the number of words in a string.}
234    
235     function AsciiPositionZ(N : Cardinal; S : PAnsiChar; WordDelims : PAnsiChar;
236     Quote : AnsiChar; var Pos : Cardinal) : Boolean;
237     {-Return the position of the N'th word in a string.}
238    
239     function ExtractAsciiZ(Dest : PAnsiChar; N : Cardinal; Src : PAnsiChar;
240     WordDelims : PAnsiChar; Quote : AnsiChar) : PAnsiChar;
241     {-Given an array of word delimiters, return the N'th word in a string. Any
242     text within Quote characters is counted as one word.}
243    
244     procedure WordWrapZ(Dest : PAnsiChar; InSt, Overlap : PAnsiChar;
245     Margin : Cardinal;
246     PadToMargin : Boolean);
247     {-Wrap a text string at a specified margin.}
248    
249     {--------------- String comparison and searching -----------------}
250     function CompStringZ(S1, S2 : PAnsiChar) : Integer;
251     {-Compare two strings.}
252    
253     function CompUCStringZ(S1, S2 : PAnsiChar) : Integer;
254     {-Compare two strings. This compare is not case sensitive.}
255    
256     function SoundexZ(Dest : PAnsiChar; S : PAnsiChar) : PAnsiChar;
257     {-Return 4 character soundex of an input string}
258    
259     function MakeLetterSetZ(S : PAnsiChar) : Longint;
260     {-Return a bit-mapped long storing the individual letters contained in S.}
261    
262     procedure BMMakeTableZ(MatchString : PAnsiChar; var BT : BTable);
263     {-Build a Boyer-Moore link table}
264    
265     function BMSearchZ(var Buffer; BufLength : Cardinal; var BT : BTable;
266     MatchString : PAnsiChar ; var Pos : Cardinal) : Boolean;
267     {-Use the Boyer-Moore search method to search a buffer for a string.}
268    
269     function BMSearchUCZ(var Buffer; BufLength : Cardinal; var BT : BTable;
270     MatchString : PAnsiChar ; var Pos : Cardinal) : Boolean;
271     {-Use the Boyer-Moore search method to search a buffer for a string. This
272     search is not case sensitive.}
273    
274     {--------------- DOS pathname parsing -----------------}
275    
276     function DefaultExtensionZ(Dest : PAnsiChar; Name, Ext : PAnsiChar) : PAnsiChar;
277     {-Return a file name with a default extension attached.}
278    
279     function ForceExtensionZ(Dest : PAnsiChar; Name, Ext : PAnsiChar) : PAnsiChar;
280     {-Force the specified extension onto the file name.}
281    
282     function JustFilenameZ(Dest : PAnsiChar; PathName : PAnsiChar) : PAnsiChar; overload;
283     {$IFDEF UNICODE}
284     function JustFilenameZ(Dest : PWideChar; PathName : PWideChar) : PWideChar; overload;
285     {$ENDIF}
286     {-Return just the filename and extension of a pathname.}
287    
288     function JustNameZ(Dest : PAnsiChar; PathName : PAnsiChar) : PAnsiChar;
289     {-Return just the filename (no extension, path, or drive) of a pathname.}
290    
291     function JustExtensionZ(Dest : PAnsiChar; Name : PAnsiChar) : PAnsiChar;
292     {-Return just the extension of a pathname.}
293    
294     function JustPathnameZ(Dest : PAnsiChar; PathName : PAnsiChar) : PAnsiChar;
295     {-Return just the drive and directory portion of a pathname.}
296    
297     function AddBackSlashZ(Dest : PAnsiChar; DirName : PAnsiChar) : PAnsiChar;
298     {-Add a default backslash to a directory name.}
299    
300     function CleanPathNameZ(Dest : PAnsiChar; PathName : PAnsiChar) : PAnsiChar;
301     {-Return a pathname cleaned up as DOS does it.}
302    
303     function HasExtensionZ(Name : PAnsiChar; var DotPos : Cardinal) : Boolean; overload;
304     {$IFDEF UNICODE}
305     function HasExtensionZ(Name : PWideChar; var DotPos : Cardinal) : Boolean; overload;
306     {$ENDIF}
307     {-Determine if a pathname contains an extension and, if so, return the
308     position of the dot in front of the extension.}
309    
310     {------------------ Formatting routines --------------------}
311    
312     function CommaizeZ(Dest : PAnsiChar; L : LongInt) : PAnsiChar;
313     {-Convert a long integer to a string with commas.}
314    
315     function CommaizeChZ(Dest : PAnsiChar; L : Longint; Ch : AnsiChar) : PAnsiChar;
316     {-Convert a long integer to a string with Ch in comma positions.}
317    
318     function FloatFormZ(Dest, Mask : PAnsiChar ; R : TstFloat ; LtCurr,
319     RtCurr : PAnsiChar ; Sep, DecPt : AnsiChar) : PAnsiChar;
320     {-Return a formatted string with digits from R merged into mask.}
321    
322     function LongIntFormZ(Dest, Mask : PAnsiChar ; L : LongInt ; LtCurr,
323     RtCurr : PAnsiChar ; Sep : AnsiChar) : PAnsiChar;
324     {-Return a formatted string with digits from L merged into mask.}
325    
326     function StrChPosZ(P : PAnsiChar; C : AnsiChar; var Pos : Cardinal) : Boolean; overload;
327     {$IFDEF UNICODE}
328     function StrChPosZ(P : PWideChar; C : Char; var Pos : Cardinal) : Boolean; overload;
329     {$ENDIF}
330     {-Return the position of a specified character within a string.}
331    
332     function StrStPosZ(P, S : PAnsiChar; var Pos : Cardinal) : Boolean;
333     {-Return the position of a specified substring within a string.}
334    
335     function StrStCopyZ(Dest, S : PAnsiChar; Pos, Count : Cardinal) : PAnsiChar; overload;
336     {$IFDEF UNICODE}
337     function StrStCopyZ(Dest, S : PWideChar; Pos, Count : Cardinal) : PWideChar; overload;
338     {$ENDIF}
339     {-Copy characters at a specified position in a string.}
340    
341     function StrChInsertZ(Dest, S : PAnsiChar; C : AnsiChar; Pos : Cardinal) : PAnsiChar;
342     {-Insert a character into a string at a specified position.}
343    
344     function StrStInsertZ(Dest, S1, S2 : PAnsiChar; Pos : Cardinal) : PAnsiChar;
345     {-Insert a string into another string at a specified position.}
346    
347     function StrChDeleteZ(Dest, S : PAnsiChar; Pos : Cardinal) : PAnsiChar;
348     {-Delete the character at a specified position in a string.}
349    
350     function StrStDeleteZ(Dest, S : PAnsiChar; Pos, Count : Cardinal) : PAnsiChar;
351     {-Delete characters at a specified position in a string.}
352    
353     function StrChInsertPrimZ(Dest : PAnsiChar; C : AnsiChar; Pos : Cardinal) : PAnsiChar;
354     {-Insert a character into a string at a specified position. This primitive
355     version modifies the source string directly.}
356    
357     function StrStInsertPrimZ(Dest, S : PAnsiChar; Pos : Cardinal) : PAnsiChar;
358     {-Insert a string into another string at a specified position. This
359     primitive version modifies the source string directly.}
360    
361     function StrChDeletePrimZ(P : PAnsiChar; Pos : Cardinal) : PAnsiChar;
362     {-Delete the character at a specified position in a string. This primitive
363     version modifies the source string directly.}
364    
365     function StrStDeletePrimZ(P : PAnsiChar; Pos, Count : Cardinal) : PAnsiChar; overload;
366     function StrStDeletePrimZ(P : PWideChar; Pos, Count : Cardinal) : PWideChar; overload;
367     {-Delete characters at a specified position in a string. This primitive
368     version modifies the source string directly.}
369    
370    
371     {-------------------------- New Functions -----------------------------------}
372    
373     function ContainsOnlyZ(const S, Chars : PAnsiChar;
374     var BadPos : Cardinal) : Boolean;
375    
376     function ContainsOtherThanZ(const S, Chars : PAnsiChar;
377     var BadPos : Cardinal) : Boolean;
378    
379     function CopyFromNthWordZ(Dest, S, WordDelims, AWord : PAnsiChar;
380     N : Cardinal) : Boolean;
381    
382     function CopyFromToWordZ(Dest, S, WordDelims, Word1, Word2 : PAnsiChar;
383     N1, N2 : Cardinal) : Boolean;
384    
385     function CopyLeftZ(Dest, S : PAnsiChar; Len : Cardinal) : PAnsiChar;
386     {-Return the left Len characters of a string}
387    
388     function CopyMidZ(Dest, S : PAnsiChar; First, Len : Cardinal) : PAnsiChar;
389     {-Return the mid part of a string}
390    
391     function CopyRightZ(Dest, S : PAnsiChar; First : Cardinal) : PAnsiChar;
392     {-Return the right Len characters of a string}
393    
394     function CopyRightAbsZ(Dest, S : PAnsiChar; NumChars : Cardinal) : PAnsiChar;
395     {-Return the right Len characters of a string}
396    
397    
398     function CopyWithinZ(Dest, S, Delimiter : PAnsiChar;
399     Strip : Boolean) : PAnsiChar;
400    
401     function DeleteFromNthWordZ(Dest, S, WordDelims, AWord : PAnsiChar;
402     N : Cardinal) : Boolean;
403    
404     function DeleteFromToWordZ(Dest, S, WordDelims, Word1, Word2 : PAnsiChar;
405     N1, N2 : Cardinal) : Boolean;
406    
407     function DeleteWithinZ(Dest, S, Delimiter : PAnsiChar) : PAnsiChar;
408    
409     function ExtractTokensZ(S, Delims : PAnsiChar;
410     QuoteChar : AnsiChar;
411     AllowNulls : Boolean;
412     Tokens : TStrings) : Cardinal;
413    
414     function IsChAlphaZ(C : Char) : Boolean;
415     {-Returns true if Ch is an alpha}
416    
417     function IsChNumericZ(C : AnsiChar; Numbers : PAnsiChar) : Boolean;
418     {-Returns true if Ch in numeric set}
419    
420     function IsChAlphaNumericZ(C : Char; Numbers : PChar) : Boolean;
421     {-Returns true if Ch is an alpha or numeric}
422    
423     function IsStrAlphaZ(S : PChar) : Boolean;
424     {-Returns true if all characters in string are an alpha}
425    
426     function IsStrNumericZ(S, Numbers : PAnsiChar) : Boolean;
427     {-Returns true if all characters in string are in numeric set}
428    
429     function IsStrAlphaNumericZ(S, Numbers : PChar) : Boolean;
430     {-Returns true if all characters in string are alpha or numeric}
431    
432     function KeepCharsZ(Dest, S, Chars : PAnsiChar) : PAnsiChar;
433    
434     function LastStringZ(S, AString : PAnsiChar;
435     var Position : Cardinal) : Boolean;
436    
437     function LastWordZ(S, WordDelims, AWord : PAnsiChar;
438     var Position : Cardinal) : Boolean;
439    
440    
441     function LastWordAbsZ(S, WordDelims : PAnsiChar;
442     var Position : Cardinal) : Boolean;
443    
444     function LeftTrimCharsZ(Dest, S, Chars : PAnsiChar) : PAnsiChar;
445    
446     function RepeatStringZ(Dest, RepeatString : PAnsiChar;
447     var Repetitions : Cardinal;
448     MaxLen : Cardinal) : PAnsiChar;
449    
450     function ReplaceWordZ(Dest, S, WordDelims, OldWord, NewWord : PAnsiChar;
451     N : Cardinal;
452     var Replacements : Cardinal) : PAnsiChar;
453    
454     function ReplaceWordAllZ(Dest, S, WordDelims, OldWord, NewWord : PAnsiChar;
455     var Replacements : Cardinal) : PAnsiChar;
456    
457     function ReplaceStringZ(Dest, S, OldString, NewString : PAnsiChar;
458     N : Cardinal;
459     var Replacements : Cardinal) : PAnsiChar;
460    
461     function ReplaceStringAllZ(Dest, S, OldString, NewString : PAnsiChar;
462     var Replacements : Cardinal) : PAnsiChar;
463    
464     function RightTrimCharsZ(Dest, S, Chars : PAnsiChar) : PAnsiChar;
465    
466     function StrWithinZ(S, SearchStr : PAnsiChar;
467     Start : Cardinal;
468     var Position : Cardinal) : Boolean;
469    
470     function TrimCharsZ(Dest, S, Chars : PAnsiChar) : PAnsiChar;
471    
472    
473     function WordPosZ(S, WordDelims, AWord : PAnsiChar;
474     N : Cardinal; var Position : Cardinal) : Boolean;
475     {-returns the Occurrence instance of a word within a string}
476    
477    
478    
479     implementation
480    
481    
482     function HexBZ(Dest : PAnsiChar; B : Byte) : PAnsiChar;
483     {-Return hex string for byte}
484     begin
485     Result := Dest;
486     Dest^ := StHexDigits[B shr 4];
487     Inc(Dest);
488     Dest^ := StHexDigits[B and $F];
489     Inc(Dest);
490     Dest^ := #0;
491     end;
492    
493     function HexBZ(Dest : PWideChar; B : Byte) : PWideChar;
494     {-Return hex string for byte}
495     begin
496     Result := Dest;
497     Dest^ := WideChar(StHexDigits[B shr 4]);
498     Inc(Dest);
499     Dest^ := WideChar(StHexDigits[B and $F]);
500     Inc(Dest);
501     Dest^ := #0;
502     end;
503    
504     function HexWZ(Dest : PAnsiChar; W : Word) : PAnsiChar;
505     {-Return hex string for word}
506     begin
507     Result := Dest;
508     Dest^ := StHexDigits[hi(W) shr 4];
509     Inc(Dest);
510     Dest^ := StHexDigits[hi(W) and $F];
511     Inc(Dest);
512     Dest^ := StHexDigits[lo(W) shr 4];
513     Inc(Dest);
514     Dest^ := StHexDigits[lo(W) and $F];
515     Inc(Dest);
516     Dest^ := #0;
517     end;
518    
519     function HexLZ(Dest : PAnsiChar; L : LongInt) : PAnsiChar;
520     {-Return hex string for LongInt}
521     //type {!!.02}
522     // LH = record L, H : word; end; {!!.02}
523     var
524     T2 : Array[0..4] of AnsiChar;
525     begin
526     // Result := StrCat(HexWZ(Dest, LH(L).H), HexWZ(T2, LH(L).L)); {!!.02}
527     Result := StrCat(HexWZ(Dest, HiWord(DWORD(L))), {!!.02}
528     HexWZ(T2, LoWord(DWORD(L)))); {!!.02}
529     end;
530    
531     function HexPtrZ(Dest : PAnsiChar; P : Pointer) : PAnsiChar;
532     {-Return hex string for pointer}
533     var
534     T2 : array[0..8] of AnsiChar;
535     begin
536     StrCopy(Dest, ':');
537     Result := StrCat(Dest, HexLZ(T2, LongInt(P)));
538     end;
539    
540     function BinaryBZ(Dest : PAnsiChar; B : Byte) : PAnsiChar;
541     {-Return binary string for byte}
542     var
543     I : Word;
544     begin
545     Result := Dest;
546     for I := 7 downto 0 do begin
547     Dest^ := StHexDigits[Ord(B and (1 shl I) <> 0)]; {0 or 1}
548     Inc(Dest);
549     end;
550     Dest^ := #0;
551     end;
552    
553     function BinaryWZ(Dest : PAnsiChar; W : Word) : PAnsiChar;
554     {-Return binary string for word}
555     var
556     I : Word;
557     begin
558     Result := Dest;
559     for I := 15 downto 0 do begin
560     Dest^ := StHexDigits[Ord(W and (1 shl I) <> 0)]; {0 or 1}
561     Inc(Dest);
562     end;
563     Dest^ := #0;
564     end;
565    
566     function BinaryLZ(Dest : PAnsiChar; L : LongInt) : PAnsiChar;
567     {-Return binary string for LongInt}
568     var
569     I : Longint;
570     begin
571     Result := Dest;
572     for I := 31 downto 0 do begin
573     Dest^ := StHexDigits[Ord(L and LongInt(1 shl I) <> 0)]; {0 or 1}
574     Inc(Dest);
575     end;
576     Dest^ := #0;
577     end;
578    
579     function OctalBZ(Dest : PAnsiChar; B : Byte) : PAnsiChar;
580     {-Return octal string for byte}
581     var
582     I : Word;
583     begin
584     Result := Dest;
585     for I := 0 to 2 do begin
586     Dest[2-I] := StHexDigits[B and 7];
587     B := B shr 3;
588     end;
589     Dest[3] := #0;
590     end;
591    
592     function OctalWZ(Dest : PAnsiChar; W : Word) : PAnsiChar;
593     {-Return octal string for word}
594     var
595     I : Word;
596     begin
597     Result := Dest;
598     for I := 0 to 5 do begin
599     Dest[5-I] := StHexDigits[W and 7];
600     W := W shr 3;
601     end;
602     Dest[6] := #0;
603     end;
604    
605     function OctalLZ(Dest : PAnsiChar; L : LongInt) : PAnsiChar;
606     {-Return octal string for word}
607     var
608     I : Word;
609     begin
610     Result := Dest;
611     for I := 0 to 11 do begin
612     Dest[11-I] := StHexDigits[L and 7];
613     L := L shr 3;
614     end;
615     Dest[12] := #0;
616     end;
617    
618     function CharStrZ(Dest : PAnsiChar; C : AnsiChar; Len : Cardinal) : PAnsiChar;
619     register;
620     asm
621     push edi { Save EDI-about to change it }
622     push eax { Save Dest pointer for return }
623     mov edi, eax { Point EDI to Dest }
624    
625     mov dh, dl { Dup character 4 times }
626     mov eax, edx
627     shl eax, $10
628     mov ax, dx
629    
630     mov edx, ecx { Save Len }
631    
632     shr ecx, 2 { Store dword char chunks first }
633     rep stosd
634     mov ecx, edx { Store remaining characters }
635     and ecx, 3
636     rep stosb
637    
638     xor al,al { Add null terminator }
639     mov [edi], al
640    
641     pop eax { Return Dest pointer }
642     pop edi { Restore orig value of EDI }
643     end;
644    
645     function PadChPrimZ(S : PAnsiChar; C : AnsiChar; Len : Cardinal) : PAnsiChar;
646     register;
647     asm
648     push eax
649     push ebx
650     push edi
651    
652     mov edi, eax
653     mov ebx, ecx
654     xor eax, eax
655     or ecx, -1
656     repne scasb
657     not ecx
658     dec ecx
659     dec edi
660     mov eax, ebx
661     sub eax, ecx
662     jbe @@ExitPoint
663    
664     mov ecx, eax
665     mov eax, edx
666     rep stosb
667    
668     @@ExitPoint:
669     xor eax, eax
670     mov [edi], al
671    
672     pop edi
673     pop ebx
674     pop eax
675     end;
676    
677     function PadPrimZ(S : PAnsiChar; Len : Cardinal) : PAnsiChar;
678     {-Return a string right-padded to length len with blanks}
679     begin
680     Result := PadChPrimZ(S, ' ', Len);
681     end;
682    
683     function LeftPadChPrimZ(S : PAnsiChar; C : AnsiChar; Len : Cardinal) : PAnsiChar;
684     {-Return a string left-padded to length len with C}
685     register;
686     asm
687     push ebx
688     push edi
689     push esi
690    
691     mov edi, eax
692     mov esi, edi
693     mov ebx, ecx
694    
695     xor eax, eax
696     or ecx, -1
697     repne scasb
698     not ecx
699     dec ecx
700     mov eax, ebx
701     mov edi, esi
702     add edi, ebx
703     mov ebx, esi
704     sub eax, ecx
705     jbe @@ExitPoint
706    
707     add esi, ecx
708     inc ecx
709     std
710     rep movsb
711     mov ecx, eax
712     mov eax, edx
713     rep stosb
714    
715     @@ExitPoint:
716     cld
717     mov eax, ebx
718     pop esi
719     pop edi
720     pop ebx
721     end;
722    
723     function LeftPadPrimZ(S : PAnsiChar; Len : Cardinal) : PAnsiChar;
724     {-Return a string left-padded to length len with blanks}
725     begin
726     Result := LeftPadChPrimZ(S, ' ', Len);
727     end;
728    
729     function PadChZ(Dest, S : PAnsiChar; C : AnsiChar; Len : Cardinal) : PAnsiChar;
730     {-Return a PChar right-padded to length Len with C}
731     begin
732     StrCopy(Dest, S);
733     Result := PadChPrimZ(Dest, C, Len);
734     end;
735    
736     function PadZ(Dest, S : PAnsiChar; Len : Cardinal) : PAnsiChar;
737     {-Return a string right-padded to length len with blanks}
738     begin
739     StrCopy(Dest, S);
740     Result := PadPrimZ(Dest, Len);
741     end;
742    
743     function LeftPadChZ(Dest, S : PAnsiChar; C : AnsiChar; Len : Cardinal) : PAnsiChar;
744     {-Return a string left-padded to length len with C}
745     begin
746     StrCopy(Dest, S);
747     Result := LeftPadChPrimZ(Dest, C, Len);
748     end;
749    
750     function LeftPadZ(Dest, S : PAnsiChar; Len : Cardinal) : PAnsiChar;
751     {-Return a string left-padded to length len with blanks}
752     begin
753     StrCopy(Dest, S);
754     Result := LeftPadPrimZ(Dest, Len);
755     end;
756    
757     function TrimLeadPrimZ(S : PAnsiChar) : PAnsiChar;
758     {-Return a string with leading white space removed}
759     register;
760     asm
761     push edi
762     push esi
763    
764     mov edi, eax
765     mov esi, eax
766     mov edx, eax
767     xor eax, eax
768     or ecx, -1
769     repne scasb
770     not ecx
771     dec ecx
772     mov edi, edx
773     jz @@CopyRest
774    
775     @@Lo:
776     cmp byte ptr [esi], ' '
777     ja @@CopyRest
778     inc esi
779     dec ecx
780     jnz @@Lo
781    
782     @@CopyRest:
783     inc ecx
784     rep movsb
785     mov eax, edx
786    
787     pop esi
788     pop edi
789     end;
790    
791     function TrimLeadZ(Dest, S : PAnsiChar) : PAnsiChar;
792     {-Return a string with leading white space removed}
793     begin
794     StrCopy(Dest, S);
795     Result := TrimLeadPrimZ(Dest);
796     end;
797    
798     function TrimTrailPrimZ(S : PAnsiChar) : PAnsiChar;
799     {-Return a string with trailing white space removed}
800     register;
801     asm
802     push edi
803    
804     mov edi, eax
805     mov edx, eax
806     xor eax, eax
807     or ecx, -1
808     repne scasb
809     not ecx
810     dec ecx
811     jz @@ExitPoint
812     dec edi
813     dec edi
814    
815     @@Lo:
816     cmp BYTE PTR [edi], ' '
817     ja @@AllDone
818     dec edi
819     dec ecx
820     jnz @@Lo
821    
822     @@AllDone:
823     inc edi
824     mov byte ptr [edi], 0h
825    
826     @@ExitPoint:
827     mov eax, edx
828     pop edi
829     end;
830    
831     function TrimTrailPrimZ(S : PWideChar) : PWideChar; //SZ
832     {-Return a string with trailing white space removed}
833     register;
834     asm
835     push edi
836    
837     mov edi, eax
838     mov edx, eax
839     xor eax, eax
840     or ecx, -1
841     repne scasw
842     not ecx
843     dec ecx
844     dec ecx
845     jz @@ExitPoint
846     dec edi
847     dec edi
848     dec edi
849     dec edi
850    
851     @@Lo:
852     cmp WORD PTR [edi], ' '
853     ja @@AllDone
854     dec edi
855     dec edi
856     dec ecx
857     dec ecx
858     jnz @@Lo
859    
860     @@AllDone:
861     inc edi
862     inc edi
863     mov word ptr [edi], 0h
864    
865     @@ExitPoint:
866     mov eax, edx
867     pop edi
868     end;
869    
870    
871     function TrimTrailZ(Dest, S : PAnsiChar) : PAnsiChar;
872     {-Return a string with trailing white space removed}
873     begin
874     StrCopy(Dest, S);
875     Result := TrimTrailPrimZ(Dest);
876     end;
877    
878     function TrimPrimZ(S : PAnsiChar) : PAnsiChar;
879     {-Return a string with leading and trailing white space removed}
880     begin
881     Result := TrimTrailPrimZ(TrimLeadPrimZ(S));
882     end;
883    
884     function TrimZ(Dest, S : PAnsiChar) : PAnsiChar;
885     {-Return a string with leading and trailing white space removed}
886     begin
887     StrCopy(Dest, S);
888     Result := TrimPrimZ(Dest);
889     end;
890    
891     function TrimSpacesPrimZ(S : PAnsiChar) : PAnsiChar;
892     {-Return a string with leading and trailing spaces removed}
893     var
894     I, SLen : Cardinal;
895     begin
896     Result := S;
897     SLen := StrLen(S);
898     while (SLen > 0) and (S[SLen-1] = ' ') do
899     Dec(SLen);
900     S[SLen] := #0;
901     I := 0;
902     while (I < SLen) and (S[I] = ' ') do
903     Inc(I);
904     if I > 0 then
905     StrStDeletePrimZ(S, 0, I);
906     end;
907    
908     {$IFDEF UNICODE}
909     function TrimSpacesPrimZ(S : PWideChar) : PWideChar;
910     {-Return a string with leading and trailing spaces removed}
911     var
912     I, SLen : Cardinal;
913     begin
914     Result := S;
915     SLen := StrLen(S);
916     while (SLen > 0) and (S[SLen-1] = ' ') do
917     Dec(SLen);
918     S[SLen] := #0;
919     I := 0;
920     while (I < SLen) and (S[I] = ' ') do
921     Inc(I);
922     if I > 0 then
923     StrStDeletePrimZ(S, 0, I);
924     end;
925     {$ENDIF}
926    
927     function TrimSpacesZ(Dest, S : PAnsiChar) : PAnsiChar;
928     {-Return a string with leading and trailing spaces removed}
929     begin
930     StrCopy(Dest, S);
931     Result := TrimSpacesPrimZ(Dest);
932     end;
933    
934     function CenterChPrimZ(S : PAnsiChar; C : AnsiChar; Len : Cardinal) : PAnsiChar;
935     {-Return a string centered in a string of C with specified width}
936     register;
937     asm
938     push eax { save registers }
939     push ebx
940     push edi
941     push esi
942    
943     mov edi, eax { set EDI and ESI to S }
944     mov esi, eax
945     mov ebx, ecx { store Len in EBX }
946     xor eax, eax
947     or ecx, -1
948     repne scasb { Find null terminator in S }
949     not ecx
950     dec ecx { ECX has length of S }
951     jz @@SpecialCase { if zero, jump to special case }
952    
953     cmp ecx, ebx
954     jae @@ExitPoint { if Len >= Length(S), we're done }
955    
956     mov eax, ebx { copy Len to EAX }
957     sub ebx, ecx { EBX = number of pad characters }
958     inc ebx
959     shr ebx, 1 { EBX = number of pad characters on one side }
960     sub eax, ebx
961     sub eax, ecx
962     push eax
963     add esi, ecx { set ESI to end of text in S }
964     mov edi, esi
965     add edi, ebx { set EDI to end of destination }
966     dec esi
967     push edi
968     dec edi
969     std { Backward string ops }
970     rep movsb { move string }
971     mov eax, edx { copy pad character to EAX }
972     mov ecx, ebx
973     rep stosb { pad to left of text }
974     pop edi
975     pop ecx
976     cld { forward string ops }
977     rep stosb { pad to right of text }
978     jmp @@AddNull { add null terminator }
979    
980     @@SpecialCase:
981     mov ecx, ebx { fill string with C }
982     mov eax, edx
983     mov edi, esi
984     rep stosb
985    
986     @@AddNull:
987     mov byte ptr [edi], 0h { add null at end of string }
988    
989     @@ExitPoint:
990     pop esi { restore registers }
991     pop edi
992     pop ebx
993     pop eax
994     end;
995    
996     function CenterChZ(Dest, S : PAnsiChar; C : AnsiChar; Len : Cardinal) : PAnsiChar;
997     {-Return a string centered in a string of C with specified width}
998     begin
999     StrCopy(Dest, S);
1000     Result := CenterChPrimZ(Dest, C, Len);
1001     end;
1002    
1003     function CenterPrimZ(S : PAnsiChar; Len : Cardinal) : PAnsiChar;
1004     {-Return a string centered in a blank string of specified width}
1005     begin
1006     Result := CenterChPrimZ(S, ' ', Len);
1007     end;
1008    
1009     function CenterZ(Dest, S : PAnsiChar; Len : Cardinal) : PAnsiChar;
1010     {-Return a string centered in a blank string of specified width}
1011     begin
1012     StrCopy(Dest, S);
1013     Result := CenterPrimZ(Dest, Len);
1014     end;
1015    
1016     function ScramblePrimZ(S, Key : PAnsiChar) : PAnsiChar;
1017     {-Encrypt / Decrypt string with enhanced XOR encryption. This
1018     primitive version modifies the source string directly.}
1019     var
1020     SPtr, KPtr, EndPtr : PAnsiChar;
1021     begin
1022     Result := S;
1023     if Key^ = #0 then Exit;
1024     if S^ = #0 then Exit;
1025     SPtr := S;
1026     EndPtr := StrEnd(Key);
1027     Dec(EndPtr);
1028     KPtr := EndPtr;
1029     while SPtr^ <> #0 do begin
1030     if KPtr < Key then
1031     KPtr := EndPtr;
1032     if (SPtr^ <> KPtr^) then
1033     SPtr^ := AnsiChar(Byte(SPtr^) xor Byte(KPtr^));
1034     Inc(SPtr);
1035     Dec(KPtr);
1036     end;
1037     end;
1038    
1039     function ScrambleZ(Dest, S, Key : PAnsiChar) : PAnsiChar;
1040     {-Encrypt / Decrypt string with enhanced XOR encryption.}
1041     begin
1042     StrCopy(Dest, S);
1043     Result := ScramblePrimZ(Dest, Key);
1044     end;
1045    
1046     function SubstituteZ(Dest, Src, FromStr, ToStr : PAnsiChar) : PAnsiChar;
1047     {-Return string S after mapping characters found in FromStr to the
1048     corresponding ones in ToStr}
1049     var
1050     I : Cardinal;
1051     P : Cardinal;
1052     L : Cardinal;
1053     begin
1054     StrCopy(Dest, Src);
1055     if StrLen(FromStr) = StrLen(ToStr) then begin
1056     L := StrLen(Dest);
1057     if L > 0 then
1058     for I := 0 to L-1 do begin
1059     if StrChPosZ(FromStr, Dest[I], P) then
1060     Dest[I] := ToStr[P];
1061     end;
1062     end;
1063     Result := Dest;
1064     end;
1065    
1066     function FilterZ(Dest, Src, Filters : PAnsiChar) : PAnsiChar;
1067     {-Return string S after removing all characters in Filters from it}
1068     var
1069     I : Cardinal;
1070     Len : Cardinal;
1071     L : Cardinal;
1072     begin
1073     Result := Dest;
1074     StrCopy(Dest, Src);
1075     Len := 0;
1076     L := StrLen(Dest);
1077     if L > 0 then
1078     for I := 0 to L-1 do
1079     if not CharExistsZ(Filters, Dest[I]) then begin
1080     Result[Len] := Dest[I];
1081     inc(Len);
1082     end;
1083     Result[Len] := #0;
1084     end;
1085    
1086     function EntabZ(Dest, Src : PAnsiChar; TabSize : Byte) : PAnsiChar;
1087     {-Convert blanks in a string to tabs on spacing TabSize}
1088     register;
1089     asm
1090     push eax { Save registers }
1091     push ebx
1092     push edi
1093     push esi
1094    
1095     mov edi, eax
1096     and ecx, 0FFh { zero all but low byte of ECX }
1097     jz @@Done
1098     mov esi, edx
1099     xor ebx, ebx { Zero EBX and EDX }
1100     xor edx, edx
1101     inc edx { Set EDX to 1 }
1102    
1103     @@Next:
1104     or ebx, ebx
1105     je @@NoTab { Jump to NoTab if spacecount is zero }
1106     mov eax, edx { IPos to EAX }
1107     push edx
1108     xor edx, edx
1109     div ecx
1110     cmp edx, 1 { Is mod = 1? }
1111     pop edx
1112     jne @@NoTab { If not, no tab }
1113    
1114     sub edi, ebx
1115     mov byte ptr [edi], 9h { Store a tab }
1116     inc edi
1117     xor ebx, ebx { Reset spacecount }
1118    
1119     @@NoTab:
1120     mov al, [esi] { Get next input character }
1121     inc esi
1122     or al, al { End of string? }
1123     jz @@Done { Yes, done }
1124     inc ebx { Increment SpaceCount }
1125     cmp al, 20h { Is character a space? }
1126     jz @@Store { Yes, store it for now }
1127     xor ebx, ebx { Reset SpaceCount }
1128     cmp al, 27h { Is it a quote? }
1129     jz @@Quotes { Yep, enter quote loop }
1130     cmp al, 22h { Is it a doublequote? }
1131     jnz @@Store { Nope, store it }
1132    
1133     @@Quotes:
1134     mov ah, al { Save quote start }
1135    
1136     @@NextQ:
1137     mov [edi], al { Store quoted character }
1138     inc edi
1139     mov al, [esi] { Get next character }
1140     inc esi
1141     inc edx { Increment Ipos }
1142     cmp edx, ecx { At end of line? }
1143     jae @@Store { If so, exit quote loop }
1144    
1145     cmp al, ah { Matching end quote? }
1146     jnz @@NextQ { Nope, stay in quote loop }
1147     cmp al, 27h { Single quote? }
1148     jz @@Store { Exit quote loop }
1149     cmp byte ptr [esi-2],'\' { Previous character an escape? }
1150     jz @@NextQ { Stay in if so }
1151    
1152     @@Store:
1153     mov [edi], al { Store last character }
1154     inc edi
1155     inc edx { Increment input position }
1156     jmp @@Next { Repeat while characters left }
1157    
1158     @@Done:
1159     mov byte ptr [edi], 0h
1160     pop esi
1161     pop edi
1162     pop ebx
1163     pop eax
1164     end;
1165    
1166     function DetabZ(Dest, Src : PAnsiChar; TabSize : Byte) : PAnsiChar;
1167     { -Expand tabs in a string to blanks on spacing TabSize- }
1168     register;
1169     asm
1170     push eax { Save Dest for return value }
1171     push edi { Save EDI, ESI and EBX, we'll be changing them }
1172     push esi
1173     push ebx
1174    
1175     mov esi, edx { ESI -> Src }
1176     mov edi, eax { EDI -> Dest }
1177     xor ebx, ebx { Get TabSize in EBX }
1178     add bl, cl
1179     jz @@Done { Exit if TabSize is zero }
1180    
1181     xor edx, edx { Set output length to zero }
1182    
1183     @@Next:
1184     mov al, [esi]
1185     inc esi { Get next input character }
1186     or al, al { Is it a null? }
1187     jz @@Done { Yes-all done }
1188     cmp al, 09 { Is it a tab? }
1189     je @@Tab { Yes, compute next tab stop }
1190     mov [edi], al { No, store to output }
1191     inc edi
1192     inc edx { Increment output length }
1193     jmp @@Next { Next character }
1194    
1195     @@Tab:
1196     push edx { Save output length }
1197     mov eax, edx { Get current output length in EDX:EAX }
1198     xor edx, edx
1199     div ebx { Output length MOD TabSize in DX }
1200     mov ecx, ebx { Calc number of spaces to insert... }
1201     sub ecx, edx { = TabSize - Mod value }
1202     pop edx
1203     add edx, ecx { Add count of spaces into current output length }
1204    
1205     mov eax,$2020 { Blank in AH, Blank in AL }
1206     shr ecx, 1 { Store blanks }
1207     rep stosw
1208     adc ecx, ecx
1209     rep stosb
1210     jmp @@Next { Back for next input }
1211    
1212     @@Done:
1213     mov byte ptr [edi], 0h { Store final null terminator }
1214    
1215     pop ebx { Restore caller's EBX, ESI and EDI }
1216     pop esi
1217     pop edi
1218     pop eax { Return Dest }
1219     end;
1220    
1221     function HasExtensionZ(Name : PAnsiChar; var DotPos : Cardinal) : Boolean;
1222     {-Return whether and position of extension separator dot in a pathname}
1223     var
1224     I, L : Integer;
1225     Pos : Cardinal;
1226     P : TSmallArrayA;
1227     begin
1228     I := -1;
1229     DotPos := Cardinal(I);
1230     Result := False;
1231     L := StrLen(Name);
1232     if L = 0 then
1233     Exit;
1234     for I := L-1 downto 0 do
1235     if (Name[I] = '.') and (DotPos = Cardinal(-1)) then
1236     DotPos := I;
1237     Result := (DotPos <> Cardinal(-1)) and not
1238     StrChPosZ(StrStCopyZ(P, Name, Succ(DotPos), StMaxFileLen), '\', Pos);
1239     end;
1240    
1241     {$IFDEF UNICODE}
1242     function HasExtensionZ(Name : PWideChar; var DotPos : Cardinal) : Boolean;
1243     {-Return whether and position of extension separator dot in a pathname}
1244     var
1245     I, L : Integer;
1246     Pos : Cardinal;
1247     P : TSmallArray;
1248     begin
1249     I := -1;
1250     DotPos := Cardinal(I);
1251     Result := False;
1252     L := StrLen(Name);
1253     if L = 0 then
1254     Exit;
1255     for I := L-1 downto 0 do
1256     if (Name[I] = '.') and (DotPos = Cardinal(-1)) then
1257     DotPos := I;
1258     Result := (DotPos <> Cardinal(-1)) and not
1259     StrChPosZ(StrStCopyZ(P, Name, Succ(DotPos), StMaxFileLen), '\', Pos);
1260     end;
1261     {$ENDIF}
1262    
1263    
1264     function DefaultExtensionZ(Dest : PAnsiChar; Name, Ext : PAnsiChar) : PAnsiChar;
1265     {-Return a pathname with the specified extension attached}
1266     var
1267     DotPos : Cardinal;
1268     begin
1269     if HasExtensionZ(Name, DotPos) then
1270     StrCopy(Dest, Name)
1271     else if StrLen(Name) = 0 then
1272     Dest[0] := #0
1273     else begin
1274     StrCopy(Dest, Name);
1275     StrCat(Dest, '.');
1276     StrCat(Dest, Ext);
1277     end;
1278     Result := Dest;
1279     end;
1280    
1281     function ForceExtensionZ(Dest : PAnsiChar; Name, Ext : PAnsiChar) : PAnsiChar;
1282     {-Return a pathname with the specified extension attached}
1283     var
1284     DotPos : Cardinal;
1285     begin
1286     if HasExtensionZ(Name, DotPos) then
1287     Dest := StrCat(StrStCopyZ(Dest, Name, 0, Succ(DotPos)), Ext)
1288     else if StrLen(Name) = 0 then
1289     Dest[0] := #0
1290     else begin
1291     Dest := StrCopy(Dest, Name);
1292     Dest := StrCat(Dest, '.');
1293     Dest := StrCat(Dest, Ext);
1294     end;
1295     Result := Dest;
1296     end;
1297    
1298     function JustExtensionZ(Dest : PAnsiChar; Name : PAnsiChar) : PAnsiChar;
1299     {-Return just the extension of a pathname}
1300     var
1301     DotPos : Cardinal;
1302     begin
1303     if HasExtensionZ(Name, DotPos) then
1304     Dest := StrStCopyZ(Dest, Name, Succ(DotPos), StMaxFileLen)
1305     else
1306     Dest[0] := #0;
1307     Result := Dest;
1308     end;
1309    
1310     function JustFilenameZ(Dest : PAnsiChar; PathName : PAnsiChar) : PAnsiChar;
1311     {-Return just the filename of a pathname}
1312     var
1313     I : Integer;
1314     begin
1315     I := StrLen(PathName);
1316     while (I > 0) and (not (PathName[I-1] in DosDelimSet)) do
1317     Dec(I);
1318     Dest := StrStCopyZ(Dest, PathName, I, StMaxFileLen);
1319     Result := Dest;
1320     end;
1321    
1322     {$IFDEF UNICODE}
1323     function JustFilenameZ(Dest : PWideChar; PathName : PWideChar) : PWideChar;
1324     {-Return just the filename of a pathname}
1325     var
1326     I : Integer;
1327     begin
1328     I := StrLen(PathName);
1329     while (I > 0) and (not (PathName[I-1] in DosDelimSet)) do
1330     Dec(I);
1331     Dest := StrStCopyZ(Dest, PathName, I, StMaxFileLen);
1332     Result := Dest;
1333     end;
1334     {$ENDIF}
1335    
1336    
1337     function JustNameZ(Dest : PAnsiChar; PathName : PAnsiChar) : PAnsiChar;
1338     {-Return just the name (no extension, no path) of a pathname}
1339     var
1340     DotPos : Cardinal;
1341     T : TSmallArrayA;
1342     begin
1343     JustFileNameZ(T, PathName);
1344     if HasExtensionZ(T, DotPos) then
1345     Dest := StrStCopyZ(Dest, T, 0, DotPos)
1346     else
1347     StrCopy(Dest, T);
1348     Result := Dest;
1349     end;
1350    
1351     function JustPathnameZ(Dest : PAnsiChar; PathName : PAnsiChar) : PAnsiChar;
1352     {-Return just the drive:directory portion of a pathname}
1353     var
1354     I : Longint;
1355     begin
1356     I := StrLen(PathName);
1357     repeat
1358     Dec(I);
1359     until (I = -1) or (PathName[I] in DosDelimSet);
1360    
1361     if I = -1 then
1362     {Had no drive or directory name}
1363     Dest[0] := #0
1364     else if I = 0 then begin
1365     {Either the root directory of default drive or invalid pathname}
1366     Dest[0] := PathName[0];
1367     Dest[1] := #0;
1368     end
1369     else if (PathName[I] = '\') then begin
1370     if PathName[Pred(I)] = ':' then
1371     {Root directory of a drive, leave trailing backslash}
1372     Dest := StrStCopyZ(Dest, PathName, 0, Succ(I))
1373     else
1374     {Subdirectory, remove the trailing backslash}
1375     Dest := StrStCopyZ(Dest, PathName, 0, I);
1376     end else
1377     {Either the default directory of a drive or invalid pathname}
1378     Dest:= StrStCopyZ(Dest, PathName, 0, Succ(I));
1379     Result := Dest;
1380     end;
1381    
1382     function AddBackSlashZ(Dest : PAnsiChar; DirName : PAnsiChar) : PAnsiChar;
1383     {-Add a default backslash to a directory name}
1384     var
1385     L : Integer;
1386     begin
1387     Result := Dest;
1388     StrCopy(Dest, DirName);
1389     L := StrLen(DirName);
1390     if (L > 0) then begin
1391     if ((L = 2) and (Dest[1] = ':')) or
1392     ((L > 2) and (Dest[L-1] <> '\')) then begin
1393     Dest[L] := '\';
1394     Dest[L+1] := #0;
1395     end;
1396     end;
1397     end;
1398    
1399     function CleanFileNameZ(Dest, FileName : PAnsiChar) : PAnsiChar;
1400     {-Return filename with at most 8 chars of name and 3 of extension}
1401     var
1402     DotPos : Cardinal;
1403     NameLen : Integer;
1404     P2 : TSmallArrayA;
1405     begin
1406     if HasExtensionZ(FileName, DotPos) then begin
1407     {Take the first 8 chars of name and first 3 chars of extension}
1408     NameLen := DotPos;
1409     if NameLen > 8 then
1410     NameLen := 8;
1411     StrStCopyZ(Dest, FileName, 0, NameLen);
1412     StrCat(Dest, StrStCopyZ(P2, FileName, DotPos, 4));
1413     end else
1414     {Take the first 8 chars of name}
1415     StrStCopyZ(Dest, FileName, 0, 8);
1416     Result := Dest;
1417     end;
1418    
1419     function CleanPathNameZ(Dest : PAnsiChar; PathName : PAnsiChar) : PAnsiChar;
1420     {-Return a pathname cleaned up as DOS will do it}
1421     var
1422     I : Word;
1423     S1, S, OName : TSmallArrayA;
1424     begin
1425     Result := Dest;
1426     StrCopy(Dest, PathName);
1427     I := StrLen(PathName);
1428     OName[0] := #0;
1429     while I > 0 do begin
1430     Dec(I);
1431     if I > 1 then
1432     if (Dest[I] = '\') and (Dest[I-1] = '\') then
1433     if (Dest[I-2] <> ':') then
1434     StrChDeletePrimZ(Dest, I);
1435     end;
1436     I := StrLen(Dest);
1437     while I > 0 do begin
1438     Dec(I);
1439     {Get the next directory or drive portion of pathname}
1440     while ((I > 0) and not (Dest[I] in DosDelimSet)) do {!!.02}
1441     Dec(I);
1442     {Clean it up and prepend it to output string}
1443     StrStCopyZ(S1, Dest, I + 1, StMaxFileLen);
1444     StrCopy(S, OName);
1445     CleanFileNameZ(OName, S1);
1446     StrCat(OName, S);
1447     {if I >= 0 then begin}
1448     StrCopy(S, OName);
1449     StrStCopyZ(OName, Dest, I, 1);
1450     StrCat(OName, S);
1451     StrStDeletePrimZ(Dest, I, 255);
1452     {end;}
1453     end;
1454     StrCopy(Dest, OName);
1455     end;
1456    
1457     function ConvertToShortString(S : PAnsiChar; var SS : ShortString) : integer;
1458    
1459     var
1460     LenS : integer;
1461     begin
1462     {returns 0 if the string was converted successfully
1463     1 if the string is nil
1464     2 if the string length is greater than 255}
1465     if (S = nil) then begin
1466     Result := 1;
1467     end
1468     else begin
1469     LenS := StrLen(S);
1470     if (LenS > 255) then begin
1471     Result := 2;
1472     end
1473     else begin
1474     {we can't use StrPas in 32-bit since it assumes a long string
1475     and that would incur too much overhead, so convert to a short
1476     string from first principles}
1477     Move(S^, SS[1], LenS);
1478     SetLength(SS, LenS);
1479     Result := 0;
1480     end;
1481     end;
1482     end;
1483    
1484     function Str2Int16Z(S : PAnsiChar; var I : SmallInt) : Boolean;
1485     {-Convert a string to an integer, returning true if successful}
1486    
1487     var
1488     ec : integer;
1489     SS : ShortString;
1490     begin
1491     case ConvertToShortString(S, SS) of
1492     0 : begin {success}
1493     ValSmallint(SS, I, ec);
1494     if (ec = 0) then
1495     Result := true
1496     else begin
1497     Result := false;
1498     if (ec < 0) then
1499     I := StrLen(S)
1500     else
1501     I := pred(ec); {null terminated strings are zero-based}
1502     end;
1503     end;
1504     1 : begin {S is nil}
1505     Result := false;
1506     I := 0;
1507     end;
1508     2 : begin {S is more than 255 characters long}
1509     Result := false;
1510     I := 256;
1511     end;
1512     else
1513     Result := false;
1514     end;
1515     end;
1516    
1517     function Str2WordZ(S : PAnsiChar; var I : Word) : Boolean;
1518     {-Convert a string to a word, returning true if successful}
1519    
1520     var
1521     ec : integer;
1522     SS : ShortString;
1523     begin
1524     case ConvertToShortString(S, SS) of
1525     0 : begin {success}
1526     ValWord(SS, I, ec);
1527     if (ec = 0) then
1528     Result := true
1529     else begin
1530     Result := false;
1531     if (ec < 0) then
1532     I := StrLen(S)
1533     else
1534     I := pred(ec); {null terminated strings are zero-based}
1535     end;
1536     end;
1537     1 : begin {S is nil}
1538     Result := false;
1539     I := 0;
1540     end;
1541     2 : begin {S is more than 255 characters long}
1542     Result := false;
1543     I := 256;
1544     end;
1545     else
1546     Result := false;
1547     end;
1548     end;
1549    
1550     function Str2LongZ(S : PAnsiChar; var I : LongInt) : Boolean;
1551     {-Convert a string to a longint, returning true if successful}
1552    
1553     var
1554     ec : integer;
1555     SS : ShortString;
1556     begin
1557     case ConvertToShortString(S, SS) of
1558     0 : begin {success}
1559     ValLongint(SS, I, ec);
1560     if (ec = 0) then
1561     Result := true
1562     else begin
1563     Result := false;
1564     if (ec < 0) then
1565     I := StrLen(S)
1566     else
1567     I := pred(ec); {null terminated strings are zero-based}
1568     end;
1569     end;
1570     1 : begin {S is nil}
1571     Result := false;
1572     I := 0;
1573     end;
1574     2 : begin {S is more than 255 characters long}
1575     Result := false;
1576     I := 256;
1577     end;
1578     else
1579     Result := false;
1580     end;
1581     end;
1582    
1583     {$IFDEF VER93}
1584     function Str2RealZ(S : PAnsiChar; var R : Double) : Boolean;
1585     {$ELSE}
1586     function Str2RealZ(S : PChar; var R : Real) : Boolean;
1587     {$ENDIF}
1588     {-Convert a string to a real, returning true if successful}
1589     var
1590     Code : Integer;
1591     P : TSmallArray;
1592     begin
1593     if StrLen(S)+1 > SizeOf(P) then begin
1594     Result := False;
1595     R := -1;
1596     Exit;
1597     end;
1598     StrCopy(P, S);
1599     TrimTrailPrimZ(P);
1600     Val(ValPrepZ(P), R, Code);
1601     if Code <> 0 then begin
1602     R := Code - 1;
1603     Result := False;
1604     end else
1605     Result := True;
1606     end;
1607    
1608     function Str2ExtZ(S : PAnsiChar; var R : Extended) : Boolean;
1609     {-Convert a string to an extended, returning true if successful}
1610     var
1611     Code : Integer;
1612     P : TSmallArrayA;
1613     begin
1614     if StrLen(S)+1 > SizeOf(P) then begin
1615     Result := False;
1616     R := -1;
1617     Exit;
1618     end;
1619     StrCopy(P, S);
1620     TrimTrailPrimZ(P);
1621     Val(ValPrepZ(P), R, Code);
1622     if Code <> 0 then begin
1623     R := Code - 1;
1624     Result := False;
1625     end else
1626     Result := True;
1627     end;
1628    
1629     function Long2StrZ(Dest : PAnsiChar; L : LongInt) : PAnsiChar;
1630     {-Convert a long/word/integer/byte/shortint to a string}
1631     type
1632     PCharArray = ^TCharArray;
1633     TCharArray = array[0..99] of AnsiChar;
1634     begin
1635     Str(L, PCharArray(Dest)^);
1636     Result := Dest;
1637     end;
1638    
1639     function Real2StrZ(Dest : PAnsiChar; R : Double; Width : Byte;
1640     Places : ShortInt) : PAnsiChar;
1641     {-Convert a real to a string}
1642     type
1643     PCharArray = ^TCharArray;
1644     TCharArray = array[0..99] of AnsiChar;
1645     begin
1646     Str(R:Width:Places, PCharArray(Dest)^);
1647     Result := Dest;
1648     end;
1649    
1650     function Ext2StrZ(Dest : PAnsiChar; R : Extended; Width : Byte;
1651     Places : ShortInt) : PAnsiChar;
1652     {-Convert an extended to a string}
1653     type
1654     PCharArray = ^TCharArray;
1655     TCharArray = array[0..99] of AnsiChar;
1656     begin
1657     Str(R:Width:Places, PCharArray(Dest)^);
1658     Result := Dest;
1659     end;
1660    
1661     function ValPrepZ(S : PAnsiChar) : PAnsiChar;
1662     {-Prepares a string for calling Val.}
1663     var
1664     P : Cardinal;
1665     begin
1666     Result := TrimSpacesPrimZ(S);
1667     if StrLen(Result) <> 0 then begin
1668     if StrChPosZ(Result, AnsiChar({$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator), P) then begin
1669     Result[P] := '.';
1670     if Succ(P) = StrLen(Result) then
1671     Result[P] := #0;
1672     end;
1673     end else begin
1674     Result := '0';
1675     end;
1676     end;
1677    
1678     {$IFDEF UNICODE}
1679     function ValPrepZ(S : PWideChar) : PWideChar;
1680     {-Prepares a string for calling Val.}
1681     var
1682     P : Cardinal;
1683     begin
1684     Result := TrimSpacesPrimZ(S);
1685     if StrLen(Result) <> 0 then begin
1686     if StrChPosZ(Result, {$IFDEF DELPHIXE2}FormatSettings.{$ENDIF}DecimalSeparator, P) then begin
1687     Result[P] := '.';
1688     if Succ(P) = StrLen(Result) then
1689     Result[P] := #0;
1690     end;
1691     end else begin
1692     Result := '0';
1693     end;
1694     end;
1695     {$ENDIF}
1696    
1697     function CharExistsZ(S : PAnsiChar; C : AnsiChar) : Boolean;
1698     {-Determine whether the given character exists in a string. }
1699     register;
1700     asm
1701     xor dh, dh
1702     xor ecx, ecx
1703     @@Loop:
1704     cmp dh, [eax+0]
1705     je @@Done
1706     cmp dl, [eax+0]
1707     jne @@1
1708     inc ecx
1709     jmp @@Done
1710     @@1:
1711     cmp dh, [eax+1]
1712     je @@Done
1713     cmp dl, [eax+1]
1714     jne @@2
1715     inc ecx
1716     jmp @@Done
1717     @@2:
1718     cmp dh, [eax+2]
1719     je @@Done
1720     cmp dl, [eax+2]
1721     jne @@3
1722     inc ecx
1723     jmp @@Done
1724     @@3:
1725     cmp dh, [eax+3]
1726     je @@Done
1727     cmp dl, [eax+3]
1728     jne @@4
1729     inc ecx
1730     jmp @@Done
1731     @@4:
1732     add eax, 4
1733     jmp @@Loop
1734     @@Done:
1735     mov eax, ecx
1736     end;
1737    
1738     function CharExistsZ(S : PWideChar; C : Char) : Boolean; //SZ
1739     {-Determine whether the given character exists in a string. }
1740     register;
1741     asm
1742     xor dx, dx
1743     xor ecx, ecx
1744     @@Loop:
1745     cmp dx, [eax+0]
1746     je @@Done
1747     cmp dx, [eax+0]
1748     jne @@1
1749     inc ecx
1750     inc ecx
1751     jmp @@Done
1752     @@1:
1753     cmp dx, [eax+2]
1754     je @@Done
1755     cmp dx, [eax+2]
1756     jne @@2
1757     inc ecx
1758     inc ecx
1759     jmp @@Done
1760     @@2:
1761     cmp dx, [eax+4]
1762     je @@Done
1763     cmp dx, [eax+4]
1764     jne @@3
1765     inc ecx
1766     inc ecx
1767     jmp @@Done
1768     @@3:
1769     cmp dx, [eax+6]
1770     je @@Done
1771     cmp dx, [eax+6]
1772     jne @@4
1773     inc ecx
1774     inc ecx
1775     jmp @@Done
1776     @@4:
1777     add eax, 8
1778     jmp @@Loop
1779     @@Done:
1780     mov eax, ecx
1781     end;
1782    
1783    
1784     function CharCountZ(S : PAnsiChar; C : AnsiChar) : Cardinal;
1785     {-Count the number of a given character in a string. }
1786     register;
1787     asm
1788     xor dh, dh
1789     xor ecx, ecx
1790     @@Loop:
1791     cmp dh, [eax+0]
1792     je @@Done
1793     cmp dl, [eax+0]
1794     jne @@1
1795     inc ecx
1796     @@1:
1797     cmp dh, [eax+1]
1798     je @@Done
1799     cmp dl, [eax+1]
1800     jne @@2
1801     inc ecx
1802     @@2:
1803     cmp dh, [eax+2]
1804     je @@Done
1805     cmp dl, [eax+2]
1806     jne @@3
1807     inc ecx
1808     @@3:
1809     cmp dh, [eax+3]
1810     je @@Done
1811     cmp dl, [eax+3]
1812     jne @@4
1813     inc ecx
1814     @@4:
1815     add eax, 4
1816     jmp @@Loop
1817     @@Done:
1818     mov eax, ecx
1819     end;
1820    
1821     function WordCountZ(S : PAnsiChar; WordDelims : PAnsiChar) : Cardinal;
1822     {-Given a set of word delimiters, return number of words in S}
1823     var
1824     Count : Cardinal;
1825     I : Cardinal;
1826     SLen : Cardinal;
1827    
1828     begin
1829     Count := 0;
1830     I := 0;
1831     SLen := StrLen(S);
1832     while I < SLen do begin
1833     {skip over delimiters}
1834     while (I < SLen) and (CharExistsZ(WordDelims, S^)) do begin
1835     Inc(I);
1836     Inc(S);
1837     end;
1838     {if we're not beyond end of S, we're at the start of a word}
1839     if I < SLen then
1840     Inc(Count);
1841    
1842     {find the end of the current word}
1843     while (I < SLen) and (not CharExistsZ(WordDelims, S^)) do begin
1844     Inc(I);
1845     Inc(S);
1846     end;
1847     end;
1848    
1849     Result := Count;
1850     end;
1851    
1852     function WordPositionZ(N : Cardinal; S : PAnsiChar; WordDelims : PAnsiChar;
1853     var Pos : Cardinal) : Boolean;
1854     {-Given a set of word delimiters, return start position of N'th word in S}
1855     var
1856     Count : Cardinal;
1857     SLen : Cardinal;
1858     begin
1859     Count := 0;
1860     Pos := 0;
1861     Result := False;
1862     SLen := StrLen(S);
1863    
1864     while (Pos < SLen) and (Count <> N) do begin
1865     {skip over delimiters}
1866     while (Pos < SLen) and (CharExistsZ(WordDelims, S^)) do begin
1867     Inc(Pos);
1868     Inc(S);
1869     end;
1870     {if we're not beyond end of S, we're at the start of a word}
1871     if Pos < SLen then
1872     Inc(Count);
1873    
1874     {if not finished, find the end of the current word}
1875     if Count <> N then begin
1876     while (Pos < SLen) and (not CharExistsZ(WordDelims, S^)) do begin
1877     Inc(Pos);
1878     Inc(S);
1879     end;
1880     end
1881     else
1882     Result := True;
1883     end;
1884     end;
1885    
1886     function ExtractWordZ(Dest : PAnsiChar; N : Cardinal; Src : PAnsiChar;
1887     WordDelims : PAnsiChar) : PAnsiChar;
1888     {-Given a set of word delimiters, return in Dest the N'th word in Src}
1889     var
1890     I : Cardinal;
1891     SLen : Cardinal;
1892     begin
1893     Result := Dest;
1894     SLen := StrLen(Src);
1895     if WordPositionZ(N, Src, WordDelims, I) then begin
1896     Inc(Src, I);
1897     {find the end of the current word}
1898     while (I <= SLen) and (not CharExistsZ(WordDelims, Src^)) do begin
1899     {add the I'th character to result}
1900     Dest^ := Src^;
1901     Inc(Dest);
1902     Inc(Src);
1903     Inc(I);
1904     end;
1905     end;
1906     Dest^ := #0;
1907     end;
1908    
1909     function AsciiCountZ(S : PAnsiChar; WordDelims : PAnsiChar; Quote : AnsiChar) : Cardinal;
1910     {-Given a set of word delimiters, return number of words in S}
1911     var
1912     Count : Cardinal;
1913     I : Cardinal;
1914     SLen : Cardinal;
1915     InQuote : Boolean;
1916     begin
1917     Count := 0;
1918     I := 1;
1919     InQuote := False;
1920     SLen := StrLen(S);
1921     while I <= SLen do begin
1922     {skip over delimiters}
1923     while (I <= SLen) and (S^ <> Quote) and CharExistsZ(WordDelims, S^) do begin
1924     Inc(I);
1925     Inc(S);
1926     end;
1927     {if we're not beyond end of S, we're at the start of a word}
1928     if I <= SLen then
1929     Inc(Count);
1930     {find the end of the current word}
1931     while (I <= SLen) and ((InQuote) or (not CharExistsZ(WordDelims, S^))) do begin
1932     if S^ = Quote then
1933     InQuote := not(InQuote);
1934     Inc(I);
1935     Inc(S);
1936     end;
1937     end;
1938    
1939     Result := Count;
1940     end;
1941    
1942     function AsciiPositionZ(N : Cardinal; S : PAnsiChar; WordDelims : PAnsiChar;
1943     Quote : AnsiChar; var Pos : Cardinal) : Boolean;
1944     {-Given a set of word delimiters, return start position of N'th word in S}
1945     var
1946     Count : Cardinal;
1947     SLen : Cardinal;
1948     InQuote : Boolean;
1949     begin
1950     Count := 0;
1951     Pos := 0;
1952     InQuote := False;
1953     Result := False;
1954     SLen := StrLen(S);
1955     while (Pos < SLen) and (Count <= N) do begin
1956     {skip over delimiters}
1957     while (Pos < SLen) and (S^ <> Quote) and CharExistsZ(WordDelims, S^) do begin
1958     Inc(Pos);
1959     Inc(S);
1960     end;
1961    
1962     {if we're not beyond end of S, we're at the start of a word}
1963     if Pos < SLen then
1964     Inc(Count);
1965    
1966     {if not finished, find the end of the current word}
1967     if Count <> N then
1968     while (Pos < SLen) and ((InQuote) or (not CharExistsZ(WordDelims, S^))) do begin
1969     if S^ = Quote then
1970     InQuote := not(InQuote);
1971     Inc(Pos);
1972     Inc(S);
1973     end
1974     else begin
1975     Result := True;
1976     Exit;
1977     end;
1978     end;
1979     end;
1980    
1981     function ExtractAsciiZ(Dest : PAnsiChar; N : Cardinal; Src : PAnsiChar;
1982     WordDelims : PAnsiChar; Quote : AnsiChar) : PAnsiChar;
1983     {-Given a set of word delimiters, return in Dest the N'th word in Src}
1984     var
1985     I : Cardinal;
1986     Len : Cardinal;
1987     SLen : Cardinal;
1988     InQuote : Boolean;
1989     begin
1990     Len := 0;
1991     InQuote := False;
1992     Dest[0] := #0;
1993     Result := Dest;
1994     SLen := StrLen(Src);
1995     if AsciiPositionZ(N, Src, WordDelims, Quote, I) then
1996     {find the end of the current word}
1997     while (I < SLen) and ((InQuote) or (not CharExistsZ(WordDelims, Src[I]))) do begin
1998     {add the I'th character to result}
1999     if Src[I] = Quote then
2000     InQuote := Not(InQuote);
2001     Dest[Len] := Src[I];
2002     Inc(Len);
2003     Inc(I);
2004     end;
2005     Dest[Len] := #0;
2006     end;
2007    
2008     procedure WordWrapZ(Dest : PAnsiChar; InSt, Overlap : PAnsiChar;
2009     Margin : Cardinal;
2010     PadToMargin : Boolean);
2011     {-Wrap InSt at Margin, storing the result in Dest and the remainder
2012     in Overlap}
2013     var
2014     InStLen : Cardinal;
2015     OutStLen : Cardinal;
2016     OvrLen : Cardinal;
2017     EOS, BOS : Cardinal;
2018     begin
2019     OutStLen := 0;
2020     InStLen := StrLen(InSt);
2021    
2022     {!!.02 - Added }
2023     { handle empty string on input }
2024     if InStLen = 0 then begin
2025     if Assigned(Dest) then
2026     Dest[0] := #0;
2027     if Assigned(Overlap) then
2028     Overlap[0] := #0;
2029     Exit;
2030     end;
2031     {!!.02 - End Added }
2032    
2033     {find the end of the new output string}
2034     if InStLen > Margin then begin
2035     {assume this is a good break point}
2036     EOS := Margin-1;
2037    
2038     {is this the position of the last character of a word}
2039     if InSt[EOS+1] <> ' ' then begin {check next char}
2040     {look for the space before the current word}
2041     while (EOS > 0) and (InSt[EOS] <> ' ') do
2042     Dec(EOS);
2043     {when done, EOS points to a space char or is zero}
2044    
2045     {if EOS = 0 then - can't wrap it properly}
2046     if EOS = 0 then
2047     EOS := Margin-1 {set up to break line at margin}
2048     else
2049     while (InSt[EOS] = ' ') and (EOS > 0) do {trim trailing blanks}
2050     Dec(EOS);
2051     end else
2052     while (EOS > 0) and (InSt[EOS] = ' ') do {trim trailing blanks}
2053     Dec(EOS);
2054     end
2055     else
2056     EOS := InStLen-1;
2057    
2058     {at this point EOS points to the break point, the end of the line,
2059     or is zero}
2060    
2061     {copy the unwrapped portion of the line}
2062     if (EOS = 0) and (InSt[EOS] = ' ') then
2063     Dest[0] := #0
2064     else begin
2065     OutStLen := EOS+1;
2066     Move(InSt^, Dest^, OutStLen);
2067     Dest[OutStLen] := #0;
2068     end;
2069    
2070     {find the start of the next word in the line}
2071     BOS := EOS+1;
2072     while (BOS < InStLen) and (InSt[BOS] = ' ') do
2073     Inc(BOS);
2074    
2075     if BOS >= InStLen then begin
2076     OverLap[0] := #0;
2077     end else begin
2078     {copy from the start of the next word to the end of the line}
2079     OvrLen := InStLen-BOS;
2080     Move(InSt[BOS], Overlap^, OvrLen);
2081     Overlap[OvrLen] := #0;
2082     end;
2083    
2084     {pad the end of the output string if requested}
2085     if PadToMargin and (OutStLen < Margin) then begin
2086     FillChar(Dest[OutStLen], Margin-OutStLen, ' ');
2087     Dest[Margin] := #0;
2088     end;
2089     end;
2090    
2091     function CompStringZ(S1, S2 : PAnsiChar) : Integer;
2092     {-Return -1, 0, 1 if S1<S2, S1=S2, or S1>S2}
2093     register;
2094     asm
2095     push ebx
2096     push edi
2097     push esi
2098    
2099     mov edi, eax
2100     mov esi, eax
2101     xor eax, eax
2102     or ecx, -1
2103     repne scasb
2104     not ecx
2105     dec ecx
2106    
2107     mov edi, edx
2108     mov ebx, edx
2109     mov edx, ecx
2110     or ecx, -1
2111     repne scasb
2112     not ecx
2113     dec ecx
2114     mov edi, ebx
2115     or ebx, -1
2116     cmp edx, ecx
2117     je @@EqLen
2118     jb @@Comp
2119    
2120     inc ebx
2121     mov ecx, edx
2122    
2123     @@EqLen:
2124     inc ebx
2125    
2126     @@Comp:
2127     or ecx, ecx
2128     jz @@Done
2129    
2130     repe cmpsb
2131     je @@Done
2132    
2133     mov ebx, 1
2134     ja @@Done
2135     or ebx, -1
2136    
2137     @@Done:
2138     mov eax, ebx
2139     pop esi
2140     pop edi
2141     pop ebx
2142     end;
2143    
2144    
2145     function CompUCStringZ(S1, S2 : PAnsiChar) : Integer;
2146     {-Return -1, 0, 1 if s1<s2, s1=s2, or s1>s2. Comparison is done in
2147     uppercase}
2148     register;
2149     asm
2150     push ebx
2151     push edi
2152     push esi
2153    
2154     mov edi, eax
2155     mov esi, eax
2156     xor eax, eax
2157     or ecx, -1
2158     repne scasb
2159     not ecx
2160     dec ecx
2161    
2162     mov edi, edx
2163     mov ebx, edx
2164     mov edx, ecx
2165     or ecx, -1
2166     repne scasb
2167     not ecx
2168     dec ecx
2169     mov edi, ebx
2170     or ebx, -1
2171     cmp edx, ecx
2172     je @@EqLen
2173     jb @@Comp
2174    
2175     inc ebx
2176     mov ecx, edx
2177    
2178     @@EqLen:
2179     inc ebx
2180    
2181     @@Comp:
2182     or ecx, ecx
2183     jz @@Done { Done if either is empty }
2184    
2185     @@Start:
2186     mov al, [esi]
2187     inc esi
2188     push ebx { Save registers }
2189     push ecx
2190     push edx
2191     push eax { Push Char onto stack for CharUpper }
2192     call CharUpper
2193     pop edx { Restore registers }
2194     pop ecx
2195     pop ebx
2196    
2197     mov edx, eax
2198     mov al, [edi]
2199     inc edi
2200    
2201     push ebx { Save registers }
2202     push ecx
2203     push edx
2204     push eax { Push Char onto stack for CharUpper }
2205     call CharUpper
2206     pop edx { Restore registers }
2207     pop ecx
2208     pop ebx
2209    
2210     cmp edx, eax
2211     jne @@Output
2212     dec ecx
2213     jnz @@Start
2214     je @@Done
2215    
2216     @@Output:
2217     mov ebx, 1
2218     ja @@Done
2219     or ebx, -1
2220    
2221     @@Done:
2222     mov eax, ebx
2223     pop esi
2224     pop edi
2225     pop ebx
2226     end;
2227    
2228     function SoundexZ(Dest : PAnsiChar; S : PAnsiChar) : PAnsiChar; assembler;
2229     {-Return 4 character soundex of input string}
2230     register;
2231     const
2232     SoundexTable : array[0..255] of AnsiChar =
2233     (#0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2234     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2235     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2236     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2237     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2238     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2239     #0, #0, #0, #0, #0,
2240     { A B C D E F G H I J K L M }
2241     #0, '1', '2', '3', #0, '1', '2', #0, #0, '2', '2', '4', '5',
2242     { N O P Q R S T U V W X Y X }
2243     '5', #0, '1', '2', '6', '2', '3', #0, '1', #0, '2', #0, '2',
2244     #0, #0, #0, #0, #0, #0,
2245     { a b c d e f g h i j k l m }
2246     #0, '1', '2', '3', #0, '1', '2', #0, #0, '2', '2', '4', '5',
2247     { n o p q r s t u v w x y x }
2248     '5', #0, '1', '2', '6', '2', '3', #0, '1', #0, '2', #0, '2',
2249     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2250     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2251     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2252     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2253     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2254     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2255     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2256     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2257     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2258     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2259     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2260     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2261     #0, #0, #0, #0, #0, #0, #0, #0, #0, #0,
2262     #0, #0, #0);
2263     asm
2264     push eax { Save registers }
2265     push ebx
2266     push edi
2267     push esi
2268     mov edi, edx
2269     mov ebx, eax
2270     mov esi, edx
2271    
2272     mov dword ptr [ebx], '0000' { Initialize output string to '0000'. }
2273     xor eax, eax
2274     mov [ebx+4], al { Set null at end of string. }
2275    
2276     or ecx, -1 { Set ECX to $FFFFFFFF }
2277     repne scasb
2278     not ecx
2279     dec ecx { ECX has length of S }
2280     jz @@Done { Exit if null string. }
2281    
2282     mov edi, ebx
2283     mov al, [esi] { Get first character of input string. }
2284     inc esi
2285    
2286     push ecx { Save ECX across call to CharUpper. }
2287     push eax { Push Char onto stack for CharUpper. }
2288     call CharUpper { Uppercase AL. }
2289     pop ecx { Restore saved register. }
2290    
2291     mov [edi], al { Store first output character. }
2292     inc edi
2293    
2294     dec ecx { One input character used. }
2295     jz @@Done { Was input string one char long?. }
2296    
2297     mov bh, 03h { Output max 3 chars beyond first. }
2298     mov edx, offset SoundexTable { EDX => Soundex table. }
2299     xor eax, eax { Prepare for address calc. }
2300     xor bl, bl { BL will be used to store 'previous char'. }
2301    
2302     @@Next:
2303     mov al, [esi] { Get next char in AL. }
2304     inc esi
2305     mov al, [edx+eax] { Get soundex code into AL. }
2306     or al, al { Is AL zero? }
2307     jz @@NoStore { If yes, skip this char. }
2308     cmp bl, al { Is it the same as the previous stored char? }
2309     je @@NoStore { If yes, skip this char. }
2310     mov [edi], al { Store char to Dest. }
2311     inc edi
2312     dec bh { Decrement output counter. }
2313     jz @@Done { If zero, we're done. }
2314     mov bl, al { New previous character. }
2315    
2316     @@NoStore:
2317     dec ecx { Decrement input counter. }
2318     jnz @@Next
2319    
2320     @@Done: { Restore registers }
2321     pop esi
2322     pop edi
2323     pop ebx
2324     pop eax
2325     end;
2326    
2327     function MakeLetterSetZ(S : PAnsiChar) : Longint;
2328     {-Return a bit-mapped long storing the individual letters contained in S.}
2329     register;
2330     asm
2331     push ebx { Save registers }
2332     push edi
2333     push esi
2334     mov esi, eax
2335     mov edi, eax
2336     xor edx, edx
2337     xor eax, eax { Measure S }
2338     or ecx, -1
2339     repne scasb
2340     not ecx
2341     dec ecx { ECX has length of S }
2342     jz @@Exit
2343    
2344     @@Next:
2345     mov al, [esi] { EAX has next char in S }
2346     inc esi
2347    
2348     push ecx { Save registers }
2349     push edx
2350     push eax { Push Char onto stack for CharUpper }
2351     call CharUpper
2352     pop edx { Restore registers }
2353     pop ecx
2354    
2355     sub eax, 'A' { Convert to bit number }
2356     cmp eax, 'Z'-'A' { Was char in range 'A'..'Z'? }
2357     ja @@Skip { Skip it if not }
2358    
2359     mov ebx, eax { Exchange EAX and ECX }
2360     mov eax, ecx
2361     mov ecx, ebx
2362     ror edx, cl
2363     or edx, 01h { Set appropriate bit }
2364     rol edx, cl
2365     mov ebx, eax { Exchange EAX and ECX }
2366     mov eax, ecx
2367     mov ecx, ebx
2368    
2369     @@Skip:
2370     dec ecx
2371     jnz @@Next { Get next character }
2372    
2373     @@Exit:
2374     mov eax, edx { Move EDX to result }
2375     pop esi
2376     pop edi { Restore registers }
2377     pop ebx
2378     end;
2379    
2380     procedure BMMakeTableZ(MatchString : PAnsiChar; var BT : BTable);
2381     {Build Boyer-Moore link table}
2382     register;
2383     asm
2384     push esi { Save registers because they will be changed }
2385     push edi
2386     push ebx
2387    
2388     mov edi, eax { Move EAX to ESI & EDI }
2389     mov esi, eax
2390     xor eax, eax { Zero EAX }
2391     or ecx, -1
2392     repne scasb { Search for null terminator }
2393     not ecx
2394     dec ecx { ECX is length of search string }
2395     cmp ecx, 0FFh { If ECX > 255, force to 255 }
2396     jbe @@1
2397     mov ecx, 0FFh
2398    
2399     @@1:
2400     mov ch, cl { Duplicate CL in CH }
2401     mov eax, ecx { Fill each byte in EAX with length }
2402     shl eax, 16
2403     mov ax, cx
2404     mov edi, edx { Point to the table }
2405     mov ecx, 64 { Fill table bytes with length }
2406     rep stosd
2407     cmp al, 1 { If length <= 1, we're done }
2408     jbe @@MTDone
2409     mov edi, edx { Reset EDI to beginning of table }
2410     xor ebx, ebx { Zero EBX }
2411     mov cl, al { Restore CL to length of string }
2412     dec ecx
2413    
2414     @@MTNext:
2415     mov bl, [esi] { Load table with positions of letters }
2416     inc esi { That exist in the search string }
2417     mov [edi+ebx], cl
2418     dec ecx
2419     jnz @@MTNext
2420    
2421     @@MTDone:
2422     pop ebx { Restore registers }
2423     pop edi
2424     pop esi
2425     end;
2426    
2427     function BMSearchZ(var Buffer; BufLength : Cardinal; var BT : BTable;
2428     MatchString : PAnsiChar; var Pos : Cardinal) : Boolean; assembler;
2429     register;
2430     var
2431     BufPtr : Pointer;
2432     asm
2433     push edi { Save registers since we will be changing }
2434     push esi
2435     push ebx
2436     push edx
2437    
2438     mov BufPtr, eax { Copy Buffer to local variable and ESI }
2439     mov esi, eax
2440     mov ebx, ecx { Copy BT ptr to EBX }
2441    
2442     xor eax, eax { Zero out EAX so we can search for null }
2443     mov edi, MatchString { Set EDI to beginning of MatchString }
2444     or ecx, -1 { We will be counting down }
2445     repne scasb { Find null }
2446     not ecx { ECX = length of MatchString + null }
2447     dec ecx { ECX = length of MatchString }
2448     mov edx, ecx { Copy length of MatchString to EDX }
2449    
2450     pop ecx { Pop length of buffer into ECX }
2451     mov edi, esi { Set EDI to beginning of search buffer }
2452     mov esi, MatchString { Set ESI to beginning of MatchString }
2453    
2454     cmp dl, 1 { Check to see if we have a trivial case }
2455     ja @@BMSInit { If Length(MatchString) > 1 do BM search }
2456     jb @@BMSNotFound { If Length(MatchString) = 0 we're done }
2457    
2458     mov al,[esi] { If Length(MatchString) = 1 do a REPNE SCASB }
2459     mov ebx, edi
2460     repne scasb
2461     jne @@BMSNotFound { No match during REP SCASB }
2462     dec edi { Found, calculate position }
2463     sub edi, ebx
2464     mov esi, Pos { Set position in Pos }
2465     mov [esi], edi
2466     mov eax, 1 { Set result to True }
2467     jmp @@BMSDone { We're done }
2468    
2469     @@BMSInit:
2470     dec edx { Set up for BM Search }
2471     add esi, edx { Set ESI to end of MatchString }
2472     add ecx, edi { Set ECX to end of buffer }
2473     add edi, edx { Set EDI to first check point }
2474     mov dh, [esi] { Set DH to character we'll be looking for }
2475     dec esi { Dec ESI in prep for BMSFound loop }
2476     std { Backward string ops }
2477     jmp @@BMSComp { Jump to first comparison }
2478    
2479     @@BMSNext:
2480     mov al, [ebx+eax] { Look up skip distance from table }
2481     add edi, eax { Skip EDI ahead to next check point }
2482    
2483     @@BMSComp:
2484     cmp edi, ecx { Have we reached end of buffer? }
2485     jae @@BMSNotFound { If so, we're done }
2486     mov al, [edi] { Move character from buffer into AL for comparison }
2487     cmp dh, al { Compare }
2488     jne @@BMSNext { If not equal, go to next checkpoint }
2489    
2490     push ecx { Save ECX }
2491     dec edi
2492     xor ecx, ecx { Zero ECX }
2493     mov cl, dl { Move Length(MatchString) to ECX }
2494     repe cmpsb { Compare MatchString to buffer }
2495     je @@BMSFound { If equal, string is found }
2496    
2497     mov al, dl { Move Length(MatchString) to AL }
2498     sub al, cl { Calculate offset that string didn't match }
2499     add esi, eax { Move ESI back to end of MatchString }
2500     add edi, eax { Move EDI to pre-string compare location }
2501     inc edi
2502     mov al, dh { Move character back to AL }
2503     pop ecx { Restore ECX }
2504     jmp @@BMSNext { Do another compare }
2505    
2506     @@BMSFound: { EDI points to start of match }
2507     mov edx, BufPtr { Move pointer to buffer into EDX }
2508     sub edi, edx { Calculate position of match }
2509     mov eax, edi
2510     inc eax
2511     mov esi, Pos
2512     mov [esi], eax { Set Pos to position of match }
2513     mov eax, 1 { Set result to True }
2514     pop ecx { Restore ESP }
2515     jmp @@BMSDone
2516    
2517     @@BMSNotFound:
2518     xor eax, eax { Set result to False }
2519    
2520     @@BMSDone:
2521     cld { Restore direction flag }
2522     pop ebx { Restore registers }
2523     pop esi
2524     pop edi
2525     end;
2526    
2527     function BMSearchUCZ(var Buffer; BufLength : Cardinal; var BT : BTable;
2528     MatchString : PAnsiChar; var Pos : Cardinal) : Boolean; assembler;
2529     {- Case-insensitive search of Buffer for MatchString. Return indicates
2530     success or failure. Assumes MatchString is already raised to
2531     uppercase (PRIOR to creating the table) -}
2532     register;
2533     var
2534     BufPtr : Pointer;
2535     asm
2536     push edi { Save registers since we will be changing }
2537     push esi
2538     push ebx
2539     push edx
2540    
2541     mov BufPtr, eax { Copy Buffer to local variable and ESI }
2542     mov esi, eax
2543     mov ebx, ecx { Copy BufLength to EBX }
2544    
2545     xor eax, eax { Zero out EAX so we can search for null }
2546     mov edi, MatchString { Set EDI to beginning of MatchString }
2547     or ecx, -1 { We will be counting down }
2548     repne scasb { Find null }
2549     not ecx { ECX = length of MatchString + null }
2550     dec ecx { ECX = length of MatchString }
2551     mov edx, ecx { Copy length of MatchString to EDX }
2552    
2553     pop ecx { Pop length of buffer into ECX }
2554     mov edi, esi { Set EDI to beginning of search buffer }
2555     mov esi, MatchString { Set ESI to beginning of MatchString }
2556    
2557     or dl, dl { Check to see if we have a trivial case }
2558     jz @@BMSNotFound { If Length(MatchString) = 0 we're done }
2559    
2560     @@BMSInit:
2561     dec edx { Set up for BM Search }
2562     add esi, edx { Set ESI to end of MatchString }
2563     add ecx, edi { Set ECX to end of buffer }
2564     add edi, edx { Set EDI to first check point }
2565     mov dh, [esi] { Set DH to character we'll be looking for }
2566     dec esi { Dec ESI in prep for BMSFound loop }
2567     std { Backward string ops }
2568     jmp @@BMSComp { Jump to first comparison }
2569    
2570     @@BMSNext:
2571     mov al, [ebx+eax] { Look up skip distance from table }
2572     add edi, eax { Skip EDI ahead to next check point }
2573    
2574     @@BMSComp:
2575     cmp edi, ecx { Have we reached end of buffer? }
2576     jae @@BMSNotFound { If so, we're done }
2577     mov al, [edi] { Move character from buffer into AL for comparison }
2578    
2579     push ebx { Save registers }
2580     push ecx
2581     push edx
2582     push eax { Push Char onto stack for CharUpper }
2583     cld
2584     call CharUpper
2585     std
2586     pop edx { Restore registers }
2587     pop ecx
2588     pop ebx
2589    
2590     cmp dh, al { Compare }
2591     jne @@BMSNext { If not equal, go to next checkpoint }
2592    
2593     push ecx { Save ECX }
2594     dec edi
2595     xor ecx, ecx { Zero ECX }
2596     mov cl, dl { Move Length(MatchString) to ECX }
2597     jecxz @@BMSFound { If ECX is zero, string is found }
2598    
2599     @@StringComp:
2600     mov al, [edi] { Get char from buffer }
2601     dec edi { Dec buffer index }
2602    
2603     push ebx { Save registers }
2604     push ecx
2605     push edx
2606     push eax { Push Char onto stack for CharUpper }
2607     cld
2608     call CharUpper
2609     std
2610     pop edx { Restore registers }
2611     pop ecx
2612     pop ebx
2613    
2614     mov ah, al { Move buffer char to AH }
2615     lodsb { Get MatchString char }
2616     cmp ah, al { Compare }
2617     loope @@StringComp { OK? Get next character }
2618     je @@BMSFound { Matched! }
2619    
2620     xor ah, ah { Zero AH }
2621     mov al, dl { Move Length(MatchString) to AL }
2622     sub al, cl { Calculate offset that string didn't match }
2623     add esi, eax { Move ESI back to end of MatchString }
2624     add edi, eax { Move EDI to pre-string compare location }
2625     inc edi
2626     mov al, dh { Move character back to AL }
2627     pop ecx { Restore ECX }
2628     jmp @@BMSNext { Do another compare }
2629    
2630     @@BMSFound: { EDI points to start of match }
2631     mov edx, BufPtr { Move pointer to buffer into EDX }
2632     sub edi, edx { Calculate position of match }
2633     mov eax, edi
2634     inc eax
2635     mov esi, Pos
2636     mov [esi], eax { Set Pos to position of match }
2637     mov eax, 1 { Set result to True }
2638     pop ecx { Restore ESP }
2639     jmp @@BMSDone
2640    
2641     @@BMSNotFound:
2642     xor eax, eax { Set result to False }
2643    
2644     @@BMSDone:
2645     cld { Restore direction flag }
2646     pop ebx { Restore registers }
2647     pop esi
2648     pop edi
2649     end;
2650    
2651     {------------------ Formatting routines --------------------}
2652    
2653     function CommaizeChZ(Dest : PAnsiChar; L : Longint; Ch : AnsiChar) : PAnsiChar;
2654     var
2655     NumCommas, Len, I : Cardinal;
2656     begin
2657     Result := Dest;
2658     Long2StrZ(Dest, L);
2659     Len := StrLen(Dest);
2660     NumCommas := (Len - 1) div 3;
2661     for I := 1 to NumCommas do
2662     StrChInsertPrimZ(Dest, Ch, Len - (I * 3));
2663     end;
2664    
2665     function CommaizeZ(Dest : PAnsiChar; L : LongInt) : PAnsiChar;
2666     begin
2667     Result := CommaizeChZ(Dest, L, ',');
2668     end;
2669    
2670     function FormPrimZ(Dest, Mask : PAnsiChar; R : TstFloat; LtCurr,
2671     RtCurr : PAnsiChar; Sep, DecPt : AnsiChar;
2672     AssumeDP : Boolean) : PAnsiChar;
2673     {-Returns a formatted string with digits from R merged into the Mask}
2674     const
2675     Blank = 0;
2676     Asterisk = 1;
2677     Zero = 2;
2678     const
2679     {$IFOPT N+}
2680     MaxPlaces = 18;
2681     {$ELSE}
2682     MaxPlaces = 11;
2683     {$ENDIF}
2684     FormChars : array[0..8] of AnsiChar = '#@*$-+,.';
2685     PlusArray : array[Boolean] of AnsiChar = ('+', '-');
2686     MinusArray : array[Boolean] of AnsiChar = (' ', '-');
2687     FillArray : array[Blank..Zero] of AnsiChar = (' ', '*', '0');
2688     var
2689     Temp : PAnsiChar;
2690     S : array[0..20] of AnsiChar; {temporary string}
2691     Filler : integer;{char for unused digit slots: ' ', '*', '0'}
2692     WontFit, {true if number won't fit in the mask}
2693     AddMinus, {true if minus sign needs to be added}
2694     Dollar, {true if floating dollar sign is desired}
2695     Negative : Boolean; {true if B is negative}
2696     StartF, {starting point of the numeric field}
2697     EndF : Cardinal; {end of numeric field}
2698     RtChars, {# of chars to add to right}
2699     LtChars, {# of chars to add to left}
2700     DotPos, {position of '.' in Mask}
2701     Digits, {total # of digits}
2702     Places, {# of digits after the '.'}
2703     Blanks, {# of blanks returned by Str}
2704     FirstDigit, {pos. of first digit returned by Str}
2705     Extras, {# of extra digits needed for special cases}
2706     I : Cardinal;
2707     label
2708     EndFound,
2709     RedoCase,
2710     Done;
2711     begin
2712     {assume decimal point at end?}
2713     Result := Dest;
2714     StrCopy(Result, Mask);
2715     if (not AssumeDP) and (not CharExistsZ(Result, '.')) then
2716     AssumeDP := true;
2717     if AssumeDP and (Result^ <> #0) then
2718     StrCat(Result, '.');
2719    
2720     RtChars := 0;
2721     LtChars := 0;
2722    
2723     {check for empty string}
2724     if Result^ = #0 then
2725     goto Done;
2726    
2727     {initialize variables}
2728     Filler := Blank;
2729     DotPos := 0;
2730     Places := 0;
2731     Digits := 0;
2732     Dollar := False;
2733     AddMinus := True;
2734     StartF := 0;
2735    
2736     {store the sign of the real and make it positive}
2737     Negative := (R < 0);
2738     R := Abs(R);
2739    
2740     {strip and count c's}
2741     Temp := StrEnd(Result);
2742     Dec(Temp);
2743     while Temp >= Result do begin
2744     if Temp^ = 'C' then begin
2745     Inc(RtChars);
2746     StrChDeletePrimZ(Result, Temp - Result);
2747     end else if Temp^ = 'c' then begin
2748     Inc(LtChars);
2749     StrChDeletePrimZ(Result, Temp - Result);
2750     end;
2751     Dec(Temp);
2752     end;
2753    
2754     {find the starting point for the field}
2755     Temp := Result;
2756     while (Temp^ <> #0) and not CharExistsZ(FormChars, Temp^) do begin
2757     Inc(StartF);
2758     Inc(Temp);
2759     end;
2760     if Succ(StartF) > StrLen(Result) then
2761     goto Done;
2762    
2763     {find the end point for the field}
2764     EndF := StartF;
2765     while (Temp^ <> #0) do begin
2766     case Temp^ of
2767     '*' : Filler := Asterisk;
2768     '@' : Filler := Zero;
2769     '$' : Dollar := True;
2770     '-',
2771     '+' : AddMinus := False;
2772     '#' : {ignore} ;
2773     ',',
2774     '.' : DotPos := EndF;
2775     else
2776     goto EndFound;
2777     end;
2778     Inc(Temp);
2779     Inc(EndF);
2780     end;
2781    
2782     EndFound:
2783     {correct the off-by-one nature of the loop}
2784     Dec(EndF);
2785    
2786     {disallow Dollar if Filler is Zero}
2787     if Filler = Zero then
2788     Dollar := False;
2789    
2790     {we need an extra slot if Dollar is True}
2791     Extras := Ord(Dollar);
2792    
2793     {get total # of digits and # after the decimal point}
2794     for I := StartF to EndF do
2795     case Result[I] of
2796     '#', '@',
2797     '*', '$' :
2798     begin
2799     Inc(Digits);
2800     if (I > DotPos) and (DotPos <> 0) then
2801     Inc(Places);
2802     end;
2803     end;
2804    
2805     {need one more 'digit' if Places > 0}
2806     Inc(Digits, Ord(Places > 0));
2807    
2808     {also need an extra blank if (1) Negative is true, and (2) Filler is Blank,
2809     and (3) AddMinus is true}
2810     if Negative and AddMinus and (Filler = Blank) then
2811     Inc(Extras)
2812     else
2813     AddMinus := False;
2814    
2815     {translate the real to a string}
2816     Real2StrZ(S, R, Digits, Places);
2817    
2818     {add zeros that Str may have left out}
2819     if Places > MaxPlaces then begin
2820     Temp := StrEnd(S);
2821     CharStrZ(Temp, '0', Places-MaxPlaces);
2822     while (StrLen(S) > Digits) and (S[0] = ' ') do
2823     StrChDeletePrimZ(S, 0);
2824     end;
2825    
2826     {count number of initial blanks}
2827     Blanks := 0;
2828     while S[Blanks] = ' ' do
2829     Inc(Blanks);
2830     FirstDigit := Blanks;
2831    
2832     {the number won't fit if (a) S is longer than Digits or (b) the number of
2833     initial blanks is less than Extras}
2834     WontFit := (StrLen(S) > Digits) or (Blanks < Extras);
2835    
2836     {if it won't fit, fill decimal slots with '*'}
2837     if WontFit then begin
2838     for I := StartF to EndF do
2839     case Result[I] of
2840     '#', '@', '*', '$' : Result[I] := '*';
2841     '+' : Result[I] := PlusArray[Negative];
2842     '-' : Result[I] := MinusArray[Negative];
2843     end;
2844     goto Done;
2845     end;
2846    
2847     {fill initial blanks in S with Filler; insert floating dollar sign}
2848     if Blanks > 0 then begin
2849     FillChar(S[0], Blanks, FillArray[Filler]);
2850    
2851     {put floating dollar sign in last blank slot if necessary}
2852     if Dollar then begin
2853     S[Pred(Blanks)] := LtCurr[0];
2854     Dec(Blanks);
2855     end;
2856    
2857     {insert a minus sign if necessary}
2858     if AddMinus then
2859     S[Pred(Blanks)] := '-';
2860     end;
2861    
2862     {put in the digits / signs}
2863     Temp := StrEnd(S);
2864     Dec(Temp);
2865     for I := EndF downto StartF do begin
2866     RedoCase:
2867     case Result[I] of
2868     '#', '@', '*', '$' :
2869     if Temp >= S then begin
2870     Result[I] := Temp^;
2871     Dec(Temp);
2872     if (Temp^ = '.') and (Temp >= S) then
2873     Dec(Temp);
2874     end
2875     else
2876     Result[I] := FillArray[Filler];
2877     ',' :
2878     begin
2879     Result[I] := Sep;
2880     if (I < DotPos) and (Temp < (S + FirstDigit)) then begin
2881     Result[I] := '#';
2882     goto RedoCase;
2883     end;
2884     end;
2885     '.' :
2886     begin
2887     Result[I] := DecPt;
2888     if (I < DotPos) and (Temp < (S + FirstDigit)) then begin
2889     Result[I] := '#';
2890     goto RedoCase;
2891     end;
2892     end;
2893     '+' : Result[I] := PlusArray[Negative];
2894     '-' : Result[I] := MinusArray[Negative];
2895     end;
2896     end;
2897    
2898     Done:
2899     if AssumeDP then
2900     Result[Pred(StrLen(Result))] := #0;
2901     if RtChars > 0 then begin
2902     StrLCopy(S, RtCurr, RtChars);
2903     LeftPadPrimZ(S, RtChars);
2904     StrCat(Result, S);
2905     end;
2906     if LtChars > 0 then begin
2907     StrLCopy(S, LtCurr, LtChars);
2908     PadPrimZ(S, LtChars);
2909     StrStInsertPrimZ(Result, S, 0);
2910     end;
2911     end;
2912    
2913     function FloatFormZ(Dest, Mask : PAnsiChar; R : TstFloat; LtCurr,
2914     RtCurr : PAnsiChar; Sep, DecPt : AnsiChar) : PAnsiChar;
2915     {-Return a formatted string with digits from R merged into mask.}
2916     begin
2917     Result := FormPrimZ(Dest, Mask, R, LtCurr, RtCurr, Sep, DecPt, False);
2918     end;
2919    
2920     function LongIntFormZ(Dest, Mask : PAnsiChar; L : Longint; LtCurr,
2921     RtCurr : PAnsiChar; Sep : AnsiChar) : PAnsiChar;
2922     {-Return a formatted string with digits from L merged into mask.}
2923     begin
2924     Result := FormPrimZ(Dest, Mask, L, LtCurr, RtCurr, Sep, '.', True);
2925     end;
2926    
2927     function StrChPosZ(P : PAnsiChar; C : AnsiChar; var Pos : Cardinal): Boolean;
2928     {-Sets Pos to position of character C within string P returns True if found}
2929     var
2930     Temp : PAnsiChar;
2931     begin
2932     Result := False;
2933     Temp := StrScan(P, C);
2934     if Temp <> nil then begin
2935     Pos := Temp - P;
2936     Result := True;
2937     end;
2938     end;
2939    
2940     {$IFDEF UNICODE}
2941     function StrChPosZ(P : PWideChar; C : Char; var Pos : Cardinal): Boolean;
2942     {-Sets Pos to position of character C within string P returns True if found}
2943     var
2944     Temp : PChar;
2945     begin
2946     Result := False;
2947     Temp := StrScan(P, C);
2948     if Temp <> nil then begin
2949     Pos := Temp - P;
2950     Result := True;
2951     end;
2952     end;
2953     {$ENDIF}
2954    
2955     function StrStPosZ(P, S : PAnsiChar; var Pos : Cardinal) : boolean;
2956     {-Sets Pos to position of string S within string P returns True if found}
2957     var
2958     Temp : PAnsiChar;
2959     begin
2960     Result := False;
2961     Temp := StrPos(P, S);
2962     if Temp <> nil then begin
2963     Pos := Temp - P;
2964     Result := True;
2965     end;
2966     end;
2967    
2968     function StrChInsertPrimZ(Dest : PAnsiChar; C : AnsiChar;
2969     Pos : Cardinal) : PAnsiChar;
2970     register;
2971     asm
2972     push eax {save because we will be changing them}
2973     push edi
2974     push esi
2975    
2976     mov esi, eax {copy Dest to ESI and EDI}
2977     mov edi, eax
2978     mov ah, dl
2979     mov edx, ecx {move POS to edx}
2980    
2981     xor al, al {zero}
2982     or ecx, -1 {set ECX to $FFFFFFFF}
2983     repne scasb {find null terminator}
2984    
2985     not ecx {calc length (including null)}
2986     std {backwards string ops}
2987     add esi, ecx
2988     dec esi {point to end of source string}
2989     sub ecx, edx {calculate number to do}
2990     jae @@1 {set ECX to 1 if Pos greater than strlen + 1}
2991     mov ecx, 1
2992    
2993     @@1:
2994     rep movsb {adjust tail of string}
2995     mov [edi], ah {insert the new character}
2996    
2997     @@ExitPoint:
2998     cld {be a good neighbor}
2999    
3000     pop esi {restore registers}
3001     pop edi
3002     pop eax
3003     end;
3004    
3005     function StrStInsertPrimZ(Dest : PAnsiChar; S : PAnsiChar;
3006     Pos : Cardinal) : PAnsiChar;
3007     register;
3008     asm
3009     push eax {save because we will be changing them}
3010     push edi
3011     push esi
3012     push ebx
3013    
3014     mov ebx, ecx {move POS to ebx}
3015     mov esi, eax {copy Dest to ESI, S to EDI}
3016     mov edi, edx
3017    
3018     xor al, al {zero}
3019     or ecx, -1 {set ECX to $FFFFFFFF}
3020     repne scasb {find null terminator}
3021     not ecx {calc length of source string (including null)}
3022     dec ecx {length without null}
3023     jz @@ExitPoint {if source length = 0, exit}
3024     push ecx {save length for later}
3025    
3026     mov edi, esi {reset EDI to Dest}
3027     or ecx, -1
3028     repne scasb {find null}
3029     not ecx {length of dest string (including null)}
3030    
3031     cmp ebx, ecx
3032     jb @@1
3033     mov ebx, ecx
3034     dec ebx
3035    
3036     @@1:
3037     std {backwards string ops}
3038     pop eax {restore length of S from stack}
3039     add edi, eax {set EDI S beyond end of Dest}
3040     dec edi {back up one for null}
3041    
3042     add esi, ecx {set ESI to end of Dest}
3043     dec esi {back up one for null}
3044     sub ecx, ebx {# of chars in Dest that are past Pos}
3045     rep movsb {adjust tail of string}
3046    
3047     mov esi, edx {set ESI to S}
3048     add esi, eax {set ESI to end of S}
3049     dec esi {back up one for null}
3050     mov ecx, eax {# of chars in S}
3051     rep movsb {copy S into Dest}
3052    
3053     cld {be a good neighbor}
3054    
3055     @@ExitPoint:
3056    
3057     pop ebx {restore registers}
3058     pop esi
3059     pop edi
3060     pop eax
3061     end;
3062    
3063     function StrStCopyZ(Dest : PAnsiChar; S : PAnsiChar; Pos, Count : Cardinal) : PAnsiChar;
3064     var
3065     Len : Cardinal;
3066     begin
3067     Len := StrLen(S);
3068     if Pos < Len then begin
3069     if (Len-Pos) < Count then
3070     Count := Len-Pos;
3071     Move(S[Pos], Dest^, Count);
3072     Dest[Count] := #0;
3073     end else
3074     Dest[0] := #0;
3075     Result := Dest;
3076     end;
3077    
3078     {$IFDEF UNICODE}
3079     function StrStCopyZ(Dest : PWideChar; S : PWideChar; Pos, Count : Cardinal) : PWideChar;
3080     var
3081     Len : Cardinal;
3082     begin
3083     Len := StrLen(S);
3084     if Pos < Len then begin
3085     if (Len-Pos) < Count then
3086     Count := Len-Pos;
3087     Move(S[Pos], Dest^, Count * SizeOf(WideChar));
3088     Dest[Count] := #0;
3089     end else
3090     Dest[0] := #0;
3091     Result := Dest;
3092     end;
3093     {$ENDIF}
3094    
3095     function StrChDeletePrimZ(P : PAnsiChar; Pos : Cardinal) : PAnsiChar;
3096     register;
3097     asm
3098     push edi { Save because we will be changing them }
3099     push esi
3100     push ebx
3101    
3102     mov ebx, eax { Save P to EDI & EBX }
3103     mov edi, eax
3104    
3105     xor al, al { Zero }
3106     or ecx, -1 { Set ECX to $FFFFFFFF }
3107     repne scasb { Find null terminator }
3108     not ecx
3109     dec ecx
3110     or ecx, ecx
3111     jz @@ExitPoint
3112     sub ecx, edx { Calc number to move }
3113     jb @@ExitPoint { Exit if Pos > StrLen }
3114    
3115     mov edi, ebx
3116     add edi, edx { Point to position to adjust }
3117     mov esi, edi
3118     inc esi { Offset for source string }
3119     inc ecx { One more to include null terminator }
3120     rep movsb { Adjust the string }
3121    
3122     @@ExitPoint:
3123     mov eax, ebx
3124     pop ebx { restore registers }
3125     pop esi
3126     pop edi
3127     end;
3128    
3129     function StrStDeletePrimZ(P : PAnsiChar; Pos, Count : Cardinal) : PAnsiChar;
3130     register;
3131     asm
3132     push eax {save because we will be changing them}
3133     push edi
3134     push esi
3135     push ebx
3136    
3137     mov ebx, ecx {move Count to BX}
3138     mov esi, eax {move P to ESI and EDI}
3139     mov edi, eax
3140    
3141     xor eax, eax {null}
3142     or ecx, -1
3143     repne scasb {find null terminator}
3144     not ecx {calc length}
3145     or ecx, ecx
3146     jz @@ExitPoint
3147    
3148     sub ecx, ebx {subtract Count}
3149     sub ecx, edx {subtract Pos}
3150     jns @@L1
3151    
3152     mov edi,esi {delete everything after Pos}
3153     add edi,edx
3154     mov [edi], al
3155     jmp @@ExitPoint
3156    
3157     @@L1:
3158     mov edi,esi
3159     add edi,edx {point to position to adjust}
3160     mov esi,edi
3161     add esi,ebx {point past string to delete in src}
3162     inc ecx {one more to include null terminator}
3163     rep movsb {adjust the string}
3164    
3165     @@ExitPoint:
3166    
3167     pop ebx {restore registers}
3168     pop esi
3169     pop edi
3170     pop eax
3171     end;
3172    
3173     function StrStDeletePrimZ(P : PWideChar; Pos, Count : Cardinal) : PWideChar; //SZ
3174     register;
3175     asm
3176     push eax {save because we will be changing them}
3177     push edi
3178     push esi
3179     push ebx
3180    
3181     mov ebx, ecx {move Count to BX}
3182     mov esi, eax {move P to ESI and EDI}
3183     mov edi, eax
3184    
3185     xor eax, eax {null}
3186     or ecx, -1
3187     repne scasw {find null terminator}
3188     not ecx {calc length}
3189     or ecx, ecx
3190     jz @@ExitPoint
3191    
3192     sub ecx, ebx {subtract Count}
3193     sub ecx, ebx {subtract Count}
3194     sub ecx, edx {subtract Pos}
3195     sub ecx, edx {subtract Pos}
3196     jns @@L1
3197    
3198     mov edi,esi {delete everything after Pos}
3199     add edi,edx
3200     mov [edi], ax
3201     jmp @@ExitPoint
3202    
3203     @@L1:
3204     mov edi,esi
3205     add edi,edx {point to position to adjust}
3206     add edi,edx {point to position to adjust}
3207     mov esi,edi
3208     add esi,ebx {point past string to delete in src}
3209     add esi,ebx {point past string to delete in src}
3210     inc ecx {one more to include null terminator}
3211     inc ecx
3212     rep movsw {adjust the string}
3213    
3214     @@ExitPoint:
3215    
3216     pop ebx {restore registers}
3217     pop esi
3218     pop edi
3219     pop eax
3220     end;
3221    
3222     function StrChDeleteZ(Dest, S : PAnsiChar; Pos : Cardinal) : PAnsiChar;
3223     begin
3224     StrCopy(Dest, S);
3225     Result := StrChDeletePrimZ(Dest, Pos);
3226     end;
3227    
3228     function StrStDeleteZ(Dest, S : PAnsiChar; Pos, Count : Cardinal) : PAnsiChar;
3229     begin
3230     StrCopy(Dest, S);
3231     Result := StrStDeletePrimZ(Dest, Pos, Count);
3232     end;
3233    
3234     function StrChInsertZ(Dest, S : PAnsiChar; C : AnsiChar; Pos : Cardinal) : PAnsiChar;
3235     begin
3236     StrCopy(Dest, S);
3237     Result := StrChInsertPrimZ(Dest, C, Pos);
3238     end;
3239    
3240     function StrStInsertZ(Dest : PAnsiChar; S1, S2 : PAnsiChar; Pos : Cardinal) : PAnsiChar;
3241     begin
3242     StrCopy(Dest, S1);
3243     Result := StrStInsertPrimZ(Dest, S2, Pos);
3244     end;
3245    
3246    
3247     {----------------------------------------------------------------------------}
3248    
3249     function CopyLeftZ(Dest, S : PAnsiChar; Len : Cardinal) : PAnsiChar;
3250     {-Return the left Len characters of a string}
3251     begin
3252     if (Len < 1) or (S[0] = #0) then
3253     Dest[0] := #0
3254     else
3255     Dest := StrStCopyZ(Dest, S, 0, Len);
3256     Result := Dest;
3257     end;
3258    
3259     {----------------------------------------------------------------------------}
3260    
3261     function CopyMidZ(Dest, S : PAnsiChar; First, Len : Cardinal) : PAnsiChar;
3262     {-Return the mid part of a string}
3263     begin
3264     if (First >= StrLen(S)) or (LongInt(Len) < 1) or (S[0] = #0) then
3265     Dest[0] := #0
3266     else
3267     Dest := StrStCopyZ(Dest, S, First, Len);
3268     Result := Dest;
3269     end;
3270    
3271     {----------------------------------------------------------------------------}
3272    
3273     function CopyRightZ(Dest, S : PAnsiChar; First : Cardinal) : PAnsiChar;
3274     {-Return the right characters of a string}
3275     begin
3276     if (First >= StrLen(Dest)) or (S[0] = #0) then
3277     Dest[0] := #0
3278     else
3279     Dest := StrStCopyZ(Dest, S, First, StrLen(S)-First+1);
3280     Result := Dest;
3281     end;
3282    
3283     {----------------------------------------------------------------------------}
3284     function CopyRightAbsZ(Dest, S : PAnsiChar; NumChars : Cardinal) : PAnsiChar;
3285     {-Return the right Len characters of a string}
3286     var
3287     I : Cardinal;
3288     begin
3289     if (StrLen(S) > NumChars) then begin
3290     I := StrLen(S) - NumChars;
3291     Dest := StrStCopyZ(Dest, S, I, NumChars)
3292     end else
3293     Dest := S;
3294     Result := Dest;
3295     end;
3296    
3297     {----------------------------------------------------------------------------}
3298    
3299     function WordPosZ(S, WordDelims, AWord : PAnsiChar;
3300     N : Cardinal; var Position : Cardinal) : Boolean;
3301     {-returns the Occurrence instance of a given word within a string}
3302     var
3303     P,
3304     TmpStr : PAnsiChar;
3305     Len,
3306     I,
3307     P1,
3308     P2 : Cardinal;
3309     begin
3310     if (S[0] = #0) or (AWord[0] = #0) or
3311     (StrPos(S, AWord) = nil) or (N < 1) then begin
3312     Result := False;
3313     Position := 0;
3314     Exit;
3315     end;
3316    
3317     Result := False;
3318     Position := 0;
3319    
3320     GetMem(TmpStr, StrLen(S)+1);
3321     try
3322     StrCopy(TmpStr, S);
3323     I := 0;
3324     Len := StrLen(AWord);
3325     P := StrPos(TmpStr, AWord);
3326     P1 := P - TmpStr;
3327    
3328     while (StrLen(TmpStr) > 0) do begin
3329     P2 := P1 + pred(Len);
3330     if (P1 = 0) then begin
3331     if (CharExistsZ(WordDelims, TmpStr[P2+1])) then begin
3332     Inc(I);
3333     end else
3334     StrStDeleteZ(TmpStr, TmpStr, 0, P2);
3335     end else if (CharExistsZ(WordDelims, TmpStr[P1-1])) and
3336     ((CharExistsZ(WordDelims, TmpStr[P2+1])) or (P2+1 = StrLen(TmpStr))) then begin
3337     Inc(I);
3338     end else if ((P1 + pred(Len)) = StrLen(TmpStr)) then begin
3339     if (CharExistsZ(WordDelims, TmpStr[P1-1])) then
3340     Inc(I);
3341     end;
3342    
3343     if (I = N) then begin
3344     Result := True;
3345     Position := Position + P1;
3346     Exit;
3347     end;
3348     StrStDeletePrimZ(TmpStr, 0, P2+1);
3349     Position := Position + P2+1;
3350     P := StrPos(TmpStr, AWord);
3351     if (P <> nil) then
3352     P1 := P - TmpStr
3353     else
3354     break;
3355     end;
3356     finally
3357     FreeMem(TmpStr, StrLen(S)+1);
3358     end;
3359     end;
3360    
3361    
3362     {----------------------------------------------------------------------------}
3363    
3364     function CopyFromNthWordZ(Dest, S, WordDelims, AWord : PAnsiChar;
3365     N : Cardinal) : Boolean;
3366     var
3367     P : Cardinal;
3368     begin
3369     if (WordPosZ(S, WordDelims, AWord, N, P)) then begin
3370     StrStCopyZ(Dest, S, P, StrLen(S)-P+1);
3371     Result := True;
3372     end else begin
3373     Dest[0] := #0;
3374     Result := False;
3375     end;
3376     end;
3377    
3378     {----------------------------------------------------------------------------}
3379    
3380    
3381     function DeleteFromNthWordZ(Dest, S, WordDelims, AWord : PAnsiChar;
3382     N : Cardinal) : Boolean;
3383     var
3384     P : Cardinal;
3385     begin
3386     if (WordPosZ(S, WordDelims, AWord, N, P)) then begin
3387     StrStDeleteZ(Dest, S, P, StrLen(S)-P+1);
3388     Result := False;
3389     end else begin
3390     Dest[0] := #0;
3391     Result := False;
3392     end;
3393     end;
3394    
3395     {----------------------------------------------------------------------------}
3396    
3397     function CopyFromToWordZ(Dest, S, WordDelims, Word1, Word2 : PAnsiChar;
3398     N1, N2 : Cardinal) : Boolean;
3399     var
3400     P1,
3401     P2 : Cardinal;
3402     begin
3403     if (WordPosZ(S, WordDelims, Word1, N1, P1)) then begin
3404     if (WordPosZ(S, WordDelims, Word2, N2, P2)) then begin
3405     Dec(P2);
3406     if (P2 > P1) then begin
3407     Result := True;
3408     StrStCopyZ(Dest, S, P1, P2-P1);
3409     end else begin
3410     Result := False;
3411     Dest[0] := #0;
3412     end;
3413     end else begin
3414     Result := False;
3415     Dest[0] := #0;
3416     end;
3417     end else begin
3418     Result := False;
3419     Dest[0] := #0;
3420     end;
3421     end;
3422    
3423     {----------------------------------------------------------------------------}
3424    
3425     function DeleteFromToWordZ(Dest, S, WordDelims, Word1, Word2 : PAnsiChar;
3426     N1, N2 : Cardinal) : Boolean;
3427     var
3428     P1,
3429     P2 : Cardinal;
3430     begin
3431     if (WordPosZ(S, WordDelims, Word1, N1, P1)) then begin
3432     if (WordPosZ(S, WordDelims, Word2, N2, P2)) then begin
3433     Dec(P2);
3434     if (P2 > P1) then begin
3435     Result := True;
3436     StrStDeleteZ(Dest, S, P1, P2-P1+1);
3437     end else begin
3438     Result := False;
3439     Dest[0] := #0;
3440     end;
3441     end else begin
3442     Result := False;
3443     Dest[0] := #0;
3444     end;
3445     end else begin
3446     Result := False;
3447     Dest[0] := #0;
3448     end;
3449     end;
3450    
3451     {----------------------------------------------------------------------------}
3452    
3453     function CopyWithinZ(Dest, S, Delimiter : PAnsiChar; Strip : Boolean) : PAnsiChar;
3454     var
3455     P1,
3456     P2 : Cardinal;
3457     L : Cardinal;
3458     TmpStr : PAnsiChar;
3459     begin
3460     if (S[0] = #0) or (Delimiter[0] = #0) or
3461     (StrPos(S, Delimiter) = nil) then begin
3462     Dest[0] := #0;
3463     Result := Dest;
3464     end else begin
3465     if (StrStPosZ(S, Delimiter, P1)) then begin
3466     L := StrLen(S) - (P1 + StrLen(Delimiter)) + 1;
3467     GetMem(TmpStr, L);
3468     try
3469     StrStCopyZ(TmpStr, S, P1 + StrLen(Delimiter), StrLen(S));
3470     if (StrStPosZ(TmpStr, Delimiter, P2)) then begin
3471     StrStCopyZ(Dest, TmpStr, 0, P2);
3472     if (not Strip) then
3473     StrCat(StrStInsertZ(Dest, Dest, Delimiter, 0), Delimiter)
3474     end else begin
3475     StrCopy(Dest, TmpStr);
3476     if (not Strip) then
3477     StrStInsertZ(Dest, Dest, Delimiter, 0);
3478     end;
3479     finally
3480     FreeMem(TmpStr, L);
3481     end;
3482     end;
3483     Result := Dest;
3484     end;
3485     end;
3486    
3487     {----------------------------------------------------------------------------}
3488    
3489     function DeleteWithinZ(Dest, S, Delimiter : PAnsiChar) : PAnsiChar;
3490     var
3491     P1,
3492     P2 : Cardinal;
3493     L : Cardinal;
3494     TmpStr : PAnsiChar;
3495     begin
3496     if (S[0] = #0) or (Delimiter[0] = #0) or
3497     (StrPos(S, Delimiter) = nil) then begin
3498     Dest[0] := #0;
3499     Result := Dest;
3500     end else begin
3501     if (StrStPosZ(S, Delimiter, P1)) then begin
3502     L := StrLen(S) - (P1 + StrLen(Delimiter)) + 1;
3503     GetMem(TmpStr, L);
3504     try
3505     StrStCopyZ(TmpStr, S, P1 + StrLen(Delimiter), StrLen(S));
3506     if not (StrStPosZ(TmpStr, Delimiter, P2)) then
3507     StrStCopyZ(Dest, S, 0, P1)
3508     else begin
3509     P2 := P2 + (2*StrLen(Delimiter));
3510     StrStDeleteZ(Dest, S, P1, P2);
3511     end;
3512     finally
3513     FreeMem(TmpStr, L);
3514     end;
3515     end;
3516     Result := Dest;
3517     end;
3518     end;
3519    
3520     {----------------------------------------------------------------------------}
3521    
3522     function ReplaceWordZ(Dest, S, WordDelims, OldWord, NewWord : PAnsiChar;
3523     N : Cardinal;
3524     var Replacements : Cardinal) : PAnsiChar;
3525     var
3526     I,
3527     C,
3528     P1 : Cardinal;
3529     begin
3530     if (S[0] = #0) or (WordDelims[0] = #0) or (OldWord[0] = #0) or
3531     (StrPos(S, OldWord) = nil) then begin
3532     StrCopy(Dest, S);
3533     Replacements := 0;
3534     Result := Dest;
3535     end else begin
3536     if (WordPosZ(S, WordDelims, OldWord, N, P1)) then begin
3537     StrCopy(Dest, S);
3538     StrStDeleteZ(Dest, Dest, P1, StrLen(OldWord));
3539    
3540     C := 0;
3541     for I := 1 to Replacements do begin
3542     if (StrLen(NewWord) + 1 + StrLen(Dest)) < High(Cardinal) then begin
3543     Inc(C);
3544     StrStInsertZ(Dest, Dest, NewWord, P1);
3545     Inc(P1, StrLen(NewWord) + 1);
3546     end else begin
3547     Replacements := C;
3548     Result := Dest;
3549     Exit;
3550     end;
3551     end;
3552     Result := Dest;
3553     end else begin
3554     Replacements := 0;
3555     Result := Dest;
3556     end;
3557     end;
3558     end;
3559    
3560    
3561     function ReplaceWordAllZ(Dest, S, WordDelims, OldWord, NewWord : PAnsiChar;
3562     var Replacements : Cardinal) : PAnsiChar;
3563     var
3564     I,
3565     C,
3566     P1 : Cardinal;
3567     begin
3568     if (S[0] = #0) or (WordDelims[0] = #0) or (OldWord[0] = #0) or
3569     (StrPos(S, OldWord) = nil) then begin
3570     Replacements := 0;
3571     StrCopy(Dest, S);
3572     Result := Dest;
3573     end else begin
3574     StrCopy(Dest, S);
3575     C := 0;
3576     while (WordPosZ(Dest, WordDelims, OldWord, 1, P1)) do begin
3577     StrStDeleteZ(Dest, Dest, P1, StrLen(OldWord));
3578     for I := 1 to Replacements do begin
3579     if ((StrLen(NewWord) + 1 + StrLen(Dest)) < High(Cardinal)) then begin
3580     Inc(C);
3581     StrStInsertZ(Dest, Dest, NewWord, P1);
3582     end else begin
3583     Result := Dest;
3584     Replacements := C;
3585     Exit;
3586     end;
3587     end;
3588     end;
3589     Replacements := C;
3590     Result := Dest;
3591     end;
3592     end;
3593    
3594    
3595     function ReplaceStringZ(Dest, S, OldString, NewString : PAnsiChar;
3596     N : Cardinal;
3597     var Replacements : Cardinal) : PAnsiChar;
3598     var
3599     I,
3600     L,
3601     C,
3602     P1 : Cardinal;
3603     TmpStr : PAnsiChar;
3604     begin
3605     if (S[0] = #0) or (OldString[0] = #0) or
3606     (StrPos(S, OldString) = nil) then begin
3607     StrCopy(Dest, S);
3608     Replacements := 0;
3609     Result := Dest;
3610     Exit;
3611     end;
3612    
3613     L := StrLen(S) + 1;
3614     GetMem(TmpStr, L);
3615     try
3616     StrCopy(TmpStr, S);
3617    
3618     I := 1;
3619     StrStPosZ(TmpStr, OldString, P1);
3620     C := P1;
3621     while (I < N) and (C < StrLen(TmpStr)) do begin
3622     Inc(I);
3623     StrStDeleteZ(TmpStr, TmpStr, P1, P1 + StrLen(OldString));
3624     Inc(C, P1 + StrLen(OldString));
3625     end;
3626     finally
3627     FreeMem(TmpStr, L);
3628     end;
3629     StrCopy(Dest, S);
3630     StrStDeleteZ(Dest, Dest, C, StrLen(OldString));
3631    
3632     C := 0;
3633     for I := 1 to Replacements do begin
3634     if ((StrLen(NewString) + 1 + StrLen(Dest)) < High(Cardinal)) then begin
3635     Inc(C);
3636     StrStInsertZ(Dest, Dest, NewString, P1);
3637     Inc(P1, StrLen(NewString) + 1);
3638     end else begin
3639     Replacements := C;
3640     Result := Dest;
3641     Exit;
3642     end;
3643     end;
3644     Result := Dest;
3645     end;
3646    
3647    
3648     function ReplaceStringAllZ(Dest, S, OldString, NewString : PAnsiChar;
3649     var Replacements : Cardinal) : PAnsiChar;
3650     var
3651     I,
3652     C,
3653     P1 : Cardinal;
3654     begin
3655     if (S[0] = #0) or (OldString[0] = #0) or (StrPos(S, OldString) = nil) then begin
3656     StrCopy(Dest, S);
3657     Result := Dest;
3658     Replacements := 0;
3659     end else begin
3660     StrCopy(Dest, S);
3661     C := 0;
3662     while StrStPosZ(Dest, OldString, P1) do begin
3663     StrStDeleteZ(Dest, Dest, P1, StrLen(OldString));
3664     for I := 1 to Replacements do begin
3665     if (LongInt((StrLen(NewString) + 1 + StrLen(Dest))) < MaxLongInt) then begin
3666     Inc(C);
3667     StrStInsertZ(Dest, Dest, NewString, P1);
3668     end else begin
3669     Replacements := C;
3670     Result := Dest;
3671     Exit;
3672     end;
3673     end;
3674     end;
3675     Replacements := C;
3676     Result := Dest;
3677     end;
3678     end;
3679    
3680    
3681    
3682     function LastWordZ(S, WordDelims, AWord : PAnsiChar;
3683     var Position : Cardinal) : Boolean;
3684     var
3685     TmpStr1,
3686     TmpStr2 : PAnsiChar;
3687     begin
3688     if (S[0] = #0) or (WordDelims[0] = #0) or
3689     (AWord[0] = #0) or (StrPos(S, AWord) = nil) then begin
3690     Result := False;
3691     Position := 0;
3692     Exit;
3693     end;
3694    
3695     GetMem(TmpStr1, StrLen(S) + 1);
3696     GetMem(TmpStr2, StrLen(AWord) + 1);
3697     try
3698     StrCopy(TmpStr1, S);
3699     Position := StrLen(TmpStr1)-1;
3700     while (CharExistsZ(WordDelims, TmpStr1[Position])) do
3701     Dec(Position);
3702    
3703     Position := StrLen(TmpStr1)-1;
3704     repeat
3705     while (not CharExistsZ(WordDelims, TmpStr1[Position])) and (Position > 0) do
3706     Dec(Position);
3707     if (CompStringZ(
3708     StrStCopyZ(TmpStr2, TmpStr1, Position+1, StrLen(AWord)),
3709     AWord) = 0) then begin
3710     Inc(Position);
3711     Result := True;
3712     Exit;
3713     end;
3714     StrStDeleteZ(TmpStr1, TmpStr1, Position, StrLen(TmpStr1));
3715     Position := StrLen(TmpStr1)-1;
3716     until (Position = 0);
3717     Result := False;
3718     Position := 0;
3719     finally
3720     FreeMem(TmpStr1, StrLen(S)+1);
3721     FreeMem(TmpStr2, StrLen(AWord)+1);
3722     end;
3723     end;
3724    
3725     {----------------------------------------------------------------------------}
3726    
3727     function LastWordAbsZ(S, WordDelims : PAnsiChar;
3728     var Position : Cardinal) : Boolean;
3729     begin
3730     if (S[0] = #0) or (WordDelims[0] = #0) then begin
3731     Result := False;
3732     Position := 0;
3733     Exit;
3734     end;
3735    
3736     {find first non-delimiter character, if any. If not, it's a "one word wonder"}
3737     Position := StrLen(S)-1;
3738     while (Position > 0) and (CharExistsZ(WordDelims, S[Position])) do
3739     Dec(Position);
3740    
3741     if (Position = 0) then begin
3742     if (CharExistsZ(WordDelims, S[Position])) then begin
3743     Result := True;
3744     Position := 1;
3745     Exit;
3746     end else begin
3747     Result := True;
3748     Exit;
3749     end;
3750     end;
3751    
3752     {find next non-delimiter character}
3753     Result := True;
3754     while (Position > 0) and (not CharExistsZ(WordDelims, S[Position])) do
3755     Dec(Position);
3756     if (Position = 0) then begin
3757     if (CharExistsZ(WordDelims, S[Position])) then begin
3758     Position := 1;
3759     end else begin
3760     Position := 0;
3761     end;
3762     end else begin
3763     Inc(Position);
3764     end;
3765     end;
3766    
3767     {----------------------------------------------------------------------------}
3768    
3769     function LastStringZ(S, AString : PAnsiChar;
3770     var Position : Cardinal) : Boolean;
3771     var
3772     TmpStr : PAnsiChar;
3773     I, C : Cardinal;
3774     begin
3775     if (S[0] = #0) or (StrPos(S, AString) = nil) then begin
3776     Result := False;
3777     Position := 0;
3778     Exit;
3779     end;
3780    
3781     GetMem(TmpStr, StrLen(S)+1);
3782     try
3783     StrCopy(TmpStr, S);
3784     C := 0;
3785     while (StrStPosZ(TmpStr, AString, I)) do begin
3786     Inc(C, I + StrLen(AString));
3787     StrStDeleteZ(TmpStr, TmpStr, 0, I + StrLen(AString));
3788     end;
3789    
3790     {Go back the length of AString since the while loop deletes the last instance}
3791     Dec(C, StrLen(AString));
3792     Position := C;
3793     Result := True;
3794     finally
3795     FreeMem(TmpStr, StrLen(S)+1);
3796     end;
3797     end;
3798    
3799    
3800     {----------------------------------------------------------------------------}
3801    
3802     function KeepCharsZ(Dest, S, Chars : PAnsiChar) : PAnsiChar;
3803    
3804     begin
3805     Result := Dest;
3806     while (S^ <> #0) do begin
3807     if CharExistsZ(Chars, S^) then begin
3808     Dest^ := S^;
3809     inc(Dest);
3810     end;
3811     inc(S);
3812     end;
3813     Dest^ := #0;
3814     end;
3815    
3816     {----------------------------------------------------------------------------}
3817    
3818     function RepeatStringZ(Dest, RepeatString : PAnsiChar;
3819     var Repetitions : Cardinal;
3820     MaxLen : Cardinal) : PAnsiChar;
3821    
3822     var
3823     i : Cardinal;
3824     Len : Cardinal;
3825     ActualReps : Cardinal;
3826     begin
3827     Result := Dest;
3828     Result^ := #0;
3829     Len := StrLen(RepeatString);
3830     if (MaxLen <> 0) and
3831     (Repetitions <> 0) and
3832     (Len <> 0) then begin
3833     ActualReps := MaxLen div Len;
3834     if (ActualReps > Repetitions) then
3835     ActualReps := Repetitions
3836     else
3837     Repetitions := ActualReps;
3838     if (ActualReps > 0) then begin
3839     for i := 0 to pred(ActualReps) do begin
3840     Move(RepeatString[0], Dest[0], Len);
3841     inc(Dest, Len);
3842     end;
3843     Dest^ := #0;
3844     end;
3845     end;
3846     end;
3847    
3848     {----------------------------------------------------------------------------}
3849    
3850     function TrimCharsZ(Dest, S, Chars : PAnsiChar) : PAnsiChar;
3851    
3852     begin
3853     Result := LeftTrimCharsZ(Dest, RightTrimCharsZ(Dest, S, Chars), Chars);
3854     end;
3855    
3856     {----------------------------------------------------------------------------}
3857    
3858     function RightTrimCharsZ(Dest, S, Chars : PAnsiChar) : PAnsiChar;
3859    
3860     var
3861     EndS : PAnsiChar;
3862     begin
3863     Result := Dest;
3864     EndS := StrEnd(S);
3865     while (EndS <> S) do begin
3866     dec(EndS);
3867     if not CharExistsZ(Chars, EndS^) then begin
3868     if (Dest <> S) then
3869     StrLCopy(Dest, S, succ(EndS - S))
3870     else begin
3871     inc(EndS);
3872     EndS^ := #0;
3873     end;
3874     Exit;
3875     end;
3876     end;
3877     Result^ := #0;
3878     end;
3879    
3880     {----------------------------------------------------------------------------}
3881    
3882     function LeftTrimCharsZ(Dest, S, Chars : PAnsiChar) : PAnsiChar;
3883    
3884     begin
3885     Result := Dest;
3886     while (S^ <> #0) and CharExistsZ(Chars, S^) do
3887     inc(S);
3888     if (S^ <> #0) then
3889     StrCopy(Result, S)
3890     else
3891     Result^ := #0;
3892     end;
3893    
3894     {----------------------------------------------------------------------------}
3895    
3896     function ExtractTokensZ(S, Delims : PAnsiChar;
3897     QuoteChar : AnsiChar;
3898     AllowNulls : Boolean;
3899     Tokens : TStrings) : Cardinal;
3900    
3901     var
3902     State : (ScanStart,
3903     ScanQuotedToken,
3904     ScanQuotedTokenEnd,
3905     ScanNormalToken,
3906     ScanNormalTokenWithQuote);
3907     CurChar : PAnsiChar;
3908     TokenStart : PAnsiChar;
3909     TempStr : PAnsiChar;
3910     SLen : integer;
3911     begin
3912     {Notes: this routine implements the following state machine
3913     start ----> ScanStart
3914     ScanStart-----quote----->ScanQuotedToken (4)
3915     ScanStart-----delim----->ScanStart (1)
3916     ScanStart-----other----->ScanNormalToken
3917     ScanQuotedToken-----quote----->ScanQuotedTokenEnd
3918     ScanQuotedToken-----other----->ScanQuotedToken
3919     ScanQuotedTokenEnd-----quote----->ScanNormalTokenWithQuote
3920     ScanQuotedTokenEnd-----delim----->ScanStart (2)
3921     ScanQuotedTokenEnd-----other----->ScanNormalToken
3922     ScanNormalToken-----quote----->ScanNormalTokenWithQuote (4)
3923     ScanNormalToken-----delim----->ScanStart (3)
3924     ScanNormalToken-----other----->ScanNormalToken
3925     ScanNormalTokenWithQuote-----quote----->ScanNormalTokenWithQuote
3926     ScanNormalTokenWithQuote-----other----->ScanNormalToken
3927    
3928     (1) output a null token if allowed
3929     (2) output a token, stripping quotes (if the dequoted token is
3930     empty, output a null token if allowed)
3931     (3) output a token; no quote stripping
3932     (4) if the quote character is #0, it's taken to mean that the
3933     routine should not check for quoted substrings. These marked
3934     transitions are the only places this is checked.}
3935    
3936     {clear the tokens string list, set the return value to zero}
3937     Tokens.Clear;
3938     Result := 0;
3939    
3940     {if the input string is empty or the delimiter list is empty or
3941     the quote character is found in the delimiter list, return zero
3942     tokens found}
3943     if (S[0] = #0) or
3944     (Delims[0] = #0) or
3945     CharExistsZ(Delims, QuoteChar) then
3946     Exit;
3947    
3948     {allocate ourselves some scratch space for temporary tokens}
3949     SLen := StrLen(S);
3950     GetMem(TempStr, SLen+1);
3951     try
3952    
3953     {start off in the normal scanning state}
3954     State := ScanStart;
3955    
3956     {the first token starts at the beginning of the string}
3957     TokenStart := S;
3958    
3959     {read through the entire string}
3960     CurChar := S;
3961     while (CurChar^ <> #0) do begin
3962    
3963     {process the character according to the current state}
3964     case State of
3965     ScanStart :
3966     begin
3967     {if the current char is the quote character, switch
3968     states}
3969     if (QuoteChar <> #0) and (CurChar^ = QuoteChar) then
3970     State := ScanQuotedToken
3971    
3972     {if the current char is a delimiter, output a null token}
3973     else if CharExistsZ(Delims, CurChar^) then begin
3974    
3975     {if allowed to, output a null token}
3976     if AllowNulls then begin
3977     Tokens.Add('');
3978     inc(Result);
3979     end;
3980    
3981     {set the start of the next token to be one character
3982     after this delimiter}
3983     TokenStart := CurChar + 1;
3984     end
3985    
3986     {otherwise, the current char is starting a normal token,
3987     so switch states}
3988     else
3989     State := ScanNormalToken
3990     end;
3991    
3992     ScanQuotedToken :
3993     begin
3994     {if the current char is the quote character, switch
3995     states}
3996     if (CurChar^ = QuoteChar) then
3997     State := ScanQuotedTokenEnd
3998     end;
3999    
4000     ScanQuotedTokenEnd :
4001     begin
4002     {if the current char is the quote character, we have a
4003     token consisting of two (or more) quoted substrings, so
4004     switch states}
4005     if (CurChar^ = QuoteChar) then
4006     State := ScanNormalTokenWithQuote
4007    
4008     {if the current char is a delimiter, output the token
4009     without the quotes}
4010     else if CharExistsZ(Delims, CurChar^) then begin
4011    
4012     {if the token is empty without the quotes, output a null
4013     token only if allowed to}
4014     if ((CurChar - TokenStart) = 2) then begin
4015     if AllowNulls then begin
4016     Tokens.Add('');
4017     inc(Result);
4018     end
4019     end
4020    
4021     {else output the token without the quotes}
4022     else begin
4023     inc(TokenStart);
4024     StrLCopy(TempStr, TokenStart, CurChar - TokenStart - 1);
4025     Tokens.Add(StrPas(TempStr));
4026     inc(Result);
4027     end;
4028    
4029     {set the start of the next token to be one character
4030     after this delimiter}
4031     TokenStart := CurChar + 1;
4032    
4033     {switch states back to the start state}
4034     State := ScanStart;
4035     end
4036    
4037     {otherwise it's a (complex) normal token, so switch
4038     states}
4039     else
4040     State := ScanNormalToken
4041     end;
4042    
4043     ScanNormalToken :
4044     begin
4045     {if the current char is the quote character, we have a
4046     complex token with at least one quoted substring, so
4047     switch states}
4048     if (QuoteChar <> #0) and (CurChar^ = QuoteChar) then
4049     State := ScanNormalTokenWithQuote
4050    
4051     {if the current char is a delimiter, output the token}
4052     else if CharExistsZ(Delims, CurChar^) then begin
4053     StrLCopy(TempStr, TokenStart, CurChar - TokenStart);
4054     Tokens.Add(StrPas(TempStr));
4055     inc(Result);
4056    
4057     {set the start of the next token to be one character
4058     after this delimiter}
4059     TokenStart := CurChar + 1;
4060    
4061     {switch states back to the start state}
4062     State := ScanStart;
4063     end;
4064     end;
4065    
4066     ScanNormalTokenWithQuote :
4067     begin
4068     {if the current char is the quote character, switch states
4069     back to scanning a normal token}
4070     if (CurChar^ = QuoteChar) then
4071     State := ScanNormalToken;
4072     end;
4073    
4074     end;
4075    
4076     inc(CurChar);
4077     end;
4078    
4079     {we need to process the (possible) final token}
4080    
4081     {if we are in the scanning quoted token state, we've read an
4082     opening quote, but no closing one; increment the token start
4083     value}
4084     if (State = ScanQuotedToken) then
4085     inc(TokenStart)
4086    
4087     {if we've finished scanning a quoted token, we've read both
4088     quotes; increment the token start value, and decrement the
4089     current index}
4090     else if (State = ScanQuotedTokenEnd) then begin
4091     inc(TokenStart);
4092     dec(CurChar);
4093     end;
4094    
4095     {if the final token is not empty, output the token}
4096     if (TokenStart < CurChar) then begin
4097     StrLCopy(TempStr, TokenStart, CurChar - TokenStart);
4098     Tokens.Add(StrPas(TempStr));
4099     inc(Result);
4100     end
4101     {otherwise the final token is empty, so output a null token if
4102     allowed to}
4103     else if AllowNulls then begin
4104     Tokens.Add('');
4105     inc(Result);
4106     end;
4107    
4108     finally
4109     FreeMem(TempStr, SLen+1);
4110     end;
4111     end;
4112    
4113     {----------------------------------------------------------------------------}
4114    
4115     function ContainsOnlyZ(const S, Chars : PAnsiChar;
4116     var BadPos : Cardinal) : Boolean;
4117     var
4118     Walker : PAnsiChar;
4119     begin
4120     {if the input string is empty, exit}
4121     if (S^ = #0) then begin
4122     Result := false;
4123     BadPos := 0;
4124     Exit;
4125     end;
4126     {otherwise walk through the string until we reach the end or we find
4127     the first char not in our list}
4128     Walker := S;
4129     while (Walker^ <> #0) do begin
4130     if not CharExistsZ(Chars, Walker^) then begin
4131     BadPos := Walker - S;
4132     Result := false;
4133     Exit;
4134     end;
4135     inc(Walker);
4136     end;
4137     {if we reach here, all chars are in the list}
4138     Result := true;
4139     BadPos := 0;
4140     end;
4141    
4142     {----------------------------------------------------------------------------}
4143    
4144     function ContainsOtherThanZ(const S, Chars : PAnsiChar;
4145     var BadPos : Cardinal) : Boolean;
4146     var
4147     Walker : PAnsiChar;
4148     begin
4149     {if the input string is empty, exit}
4150     if (S^ = #0) then begin
4151     Result := false;
4152     BadPos := 0;
4153     Exit;
4154     end;
4155     {otherwise walk through the string until we reach the end or we find
4156     the first char not in our list}
4157     Walker := S;
4158     while (Walker^ <> #0) do begin
4159     if not CharExistsZ(Chars, Walker^) then begin
4160     BadPos := Walker - S;
4161     Result := true;
4162     Exit;
4163     end;
4164     inc(Walker);
4165     end;
4166     {if we reach here, all chars are in the list}
4167     Result := false;
4168     BadPos := 0;
4169     end;
4170    
4171     {----------------------------------------------------------------------------}
4172    
4173     function IsChAlphaZ(C : Char) : Boolean;
4174     {-Returns true if Ch is an alpha}
4175     begin
4176     Result := Windows.IsCharAlpha(C);
4177     end;
4178    
4179     {----------------------------------------------------------------------------}
4180    
4181     function IsChNumericZ(C : AnsiChar; Numbers : PAnsiChar) : Boolean;
4182     {-Returns true if Ch in numeric set}
4183     begin
4184     Result := CharExistsZ(Numbers, C);
4185     end;
4186    
4187     {----------------------------------------------------------------------------}
4188    
4189     function IsChAlphaNumericZ(C : Char; Numbers : PChar) : Boolean;
4190     {-Returns true if Ch is an alpha or numeric}
4191     begin
4192     Result := Windows.IsCharAlpha(C) or CharExistsZ(Numbers, C);
4193     end;
4194    
4195     {----------------------------------------------------------------------------}
4196    
4197     function IsStrAlphaZ(S : PChar) : Boolean;
4198     {-Returns true if all characters in string are an alpha}
4199     begin
4200     Result := false;
4201     if (S^ <> #0) then begin
4202     while (S^ <> #0) do begin
4203     if not Windows.IsCharAlpha(S^) then
4204     Exit;
4205     inc(S);
4206     end;
4207     Result := true;
4208     end;
4209     end;
4210    
4211     {----------------------------------------------------------------------------}
4212    
4213     function IsStrNumericZ(S, Numbers : PAnsiChar) : Boolean;
4214     {-Returns true if all characters in string are in numeric set}
4215     begin
4216     Result := false;
4217     if (S^ <> #0) then begin
4218     while (S^ <> #0) do begin
4219     if not CharExistsZ(Numbers, S^) then
4220     Exit;
4221     inc(S);
4222     end;
4223     Result := true;
4224     end;
4225     end;
4226    
4227     {----------------------------------------------------------------------------}
4228    
4229     function IsStrAlphaNumericZ(S, Numbers : PChar) : Boolean;
4230     {-Returns true if all characters in string are alpha or numeric}
4231     begin
4232     Result := false;
4233     if (S^ <> #0) then begin
4234     while (S^ <> #0) do begin
4235     if (not Windows.IsCharAlpha(S^)) and
4236     (not CharExistsZ(Numbers, S^)) then
4237     Exit;
4238     inc(S);
4239     end;
4240     Result := true;
4241     end;
4242     end;
4243    
4244    
4245     function StrWithinZ(S, SearchStr : PAnsiChar;
4246     Start : Cardinal;
4247     var Position : Cardinal) : Boolean;
4248     var
4249     TmpStr : PAnsiChar;
4250     begin
4251     GetMem(TmpStr, StrLen(S) + 1);
4252     try
4253     StrCopy(TmpStr, S);
4254     if (Start > 0) then
4255     StrStDeleteZ(TmpStr, TmpStr, 0, Start);
4256     Result := StrStPosZ(TmpStr, SearchStr, Position);
4257     if (Result) then
4258     Position := Position + Start;
4259     finally
4260     FreeMem(TmpStr, StrLen(S) + 1);
4261     end;
4262     end;
4263    
4264    
4265     end.

  ViewVC Help
Powered by ViewVC 1.1.20