source: 2.19_branch/Sibyl/SPCC/SYSUTILS.PAS@ 376

Last change on this file since 376 was 7, checked in by RBRi, 19 years ago

+ sibyl staff

  • Property svn:eol-style set to native
File size: 161.2 KB
Line 
1
2{ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
3 º º
4 º Sibyl Portable Component Classes º
5 º º
6 º Copyright (C) 1995,97 SpeedSoft Germany, All rights reserved. º
7 º º
8 ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍŒ}
9
10{*******************************************************}
11{ }
12{ System Utilities Unit (Delphi compatible) }
13{ }
14{ (C) 1995-96 Joerg Pleumann }
15{ (C) 1996 SpeedSoft }
16{ }
17{ Please mail All bugs And suggestions To: }
18{ }
19{ Internet: sa021pl @ uni-duisburg.de }
20{ FidoNet: Joerg Pleumann @ 2:2448/136.6 }
21{ }
22{*******************************************************}
23
24Unit SysUtils;
25
26
27Interface
28
29{ define Compiler symbol GUI To Include FUNCTIONs from
30 OS/2 PM API. If you need A Version Of SysUtils that
31 Uses only OS/2 base API FUNCTIONs (And therefore lacks
32 Some features), comment This Line out And recompile the
33 Unit. Change This To produce programs that Run without
34 the OS/2 PM being Active (may also need changes In
35 System Unit). Normally you shouldn't Change This. }
36
37{$DEFINE GUI}
38
39{$IFDEF OS2}
40 {$IFDEF GUI}
41Uses
42 Os2Def,BseDos, BseErr, PmWin, PMSHL;
43 {$ELSE GUI}
44Uses
45 Os2Def,BseDos, BseErr;
46 {$ENDIF GUI}
47{$ENDIF OS2}
48
49{$IFDEF Win95}
50Uses
51 WinNt, WinBase, WinUser;
52{$ENDIF Win95}
53
54{ constants For SPCC Notification And Error Messages And Month / Day Names. }
55{$I SPCC.Inc}
56
57Type
58 { Pointer To floating Point Value. }
59 PExtended = ^Extended;
60
61Type
62 //Override Exception definition from System To allow formatted Create...
63 Exception=Class(SysException)
64 Public
65 Constructor CreateFmt(Const Msg:String;Const Args:Array Of Const);
66 Constructor CreateRes(Ident:Word);
67 Constructor CreateResFmt(Ident:Word;Const Args:Array Of Const);
68 Constructor CreateResNLS(Ident:Word);
69 Constructor CreateResNLSFmt(Ident:Word;Const Args:Array Of Const);
70 Constructor CreateHelp(Const Msg:String;AHelpContext:LongInt);
71 Constructor CreateFmtHelp(Const Msg:String;Const Args:Array Of Const;AHelpContext:LongInt);
72 Constructor CreateResHelp(Ident:Word;AHelpContext:LongInt);
73 Constructor CreateResFmtHelp(Ident:Word;Const Args:Array Of Const;AHelpContext:LongInt);
74 Constructor CreateResNLSHelp(Ident:Word;AHelpContext:LongInt);
75 Constructor CreateResNLSFmtHelp(Ident:Word;Const Args:Array Of Const;AHelpContext:LongInt);
76 End;
77
78 ExceptClass = Class Of Exception;
79
80 EConvertError = Class(Exception);
81
82Const
83
84{ File Open modes - A legal File Open Mode Is A logical combination
85 Of an Open Mode And A sharing Mode. Please note that OS/2 Normally
86 doesn't allow fmShareCompat, but For reasons Of compatibility the
87 File FUNCTIONs automatically replace This constant by
88 fmShareDenyNone. }
89
90 {$IFDEF OS2}
91 fmOpenRead = $0000;
92 fmOpenWrite = $0001;
93 fmOpenReadWrite = $0002;
94 fmShareCompat = $0000;
95 fmShareExclusive = $0010;
96 fmShareDenyWrite = $0020;
97 fmShareDenyRead = $0030;
98 fmShareDenyNone = $0040;
99 {$ENDIF}
100
101 {$IFDEF Win95}
102 fmOpenRead = $80000000;
103 fmOpenWrite = $40000000;
104 fmOpenReadWrite = $C0000000;
105 fmShareCompat = $00000003;
106 fmShareExclusive = $00000000;
107 fmShareDenyWrite = $00000001;
108 fmShareDenyRead = $00000002;
109 fmShareDenyNone = $00000003;
110 {$ENDIF}
111
112{ File Record}
113Type
114 TFileRec=FileRec;
115
116{ File attribute constants - Please note that there Is no constant
117 faVolumeID, since OS/2 handles volume Ids In another way than Dos
118 does. }
119Const
120 faReadOnly = $0001;
121 faHidden = $0002;
122 faSysFile = $0004;
123 faDirectory = $0010;
124 faArchive = $0020;
125
126 faAnyFile = faReadOnly Or faHidden Or faSysFile Or faDirectory Or faArchive;
127
128{ 'Must' attribute constants - OS/2-specific File attribute constants
129 For searching files. Use these constants In logical combination
130 With the normal File Attributes when calling FindFirst() To restrict
131 the Search results. }
132
133 faMustReadOnly = $0100;
134 faMustHidden = $0200;
135 faMustSysFile = $0400;
136 faMustDirectory = $1000;
137 faMustArchive = $2000;
138
139Const
140
141{ File Lock-TimeOut - This TimeOut Value Is used when performing File
142 locking / unlocking operations. Value Is given In ms. }
143
144 LockTimeout: LongInt = 5000;
145
146Type
147
148{ support For date And Time operations - both values are stored In
149 one floating Point Value. the Integer part Contains the days passed
150 since 31-Dec-0000, assuming that the Gregorian calendar has always
151 been used. the fractional part Contains the part Of the Day since
152 00:00:00. the Time part Is always equal To Or greater than Zero
153 And smaller than one. }
154
155 TDateTime = Extended;
156
157Const
158
159 SecsPerDay = 24 * 60 * 60;
160 MSecsPerDay = SecsPerDay * 1000;
161
162Type
163
164{ Some Type conversion records. }
165
166 WordRec = Record
167 Lo, Hi: Byte;
168 End;
169
170 LongRec = Record
171 Lo, Hi: Word;
172 End;
173
174 TMethod = Record
175 Code, Data: Pointer;
176 End;
177
178{ Some useful arrays. }
179
180 PByteArray = ^TByteArray;
181 TByteArray = Array[0..MaxLongInt] Of Byte;
182
183 PWordArray = ^TWordArray;
184 TWordArray = Array[0..MaxLongInt Div 2] Of Word;
185
186{ Generic Procedure Type. }
187
188 TProcedure = Procedure;
189
190{ Generic FileName Type }
191
192 TFileName = String;
193
194{ File Search Record - This Is the Data structure internally used
195 by the FindFirst, FindNext, And FindClose FUNCTIONs. }
196
197 TSearchRec = Record
198 {$IFDEF Win95}
199 InternalAttr:LongWord;
200 SearchRecIntern:WIN32_FIND_DATA;
201 {$ENDIF}
202 HDir: LongWord;
203 Attr: Byte;
204 Time: LongInt;
205 Size: LongInt;
206 Name: String;
207 End;
208
209{ FloatToText codes - these codes are used To specify the basic
210 Output format Of the various FUNCTIONs that Convert floating
211 Point values To Strings. }
212
213 TFloatFormat = (ffGeneral, ffExponent, ffFixed, ffNumber, ffCurrency);
214
215{ FloatToDecimal Result Record - This Record Is used To hold the return
216 Value Of the FloatToDecimal Function. }
217
218 TFloatRec = Record
219 Exponent: Integer;
220 Negative: Boolean;
221 Digits: Array[0..18] Of Char;
222 End;
223
224Const
225
226{ Empty String And Pointer To Empty String - used internally by various
227 String FUNCTIONs. }
228
229 EmptyStr: String[1] = '';
230 NullStr: PString = @EmptyStr;
231
232Var
233
234{ --- date, Time, And currency defaults ---
235
236 the following global variables contain Default values For formatting
237 date, Time, And currency values. most Of them are queried from the
238 System At Program startup. Some others are taken from the
239 application's resources. }
240
241{ DateSeparator - the character used To separate Year, Month, And Day,
242 when converting A TDateTime Value To Text. queried from the System
243 At Program startup. }
244
245 DateSeparator: Char;
246
247{ ShortDateFormat - the Default format String used when converting a
248 TDateTime Value To Text. This one Is used whenever A short Result
249 Is desired. the Value Is computed At Program startup. }
250
251 ShortDateFormat: String[15];
252
253{ LongDateFormat - the Default format String used when converting a
254 TDateTime Value To Text. This one Is used whenever A LONG Result
255 Is desired. the Value Is computed At Program startup. }
256
257 LongDateFormat: String[31];
258
259{ ShortMonthNames - Abbreviations For Month Names used when converting
260 A TDateTime Value To Text. the Names are taken from the program's
261 resources. }
262
263 ShortMonthNames: Array[1..12] Of String[7];
264
265{ LongMonthNames - the full Month Names used when converting a
266 TDateTime Value To Text. the Names are taken from the program's
267 resources. }
268
269 LongMonthNames: Array[1..12] Of String[15];
270
271{ ShortDayNames - Abbreviations For Day Names used when converting
272 A TDateTime Value To Text. the Names are taken from the program's
273 resources. }
274
275 ShortDayNames: Array[1..7] Of String[7];
276
277{ LongDayNames - the full Day Names used when converting A TDateTime
278 Value To Text. the Names are taken from the program's resources. }
279
280 LongDayNames: Array[1..7] Of String[15];
281
282{ DateOrder - the order Of Year, Month, And Day assumed when trying To
283 extract date information from A String. queried from the System At
284 Program startup. }
285
286 DateOrder: Byte;
287
288{ TimeSeparator - the character used To separate Hour, Minute, And
289 Second, when converting A TDateTime Value To Text. queried from the
290 System At Program startup. }
291
292 TimeSeparator: Char;
293
294{ TimeAMString - the String appended To Time values between 00:00 And
295 11:59 when converting A DateTime Value To Text. only used when
296 12-Hour clock format Is used. queried from the System At Program
297 startup. }
298
299 TimeAMString: String[7];
300
301{ TimePMString - the String appended To Time values between 12:00 And
302 23:59 when converting A DateTime Value To Text. only used when
303 12-Hour clock format Is used. queried from the System At Program
304 startup. }
305
306 TimePMString: String[7];
307
308{ ShortTimeFormat - the Default format String used when converting a
309 TDateTime Value To Text. This one Is used whenever A shorter Result
310 Is desired. queried from the System At Program startup. }
311
312 ShortTimeFormat: String[15];
313
314{ LongTimeFormat - the Default format String used when converting a
315 TDateTime Value To Text. This one Is used whenever A longer Result
316 Is desired. queried from the System At Program startup. }
317
318 LongTimeFormat: String[31];
319
320{ TwelveHours - Indicates whether 12-Hour clock format Is used when
321 trying To extract Time information from A String. queried from
322 the System At Program startup. }
323
324 TwelveHours: Boolean;
325
326{ CurrencyString - the local currency String used when converting
327 currency values To Text. Default Value Is queried from the System
328 At Program startup. }
329
330 CurrencyString: String[7];
331
332{ CurrencyFormat - the order Of currency Value, currency String, And
333 separating space used when converting currency values To Text.
334 Default Value Is queried from the System At Program startup.
335
336 the following values four are possible, With the fifth one
337 being an additional Value that Is only supported by OS/2:
338
339 0 = '$1' 1 = '1$' 2 = '$ 1' 3 = '1 $'
340
341 4 = currency String replaces DECIMAL indicator }
342
343 CurrencyFormat: Byte;
344
345{ NegCurrFormat - Corresponds To CurrencyFormat, but Is used when
346 converting Negative currency values To Text. queried from the
347 System At Program startup.
348
349 the following values are possible:
350
351 0 = '($1)' 1 = '-$1' 2 = '$-1' 3 = '$1-'
352 4 = '(1$)' 5 = '-1$' 6 = '1-$' 7 = '1$-'
353 8 = '-1 $' 9 = '-$ 1' 10 = '$ 1-'
354
355 since OS/2 doesn't support A Special format For Negative currency
356 values, A format Is chosen that matches the CurrencyFormat With
357 A preceding '-'. the following List shows the possible values:
358
359 CurrencyFormat NegCurrFormat
360
361 0 = '$1' 1 = -$1
362 1 = '1$' 5 = -1$
363 2 = '$ 1' 9 = -$ 1
364 3 = '1 $' 8 = -1 $ }
365
366 NegCurrFormat: Byte;
367
368{ ThousandSeparator - the character used To separate blocks Of three
369 Digits when converting floating Point values To Text. queried from
370 the System At Program startup. }
371
372 ThousandSeparator: Char;
373
374 { DecimalSeparator - the character used To separate the Integer part
375 from the fractional part when converting floating Point values To
376 Text. queried from the System At Program startup. }
377
378 DecimalSeparator: Char;
379
380{ CurrencyDigits - the Number Of Digits used In the fractional part
381 Of A currency Value when converting A currency Value To Text.
382 queried from the System At Program startup. }
383
384 CurrencyDecimals: Byte;
385
386{ ListSeparator - the character To Use when separating Items In A List.
387 Currently Not used by any Function. }
388
389 ListSeparator: Char;
390
391{ --- Memory management --- }
392
393{ AllocMem - Allocates A Memory block Of the desired Size ON the heap.
394 In contrast To the GetMem Standard Procedure, AllocMem fills the
395 whole block With zeroes. }
396
397Function AllocMem(Size: Cardinal): Pointer;
398
399{ ReAllocMem - re-Allocates A previously allocated Memory block And
400 changes its Size. copies the contents Of the old block into the
401 New one. CurSize And NewSize specify the Current And the New Size
402 Of the block. If the New Size Is larger than the Current Size, the
403 additional Bytes are zeroed. the old Memory block Is automatically
404 disposed. note that the resulting Pointer will always be different
405 from the old Pointer, even If the Size isn't changed. the Function
406 can Handle Nil pointers And Zero blocks. }
407
408Function ReAllocMem(P: Pointer; CurSize, NewSize: Cardinal): Pointer;
409
410{ --- Exit Procedure Handling --- }
411
412{ AddExitProc - Adds A parameterless Procedure To the List Of
413 procedures To be called when the Program Is Terminated. note that
414 the Procedure that Is added Last will be called First. }
415
416Procedure AddExitProc(Proc: TProcedure);
417
418{ CallExitProcs - calls All procedures that were installed by
419 AddExitProc And deletes them from the List. note that the
420 Procedure that was added Last will be called First. }
421
422Procedure CallExitProcs;
423
424{ --- String Handling --- }
425
426{ NewStr - Allocates A block Of Memory ON the heap And fills it With
427 the given String, returns A PString To the Memory block. the Memory
428 block's Size will be exactly one Byte more than the string's Real
429 Length. Empty Strings don't Use any heap space, the Function returns
430 NullStr In This Case. since NullStr Points To EmptyStr, the Function
431 never returns Nil, So you can always de-Reference the resulting
432 Pointer. Use DisposeStr To Free the Memory block. }
433
434Function NewStr(Const S: String): PString;
435
436{ DisposeStr - Disposes A block Of Memory ON the heap that Contains
437 A String. the block MUST have been allocated by A call To NewStr.
438 If the given Pointer Is NullStr (And thereby references the Empty
439 String) Or Nil, the Function does absolutely Nothing. }
440
441Procedure DisposeStr(P: PString);
442
443{ AssignStr - Assigns A New Value To A String Pointer that has been
444 previously allocated by A call To NewStr, Or Is Nil. the old String
445 Is disposed by DisposeStr, And the New one Is allocated by NewStr. }
446
447Procedure AssignStr(Var P: PString; Const S: String);
448
449{ AppendStr - Appends A String To the End Of another. }
450
451Procedure AppendStr(Var Dest: String; Const S: String);
452
453{ uppercase - Converts A String To upper Case by simply Changing All
454 occurences Of 'a'..'z' To the corresponding upper Case characters.
455 If you want A conversion that also considers international Special
456 characters, Use AnsiUpperCase. }
457
458Function uppercase(Const S: String): String;
459
460{ lowercase - Converts A String To lower Case by simply Changing All
461 occurences Of 'A'..'Z' To the corresponding lower Case characters.
462 If you want A conversion that also considers international Special
463 characters, Use AnsiLowerCase. }
464
465Function lowercase(Const S: String): String;
466
467{ CompareStr - Compares two Strings And returns an Integer Value
468 As In the following Table:
469
470 s1 < s2 Result < 0
471 s1 = s2 Result = 0
472 s1 > s2 Result > 0
473
474 CompareStr Is Case-sensitive, but does Not take international
475 Special characters Or the Currently Selected codepage into account. }
476
477Function CompareStr(Const s1, s2: String): Integer;
478
479{ CompareText - Compares two Strings And returns an Integer Value
480 As In the following Table:
481
482 s1 < s2 Result < 0
483 s1 = s2 Result = 0
484 s1 > s2 Result > 0
485
486 CompareText Is Case-insensitive, And does Not take international
487 Special characters Or the Currently Selected codepage into account. }
488
489Function CompareText(Const s1, s2: String): Integer;
490
491{ AnsiUpperCase - Converts A String To upper Case. This Function
492 also takes international Special characters And the Currently
493 Selected codepage into account. If you don't want This, Use
494 uppercase. }
495
496Function AnsiUpperCase(Const S: String): String;
497
498{ AnsiLowerCase - Converts A String To lower Case. This Function
499 also takes international Special characters And the Currently
500 Selected codepage into account. If you don't want This, Use
501 lowercase. note that AnsiLowerCase Is Not available under OS/2. }
502
503{$IFNDEF OS2}
504Function AnsiLowerCase(Const S: String): String;
505{$ENDIF}
506
507{ AnsiCompareStr - Compares two Strings And returns an Integer Value
508 As In the following Table:
509
510 s1 < s2 Result < 0
511 s1 = s2 Result = 0
512 s1 > s2 Result > 0
513
514 AnsiCompareStr Is Case-sensitive, And takes international Special
515 characters And the Currently Selected codepage into account. note
516 that the Function Is Not available under OS/2. }
517
518{$IFNDEF OS2}
519Function AnsiCompareStr(Const s1, s2: String): Integer;
520{$ENDIF}
521
522{ AnsiCompareText - Compares two Strings And returns an Integer Value
523 As In the following Table:
524
525 s1 < s2 Result < 0
526 s1 = s2 Result = 0
527 s1 > s2 Result > 0
528
529 AnsiCompareText Is Case-insensitive, And takes international Special
530 characters And the Currently Selected codepage into account. }
531
532Function AnsiCompareText(Const s1, s2: String): Integer;
533
534{ Trim - Removes leading And trailing spaces And Control characters. }
535
536Function Trim(Const S: String): String;
537
538{ TrimLeft - Removes leading spaces And Control characters. }
539
540Function TrimLeft(Const S: String): String;
541
542{ TrimRight - Removes trailing spaces And Control characters. }
543
544Function TrimRight(Const S: String): String;
545
546{ QuotedStr - returns the given String enclosed In quotes. quotes already
547 included In the String are returned As two quote characters. }
548
549Function QuotedStr(Const S: String): String;
550
551{ IsValidIdent - Checks whether the given String Contains A legal
552 Pascal identifier. check your Speed-Pascal manual To See what A
553 legal identifier looks like. :-) }
554
555Function IsValidIdent(Const Ident: String): Boolean;
556
557{ IntToStr - Converts an Integer Value To A String Of Digits. }
558
559Function IntToStr(Value: LongInt): String;
560
561{ IntToHex - Converts an Integer Value To A String Of hexadecimal
562 Digits. the minimum desired Number Of Digits can be specified.
563 If the Result Contains less Digits, it Is Left-padded With zeroes. }
564
565Function IntToHex(Value: LongInt; Digits: Integer): String;
566
567{ StrToInt - Extracts an Integer Value from A String. If the String
568 doesn't contain A legal Integer Value, Exception EConvertError
569 Is raised. }
570
571Function StrToInt(Const S: String): LongInt;
572
573{ StrToIntDef - Extracts an Integer Value from A String. If the String
574 doesn't contain A legal Integer Value, the desired Default Value
575 Is returned instead. }
576
577{$IFDEF GUI}
578Function StrToIntDef(Const S: String; Default: LongInt): LongInt;
579{$ENDIF GUI}
580
581{ LoadStr - Loads A String from the application's resources. the
582 String Is retrieved by an Integer Number. If the resources don't
583 contain A String With the given Number, LoadStr returns an Empty
584 String. }
585
586{$IFDEF GUI}
587Function LoadStr(Ident: Word): String;
588{$ENDIF GUI}
589
590{ LoadNLSStr - Loads A String from the application's Current Language Table. the
591 String Is retrieved by an Integer Number. If the resources don't
592 contain A String With the given Number, LoadStr returns an Empty
593 String. }
594
595Function LoadNLSStr(Ident: Word): String;
596
597{ LoadTableStr - Loads A String from the specified String Table. the
598 String Is retrieved by an Integer Number. If the resources don't
599 contain A String With the given Number, LoadStr returns an Empty
600 String. }
601
602Function LoadTableStr(Const Table:String;Ident: Word): String;
603
604{ FmtLoadStr - Loads A String from the application's resources And
605 replaces Some placeholders by values given In an Open-Array. the
606 String Is retrieved by an Integer Number. If the resources don't
607 contain A String With the given Number, FmtLoadStr returns an
608 Empty String. }
609
610{$IFDEF GUI}
611Function FmtLoadStr(Ident: Word; Const Args: Array Of Const): String;
612{$ENDIF GUI}
613
614{ FmtLoadNLSStr - Loads A String from the application's Current Language Table And
615 replaces Some placeholders by values given In an Open-Array. the
616 String Is retrieved by an Integer Number. If the resources don't
617 contain A String With the given Number, FmtLoadStr returns an
618 Empty String. }
619
620Function FmtLoadNLSStr(Ident: Word; Const Args: Array Of Const): String;
621
622{ FmtLoadTableStr - Loads A String from the specified String Table And
623 replaces Some placeholders by values given In an Open-Array. the
624 String Is retrieved by an Integer Number. If the resources don't
625 contain A String With the given Number, FmtLoadStr returns an
626 Empty String. }
627
628Function FmtLoadTableStr(Const Table:String;Ident: Word; Const Args: Array Of Const): String;
629
630
631{ SysErrorMessage - returns A System Error Message. }
632
633{$IFDEF OS2}
634Function SysErrorMessage(MsgNum: LongInt): String;
635{$ENDIF OS2}
636
637{ --- File management --- }
638
639{ FileOpen - Opens an existing File With A given File Mode. the File
640 Mode Is A logical combination Of one Of the File Open constants
641 (fmOpenXXX) And one Of the sharing Mode constants (fmShareXXX). If
642 the File Is successfully opended, the resulting Integer Value Is
643 positive And Contains the File Handle. Otherwise the Result Is the
644 Negative Value Of the Error Code returned by the operating System. }
645
646Function FileOpen(Const FileName: String; Mode: Word): LongInt;
647
648{ FileCreate - creates A New File Or overwrites an existing one. no
649 File Mode can be specified, So the File Is always created With
650 fmOpenWrite Or fmShareExclusive. If the File Is successfully
651 created, the resulting Integer Value Is positive And Contains the
652 File Handle. Otherwiese the Result Is the Negative Value Of the
653 Error Code returned by the operating System. }
654
655Function FileCreate(Const FileName: String): LongInt;
656
657{ FileOpenOrCreate - Opens Or creates A File, depending ON whether
658 the File already exists Or Not. A File Mode can be specified. the
659 File Mode Is A logical combination Of one Of the File Open constants
660 (fmOpenXXX) And one Of the sharing Mode constants (fmShareXXX). If
661 the File Is successfully opended Or created, the resulting Integer
662 Value Is positive And Contains the File Handle. Otherwise the
663 Result Is the Negative Value Of the Error Code returned by the
664 operating System. }
665
666Function FileOpenOrCreate(Const FileName: String; Mode: Word): LongInt;
667
668{ FileCreateIfNew - creates A File If there's Not already A File With
669 the same Name. A File Mode can be specified. the File Mode Is a
670 logical combination Of one Of the File Open constants (fmOpenXXX)
671 And one Of the sharing Mode constants (fmShareXXX). If the New File
672 Is successfully created, the resulting Integer Value Is positive And
673 Contains the File Handle. Otherwise the Result Is the Negative Value
674 Of the Error Code returned by the operating System. note that This
675 Function also fails If the File already exists. }
676
677Function FileCreateIfNew(Const FileName: String; Mode: Word): LongInt;
678
679{ FileRead - Attempts To Read up To Count Bytes from the given File
680 Handle And returns the Number Of Bytes actually Read. If an Error
681 occurs, the Result Is -1. }
682
683Function FileRead(Handle: LongInt; Var Buffer; Count: LongInt): LongInt;
684
685{ FileWrite - Attempts To Write up To Count Bytes To the given File
686 Handle And returns the Number Of Bytes actually written. If an Error
687 occurs, the Result Is -1. }
688
689Function FileWrite(Handle: LongInt; Const Buffer; Count: LongInt): LongInt;
690
691{ FileSeek - changes the Current Position Of A File Handle by Count
692 Bytes. the actual Movement depends ON the Value Of Origin, according
693 To the following Table:
694
695 Origin Action
696
697 0 Move relative To the file's beginning
698 1 Move relative To the Current Position
699 2 Move relative To the file's End
700
701 the Function returns the New Position, Or -1 If an Error occured. }
702
703Function FileSeek(Handle: LongInt; Offset: LongInt; Origin: Integer): LongInt;
704
705{ FileClose - Closes A File And frees the Handle. }
706
707Procedure FileClose(Handle: LongInt);
708
709{ FileLock - Locks A Range Of A File For exclusive access by the
710 Application. returns A Boolean Value indicating Success Or
711 failure. note that the Function waits up To the Time specified
712 In the LockTimeout global variable before it fails. }
713
714Function FileLock(Handle, Offset, Range: LongInt): Boolean;
715
716{ FileUnLock - Unlocks A Range Of A File that was previously locked
717 For exclusive access by the Application. returns A Boolean Value
718 indicating Success Or failure. }
719
720Function FileUnLock(Handle, Offset, Range: LongInt): Boolean;
721
722{ FileAge - returns the date And Time Of A file's Last modification.
723
724 If the File doesn't exist, -1 Is returned instead.
725
726 To Use date / Time formatting FUNCTIONs For This Value, Convert it
727 To A TDateTime by A call To FileDateToDateTime First. }
728
729Function FileAge(Const FileName: String): LongInt;
730
731{ FileExists - Indicates whether A File exists Or Not. }
732
733Function FileExists(Const FileName: String): Boolean;
734
735{ FindFirst - Starts A Search For files specified by A Name Pattern
736 And File Attributes.
737
738 any Pattern that Is allowed ON the Command Line Is also A legal
739 argument For Path.
740
741 Attr Is A logical combination Of File Attributes (faXXX) And
742 File-MUST Attributes (faMustXXX), the latter being available only
743 under OS/2.
744
745 the Var SearchRec will contain Name And Attributes Of the First File
746 that matched the given specs. In This Case the Function returns 0.
747 If an Error occurs, the Result Is the Negative Value Of the Error
748 Code returned by the operating System.
749
750 Use FindNext To Find more files And FindClose To End the File
751 Search. note that you MUST Use FindClose, Or you may Run out Of
752 handles after A While. }
753
754Function FindFirst(Const Path: String; Attr: Integer; Var SearchRec: TSearchRec): LongInt;
755
756{ FindNext - after A call To FindNext, the Var SearchRec Contains the
757 Next File that matches the specs Of A File Search previously started
758 by FindFirst.
759
760 A return Value Of 0 Indicates Success. you may call FindNext Until
761 an Error occures (With the Negative Value Of the operating system's
762 Error Code returned), Or Until no more matching files are found
763 (usually indicated by A return Value Of -18.) }
764
765Function FindNext(Var SearchRec: TSearchRec): LongInt;
766
767{ FindClose - Ends A File Search previously started by FindFirst. note
768 that you MUST Use FindClose, Or you may Run out Of handles after a
769 While. }
770
771Procedure FindClose(Var SearchRec: TSearchRec);
772
773{ FileGetDate - returns the date And Time Of A file's Last
774 modification. If the given File Handle Is invalid, -1 Is returned
775 instead.
776
777 To Use date / Time formatting FUNCTIONs For the Result, Convert
778 it To A TDateTime by A call To FileDateToDateTime First. }
779
780Function FileGetDate(Handle: LongInt): LongInt;
781
782{ FileSetDate - changes the date And Time Of A file's Last
783 modification. If the Operation fails due To an invalid Handle Or
784 an illegal Age Parameter, the date And Time remain unchanged.
785
786 This Procedure doesn't Accept TDateTime values. you have To Convert
787 them To A LongInt by DateTimeToFileDate First. }
788
789Procedure FileSetDate(Handle: Integer; Age: LongInt);
790
791{ FileGetAttr - returns A file's Attributes. the Result Value Is a
792 logical combination Of File attribute constants (faXXX). If the
793 Function fails due To A non-existing File Or another Error
794 condition, the Result Is the Negative Value Of the operating
795 system's Error Code. }
796
797Function FileGetAttr(Const FileName: String): LongInt;
798
799{ FileSetAttr - changes A file's Attributes. the Attr Parameter may
800 contain any logical combination Of File attribute constants
801 (faXXX). A Result Value Of 0 Indicates Success. If the Function
802 fails due To A non-existing File Or another Error condition, the
803 Result Is the Negative Value Of the operating system's Error Code. }
804
805Function FileSetAttr(Const FileName: String; Attr: Integer): Integer;
806
807{ CopyFile - copies A File. Result Is A Boolean indicating Success Or
808 failure. }
809
810Function CopyFile(Const SourceName, DestName: String): Boolean;
811
812{ DeleteFile - deletes A File. Result Is A Boolean indicating Success
813 Or failure. }
814
815Function DeleteFile(Const FileName: String): Boolean;
816
817{ RenameFile - Renames A File. Result Is A Boolean indicating Success
818 Or failure. you may Use RenameFile To Move A File To A New location,
819 but only If the Drive stays the same. }
820
821Function RenameFile(Const OldName, NewName: String): Boolean;
822
823{ ChangeFileExt - changes the extension Of A given FileName. the
824 extension Is the part from the rightmost dot To the End Of the
825 FileName. If the old FileName doesn't contain an extension, it
826 Is simply added. the extension MUST Start With A dot.
827
828 note that the Function only handles A String, but does Not Perform
829 any Physical changes To files. }
830
831Function ChangeFileExt(Const FileName, extension: String): String;
832
833{ ExtractFilePath - returns the Drive And Directory parts Of a
834 FileName, that Is, everything from the Start To the rightmost colon
835 Or backslash In the String. If the FileName doesn't contain Drive Or
836 Directory information, an Empty String Is returned. }
837
838Function ExtractFilePath(Const FileName: String): String;
839
840{ ExtractFileName - returns the Name And extension parts Of A
841 FileName, that Is, everything from rightmost colon Or backslash To
842 the End Of the String. If the FileName doesn't contain A Name Or
843 extension, an Empty String Is returned. }
844
845Function ExtractFileName(Const FileName: String): String;
846
847{ ExtractFileExt - returns the extension part Of A FileName, that Is,
848 everything from rightmost dot To the End Of the String. If the
849 FileName doesn't contain A dot, an Empty String Is returned. }
850
851Function ExtractFileExt(Const FileName: String): String;
852
853{ ConcatFileName - Concatenates two filenames, assuming the First
854 one specifies Some Kind Of Directory information, And the Second
855 one A FileName. the Result Is A Complete legal pathname. the
856 Function automatically inserts A backslash, If necessary. }
857
858Function ConcatFileName(Const pathname, FileName: String): String;
859
860{ ExpandFileName - Expands A FileName To an Absolute FileName, that
861 Is, A FileName containing A Drive letter, Directory information
862 relative To the root Of the Drive, And the FileName. Embedded '..'
863 are removed. }
864
865Function ExpandFileName(FileName: String): String;
866
867{ EditFileName - changes A FileName using A Pattern possibly
868 containing the wildcards '*' And '?'. everything that would
869 be Accepted by the Copy Command should be legal For Name And
870 edit. }
871
872Function EditFileName(Const Name, edit: String): String;
873
874{ FileSearch - Searches For A File Name In A List Of directories
875 given by DirList. the Directory entries MUST be separated by
876 semicolons, just like the system's Path. the working Directory
877 Is implicitly prepended To the List Of directories. the Result
878 String Is either the First occurence Of the File Complete With
879 the Directory it was found In, Or the Empty String, If the File
880 could Not be found. }
881
882Function FileSearch(Const Name, DirList: String): String;
883
884{ DiskFree - returns the Free space Of the given disk Drive. Drive 0
885 Is the Current Drive, Drive 1 Is 'A:', And So ON. If the given Drive
886 Is invalid Or cannot be Read, -1 Is returned, Otherwise the Result
887 Contains the Number Of Bytes Free. }
888
889Function DiskFree(Drive: Byte): LongInt;
890
891{ DiskSize - returns the disk Size Of the given disk Drive. Drive 0
892 Is the Current Drive, Drive 1 Is 'A:', And So ON. If the given Drive
893 Is invalid Or cannot be Read, -1 Is returned, Otherwise the Result
894 Contains the Number Of Bytes that can be potentially used For File
895 storage. }
896
897Function DiskSize(Drive: Byte): LongInt;
898
899{ FileDateToDateTime - Converts A File date / Time Value To a
900 TDateTime that can be used within formatting operations. }
901
902Function FileDateToDateTime(FileDate: LongInt): TDateTime;
903
904{ FileDateToDateTime - Converts A TDateTime To A File date / Time
905 Value that can be used within File FUNCTIONs. }
906
907Function DateTimeToFileDate(DateTime: TDateTime): LongInt;
908
909{ --- 'C'-like String Handling --- }
910
911{ StrLen - returns the Length Of Str, ignoring the terminating Zero. }
912
913Function StrLen(Str: PChar): Cardinal;
914
915{ StrEnd - returns A Pointer To the terminating Zero Of Str. }
916
917Function StrEnd(Str: PChar): PChar;
918
919{ StrMove - copies exactly Count characters from Source To Dest. It's
920 okay when Source And Dest overlap, StrMove can Handle This. }
921
922Function StrMove(Dest, Source: PChar; Count: Cardinal): PChar;
923
924{ StrCopy - copies Source To Dest And returns Dest. }
925
926Function StrCopy(Dest, Source: PChar): PChar;
927
928{ StrECopy - copies Source To Dest And returns A Pointer To the
929 terminating Zero Of the resulting String. }
930
931Function StrECopy(Dest, Source: PChar): PChar;
932
933{ StrLCopy - copies A maximum Of MaxLen characters from Source To Dest
934 And returns Dest. }
935
936Function StrLCopy(Dest, Source: PChar; MaxLen: Cardinal): PChar;
937
938{ StrPCopy - copies A Pascal String Source To A PChar Dest And returns
939 Dest. }
940
941Function StrPCopy(Dest: PChar; Const Source: String): PChar;
942
943{ StrPLCopy - copies A maximum Of MaxLen characters from A Pascal
944 String Source To A PChar Dest. returns Dest. }
945
946Function StrPLCopy(Dest: PChar; Const Source: String; MaxLen: Cardinal): PChar;
947
948{ StrCat - Concatenates Dest And Source, that Is, Appends Source To
949 the End Of Dest, And returns Dest. }
950
951Function StrCat(Dest, Source: PChar): PChar;
952
953{ StrLCat - Concatenates Dest And Source, that Is, Appends Source To
954 the End Of Dest, but copies only So many characters that the
955 resulting String does Not exceed MaxLen characters. returns Dest. }
956
957Function StrLCat(Dest, Source: PChar; MaxLen: Cardinal): PChar;
958
959{ StrComp - Compares two Strings And returns an Integer Value
960 As In the following Table:
961
962 Str1 < Str2 Result < 0
963 Str1 = Str2 Result = 0
964 Str1 > Str2 Result > 0
965
966 StrComp Is Case-sensitive, but does Not take international Special
967 characters Or the Currently Selected codepage into account. }
968
969Function StrComp(Str1, Str2: PChar): Integer;
970
971{ StrIComp - Compares two Strings And returns an Integer Value
972 As In the following Table:
973
974 Str1 < Str2 Result < 0
975 Str1 = Str2 Result = 0
976 Str1 > Str2 Result > 0
977
978 StrComp Is Case-insensitive, And does Not take international
979 Special characters Or the Currently Selected codepage into account. }
980
981Function StrIComp(Str1, Str2: PChar): Integer;
982
983{ StrLComp - Compares up To MaxLen characters Of two Strings And
984 returns an Integer Value As In the following Table:
985
986 Str1 < Str2 Result < 0
987 Str1 = Str2 Result = 0
988 Str1 > Str2 Result > 0
989
990 StrLComp Is Case-sensitive, but does Not take international Special
991 characters Or the Currently Selected codepage into account. }
992
993Function StrLComp(Str1, Str2: PChar; MaxLen: Cardinal): Integer;
994
995{ StrLIComp - Compares up To MaxLen characters Of two Strings And
996 returns an Integer Value As In the following Table:
997
998 Str1 < Str2 Result < 0
999 Str1 = Str2 Result = 0
1000 Str1 > Str2 Result > 0
1001
1002 StrLComp Is Case-insensitive, And does Not take international
1003 Special characters Or the Currently Selected codepage into account. }
1004
1005Function StrLIComp(Str1, Str2: PChar; MaxLen: Cardinal): Integer;
1006
1007{ StrScan - Searches For the First occurence Of A character In A
1008 String. returns the Pointer To the occurence, Or Nil, If the
1009 character cannot be found. }
1010
1011Function StrScan(Str: PChar; Chr: Char): PChar;
1012
1013{ StrRScan - Searches For the Last occurence Of A character In A
1014 String. returns the Pointer To the occurence, Or Nil, If the
1015 character cannot be found. }
1016
1017Function StrRScan(Str: PChar; Chr: Char): PChar;
1018
1019{ StrScan - Searches For the First occurence Of A SubStr In A given
1020 String Str. returns the Pointer To the occurence, Or Nil, If the
1021 SubStr cannot be found. }
1022
1023Function StrPos(Str, SubStr: PChar): PChar;
1024
1025{ StrUpper - Converts A String To upper Case by simply Changing All
1026 occurences Of 'a'..'z' To the corresponding upper Case characters.
1027 returns A Pointer To the String. changes the Source String, does
1028 Not Create A New String. does also Not take international Special
1029 characters Or the Currently Selected codepage into account. }
1030
1031Function StrUpper(Str: PChar): PChar;
1032
1033{ StrLower - Converts A String To lower Case by simply Changing All
1034 occurences Of 'A'..'Z' To the corresponding lower Case characters.
1035 returns A Pointer To the String. changes the Source String, does
1036 Not Create A New String. does also Not take international Special
1037 characters Or the Currently Selected codepage into account. }
1038
1039Function StrLower(Str: PChar): PChar;
1040
1041{ StrPas - Converts A PChar Str To A Pascal String. }
1042
1043Function StrPas(Str: PChar): String;
1044
1045{ StrAlloc - Allocates A block Of Memory For storing PChars. the Size
1046 Is specified And stored In A Double Word that preceeds the Buffer.
1047 Use StrDispose To Free the Buffer. }
1048
1049Function StrAlloc(Size: Cardinal): PChar;
1050
1051{ StrBufSize - returns the Size Of A PChar Buffer that has been
1052 previously allocated by StrAlloc. }
1053
1054Function StrBufSize(Str: PChar): Cardinal;
1055
1056{ StrNew - creates A Copy Of A given String. In contrast To StrCopy,
1057 StrNew Allocates A Memory block that can hold the String, by a
1058 call To StrAlloc. Then it copies the Source String. the New
1059 String can be disposed by A call To StrDispose. }
1060
1061Function StrNew(Str: PChar): PChar;
1062
1063{ StrDispose - Disposes A PChar Buffer that has been previously
1064 allocated by A call To StrAlloc. }
1065
1066Procedure StrDispose(Str: PChar);
1067
1068{ --- String formatting --- }
1069
1070{ format - formats A String And replaces placeholders by arguments.
1071
1072 the format String can contain arbitrary Text. This Text Is simply
1073 copied into the Result. everything that Starts With A '%' Is
1074 considered A placeholder. placeholders are replaced by the
1075 Parameters given In the variant-Type Open-Array Args. the First
1076 placeholder Is replaced by the First argument, the Second one
1077 by the Second argument, And So ON. you MUST specify At least As many
1078 Parameters As there are placeholders, Otherwise an Exception
1079 EConvertError will be raised.
1080
1081 the way A placeholder / argument pair will be Handled Is controlled
1082 by Some optional specifiers. the Line below shows the possibilities.
1083
1084 Text In " " MUST appear literally, 'index', 'width' And 'precision'
1085 MUST be replaced by Integer numbers, And 'type' MUST be replaced by
1086 A character that specifies the argument Type.
1087
1088 parts enclosed In angular brackets are optional, the angular
1089 brackets MUST Not appear In the format specifier, they are only used
1090 To Show the syntax.
1091
1092 "%" [Index ":"] ["-"] [Width] ["." Precision] Type
1093
1094 the different parts Of the format specifier MUST appear In the
1095 given order, And they have the following meaning:
1096
1097 "%" Begins the format specifier
1098
1099 Index ":" takes the Next argument from the Array entry
1100 given by Integer Value Index. Normally the
1101 arguments are used one after the other. This
1102 part Of the format specifier allows To Change
1103 This behaviour.
1104
1105 "-" Left-Justifies the Text inserted For the format
1106 specifier. Normally the Text Is justified To
1107 the Right. only applies If the String Is Left-
1108 padded With spaces by the Width-specifier.
1109
1110 Width Integer Value that specifies the Width being
1111 reserved For the argument. If the String
1112 resulting from the conversion Of the argument
1113 Contains less than Width characters, it Is
1114 Left padded With spaces To achieve This minimum
1115 Length. If "-" Is used To Activate Left-
1116 justification, the String Is padded To the
1117 Right rather than To the Left. If the String
1118 already has A Length equal To Or greater than
1119 Width, no padding Is Needed.
1120
1121 "." Precision Integer Value that specifies the Precision
1122 used when converting the argument. the actual
1123 consequences Of Precision depend ON the
1124 argument Type. See descriptions below For
1125 Details.
1126
1127 the Index, Width, And Precision specifiers can also contain an
1128 asterisk ('*'). In This Case, the Real Value Is taken from the
1129 Next argument Array entry, which has To be an Integer Value, Or
1130 EConvertError will be raised.
1131
1132 following are the characters allowed To specify the argument Type.
1133 note that 'decimal point' And 'thousand separator' mean that the
1134 characters contained In the global variables DecimalSeparator And
1135 ThousandSeparator will be inserted.
1136
1137 D DECIMAL format. the corresponding argument MUST
1138 be an Integer Value, Otherwise EConvertError Is
1139 raised. the argument Is converted To A DECIMAL
1140 String. If A Precision Is specified, the String
1141 Is guaranteed To have At least A Number Of
1142 Digits equal To Precision. If the String Is
1143 shorter, it Is padded With zeroes.
1144
1145 E Scientific (exponential) format. the
1146 corresponding argument MUST be A floating Point
1147 Value, Otherwise EConvertError Is raised. the
1148 argument Is converted To A DECIMAL String using
1149 Scientific notation. the String Starts With a
1150 minus sign, If the argument Is Negative. one
1151 digit always precedes the DECIMAL Point. the
1152 Number Of Digits following the DECIMAL Point Is
1153 controlled by the optional Precision specifier.
1154 the total Number Of Digits Is always equal To
1155 Precision. If Precision Is Not specified, a
1156 Default Of 15 Is assumed, resulting In 1 digit
1157 before And 14 after the DECIMAL Point.
1158 following Is the exponential 'E' With A plus Or
1159 A minus sign And up To 3 Digits indicating the
1160 Exponent.
1161
1162 F FIXED Point format. the corresponding argument
1163 MUST be A floating Point Value, Otherwise
1164 EConvertError Is raised. the argument Is
1165 converted To A String using FIXED notation. it
1166 Starts With A minus sign, If the argument Is
1167 Negative. All Digits Of the argument's Integer
1168 part appear In the Result. following Is a
1169 DECIMAL separator And A Number Of Digits equal
1170 To Precision. If no Precision Is specified, a
1171 Default Of 2 DECIMAL places Is assumed.
1172
1173 G General Number format. the argument MUST be a
1174 floating Point Value, Otherwise EConvertError
1175 Is raised. the argument Is converted To a
1176 String using either FIXED Or Scientific format,
1177 depending ON which results In A shorter String.
1178 the optional Precision specifier Controls the
1179 Number Of significant Digits (used For
1180 rounding) With A Default Of 15. the Result will
1181 contain neither unnecessary zeroes nor an
1182 unnecessary DECIMAL Point. If the argument
1183 Value Is greater than Or equal To 0.00001, And
1184 If the Number Of Digits To the Left Of the
1185 DECIMAL Point Is less than Or equal To the
1186 Precision, FIXED format Is used. Otherwise the
1187 Result Uses Scientific format.
1188
1189 M currency (money) format. the corresponding
1190 argument MUST be A floating Point Value,
1191 Otherwise EConvertError Is raised. the argument
1192 Is converted To A String using the following
1193 global variables:
1194
1195 CurrencyString
1196 CurrencyFormat
1197 NegCurrFormat
1198 CurrencyDecimals
1199
1200 If A Precision Is specified, it overrides the
1201 Default Value Of CurrencyDecimals.
1202
1203 N Number format. equal To FIXED, but the Result
1204 String will contain thousand separators.
1205
1206 P Pointer format. the corresponding argument MUST
1207 be A Pointer Value, Otherwise EConvertError Is
1208 raised. the Value Is converted To A String
1209 containing the hexadecimal representation Of
1210 the Pointer, With an additional ':' In the
1211 middle. the resulting String has always a
1212 Length Of 9 characters. since we are dealing
1213 With flat Memory model, we have A full 32-bit
1214 Pointer With no segment part, only Offset.
1215
1216 S String format. the corresponding argument MUST
1217 be A Single character, A String Or A PChar Value,
1218 Otherwise EConvertError Is raised. the argument
1219 Is simply copied To the destination String. If
1220 A Precision Is specified, it Is considered the
1221 maximum Length Of the argument String. longer
1222 Strings will be truncated.
1223
1224 X hexadecimal format. the corresponding argument
1225 MUST be an Integer Value, Otherwise EConvertError
1226 Is raised. the argument Is converted To a
1227 hexadecimal String. If A Precision Is specified,
1228 the String Is guaranteed To have At least a
1229 Number Of Digits equal To Precision. If the
1230 String Is shorter, it Is padded With zeroes. }
1231
1232Function format(Const format: String; Const Args: Array Of Const): String;
1233
1234{ FmtStr - formats A String And replaces placeholders by arguments.
1235 See format For A detailed description Of the format String And the
1236 argument Array. }
1237
1238Procedure FmtStr(Var Result: String; Const format: String;
1239 Const Args: Array Of Const);
1240
1241{ StrFmt - formats A String And replaces placeholders by arguments.
1242 note that the Buffer MUST be large enough To hold the Complete
1243 Result, Otherwise A protection fault (EGPFault) may occur. See
1244 format For A detailed description Of the format String And the
1245 argument Array. }
1246
1247Function StrFmt(Buffer, format: PChar; Const Args: Array Of Const): PChar;
1248
1249{ StrLFmt - formats A String And replaces placeholders by arguments.
1250 the Function ensures that the Size Of the Output String written into
1251 Buffer won't exceed MaxLen characters. the function's Result Is also
1252 A Pointer To Buffer. See format For A detailed description Of the
1253 format String And the argument Array. }
1254
1255Function StrLFmt(Buffer: PChar; MaxLen: Cardinal; format: PChar;
1256 Const Args: Array Of Const): PChar;
1257
1258{ FormatBuf - formats A String And replaces placeholders by arguments.
1259 format And Buffer Strings are given As untyped Var / Const
1260 Parameters. their sizes are given In BufLen And FmtLen. the Function
1261 ensures that the Size Of the Output String written into Buffer won't
1262 exceed BufLen characters. the Result Value Is the Number Of
1263 characters actually written into Buffer. See format For A detailed
1264 description Of the format String And the argument Array. }
1265
1266Function FormatBuf(Var Buffer; BufLen: Cardinal; Const format;
1267 FmtLen: Cardinal; Const Args: Array Of Const): Cardinal;
1268
1269{ --- floating Point conversion --- }
1270
1271{ FloatToStrF - Converts A floating Point Number To A String. the
1272 appearance Of the Result String can be controlled by specifying
1273 A basic format To apply, A Precision, And A Number Of Digits.
1274 the Precision Parameter should be less than Or equal To 18. the
1275 meaning Of the Digits Parameter depends ON the format chosen.
1276
1277 following Is A detailed description Of the possible formats:
1278
1279 ffCurrency money (currency) format. the argument Is converted
1280 To A String using the following global variables:
1281
1282 CurrencyString
1283 CurrencyFormat
1284 NegCurrFormat
1285
1286 the Digits Parameter specifies the Number Of Digits
1287 following the DECIMAL Point (0 To 18 being legal
1288 values).
1289
1290 ffExponent Scientific (exponential) format. the argument Is
1291 converted To A DECIMAL String using Scientific
1292 notation. the String Starts With A minus sign, If
1293 the argument Is Negative. one digit precedes the
1294 DECIMAL Point. the Number Of Digits following the
1295 DECIMAL Point Is controlled by Precision. the total
1296 Number Of Digits Is always equal To Precision.
1297 following Is the exponential 'E' With A plus Or a
1298 minus sign And the Exponent With A minimum Length
1299 Of Digits characters (0 To 4 being legal values).
1300
1301 ffFixed FIXED Point format. the argument Is converted To a
1302 String using FIXED Point notation. it Starts With a
1303 minus sign, If the argument Is Negative. All Digits
1304 Of the argument's Integer part appear In the Result.
1305 following Is A comma And A Number Of DECIMAL Digits
1306 equal To Digits (0 To 18 being legal values). If
1307 the Number Of Digits To the Left Of the DECIMAL
1308 Point Is greater than Precision, the Output will be
1309 In Scientific format.
1310
1311 ffGeneral General Number format. the argument Is converted
1312 To A String using either FIXED Or Scientific
1313 format, depending ON which results In A shorter
1314 String. the Result will contain neither trailing
1315 zeroes nor an unnecessary DECIMAL Point. If the
1316 argument Value Is greater than Or equal To 0.00001,
1317 And If the Number Of Digits To the Left Of the
1318 DECIMAL Point Is less than Or equal To Precision,
1319 FIXED format Is used. Otherwise the Result Is
1320 formatted In Scientific format With Digits
1321 specifying the minimum Number Of Digits In the
1322 Exponent (0 To 4 being legal values).
1323
1324 ffNumber Number format. equal To FIXED, but the Result
1325 String will contain thousand separators.
1326
1327 If the Value Is Not-A-Number, positive infinity, Or Negative
1328 infinity, Then the Output String will also be NAN, INF, Or -INF. }
1329
1330Function FloatToStrF(Value: Extended; format: TFloatFormat;
1331 Precision, Digits: Integer): String;
1332
1333{ FloatToStr - Converts A floating Point Value To A String using
1334 General Number format And 15 significant Digits. See FloatToStrF
1335 For more Details. }
1336
1337Function FloatToStr(Value: Extended): String;
1338
1339{ FloatToText - Converts A floating Point Number To A String. the
1340 Result Is written To Buffer without A Zero teminator being
1341 appended. the caller has To ensure that the Buffer Is large
1342 enough To hold the Result. the Result can be controlled using
1343 format, Precision And Digits Parameters. See FloatToStrF For
1344 A detailed description Of these Parameters. }
1345
1346Function FloatToText(Buffer: PChar; Value: Extended; format: TFloatFormat;
1347 Precision, Digits: Integer): Integer;
1348
1349{ FormatFloat - Converts A floating Point Value To A String using a
1350 specified format.
1351
1352 the Parameter format Controls the appearance Of the Result String.
1353
1354 format can contain up To three Sections, separated from each other
1355 by semicolons. the First section holds the format String used For
1356 positive values, the Second one holds the format For Negative
1357 values, And the third one Is applied To Zero values. If one Of
1358 the Sections Is missing Or Empty, the First section Is used
1359 instead. If All Sections are missing Or Empty, General Number
1360 format Is used With A Precision Of 15. See FloatToStrF For more
1361 Details about General Number format.
1362
1363 each Of the three Sections can contain arbitrary Text, which Is
1364 simply copied To the Result String. Some characters have A Special
1365 meaning, they serve As placeholders For inserting Data from the
1366 Value Parameter.
1367
1368 the following List shows All placeholders And their meaning:
1369
1370 0 Mandatory digit. If the Value has A digit At This
1371 Position, it Is copied To the Result. Otherwise a
1372 0 Is inserted.
1373
1374 # optional digit. If the Value has A digit At This
1375 Position, it Is copied To the Result. Otherwise
1376 This Position Of the format String will be ignored.
1377
1378 . DECIMAL separator. the First occurence Of '.' In the
1379 format String determines the Position At which A DECIMAL
1380 separator will be inserted. the DECIMAL separator Is
1381 taken from the global variable DecimalSeparator. further
1382 occurences Of '.' will be ignored.
1383
1384 , thousand separator. any occurence Of ',' activates the
1385 insertion Of thousand separators into the Result, where
1386 necessary. the thousand separator Is taken from the
1387 global variable DecimalSeparator.
1388
1389 E+ E- Scientific (exponential) format. If any Of the four
1390 E+ E- Strings To the Left occur In the format String, the
1391 Result will be formatted using Scientific notation.
1392 the exponential E will have the same Case As In the
1393 format String. the Exponent itself will always be
1394 preceded by its sign, If E+ Or E+ are used. E- And E-
1395 contain A sign only If the Exponent Value Is Negative.
1396 up To four digit placeholders can be used To specify the
1397 minimum Number Of Digits used For the Exponent.
1398
1399 '...' characters enclosed In Single Or Double quotes will
1400 "..." simply be copied To the Result (without quotes).
1401
1402 the floating Point Value Is rounded With A Precision equal To the
1403 total Number Of digit placeholders In the format String. optional
1404 digit placeholders between the leftmost And rightmost Mandatory
1405 digit placeholders will be taken As Mandatory Digits, So it makes
1406 no sense To specify one ore more '#' between zeroes. If the rounded
1407 Value Contains more Digits In the Integer part than there are
1408 placeholders Left Of the DECIMAL separator, the additional Digits
1409 will be inserted before the First placeholder. }
1410
1411Function FormatFloat(Const format: String; Value: Extended): String;
1412
1413{ FloatToTextFmt - Converts A floating Point Value To A String using a
1414 specified format. the Result Is written To Buffer without a
1415 terminating Zero. the caller has To ensure that the Buffer Is large
1416 enough To hold the Result. the Number Of characters actually written
1417 To Buffer Is returned. See FormatFloat For A description Of the
1418 format Parameter. }
1419
1420Function FloatToTextFmt(Buffer: PChar; Value: Extended;
1421 format: PChar): Integer;
1422
1423{ StrToFloat - Converts A String To A floating Point Value. the String
1424 MUST contain A legal floating Point Value, With the DECIMAL Point
1425 being the same character As In the global variable DecimalSeparator.
1426 it MUST Not contain thousand separators Or currency symbols. leading
1427 And trailing spaces are allowed. If the String does Not conform
1428 these restrictions, EConvertError Is raised. }
1429
1430Function StrToFloat(Const S: String): Extended;
1431
1432{ TextToFloat - Converts A Zero-Terminated String To A floating Point
1433 Value. the String MUST contain A legal floating Point Value, With
1434 the DECIMAL Point being the same character As In the global variable
1435 DecimalSeparator. it MUST Not contain thousand separators Or
1436 currency symbols. leading And trailing spaces are allowed. If the
1437 String does Not conform these restrictions, EConvertError Is raised. }
1438
1439Function TextToFloat(Buffer: PChar; Var Value: Extended): Boolean;
1440
1441{ FloatToDecimal - Converts A floating Point Value To A TFloatRec
1442 Record which separates Digits, sign, And Exponent. the Precision
1443 Parameter specifies the Number Of significant Digits (With 1..18
1444 being legal values), the Decimals Parameter specifies the desired
1445 minimum Number Of Digits In the fractional part. rounding Is
1446 controlled by Precision As well As by Decimals. To force A Number
1447 Of significant Digits even With large values, specify 9999 For
1448 Decimals.
1449
1450 the resulting TFloatRec will contain the following information:
1451
1452 Exponent - the result's Exponent. an Exponent Value Of -32768
1453 Indicates that the Value Is Not-A-Number (NAN). positive Or
1454 Negative infinity (INF / -INF) Is indicated by an Exponent
1455 Value Of 32767.
1456
1457 Negative - Indicates whether the Value Is Negative Or Not. Use
1458 This To distinguish positive from Negative infinity, too. Zero
1459 Is assumed To be non-Negative.
1460
1461 Digits - Contains the significant Digits With A terminating
1462 Zero (Chr(0)). does Not contain the DECIMAL separator. Empty,
1463 If the Value Is Not-A-Number, Or positive, Or Negative infinity. }
1464
1465Procedure FloatToDecimal(Var Result: TFloatRec; Value: Extended;
1466 Precision, Decimals: Integer);
1467
1468{ --- date / Time Handling --- }
1469
1470{ EncodeDate - Encodes the given Year, Month, And Day into A Single
1471 TDateTime Value. the Result Contains the Number Of days passed since
1472 the 31-Dec-0000 And the given date, assuming Gregorian calendar has
1473 always been used. If any Parameter Contains an illegal Value,
1474 EConvertError Is raised. }
1475
1476Function EncodeDate(Year, Month, Day: Word): TDateTime;
1477
1478{ EncodeTime - Encodes the given Hour, Minute, Second And millisecond
1479 into A Single TDateTime Value. the Result Contains the fractional
1480 part Of the Day passed since 00:00:00. it Is always A Value equal To
1481 Or greater than Zero And And smaller that one. If any Parameter
1482 Contains an illegal Value, EConvertError Is raised. }
1483
1484Function EncodeTime(Hour, Min, Sec, MSec: Word): TDateTime;
1485
1486{ DecodeDate - Extracts Year, Month, And Day from A given TDateTime
1487 Value. }
1488
1489Procedure DecodeDate(date: TDateTime; Var Year, Month, Day: Word);
1490
1491{ DecodeTime - Extracts Hour, Minute, Second, And millisecond from a
1492 given TDateTime Value. }
1493
1494Procedure DecodeTime(Time: TDateTime; Var Hour, Min, Sec, MSec: Word);
1495
1496{ DayOfWeek - Extracts the Day Of the week from A given TDateTime
1497 Value. the days are numbered from 1 To 7 In the following order:
1498
1499 Sun / Mon / Tue / Wed / Thu / Fri / Sat }
1500
1501Function DayOfWeek(date: TDateTime): Integer;
1502
1503{ date - Queries the Current System date. }
1504
1505Function date: TDateTime;
1506
1507{ Time - Queries the Current System Time. }
1508
1509Function Time: TDateTime;
1510
1511{ now - Queries the Current System date And Time. }
1512
1513Function now: TDateTime;
1514
1515{ DateToStr - Converts the date part Of the given TDateTime Value
1516 To A String, using the format specified In the global variable
1517 ShortDateFormat. }
1518
1519Function DateToStr(date: TDateTime): String;
1520
1521{ TimeToStr - Converts the Time part ao the given TDateTime Value
1522 To A String, using the format specified In the global variable
1523 LongTimeFormat. }
1524
1525Function TimeToStr(Time: TDateTime): String;
1526
1527{ DateTimeToStr - Converts the given TDateTime Value To A String
1528 using the formats specified In the global variables ShortDateFormat
1529 And LongTimeFormat. the Time Is only appended, If the TDateTime
1530 Value Contains A (fractional) Time part different from 00:00:00. }
1531
1532Function DateTimeToStr(DateTime: TDateTime): String;
1533
1534{ StrToDate - Tries To exctract date information from A String.
1535 the FUNCTIONs expects the String To contain two Or three numbers
1536 separated by the character given In the global variable
1537 DateSeparator. the order In which Day, Month, And Year are
1538 expected Is determined by the global variable DateOrder.
1539 If only two numbers are found, they are assumed To specify
1540 A Month And Day Of the Current Year. If the Year Is smaller
1541 than 100, it Is assumed To be A Year Of the Current century.
1542 If no legal date can be extracted from the String,
1543 EConvertError Is raised. }
1544
1545Function StrToDate(Const S: String): TDateTime;
1546
1547{ StrToTime - Tries To exctract Time information from A String.
1548 the FUNCTIONs expects the String To contain two Or three numbers
1549 separated by the character given In the global variable
1550 TimeSeparator, optionally followed by 'AM' Or 'PM' To indicate
1551 12-Hour format. the First two numbers are taken As Hour And
1552 Minute, the optional third one As Second. If no indicator For
1553 12-Hour format Is found, the Time Is assumed To be In 24-Hour
1554 format. If no legal Time can be extracted from the String,
1555 EConvertError Is raised. }
1556
1557Function StrToTime(Const S: String): TDateTime;
1558
1559{ StrToDateTime - Tries To extract date And Time information from A
1560 String. the Function expects the String To contain A date optionally
1561 followed by A Time. See StrToDate And StrToTime For more Details
1562 about the string's contents. If no legal date And Time can be
1563 extracted from the String, EConvertError Is raised. }
1564
1565Function StrToDateTime(Const S: String): TDateTime;
1566
1567{ FormatDateTime - Converts A TDateTime Value To A String using a
1568 format specified by the Parameter format.
1569
1570 the format String may contain arbitrary Text, which Is simply
1571 copies To the Result String. Some characters Or character
1572 sequences have A Special meaning, they serve As placeholders And
1573 are replaced by values extracted from DateTime.
1574
1575 the following placeholders are allowed In the format String. their
1576 Case doesn't matter. If the format String Is Empty, 'c' Is assumed
1577 the Default format.
1578
1579 C replaced by the date formatted As specified In the
1580 global variable ShortDateFormat. If the (fractional)
1581 Time part Is different from 00:00:00, the Time Is
1582 appended using the format specified In the global
1583 variable LongTimeFormat.
1584
1585 D replaced by A Number indicating the Day Of the Month,
1586 With no leading Zero.
1587
1588 dd replaced by A Number indicating the Day Of the Month,
1589 With leading Zero.
1590
1591 ddd replaced by the Day Of the week's Name taken from the
1592 global Array ShortDayNames, resulting In an abbreviation
1593 Of the day's Name.
1594
1595 dddd replaced by the Day Of the week's Name taken from the
1596 global Array LongDayNames, resulting In the day's full
1597 Name.
1598
1599 ddddd replaced by the date formatted As specified In the
1600 global variable ShortDateFormat.
1601
1602 dddddd replaced by the date formatted As specified In the
1603 global variable LongDateFormat.
1604
1605 M when used immediately after an Hour placeholder,
1606 replaced by the Minute. Otherwise replaced by A
1607 Number indicating the Month. no leading zeroes.
1608
1609 mm when used immediately after an Hour placeholder,
1610 replaced by the Minute. Otherwise replaced by A
1611 Number indicating the Month. leading zeroes.
1612
1613 mmm replaced by the month's Name taken from the global Array
1614 ShortMonthNames, resulting In an abbreviation Of the
1615 month's Name.
1616
1617 mmmm replaced by the month's Name taken from the global Array
1618 LongMonthNames, resulting In the month's full Name.
1619
1620 yy replaced by two Digits indicating the Year. leading
1621 zeroes.
1622
1623 yyyy replaced by four Digits indicating the Year. leading
1624 zeroes.
1625
1626 H replaced by the Hour without leading Zero.
1627
1628 hh replaced by the Hour With leading Zero.
1629
1630 N replaced by the Minute without leading Zero.
1631
1632 nn replaced by the Minute With leading Zero.
1633
1634 S replaced by the Second without leading Zero.
1635
1636 SS replaced by the Second With leading Zero.
1637
1638 T replaced by the Time formatted As specified In the
1639 global variable ShortTimeFormat.
1640
1641 tt replaced by the Time formatted As specified In the
1642 global variable LongTimeFormat.
1643
1644 am/PM Indicates that 12-Hour format should be used For the
1645 preceding Hour placeholder. replaced by 'am' Or 'pm',
1646 depending ON the Time, With the same Case As specified.
1647
1648 A/P Indicates that 12-Hour format should be used For the
1649 preceding Hour placeholder. replaced by 'a' Or 'p',
1650 depending ON the Time, With the same Case As specified.
1651
1652 ampm Indicates that 12-Hour format should be used For the
1653 preceding Hour placeholder. replaced by A String taken
1654 from the global variables TimeAMString Or TimePMString,
1655 depending ON the Time.
1656
1657 / replaced by the date separator As specified In the global
1658 variable DateSeparator.
1659
1660 : replaced by the Time separator As specified In the global
1661 variable TimeSeparator.
1662
1663 '...' characters enclosed In Single Or Double quotes will
1664 "..." simply be copied To the Result (without quotes). }
1665
1666Function FormatDateTime(Const format: String; DateTime: TDateTime): String;
1667
1668{ DateTimeToString - Converts A TDateTime Value To A String using A
1669 format specified by the format Parameter . See FormatDateTime For
1670 A detailed description Of the format String. }
1671
1672Procedure DateTimeToString(Var Result: String; Const format: String;
1673 DateTime: TDateTime);
1674
1675{ --- System profile support --- }
1676
1677{$IFDEF GUI}
1678
1679{ GetProfileStr - Reads A String from the operating system's user
1680 profile. If section Or entry don't exist, A Default Value Is
1681 returned instead. }
1682
1683Function GetProfileStr(Const Section, Entry, Default: String): String;
1684
1685{ GetProfileChar - Reads A character from the operating system's user
1686 profile. If section Or entry don't exist, A Default Value Is
1687 returned instead. }
1688
1689Function GetProfileChar(Const Section, Entry: String; Default: Char): Char;
1690
1691{ GetProfileInt - Reads an Integer from the operating system's user
1692 profile. If section Or entry don't exist, A Default Value Is
1693 returned instead. }
1694
1695Function GetProfileInt(Const Section, Entry: string; Default: Integer): Integer;
1696
1697{ GetFormatSettings - Queries A lot Of Default values used For
1698 formatting FUNCTIONs from the Operation System. called automatically
1699 In the SysUtils startup Code, So an Application that Uses SysUtils
1700 can always access these values immediately after Program startup. }
1701
1702{$ENDIF GUI}
1703
1704Procedure GetFormatSettings;
1705
1706{ ConvertError - Raises EConvertError With the given Error Message. }
1707
1708Procedure ConvertError(Const Msg: String);
1709
1710{ --- Some routines that belong into System.PAS --- }
1711
1712{ SetLength - changes the Length Of A String. Please Use This
1713 Procedure instead Of writing S[0] := NewLength To maintain
1714 compatibility With the forthcoming LONG Strings that won't contain
1715 A Length-Byte any more. }
1716
1717{ Procedure SetLength(Var S: String; NewLength: Byte); }
1718
1719{ StringOfChars - returns A String that consists Of
1720 Count occurences Of the given character CH. }
1721
1722Function StringOfChars(CH: Char; Count: Integer): String;
1723
1724{ SetCurrentLanguageTable - sets the Language Table Name To the specified Language.
1725 the Name MUST Start With "SIBYL_NLS_". A Table With the Name MUST exist. If the Table
1726 cannot be found Or Some other Error occurs This Function returns False, otherise True.
1727 by convention the Table MUST Include All Sibyl Default Language identifiers
1728 (See /Language Directory For examples).}
1729
1730Function SetCurrentLanguageTable(Const Table:String):Boolean;
1731
1732{ GetCurrentLanguageTable - gets the Current Language Table Name. }
1733
1734Function GetCurrentLanguageTable:String;
1735
1736{ GetCurrentLanguage - returns the Currently Set Language. the Language String Is
1737 retrieved from the Current Language Table With the "SLanguage" Index. This Function
1738 returns an Empty String ON Error. }
1739
1740Function GetCurrentLanguage:String;
1741
1742{GetPhysicalDrives - returns information about logical drives connected
1743 to the system. The drives are encoded bitwise starting with bit 0 for
1744 drive A. A enabled bit indicates that the appropriate drive is present}
1745Function GetPhysicalDrives:LongWord;
1746
1747{$IFDEF WIN32}
1748Procedure StrOemToAnsi(Var s:String);
1749{$ENDIF}
1750
1751Implementation
1752
1753{$IFDEF WIN32}
1754Procedure StrOemToAnsi(Var s:String);
1755Var Found:Boolean;
1756 c:CString;
1757Begin
1758 Found:=True;
1759 Asm
1760 MOV EDI,s
1761 MOVZXB ECX,[EDI]
1762 INC EDI
1763 CMP ECX,0
1764 JE !End1
1765!Lo1:
1766 //Check for ä,ö,ü,Ä,Ö,Ü,ß
1767 CMPB [EDI],132
1768 JE !End2
1769 CMPB [EDI],142
1770 JE !End2
1771 CMPB [EDI],148
1772 JE !End2
1773 CMPB [EDI],153
1774 JE !End2
1775 CMPB [EDI],129
1776 JE !End2
1777 CMPB [EDI],154
1778 JE !End2
1779 CMPB [EDI],225
1780 JE !End2
1781
1782 INC EDI
1783 LOOP !Lo1
1784!End1:
1785 MOVB Found,0
1786!End2:
1787 End;
1788
1789 If Found Then
1790 Begin
1791 c:=s;
1792 OemToAnsi(c,c);
1793 s:=c;
1794 End;
1795End;
1796{$ENDIF}
1797
1798Uses
1799 Language;
1800
1801
1802Function GetPhysicalDrives:LongWord;
1803 {$IFDEF OS2}
1804Var
1805 ActualDrive:LongWord;
1806 {$ENDIF}
1807Begin
1808 {$IFDEF OS2}
1809 DosQueryCurrentDisk(ActualDrive,Result);
1810 {$ENDIF}
1811 {$IFDEF Win95}
1812 result := GetLogicalDrives;
1813 {$ENDIF}
1814End;
1815
1816{ Current Language String Table identifier. Name has preceding SIBYL_NLS_ String !}
1817Var
1818 CurrentLanguageTable:String;
1819
1820Function SetCurrentLanguageTable(Const Table:String):Boolean;
1821Var P:Pointer;
1822 len:LongWord;
1823Begin
1824 P:=FindStringTableRes(Table,len);
1825 Result:=P<>Nil;
1826 If Result Then CurrentLanguageTable:=Table;
1827End;
1828
1829Function GetCurrentLanguageTable:String;
1830Begin
1831 Result:=CurrentLanguageTable;
1832End;
1833
1834Function GetCurrentLanguage:String;
1835Begin
1836 Result:=LoadNLSStr(SLanguage);
1837End;
1838
1839Const
1840
1841{ Array With Number Of days passed since beginning Of the Year
1842 Until the 1st Of Every Month. used For date/Time conversions. }
1843
1844 DaysPassed: Array[False..True, 1..13] Of Integer =
1845 ((0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365),
1846 (0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366));
1847
1848 ShareModes = fmShareExclusive
1849 Or fmShareDenyRead
1850 Or fmShareDenyWrite
1851 Or fmShareDenyNone;
1852
1853Var
1854
1855{ Collating sequence. Needed For sorting when OS/2 base API FUNCTIONs are used. }
1856
1857 CollatingSequence: Array[#0..#255] Of Byte;
1858
1859Const
1860
1861{ Array For creation Of hexadecimal numbers }
1862
1863 Hexadecimals: Array[0..15] Of Char = '0123456789ABCDEF';
1864
1865Procedure ConvertError(Const Msg: String);
1866Begin
1867 Raise EConvertError.Create(Msg);
1868End;
1869
1870Procedure FmtLoadConvertError(Ident: Integer; Args: Array Of Const);
1871Var
1872 Msg: String;
1873Begin
1874 {$IFDEF GUI}
1875 Try
1876 Msg := FmtLoadNLSStr(Ident, Args);
1877 Except
1878 Msg := LoadNLSStr(Ident) + ' [!]';
1879 End;
1880 {$ELSE GUI}
1881 Msg := 'SysUtils conversion error #' + IntToStr(Ident);
1882 {$ENDIF GUI}
1883 ConvertError(Msg);
1884End;
1885
1886{ --- String / PChar Utility FUNCTIONs --- }
1887
1888Assembler
1889
1890 { This Function returns the Length Of A String And A Pointer To the
1891 Zero terminator.
1892
1893 Input: EDI holds Pointer String
1894 Output: EDI hols Pointer To Zero terminator, EAX holds String Length
1895 changes: EAX, EBX, ECX, EDI }
1896
1897 SysUtils.!StringLength Proc NEAR32
1898
1899 MOV EBX, EDI
1900 Xor EAX, EAX
1901 CMP EDI, 0
1902 JE !Out!StringLength
1903 MOV ECX, $FFFFFFFF
1904 CLD
1905 REPNE SCASB
1906 Not ECX
1907 MOV EAX, ECX
1908 Dec EAX
1909 Dec EDI
1910
1911 !Out!StringLength:
1912 RETN32
1913
1914 SysUtils.!StringLength ENDP
1915
1916 { This FUNCTIONs copies A maximum Number Of characters from one String
1917 To another.
1918
1919 Input: ESI holds Source, EDI holds destination, ECX hold maximum
1920 Number Of characters
1921 Output: EDI holds End Of destination String
1922 changes: EAX, EBX, ECX, EDX, ESI, EDI }
1923
1924 SysUtils.!StringCopy Proc NEAR32
1925
1926 MOV EBX, ECX // EBX now contains max chars
1927 MOV EDX, EDI // edx now contains destination
1928 Xor EAX, EAX // set eax=0
1929
1930 // Check parameters
1931 CMP EDI, 0 // if destination is null, exit
1932 JE !Out!StringCopy
1933 CMP ESI, 0 // if destination is null, exit
1934 JE !Out!StringCopy
1935
1936 MOV EDI, ESI // load source into EDI
1937 CLD
1938
1939 // look for 0 terminator, starting from EDI
1940 // or stop at max chars, when ECX = 0
1941 REPNE SCASB
1942 // ECX is now (max chars - length) or 0 if limit reached
1943
1944 SUB EBX, ECX // (max - ( max - length ) ) = length to copy
1945
1946 // BX now contains number of chars
1947 // to copy INCLUDING null terminator
1948
1949 // if reached max chars then
1950 // count will not include zero terminator
1951 CMP ECX, 0
1952 JE !ReachedMaxChars
1953 DEC EBX // Don't want to copy null teriminator
1954 !ReachedMaxChars:
1955
1956 MOV ECX, EBX // Load count into ecx
1957 Shr ECX, 2 // divide by 4 to find number of dwords to copy
1958 MOV EDI, EDX // load destination into EDI
1959
1960 REP MOVSD // copy (ECX * 4 bytes) from ESI to EDI
1961 MOV ECX, EBX // get num chars to copy, again
1962 And ECX, 3 // AND with 3 to get remaining bytes to copy
1963 REP MOVSB // Copy remaining bytes
1964
1965 STOSB // zero terminate result
1966 Dec EDI
1967
1968 !Out!StringCopy:
1969 RETN32
1970
1971 SysUtils.!StringCopy ENDP
1972
1973 // This Function Compares A maximum Number Of characters
1974 // this IS case SENSITIVE.
1975
1976 SysUtils.!StringCompare Proc NEAR32
1977
1978 REPE CMPSB
1979 Xor EAX, EAX
1980 MOV AL, [ESI - 1]
1981 MOV BL, [EDI - 1]
1982 SUB EAX, EBX
1983 RETN32
1984
1985 SysUtils.!StringCompare ENDP
1986
1987 // Compare a maximum number of characters,
1988 // ignoring case
1989 SysUtils.!StringICompare Proc NEAR32
1990
1991 Xor EAX, EAX;
1992
1993 !Loop!StringICompare:
1994
1995 REPE CMPSB
1996 JE !Out!StringICompare
1997
1998 Xor EBX, EBX
1999 MOV BL, [ESI - 1]
2000 CMP BL, 'A'
2001 JL !UpcaseSecondChar!StringICompare
2002 CMP BL, 'Z'
2003 JG !UpcaseSecondChar!StringICompare
2004 Or BL, 32
2005
2006 !UpcaseSecondChar!StringICompare:
2007
2008 Xor EDX, EDX
2009 MOV DL, [EDI - 1]
2010 CMP DL, 'A'
2011 JL !CompareSingleChar!StringICompare
2012 CMP DL, 'Z'
2013 JG !CompareSingleChar!StringICompare
2014 Or DL, 32
2015
2016 !CompareSingleChar!StringICompare:
2017
2018 SUB EBX, EDX
2019 JE !Loop!StringICompare
2020 MOV EAX, EBX
2021
2022 !Out!StringICompare:
2023
2024 RETN32
2025
2026 SysUtils.!StringICompare ENDP
2027
2028 // Compares two zero terminated strings, case insensitively
2029 // ESI : Str1
2030 // EDI : Str2
2031 // Returns in EAX: 0 : strings equal
2032 // <0 : str1 > str2
2033 // >0 : str2 > str1
2034
2035 SysUtils.!ZeroTerminatedStringICompare Proc NEAR32
2036
2037 Xor EAX, EAX; // set result (EAX) to 0 i.e. match
2038
2039 !Loop!StringICompare:
2040
2041 Xor EBX, EBX // Set EBX to 0
2042 MOV BL, [ESI] // load char out of str1 into BL
2043
2044 Xor EDX, EDX // set EDX to 0
2045 MOV DL, [EDI] // load char out of str2 into DL
2046 CMP EDX, 0
2047 jne !Str2NotTerminated!StringICompare // str2 not ended
2048 // str2 has ended.
2049 CMP EBX, 0 // Has str1 also ended?
2050 je !Out!StringICompare // Yes, strings are equal
2051 // no, str1 is continuing,
2052 // so it's "greater"
2053 MOV EAX, $ffffffff // set result = -1
2054 RETN32 // exit
2055
2056 !Str2NotTerminated!StringICompare: // str2 continues
2057 CMP EBX, 0 // has str2 ended?
2058 jne !Str1NotTerminated!StringICompare
2059 MOV EAX, 1 // set result = 1
2060 RETN32 // exit
2061
2062 !Str1NotTerminated!StringICompare:
2063 // Neither string has ended
2064 INC esi // increment str1 and str2 pointers
2065 INC edi
2066
2067 CMP EBX, EDX // char1 = char2?
2068 JE !Loop!StringICompare // yes, continue loop
2069 // no, check case insensitive
2070 // Convert char1 to lowercase, if needed
2071 CMP BL, 'A'
2072 JL !Char1Converted!StringICompare
2073 CMP BL, 'Z'
2074 JG !Char1Converted!StringICompare
2075 Or BL, 32 // change to lower case
2076 !Char1Converted!StringICompare:
2077
2078 // Convert char2 to lowercase, if needed
2079 CMP DL, 'A'
2080 JL !Char2Converted!StringICompare
2081 CMP DL, 'Z'
2082 JG !Char2Converted!StringICompare
2083 Or DL, 32 // change to lowercase
2084 !Char2Converted!StringICompare:
2085
2086 SUB EBX, EDX // Subtract char2 from char1
2087 JE !Loop!StringICompare // if chars same, continue loop
2088 MOV EAX, EBX // load difference into EAX
2089
2090 !Out!StringICompare:
2091
2092 RETN32
2093
2094 SysUtils.!ZeroTerminatedStringICompare ENDP
2095
2096End;
2097
2098{ --- Memory management --- }
2099
2100Function AllocMem(Size: Cardinal): Pointer;
2101Begin
2102 GetMem(Result, Size);
2103 FillChar(Result^, Size, 0);
2104End;
2105
2106Function ReAllocMem(P: Pointer; CurSize, NewSize: Cardinal): Pointer;
2107Var
2108 Q: PByteArray;
2109Begin
2110 If NewSize <> 0 Then GetMem(Q, NewSize) Else Q := Nil;
2111
2112 If NewSize > 0 Then
2113 Begin
2114 If NewSize > CurSize Then
2115 Begin
2116 FillChar(Q^[CurSize], NewSize - CurSize, 0);
2117 NewSize := CurSize;
2118 End;
2119 If NewSize <> 0 Then Move(P^, Q^, NewSize);
2120 End;
2121 If CurSize <> 0 Then FreeMem(P, CurSize);
2122 Result := Q;
2123End;
2124
2125{ Exit Procedure Handling }
2126
2127Type
2128 PExitNode = ^TExitNode;
2129 TExitNode = Record
2130 Next: PExitNode;
2131 Proc: TProcedure;
2132 End;
2133
2134Const
2135 ExitChain: PExitNode = Nil;
2136
2137Var
2138 SaveExitProc: Pointer;
2139
2140Procedure CallExitProcs;
2141Var
2142 First: PExitNode;
2143 Proc: TProcedure;
2144Begin
2145 While ExitChain <> Nil Do
2146 Begin
2147 First := ExitChain;
2148 Proc := First^.Proc;
2149 ExitChain := First^.Next;
2150 ExitProc := Nil; { Avoids recursion! }
2151 Dispose(First);
2152 Proc;
2153 End;
2154 ExitProc := SaveExitProc;
2155End;
2156
2157Procedure AddExitProc(Proc: TProcedure);
2158Var
2159 NewNode: PExitNode;
2160Begin
2161 If ExitChain = Nil Then SaveExitProc := ExitProc;
2162 New(NewNode);
2163 NewNode^.Next := ExitChain;
2164 NewNode^.Proc := Proc;
2165 ExitChain := NewNode;
2166 ExitProc := @CallExitProcs;
2167End;
2168
2169{ --- Pascal String Handling --- }
2170
2171Function NewStr(Const S: String): PString;
2172Begin
2173 If Length(S) = 0 Then Result := NullStr
2174 Else
2175 Begin
2176 GetMem(Result, Length(S) + 1);
2177 Result^ := S;
2178 End;
2179End;
2180
2181Procedure DisposeStr(P: PString);
2182Begin
2183 If (P <> NullStr) And (P <> Nil) Then FreeMem(P, Length(P^) + 1);
2184End;
2185
2186Procedure AssignStr(Var P: PString; Const S: String);
2187Begin
2188 DisposeStr(P);
2189 P := NewStr(S);
2190End;
2191
2192Procedure AppendStr(Var Dest: String; Const S: String);
2193Begin
2194 Insert(S, Dest, Length(Dest) + 1);
2195End;
2196
2197Function uppercase(Const S: String): String;
2198Var
2199 N, C: Integer;
2200Begin
2201 Result := S;
2202 For N := 1 To Length(Result) Do
2203 Begin
2204 C := Ord(Result[N]);
2205 If (C >= Ord('a')) And (C <= Ord('z')) Then Result[N] := Chr(C And Not 32);
2206 End;
2207End;
2208
2209Function lowercase(Const S: String): String;
2210Var
2211 N, C: Integer;
2212Begin
2213 Result := S;
2214 For N := 1 To Length(Result) Do
2215 Begin
2216 C := Ord(Result[N]);
2217 If (C >= Ord('A')) And (C <= Ord('Z')) Then Result[N] := Chr(C Or 32);
2218 End;
2219End;
2220
2221Function CompareStr(Const s1, s2: String): Integer;
2222Begin
2223 If s1 <= s2 Then
2224 Begin
2225 If s1 = s2 Then Result := 0 Else Result := -1;
2226 End
2227 Else Result := +1
2228End;
2229
2230Function CompareText(Const s1, s2: String): Integer;
2231Var
2232 l1, l2, L: Integer;
2233Begin
2234 l1 := Length(s1);
2235 l2 := Length(s2);
2236 If l1 <= l2 Then L := l1 Else L := l2;
2237 Result := StrLIComp(@s1[1], @s2[1], L);
2238 If Result = 0 Then
2239 Begin
2240 If l1 < l2 Then Result := -1 Else If l1 > l2 Then Result := 1;
2241 End;
2242End;
2243
2244{$IFDEF OS2}
2245 {$IFDEF GUI}
2246Function AnsiUpperCase(Const S: String): String;
2247Var
2248 Temp: cstring;
2249Begin
2250 Temp := S;
2251 WinUpper(AppHandle, 0, 0, Temp);
2252 Result := Temp;
2253End;
2254 {$ELSE GUI}
2255Function AnsiUpperCase(Const S: String): String;
2256Var
2257 cc: COUNTRYCODE;
2258Begin
2259 Result := S;
2260 cc.country := 0;
2261 cc.codepage := 0;
2262 DosMapCase(Length(Result), cc, Result[1]);
2263End;
2264 {$ENDIF GUI}
2265{$ENDIF OS2}
2266
2267{$IFDEF Win95}
2268Function AnsiUpperCase(Const S: String): String;
2269Var
2270 s1: cstring;
2271Begin
2272 s1 := S;
2273 AnsiUpperBuff(s1, Length(s));
2274 AnsiUpperCase:=s1;
2275End;
2276{$ENDIF Win95}
2277
2278{$IFDEF Win95}
2279Function AnsiLowerCase(Const S: String): String;
2280Var
2281 s1: cstring;
2282Begin
2283 s1 := S;
2284 AnsiLowerBuff(s1, Length(s));
2285 Result := s1;
2286End;
2287{$ENDIF Win95}
2288
2289{$IFDEF OS2}
2290 {$IFDEF GUI}
2291Function AnsiCompareText(Const s1, s2: String): Integer;
2292Var
2293 Temp1, Temp2: cstring[256];
2294Begin
2295 Temp1 := s1;
2296 Temp2 := s2;
2297 Case WinCompareStrings(AppHandle, 0, 0, Temp1, Temp2, 0) Of
2298 WCS_LT: Result := -1;
2299 WCS_EQ: Result := 0;
2300 WCS_GT: Result := 1;
2301 End;
2302End;
2303 {$ELSE GUI}
2304Function AnsiCompareText(Const s1, s2: String): Integer;
2305Var
2306 N, l1, l2: Integer;
2307Begin
2308 N := 1;
2309 l1 := Length(s1);
2310 l2 := Length(s2);
2311 While (N <= l1) And (N <= l2)
2312 And (CollatingSequence[s1[N]] = CollatingSequence[s2[N]]) Do Inc(N);
2313
2314 If (N <= l1) And (N <= l2) Then
2315 Begin
2316 If CollatingSequence[s1[N]] < CollatingSequence[s2[N]] Then Result := -1
2317 Else If CollatingSequence[s1[N]] > CollatingSequence[s2[N]] Then Result := 1
2318 Else Result := 0;
2319 End
2320 Else
2321 Begin
2322 If l1 < l2 Then Result := -1
2323 Else If l1 > l2 Then Result := 1
2324 Else Result := 0;
2325 End;
2326End;
2327 {$ENDIF GUI}
2328{$ENDIF OS2}
2329
2330{$IFDEF Win95}
2331Function AnsiCompareText(Const s1, s2: String): Integer;
2332Var
2333 Temp1, Temp2: Array[0..255] Of Char;
2334Begin
2335 AnsiCompareText:=lstrcmpi(StrPCopy(Temp1,s1)^,
2336 StrPCopy(Temp2,s2)^);
2337End;
2338{$ENDIF Win95}
2339
2340{$IFDEF Win95}
2341Function AnsiCompareStr(Const s1, s2: String): Integer;
2342Var
2343 Temp1, Temp2: Array[0..255] Of Char;
2344Begin
2345 Result := lstrcmp(StrPCopy(Temp1,s1)^, StrPCopy(Temp2,s2)^);
2346End;
2347{$ENDIF Win95}
2348
2349Function IsValidIdent(Const Ident: String): Boolean;
2350Var
2351 L, N: Integer;
2352Begin
2353 L := Length(Ident);
2354 If L = 0 Then IsValidIdent := False
2355 Else
2356 Begin
2357 If Ident[1] In ['a'..'z', 'A'..'Z', '_'] Then
2358 Begin
2359 N := 2;
2360 While (N <= L) And (Ident[N] In ['a'..'z', 'A'..'Z', '_', '0'..'9']) Do Inc(N);
2361 If N > L Then IsValidIdent := True
2362 Else IsValidIdent := False;
2363 End
2364 Else IsValidIdent := False;
2365 End;
2366End;
2367
2368Function IntToStr(Value: LongInt): String;
2369Begin
2370 Str(Value, Result);
2371End;
2372
2373Function IntToHex(Value: LongInt; Digits: Integer): String;
2374Begin
2375 Result := '';
2376 Repeat
2377 Dec(Digits);
2378 Result := Hexadecimals[Value And $0F] + Result;
2379 Value := Value Shr 4;
2380 Until Value = 0;
2381 If Digits > 0 Then
2382 Begin
2383 Move(Result[1], Result[1 + Digits], Byte(Result[0]));
2384 FillChar(Result[1], Digits, '0');
2385 Inc(Byte(Result[0]), Digits);
2386 End;
2387End;
2388
2389Function StrToInt(Const S: String): LongInt;
2390Var
2391 err: Integer;
2392Begin
2393 Val(S, Result, err);
2394 If err <> 0 Then FmtLoadConvertError(SInvalidInteger, [S]);
2395End;
2396
2397Function StrToIntDef(Const S: String; Default: LongInt): LongInt;
2398Var
2399 err: Integer;
2400Begin
2401 Val(S, Result, err);
2402 If err <> 0 Then Result := Default;
2403End;
2404
2405{$IFDEF OS2}
2406Function LoadStr(Ident: Word): String;
2407Var
2408 Buffer: cstring;
2409Begin
2410 {$IFDEF GUI}
2411 WinLoadString(AppHandle, 0, Ident, 256, Buffer);
2412 Result := Buffer;
2413 {$ELSE}
2414 Result := 'SysUtils Msg #' + IntToStr(Ident);
2415 {$ENDIF GUI}
2416End;
2417
2418Function FmtLoadStr(Ident: Word; Const Args: Array Of Const): String;
2419Begin
2420 FmtStr(Result, LoadStr(Ident), Args);
2421End;
2422{$ENDIF OS2}
2423
2424Function LoadTableStr(Const Table:String;Ident: Word): String;
2425Begin
2426 Result:=GetStringTableEntry(Table,Ident);
2427End;
2428
2429Function LoadNLSStr(Ident: Word): String;
2430Begin
2431 Result:=GetStringTableEntry(CurrentLanguageTable,Ident);
2432 //If the above failed, Try To Load from Default Table...
2433 If Result='' Then Result:=GetStringTableEntry('SIBYL_NLS_Default',Ident);
2434End;
2435
2436Function FmtLoadTableStr(Const Table:String;Ident: Word; Const Args: Array Of Const): String;
2437Begin
2438 FmtStr(Result, LoadTableStr(Table,Ident), Args);
2439End;
2440
2441Function FmtLoadNLSStr(Ident: Word; Const Args: Array Of Const): String;
2442Begin
2443 FmtStr(Result, LoadNLSStr(Ident), Args);
2444End;
2445
2446{$IFDEF Win95}
2447Function LoadStr(Ident: Word): String;
2448Begin
2449 Result[0] := Char(LoadString(DllModule,Ident,cstring(Result[1]),254));
2450End;
2451
2452Function FmtLoadStr(Ident: Word; Const Args: Array Of Const): String;
2453Begin
2454 FmtStr(Result, LoadStr(Ident), Args);
2455End;
2456{$ENDIF}
2457
2458{$IFDEF OS2}
2459Function SysErrorMessage(MsgNum: LongInt): String;
2460Begin
2461 Result := System.SysErrorMessage( MsgNum );
2462End;
2463{$ENDIF}
2464
2465{
2466Procedure SetLength(Var S: String; NewLength: Byte);
2467Begin
2468 Byte(S[0]) := NewLength;
2469End;
2470}
2471
2472Function Trim(Const S: String): String;
2473Var
2474 L, R: Integer;
2475Begin
2476 R := Length(S);
2477 While (R > 0) And (S[R] <= ' ') Do Dec(R);
2478 L := 1;
2479 While (L <= R) And (S[L] <= ' ') Do Inc(L);
2480 Result := Copy(S, L, R - L + 1);
2481End;
2482
2483Function TrimLeft(Const S: String): String;
2484Var
2485 L, R: Integer;
2486Begin
2487 R := Length(S);
2488 L := 1;
2489 While (L <= R) And (S[L] <= ' ') Do Inc(L);
2490 Result := Copy(S, L, R - L + 1);
2491End;
2492
2493Function TrimRight(Const S: String): String;
2494Var
2495 R: Integer;
2496Begin
2497 R := Length(S);
2498 While (R > 0) And (S[R] <= ' ') Do Dec(R);
2499 Result := Copy(S, 1, R);
2500End;
2501
2502Function QuotedStr(Const S: String): String;
2503Var
2504 N: Integer;
2505Begin
2506 Result := #39;
2507 For N := 1 To Length(S) Do
2508 Begin
2509 Result := Result + S[N];
2510 If S[N] = #39 Then Result := Result + #39;
2511 End;
2512 Result := Result + #39;
2513End;
2514
2515{ --- File management --- }
2516
2517Function FileOpen(Const FileName: String; Mode: Word): LongInt;
2518{$IFDEF OS2}
2519Const
2520 Action = OPEN_ACTION_OPEN_IF_EXISTS Or OPEN_ACTION_FAIL_IF_NEW;
2521Var
2522 ActionTaken, Handle: LongWord;
2523{$ENDIF}
2524{$IFDEF Win95}
2525Const
2526 Action = OPEN_EXISTING;
2527VAR SA:SECURITY_ATTRIBUTES;
2528{$ENDIF}
2529Var
2530 FileNameZ: cstring[256];
2531Begin
2532 FileNameZ := FileName;
2533 If Mode And ShareModes = 0 Then Mode := Mode Or fmShareDenyNone;
2534 {$IFDEF OS2}
2535 Result := - DosOpen(FileNameZ, Handle, ActionTaken, 0, 0, Action, Mode, Nil);
2536 If Result = NO_ERROR Then Result := Handle;
2537 {$ENDIF}
2538 {$IFDEF Win95}
2539 SA.nLength:=sizeof(SA);
2540 SA.lpSecurityDescriptor:=Nil;
2541 SA.bInheritHandle:=True;
2542 Result:=CreateFile(FileNameZ,Mode And Not 3,Mode And 3,SA,Action,
2543 FILE_ATTRIBUTE_NORMAL,0);
2544 {$ENDIF}
2545End;
2546
2547Function FileOpenOrCreate(Const FileName: String; Mode: Word): LongInt;
2548{$IFDEF OS2}
2549Const
2550 Action = OPEN_ACTION_OPEN_IF_EXISTS Or OPEN_ACTION_CREATE_IF_NEW;
2551Var
2552 ActionTaken, Handle: LongWord;
2553{$ENDIF}
2554{$IFDEF Win95}
2555Const
2556 Action = OPEN_ALWAYS;
2557Var SA:SECURITY_ATTRIBUTES;
2558{$ENDIF}
2559Var
2560 FileNameZ: cstring[256];
2561Begin
2562 FileNameZ := FileName;
2563 If Mode And ShareModes = 0 Then Mode := Mode Or fmShareDenyNone;
2564 {$IFDEF OS2}
2565 Result := - DosOpen(FileNameZ, Handle, ActionTaken, 0, 0, Action, Mode, Nil);
2566 If Result = NO_ERROR Then Result := Handle;
2567 {$ENDIF}
2568 {$IFDEF Win95}
2569 SA.nLength:=sizeof(SA);
2570 SA.lpSecurityDescriptor:=Nil;
2571 SA.bInheritHandle:=True;
2572 Result:=CreateFile(FileNameZ,Mode And Not 3,Mode And 3,SA,Action,
2573 FILE_ATTRIBUTE_NORMAL,0);
2574 {$ENDIF}
2575End;
2576
2577Function FileCreateIfNew(Const FileName: String; Mode: Word): LongInt;
2578{$IFDEF OS2}
2579Const
2580 Action = OPEN_ACTION_FAIL_IF_EXISTS Or OPEN_ACTION_CREATE_IF_NEW;
2581Var
2582 ActionTaken, Handle: LongWord;
2583{$ENDIF}
2584{$IFDEF Win95}
2585Const
2586 Action = CREATE_NEW;
2587Var SA:SECURITY_ATTRIBUTES;
2588{$ENDIF}
2589Var
2590 FileNameZ: cstring[256];
2591Begin
2592 FileNameZ := FileName;
2593 If Mode And ShareModes = 0 Then Mode := Mode Or fmShareDenyNone;
2594 {$IFDEF OS2}
2595 Result := - DosOpen(FileNameZ, Handle, ActionTaken, 0, 0, Action, Mode, Nil);
2596 If Result = NO_ERROR Then Result := Handle;
2597 {$ENDIF}
2598 {$IFDEF Win95}
2599 SA.nLength:=sizeof(SA);
2600 SA.lpSecurityDescriptor:=Nil;
2601 SA.bInheritHandle:=True;
2602 Result:=CreateFile(FileNameZ,Mode And Not 3,Mode And 3,SA,Action,
2603 FILE_ATTRIBUTE_NORMAL,0);
2604 {$ENDIF}
2605End;
2606
2607Function FileCreate(Const FileName: String): LongInt;
2608{$IFDEF OS2}
2609Const
2610 Action = OPEN_ACTION_REPLACE_IF_EXISTS Or OPEN_ACTION_CREATE_IF_NEW;
2611Var
2612 ActionTaken, Handle: LongWord;
2613{$ENDIF}
2614{$IFDEF Win95}
2615Const
2616 Action = CREATE_ALWAYS;
2617Var SA:SECURITY_ATTRIBUTES;
2618{$ENDIF}
2619Const
2620 Mode = fmOpenReadWrite Or fmShareExclusive;
2621Var
2622 FileNameZ: cstring[256];
2623Begin
2624 FileNameZ := FileName;
2625 {$IFDEF OS2}
2626 Result := - DosOpen(FileNameZ, Handle, ActionTaken, 0, 0, Action, Mode, Nil);
2627 If Result = NO_ERROR Then Result := Handle;
2628 {$ENDIF}
2629 {$IFDEF Win95}
2630 SA.nLength:=sizeof(SA);
2631 SA.lpSecurityDescriptor:=Nil;
2632 SA.bInheritHandle:=True;
2633 Result:=CreateFile(FileNameZ,Mode And Not 3,Mode And 3,SA,Action,
2634 FILE_ATTRIBUTE_NORMAL,0);
2635 {$ENDIF}
2636End;
2637
2638Function FileRead(Handle: LongInt; Var Buffer; Count: LongInt): LongInt;
2639Var
2640 Result: LongWord;
2641Begin
2642 {$IFDEF OS2}
2643 If DosRead(Handle, Buffer, Count, Result) = NO_ERROR Then FileRead := Result
2644 Else FileRead := -1;
2645 {$ENDIF}
2646 {$IFDEF Win95}
2647 If ReadFile(Handle,Buffer,Count,Result,Nil) Then FileRead := Result
2648 Else FileRead := -1;
2649 {$ENDIF}
2650End;
2651
2652Function FileWrite(Handle: LongInt; Const Buffer; Count: LongInt): LongInt;
2653Var
2654 Result:LongWord;
2655Begin
2656 {$IFDEF OS2}
2657 If DosWrite(Handle, Buffer, Count, Result) = NO_ERROR Then FileWrite := Result
2658 Else FileWrite := -1;
2659 {$ENDIF}
2660 {$IFDEF Win95}
2661 If Not WriteFile(Handle,Buffer,Count,Result,Nil) Then Result := -1
2662 Else FileWrite := Result;
2663 {$ENDIF}
2664End;
2665
2666Function FileSeek(Handle: LongInt; Offset: LongInt; Origin: Integer): LongInt;
2667{$IFDEF OS2}
2668Var
2669 NewPos: LongWord;
2670{$ENDIF}
2671Begin
2672 {$IFDEF OS2}
2673 If DosSetFilePtr(Handle, Offset, Origin, NewPos) = NO_ERROR Then FileSeek := NewPos
2674 Else FileSeek := -1;
2675 {$ENDIF}
2676 {$IFDEF Win95}
2677 Result:=SetFilePointer(Handle,Offset,Nil,Origin);
2678 {$ENDIF}
2679End;
2680
2681Procedure FileClose(Handle: LongInt);
2682Begin
2683 {$IFDEF OS2}
2684 DosClose(Handle);
2685 {$ENDIF}
2686 {$IFDEF Win95}
2687 CloseHandle(Handle);
2688 {$ENDIF}
2689End;
2690
2691Function FileLock(Handle, Offset, Range: LongInt): Boolean;
2692{$IFDEF OS2}
2693Var
2694 Lock, UnLock: BseDos.FileLock;
2695{$ENDIF}
2696Begin
2697 {$IFDEF OS2}
2698 Lock.LOffset := Offset;
2699 Lock.LRange := Range;
2700 UnLock.LOffset := 0;
2701 UnLock.LRange := 0;
2702 Result := (DosSetFileLocks(Handle, UnLock, Lock, LockTimeout, 0) = NO_ERROR);
2703 {$ENDIF}
2704 {$IFDEF Win95}
2705 Result := LockFile(Handle,Offset,0,Range,0);
2706 {$ENDIF}
2707End;
2708
2709Function FileUnLock(Handle, Offset, Range: LongInt): Boolean;
2710{$IFDEF OS2}
2711Var
2712 Lock, UnLock: BseDos.FileLock;
2713{$ENDIF}
2714Begin
2715 {$IFDEF OS2}
2716 UnLock.LOffset := Offset;
2717 UnLock.LRange := Range;
2718 Lock.LOffset := 0;
2719 Lock.LRange := 0;
2720 Result := (DosSetFileLocks(Handle, UnLock, Lock, LockTimeout, 0) = NO_ERROR);
2721 {$ENDIF}
2722 {$IFDEF Win95}
2723 Result := UnlockFile(Handle,Offset,0,Range,0);
2724 {$ENDIF}
2725End;
2726
2727Function FileAge(Const FileName: String): LongInt;
2728Var
2729 FileNameZ: cstring;
2730{$IFDEF OS2}
2731 Buffer: FILESTATUS3;
2732{$ENDIF}
2733{$IFDEF Win95}
2734 Handle:LongWord;
2735 LastAccess,creation,LastWrite,actual:FILETIME;
2736 date,Time:Word;
2737{$ENDIF}
2738Begin
2739 FileNameZ := FileName;
2740 {$IFDEF OS2}
2741 If DosQueryPathInfo(FileNameZ, FIL_STANDARD, Buffer, SizeOf(Buffer)) = NO_ERROR Then
2742 FileAge := (Buffer.fdateLastWrite Shl 16) Or Buffer.ftimeLastWrite
2743 Else FileAge := -1;
2744 {$ENDIF}
2745 {$IFDEF Win95}
2746 Handle:=CreateFile(FileNameZ,GENERIC_READ,0,Nil,OPEN_EXISTING,
2747 FILE_ATTRIBUTE_NORMAL,0);
2748 If Handle=-1 Then
2749 Begin
2750 FileAge:=-1;
2751 Exit;
2752 End;
2753 If Not GetFileTime(Handle,creation,LastAccess,LastWrite) Then
2754 Begin
2755 CloseHandle(Handle);
2756 FileAge:=-1;
2757 Exit;
2758 End;
2759 CloseHandle(Handle);
2760 FileTimeToLocalFileTime(LastWrite,actual);
2761 FileTimeToDosDateTime(actual,date,Time);
2762 FileAge := (date Shl 16) Or Time;
2763 {$ENDIF}
2764End;
2765
2766Function FileExists(Const FileName: String): Boolean;
2767Var
2768 SearchRec: TSearchRec;
2769Begin
2770 If FindFirst(FileName, faAnyFile, SearchRec) = 0 Then
2771 Begin
2772 FileExists := True;
2773 FindClose(SearchRec);
2774 End
2775 Else FileExists := False;
2776End;
2777
2778Function FindFirst(Const Path: String; Attr: Integer; Var SearchRec: TSearchRec): LongInt;
2779{$IFDEF OS2}
2780Var
2781 OS2SearchRec: FILEFINDBUF3;
2782 Result, Count: LongWord;
2783Const
2784 Size = SizeOf(OS2SearchRec);
2785{$ENDIF}
2786{$IFDEF WIN32}
2787Var Actual:FILETIME;
2788 date,time:word;
2789{$ENDIF}
2790Var
2791 PathZ: cstring;
2792Begin
2793 PathZ := Path;
2794 {$IFDEF OS2}
2795 SearchRec.HDir := HDIR_CREATE;
2796 Count := 1;
2797 Result := DosFindFirst(PathZ, SearchRec.HDir, Attr, OS2SearchRec, Size, Count, FIL_STANDARD);
2798 If Result = NO_ERROR Then
2799 Begin
2800 With OS2SearchRec Do
2801 Begin
2802 SearchRec.Name := achName;
2803 SearchRec.Size := cbFile;
2804 SearchRec.Attr := attrFile;
2805 SearchRec.Time := fdateLastWrite;
2806 SearchRec.Time := SearchRec.Time Shl 16 + ftimeLastWrite;
2807 End;
2808 FindFirst := 0;
2809 End
2810 Else FindFirst := -Result;
2811 {$ENDIF}
2812 {$IFDEF Win95}
2813 SearchRec.InternalAttr:=Attr;
2814 SearchRec.HDir:=FindFirstFile(PathZ,SearchRec.SearchRecIntern);
2815 If SearchRec.HDir=INVALID_HANDLE_VALUE Then
2816 Begin
2817 FindFirst:=-GetLastError;
2818 Exit;
2819 End;
2820 While SearchRec.SearchRecIntern.dwFileAttributes And SearchRec.InternalAttr=0 Do
2821 Begin
2822 If FindNextFile(SearchRec.HDir,SearchRec.SearchRecIntern)=False Then
2823 Begin
2824 Result:=-GetLastError;
2825 WinBase.FindClose(SearchRec.HDir);
2826 Exit;
2827 End;
2828 End;
2829
2830 FileTimeToLocalFileTime(SearchRec.SearchRecIntern.ftLastWriteTime,Actual);
2831 FileTimeToDosDateTime(Actual,date,time);
2832 SearchRec.Time:=(date Shl 16) Or Time;
2833 SearchRec.Size:=SearchRec.SearchRecIntern.nFileSizeLow;
2834 SearchRec.Attr:=SearchRec.SearchRecIntern.dwFileAttributes;
2835 SearchRec.Name:=cstring(SearchRec.SearchRecIntern.cFileName);
2836 Result := 0;
2837 {$ENDIF}
2838End;
2839
2840Function FindNext(Var SearchRec: TSearchRec): LongInt;
2841{$IFDEF OS2}
2842Var
2843 OS2SearchRec: FILEFINDBUF3;
2844 Result: Integer;
2845 Count: LongWord;
2846Const
2847 Size = SizeOf(OS2SearchRec);
2848{$ENDIF}
2849{$IFDEF WIN32}
2850Var Actual:FILETIME;
2851 date,time:word;
2852{$ENDIF}
2853Begin
2854 {$IFDEF OS2}
2855 Count := 1;
2856 Result := DosFindNext (SearchRec.HDir, OS2SearchRec, Size, Count);
2857 If Result = NO_ERROR Then
2858 Begin
2859 With OS2SearchRec Do
2860 Begin
2861 SearchRec.Name := achName;
2862 SearchRec.Size := cbFile;
2863 SearchRec.Attr := attrFile;
2864 SearchRec.Time := fdateLastWrite;
2865 SearchRec.Time := SearchRec.Time Shl 16 + ftimeLastWrite;
2866 End;
2867 FindNext := 0;
2868 End
2869 Else FindNext := -Result;
2870 {$ENDIF}
2871 {$IFDEF Win95}
2872 If FindNextFile(SearchRec.HDir,SearchRec.SearchRecIntern)=False Then
2873 Begin
2874 Result:=-GetLastError;
2875 WinBase.FindClose(SearchRec.HDir);
2876 Exit;
2877 End;
2878 While SearchRec.SearchRecIntern.dwFileAttributes And SearchRec.InternalAttr=0 Do
2879 Begin
2880 If FindNextFile(SearchRec.HDir,SearchRec.SearchRecIntern)=False Then
2881 Begin
2882 Result:=-GetLastError;
2883 WinBase.FindClose(SearchRec.HDir);
2884 Exit;
2885 End;
2886 End;
2887
2888 FileTimeToLocalFileTime(SearchRec.SearchRecIntern.ftLastWriteTime,Actual);
2889 FileTimeToDosDateTime(Actual,date,time);
2890 SearchRec.Time:=(date Shl 16) Or Time;
2891 SearchRec.Size:=SearchRec.SearchRecIntern.nFileSizeLow;
2892 SearchRec.Attr:=SearchRec.SearchRecIntern.dwFileAttributes;
2893 SearchRec.Name:=cstring(SearchRec.SearchRecIntern.cFileName);
2894 Result := 0;
2895 {$ENDIF}
2896End;
2897
2898Procedure FindClose(Var SearchRec: TSearchRec);
2899Begin
2900 {$IFDEF OS2}
2901 DosFindClose(SearchRec.HDir);
2902 {$ENDIF}
2903 {$IFDEF Win95}
2904 WinBase.FindClose(SearchRec.HDir);
2905 {$ENDIF}
2906End;
2907
2908Function FileGetDate(Handle: LongInt): LongInt;
2909{$IFDEF OS2}
2910Var
2911 Buffer: FILESTATUS3;
2912{$ENDIF}
2913{$IFDEF Win95}
2914Var
2915 LastAccess,creation,LastWrite,actual:FILETIME;
2916 date,Time:Word;
2917{$ENDIF}
2918Begin
2919 {$IFDEF OS2}
2920 If DosQueryFileInfo(Handle, FIL_STANDARD, Buffer, SizeOf(Buffer)) = NO_ERROR Then
2921 FileGetDate := (Buffer.fdateLastWrite Shl 16) Or Buffer.ftimeLastWrite
2922 Else FileGetDate := -1;
2923 {$ENDIF}
2924 {$IFDEF Win95}
2925 If Not GetFileTime(Handle,creation,LastAccess,LastWrite) Then
2926 Begin
2927 CloseHandle(Handle);
2928 FileGetDate:=-1;
2929 Exit;
2930 End;
2931 CloseHandle(Handle);
2932 FileTimeToLocalFileTime(LastWrite,actual);
2933 FileTimeToDosDateTime(actual,date,Time);
2934 FileGetDate := (date Shl 16) Or Time;
2935 {$ENDIF}
2936End;
2937
2938Procedure FileSetDate(Handle: Integer; Age: LongInt);
2939{$IFDEF OS2}
2940Var
2941 Buffer: FILESTATUS3;
2942{$ENDIF}
2943{$IFDEF Win95}
2944Var
2945 date,Time:Word;
2946 LastWrite:FILETIME;
2947{$ENDIF}
2948Begin
2949 {$IFDEF OS2}
2950 FillChar(Buffer, SizeOf(Buffer), 0);
2951 Buffer.ftimeLastWrite := Age And $FFFF;
2952 Buffer.fdateLastWrite := Age Shr 16;
2953 DosSetFileInfo(Handle, FIL_STANDARD, Buffer, SizeOf(Buffer));
2954 {$ENDIF}
2955 {$IFDEF Win95}
2956 date:= Age Shr 16;
2957 Time:= Age And $FFFF;
2958 DosDateTimeToFileTime(date,Time,LastWrite);
2959
2960 WinBase.SetFileTime(Handle,Nil,Nil,LastWrite);
2961 {$ENDIF}
2962End;
2963
2964Function FileGetAttr(Const FileName: String): LongInt;
2965{$IFDEF OS2}
2966Var
2967 Buffer: FILESTATUS3;
2968{$ENDIF}
2969Var
2970 FileNameZ: cstring;
2971Begin
2972 FileNameZ := FileName;
2973 {$IFDEF OS2}
2974 Result := - DosQueryPathInfo(FileNameZ, FIL_STANDARD, Buffer, SizeOf(Buffer));
2975 If Result = 0 Then Result := Buffer.attrFile;
2976 {$ENDIF}
2977 {$IFDEF Win95}
2978 Result := GetFileAttributes(FileNameZ);
2979 {$ENDIF}
2980End;
2981
2982Function FileSetAttr(Const FileName: String; Attr: Integer): Integer;
2983{$IFDEF OS2}
2984Var
2985 Buffer: FILESTATUS3;
2986{$ENDIF}
2987Var
2988 FileNameZ: cstring;
2989Begin
2990 FileNameZ := FileName;
2991 {$IFDEF OS2}
2992 FillChar(Buffer, SizeOf(Buffer), 0);
2993 Buffer.attrFile := Attr;
2994 Result := - DosSetPathInfo(FileNameZ, FIL_STANDARD, Buffer, SizeOf(Buffer), 0);
2995 {$ENDIF}
2996 {$IFDEF Win95}
2997 If SetFileAttributes(FileNameZ,Attr) Then Result:=0
2998 Else Result := -GetLastError;
2999 {$ENDIF}
3000End;
3001
3002Function CopyFile(Const SourceName, DestName: String): Boolean;
3003Var
3004 SourceZ, DestZ: cstring;
3005Begin
3006 SourceZ := SourceName;
3007 DestZ := DestName;
3008 {$IFDEF OS2}
3009 Result := (DosCopy(SourceZ, DestZ, DCPY_EXISTING) = NO_ERROR);
3010 {$ENDIF}
3011 {$IFDEF Win95}
3012 Result := WinBase.CopyFile(SourceZ, DestZ, True);
3013 {$ENDIF}
3014End;
3015
3016Function DeleteFile(Const FileName: String): Boolean;
3017Var
3018 FileNameZ: cstring;
3019Begin
3020 FileNameZ := FileName;
3021 {$IFDEF OS2}
3022 Result := (DosDelete(FileNameZ) = NO_ERROR);
3023 {$ENDIF}
3024 {$IFDEF Win95}
3025 Result := WinBase.DeleteFile(FileNameZ);
3026 {$ENDIF}
3027End;
3028
3029Function RenameFile(Const OldName, NewName: String): Boolean;
3030Var
3031 OldNameZ, NewNameZ: cstring;
3032Begin
3033 OldNameZ := OldName;
3034 NewNameZ := NewName;
3035 {$IFDEF OS2}
3036 Result := (DosMove(OldNameZ, NewNameZ) = NO_ERROR);
3037 {$ENDIF}
3038 {$IFDEF Win95}
3039 Result := MoveFile(OldNameZ, NewNameZ);
3040 {$ENDIF}
3041End;
3042
3043Function ChangeFileExt(Const FileName, extension: String): String;
3044Var
3045 P: Integer;
3046Begin
3047 P := Length(FileName);
3048 While (P > 0) And (FileName[P] <> '.') Do Dec(P);
3049 If P = 0 Then Result := FileName + extension
3050 Else Result := Copy(FileName, 1, P - 1) + extension;
3051End;
3052
3053Function ExtractFilePath(Const FileName: String): String;
3054Var
3055 P: Integer;
3056Begin
3057 P := Length(FileName);
3058 While (P > 0) And (FileName[P] <> ':') And (FileName[P] <> '\') Do Dec(P);
3059 Result := Copy(FileName, 1, P);
3060End;
3061
3062Function ExtractFileName(Const FileName: String): String;
3063Var
3064 P: Integer;
3065Begin
3066 P := Length(FileName);
3067 While (P > 0) And (FileName[P] <> ':') And (FileName[P] <> '\') Do Dec(P);
3068 Result := Copy(FileName, P + 1, 255);
3069End;
3070
3071Function ExtractFileExt(Const FileName: String): String;
3072Var
3073 P: Integer;
3074Begin
3075 P := Length(FileName);
3076 While (P > 0) And (FileName[P] <> '.') Do Dec(P);
3077 If P = 0 Then Result := ''
3078 Else Result := Copy(FileName, P, 255);
3079End;
3080
3081Function ConcatFileName(Const pathname, FileName: String): String;
3082Begin
3083 If (pathname = '') Or (FileName = '') Or
3084 (pathname[Length(pathname)] In ['\', ':']) Then
3085 Result := pathname + FileName
3086 Else Result := pathname + '\' + FileName;
3087End;
3088
3089Function ExpandFileName(FileName: String): String;
3090{$IFDEF OS2}
3091Const
3092 Level = FIL_QUERYFULLNAME;
3093Var
3094 Buffer:CString;
3095{$ENDIF}
3096{$IFDEF Win95}
3097Var
3098 TempName : PChar;
3099{$ENDIF}
3100Var
3101 FileNameZ: cstring;
3102Begin
3103 FileNameZ := FileName;
3104 {$IFDEF OS2}
3105 If DosQueryPathInfo(FileNameZ, Level, Buffer, SizeOf(Buffer)) = NO_ERROR Then Result := Buffer
3106 Else
3107 Begin
3108 If ((length(FileName)=2)And(FileName[2]=':')) Then
3109 Begin
3110 {$I-}
3111 GetDir(ord(Upcase(FileName[1]))-64,Result);
3112 {$I+}
3113 If IoResult<>0 Then Result:='';
3114 End
3115 Else Result:='';
3116 End;
3117 {$ENDIF}
3118 {$IFDEF Win95}
3119 Result[0]:=Chr(GetFullPathName(FileNameZ,256,cstring(Result[1]),TempName));
3120 {$ENDIF}
3121End;
3122
3123Function EditFileName(Const Name, edit: String): String;
3124{$IFDEF OS2}
3125Var
3126 Buffer: cstring;
3127{$ENDIF}
3128Var
3129 NameZ, EditZ: cstring;
3130Begin
3131 NameZ := Name;
3132 EditZ := edit;
3133 {$IFDEF OS2}
3134 If DosEditName(1, NameZ, EditZ, Buffer, 256) = 0 Then Result := Buffer
3135 Else Result := '';
3136 {$ENDIF}
3137 {$IFDEF Win95}
3138 Result := ''; //Not supported
3139 {$ENDIF}
3140End;
3141
3142Function FileSearch(Const Name, DirList: String): String;
3143{$IFDEF OS2}
3144Const
3145 Flags = SEARCH_IGNORENETERRS;
3146{$ENDIF}
3147{$IFDEF Win95}
3148Var
3149 Temp : PChar;
3150{$ENDIF}
3151Var
3152 NameZ, DirListZ, Buffer: cstring;
3153Begin
3154 NameZ := Name;
3155 DirListZ := DirList;
3156 {$IFDEF OS2}
3157 If DosSearchPath(Flags, DirListZ, NameZ, Buffer, SizeOf(Buffer)) = NO_ERROR Then
3158 Result := Buffer
3159 Else Result := '';
3160 {$ENDIF}
3161 {$IFDEF Win95}
3162 If SearchPath(DirListZ,Name,Nil,256,Buffer,Temp)=0 Then Result:=''
3163 Else Result:=Buffer;
3164 {$ENDIF}
3165End;
3166
3167Function DiskFree(Drive: Byte): LongInt;
3168{$IFDEF OS2}
3169Var
3170 Buffer: FSALLOCATE;
3171{$ENDIF}
3172{$IFDEF Win95}
3173Var
3174 C : cstring;
3175 S:LongWord;
3176 Sec,clust,freeclust:LongWord;
3177{$ENDIF}
3178Begin
3179 {$IFDEF OS2}
3180 If DosQueryFSInfo(Drive, FSIL_ALLOC, Buffer, SizeOf(Buffer)) = NO_ERROR Then
3181 With Buffer Do Result := cUnitAvail * cSectorUnit * cbSector
3182 Else Result := -1;
3183 {$ENDIF}
3184 {$IFDEF Win95}
3185 If Drive=0 Then
3186 Begin
3187 If Not GetDiskFreeSpace(Nil,S,Sec,freeclust,clust) Then
3188 Begin
3189 Result:=-1;
3190 Exit;
3191 End;
3192 End
3193 Else
3194 Begin
3195 C:=Chr(Ord('A')+(Drive-1))+':\';
3196 If Not GetDiskFreeSpace(C,S,Sec,freeclust,clust) Then
3197 Begin
3198 Result:=-1;
3199 Exit;
3200 End;
3201 End;
3202 Result:=S*Sec*freeclust;
3203 {$ENDIF}
3204End;
3205
3206Function DiskSize(Drive: Byte): LongInt;
3207{$IFDEF OS2}
3208Var
3209 Buffer: FSALLOCATE;
3210{$ENDIF}
3211{$IFDEF Win95}
3212Var
3213 C : cstring;
3214 S:LongWord;
3215 Sec,clust,freeclust:LongWord;
3216{$ENDIF}
3217Begin
3218 {$IFDEF OS2}
3219 If DosQueryFSInfo(Drive, FSIL_ALLOC, Buffer, SizeOf(Buffer)) = NO_ERROR Then
3220 With Buffer Do Result := cUnit * cSectorUnit * cbSector
3221 Else Result := -1;
3222 {$ENDIF}
3223 {$IFDEF Win95}
3224 If Drive=0 Then
3225 Begin
3226 If Not GetDiskFreeSpace(Nil,S,Sec,freeclust,clust) Then
3227 Begin
3228 Result:=-1;
3229 Exit;
3230 End;
3231 End
3232 Else
3233 Begin
3234 C:=Chr(Ord('A')+(Drive-1))+':\';
3235 If Not GetDiskFreeSpace(C,S,Sec,freeclust,clust) Then
3236 Begin
3237 Result:=-1;
3238 Exit;
3239 End;
3240 End;
3241 Result:=S*Sec*clust;
3242 {$ENDIF}
3243End;
3244
3245Function FileDateToDateTime(FileDate: LongInt): TDateTime;
3246Var
3247 Day, Month, Year, Hour, Min, Sec: Word;
3248Begin
3249 Sec := (FileDate And 31) Shl 1;
3250 FileDate := FileDate Shr 5;
3251 Min := FileDate And 63;
3252 FileDate := FileDate Shr 6;
3253 Hour := FileDate And 31;
3254 FileDate := FileDate Shr 5;
3255
3256 Day := FileDate And 31;
3257 FileDate := FileDate Shr 5;
3258 Month := FileDate And 15;
3259 FileDate := FileDate Shr 4;
3260 Year := 1980 + (FileDate And 127);
3261
3262 Result := EncodeDate(Year, Month, Day) + EncodeTime(Hour, Min, Sec, 0);
3263End;
3264
3265Function DateTimeToFileDate(DateTime: TDateTime): LongInt;
3266Var
3267 Day, Month, Year, Hour, Min, Sec, MSec: Word;
3268 FileDate, FILETIME: LongInt;
3269Begin
3270 DecodeDate(DateTime, Year, Month, Day);
3271 DecodeTime(DateTime, Hour, Min, Sec, MSec);
3272
3273 FileDate := Year - 1980;
3274 FileDate := (FileDate Shl 4) Or Month;
3275 FileDate := (FileDate Shl 5) Or Day;
3276
3277 FILETIME := Hour;
3278 FILETIME := (FILETIME Shl 6) Or Min;
3279 FILETIME := (FILETIME Shl 5) Or (Sec Div 2);
3280
3281 Result := (FileDate Shl 16) Or FILETIME;
3282End;
3283
3284/* Alte Implementierung, macht Probleme mit neuem Compiler
3285
3286Function DateTimeToFileDate(DateTime: TDateTime): LongInt;
3287Var
3288 Day, Month, Year, Hour, Min, Sec, MSec: Word;
3289 FileDate: LongInt;
3290Begin
3291 DecodeDate(DateTime, Year, Month, Day);
3292 DecodeTime(DateTime, Hour, Min, Sec, MSec);
3293
3294 FileDate := Year - 1980;
3295 FileDate := (FileDate Shl 4) Or Month;
3296 FileDate := (FileDate Shl 5) Or Day;
3297 FileDate := Hour;
3298 FileDate := (FileDate Shl 6) Or Min;
3299 FileDate := (FileDate Shl 5) Or (Sec Div 2);
3300
3301 Result := FileDate;
3302End;
3303
3304*/
3305
3306{ --- PChar Handling --- }
3307
3308Function StrLen(Str:PChar): Cardinal;
3309Begin
3310 Asm
3311 MOV EDI, Str
3312 CALLN32 !StringLength
3313 MOV Result, EAX
3314 End;
3315End;
3316
3317Function StrEnd(Str:PChar):PChar;
3318Begin
3319 Asm
3320 MOV EDI, Str
3321 CALLN32 !StringLength
3322 MOV Result, EDI
3323 End;
3324End;
3325
3326Function StrMove(Dest, Source: PChar; Count: Cardinal): PChar;
3327Begin
3328 If (Source = Nil) Or (Dest = Nil) Or (Count = 0) Then Result := Nil
3329 Else
3330 Begin
3331 Move(Source^, Dest^, Count);
3332 Result := Dest;
3333 End;
3334End;
3335
3336Function StrCopy(Dest, Source:PChar):PChar;
3337Begin
3338 Asm
3339 MOV ESI, Source
3340 MOV EDI, Dest
3341 MOV ECX, $FFFFFFFF
3342 CALLN32 !StringCopy
3343 MOV EAX, Dest
3344 MOV Result, EAX
3345 End;
3346End;
3347
3348Function StrECopy(Dest, Source:PChar):PChar;
3349Begin
3350 Asm
3351 MOV ESI, Source
3352 MOV EDI, Dest
3353 MOV ECX, $FFFFFFFF
3354 CALLN32 !StringCopy
3355 MOV Result, EDI
3356 End;
3357End;
3358
3359Function StrLCopy(Dest, Source:PChar; MaxLen: Cardinal):PChar;
3360Begin
3361 Asm
3362 MOV ESI, Source
3363 MOV EDI, Dest
3364 MOV ECX, MaxLen
3365 CALLN32 !StringCopy
3366 MOV EAX, Dest
3367 MOV Result, EAX
3368 End;
3369End;
3370
3371Function StrPCopy(Dest: PChar; Const Source: String): PChar;
3372Begin
3373 Asm
3374 MOV EDI, Dest
3375 MOV ESI, Source
3376 Xor ECX, ECX
3377 MOV CL, [ESI]
3378 Inc ESI
3379 CALLN32 !StringCopy
3380 MOV EAX, Dest
3381 MOV Result, EAX
3382 End;
3383End;
3384
3385Function StrPLCopy(Dest: PChar; Const Source: String; MaxLen: Cardinal): PChar;
3386Begin
3387 Asm
3388 MOV EDI, Dest
3389 MOV ESI, Source
3390 Xor ECX, ECX
3391 MOV CL, [ESI]
3392 Inc ESI
3393 CMP ECX, MaxLen
3394 JLE StrPLCopy_1
3395 MOV ECX, MaxLen
3396
3397 StrPLCopy_1:
3398
3399 CALLN32 !StringCopy
3400 MOV EAX, Dest
3401 MOV Result, EAX
3402 End;
3403End;
3404
3405Function StrCat(Dest, Source: PChar): PChar;
3406Begin
3407 Asm
3408 MOV EDI, Dest
3409 MOV ESI, Source
3410 CALLN32 !StringLength
3411 MOV ECX, $FFFFFFFF
3412 CALLN32 !StringCopy
3413 MOV EAX, Dest
3414 MOV Result, EAX
3415 End;
3416End;
3417
3418Function StrLCat(Dest, Source: PChar; MaxLen: Cardinal): PChar;
3419Begin
3420 Asm
3421 MOV EDI, Dest
3422 MOV ESI, Source
3423 CALLN32 !StringLength
3424 MOV ECX, MaxLen
3425 SUB ECX, EAX
3426 JLE StrLCat_1
3427 CALLN32 !StringCopy
3428
3429 StrLCat_1:
3430
3431 MOV EAX, Dest
3432 MOV Result, EAX
3433 End;
3434End;
3435
3436Function StrComp(Str1, Str2: PChar): Integer;
3437Begin
3438 Asm
3439 MOV EDI, Str1
3440 CALLN32 !StringLength
3441 MOV ECX, EAX
3442 MOV ESI, Str1
3443 MOV EDI, Str2
3444 CALLN32 !StringCompare
3445 MOV Result, EAX
3446 End;
3447End;
3448
3449Function StrLComp(Str1, Str2: PChar; MaxLen: Cardinal): Integer;
3450Begin
3451 Asm
3452 MOV EDI, Str1
3453 MOV ECX, MaxLen
3454 MOV EBX, ECX
3455 Xor EAX, EAX
3456 REPNZ SCASB
3457 SUB EBX, ECX
3458 MOV ECX, EBX
3459 MOV ESI, Str1
3460 MOV EDI, Str2
3461 CALLN32 !StringCompare
3462 MOV Result, EAX
3463 End;
3464End;
3465
3466Function StrIComp(Str1, Str2: PChar): Integer;
3467Begin
3468 Asm
3469 // Set MaxLen (ECX) to Maxint
3470 MOV ECX, $ffffffff
3471 MOV ESI, Str1 // Set ESI to Str1
3472 MOV EDI, Str2 // Set EDI to Str2
3473 CALLN32 !ZeroTerminatedStringICompare
3474 MOV Result, EAX // Set result
3475 End;
3476End;
3477
3478Function StrLIComp(Str1, Str2: PChar; MaxLen: Cardinal): Integer;
3479Begin
3480 Asm
3481 MOV ECX, MaxLen // put MaxLen into ECX
3482 MOV ESI, Str1
3483 MOV EDI, Str2
3484 CALLN32 !StringICompare
3485 MOV Result, EAX
3486 End;
3487End;
3488
3489Function StrScan(Str: PChar; Chr: Char): PChar;
3490Begin
3491 Asm
3492 MOV EDI, Str
3493 CALLN32 !StringLength
3494 Inc EAX
3495 MOV ECX, EAX
3496 Xor EBX, EBX
3497 MOV AL, Chr
3498 MOV EDI, Str
3499 REPNZ SCASB
3500 Dec EDI
3501 CMP AL, [EDI]
3502 JNE !StrScan_1
3503 MOV EBX, EDI
3504
3505 !StrScan_1:
3506
3507 MOV Result, EBX
3508 End;
3509End;
3510
3511Function StrRScan(Str: PChar; Chr: Char): PChar;
3512Begin
3513 Asm
3514 MOV EDI, Str
3515 CALLN32 !StringLength
3516 Inc EAX
3517 MOV ECX, EAX
3518 Xor EBX, EBX
3519 MOV AL, Chr
3520 STD
3521 REPNZ SCASB
3522 Inc EDI
3523 CMP AL, [EDI]
3524 JNE !StrRScan_1
3525 MOV EBX, EDI
3526
3527 !StrRScan_1:
3528
3529 CLD
3530 MOV Result, EBX
3531 End;
3532End;
3533
3534Function StrPos(Str, SubStr: PChar): PChar;
3535Begin
3536 Asm
3537 MOV EDI, SubStr
3538 CALLN32 !StringLength
3539 CMP EAX, 0
3540 JE !ErrOutStrPos
3541
3542 MOV EDX, EAX
3543 MOV EDI, Str
3544 CALLN32 !StringLength
3545 CMP EAX, 0
3546 JE !ErrOutStrPos
3547 SUB EAX, EDX
3548 JB !ErrOutStrPos
3549 MOV EDI, Str
3550
3551 !1:
3552
3553 MOV ESI, SubStr
3554 LODSB
3555 REPNE SCASB
3556 JNE !ErrOutStrPos;
3557 MOV EAX, ECX
3558 PUSH EDI
3559 MOV ECX, EDX
3560 Dec ECX
3561 REPE CMPSB
3562 MOV ECX, EAX
3563 POP EDI
3564 JNE !1
3565 MOV EAX, EDI
3566 Dec EAX
3567 JMP !out
3568
3569 !ErrOutStrPos:
3570
3571 Xor EAX,EAX
3572
3573 !out:
3574
3575 MOV Result, EAX
3576 End;
3577End;
3578
3579Function StrLower(Str: PChar): PChar;
3580Begin
3581 Asm
3582 CLD
3583 MOV ESI, Str
3584
3585 !StringLower1:
3586
3587 LODSB
3588 Or AL, AL
3589 JE !OutStrLower
3590
3591 CMP AL, 'A'
3592 JB !StringLower1
3593 CMP AL, 'Z'
3594 JA !StringLower1
3595 Or AL, 32
3596 MOV [ESI-1], AL
3597 JMP !StringLower1
3598
3599 !OutStrLower:
3600
3601 MOV EAX, Str
3602 MOV Result, EAX
3603 End;
3604End;
3605
3606Function StrUpper(Str: PChar): PChar;
3607Begin
3608 Asm
3609 CLD
3610 MOV ESI, Str
3611
3612 !StringUpper_Loop:
3613
3614 LODSB
3615 Or AL, AL
3616 JE !OutStrUpper
3617
3618 CMP AL, 'a'
3619 JB !StringUpper_Loop
3620 CMP AL, 'z'
3621 JA !StringUpper_Loop
3622 And AL, $DF
3623 MOV [ESI-1], AL
3624 JMP !StringUpper_Loop
3625
3626 !OutStrUpper:
3627
3628 MOV EAX, Str
3629 MOV Result, EAX
3630 End;
3631End;
3632
3633Function StrPas(Str: PChar): String;
3634Begin
3635 Result := Str^;
3636End;
3637
3638Function StrAlloc(Size: Cardinal): PChar;
3639Type
3640 PLong = ^LongInt;
3641Var
3642 P: PChar;
3643Begin
3644 GetMem(P, Size + 4);
3645 PLong(P)^ := Size + 4;
3646 Inc(P, 4);
3647 StrAlloc := P;
3648End;
3649
3650Function StrBufSize(Str: PChar): Cardinal;
3651Type
3652 PLong = ^LongInt;
3653Begin
3654 Dec(Str, 4);
3655 StrBufSize := PLong(Str)^ - 4;
3656End;
3657
3658Function StrNew(Str: PChar): PChar;
3659Var
3660 Size: LongInt;
3661Begin
3662 If Str = Nil Then StrNew := Nil
3663 Else
3664 Begin
3665 Size := StrLen(Str) + 1;
3666 StrNew := StrMove(StrAlloc(Size), Str, Size);
3667 End;
3668End;
3669
3670Procedure StrDispose(Str: PChar);
3671Type
3672 PLong = ^LongInt;
3673Begin
3674 If Str <> Nil Then
3675 If Str <> NullStr Then
3676 Begin
3677 Dec(Str, 4);
3678 FreeMem(Str, PLong(Str)^);
3679 End;
3680End;
3681
3682{ --- String formatting --- }
3683
3684{$HINTS OFF}
3685Function FormatBuf(Var Buffer; BufLen: Cardinal; Const format; FmtLen: Cardinal; Const Args: Array Of Const): Cardinal;
3686Var
3687 { format And Result buffers }
3688
3689 FmtPos, OldFmtPos, BufPos, ArgPos: LongInt;
3690 Buf: cstring Absolute Buffer;
3691 Fmt: cstring Absolute format;
3692
3693 { argument Buffer }
3694
3695 VArgs: Array[0..1023] Of TVarRec Absolute Args;
3696
3697 { Workaround For High() problem }
3698
3699 High_Args: LongInt;
3700
3701 { format Details }
3702
3703 Index, Width, Precision: LongInt;
3704 LeftAlign: Boolean;
3705 ArgType: Char;
3706
3707 { temporary variables }
3708
3709 C: Char;
3710 P: Pointer;
3711 E: Extended;
3712 Pnt,M:LongInt;
3713 L: LongInt;
3714 S: String[80];
3715
3716 { Raise Exception: format And argument don't match }
3717
3718 Procedure IllegalArg;
3719 Begin
3720 FmtLoadConvertError(SInvalidFormat, [ArgType]);
3721 End;
3722
3723 { Raise Exception: out Of arguments }
3724
3725 Procedure OutOfArgs;
3726 Begin
3727 FmtLoadConvertError(SArgumentMissing, [ArgType]);
3728 End;
3729
3730 { Get an argument from the Open Array. If the
3731 Type Is unexpected, Raise an Exception. }
3732
3733 Function GetIntegerArg: LongInt;
3734 Begin
3735 If ArgPos > High_Args Then OutOfArgs;
3736 If VArgs[ArgPos].VType <> vtInteger Then IllegalArg;
3737 Result := VArgs[ArgPos].VInteger;
3738 Inc(ArgPos);
3739 End;
3740
3741 Function GetExtendedArg: Extended;
3742 Begin
3743 If ArgPos > High_Args Then OutOfArgs;
3744 If VArgs[ArgPos].VType <> vtExtended Then IllegalArg;
3745 Result := VArgs[ArgPos].VExtended^;
3746 Inc(ArgPos);
3747 End;
3748
3749 Function GetPointerArg: Pointer;
3750 Begin
3751 If ArgPos > High_Args Then OutOfArgs;
3752 If VArgs[ArgPos].VType <> vtPointer Then IllegalArg;
3753 Result := VArgs[ArgPos].VPointer;
3754 Inc(ArgPos);
3755 End;
3756
3757 Procedure GetStringArg(Var FirstChar: Pointer; Var len: LongInt);
3758 Begin
3759 If ArgPos > High_Args Then OutOfArgs;
3760 Case VArgs[ArgPos].VType Of
3761 vtChar:
3762 Begin
3763 FirstChar := @VArgs[ArgPos].VChar;
3764 len := 1;
3765 End;
3766
3767 vtString:
3768 Begin
3769 FirstChar := VArgs[ArgPos].VString;
3770 len := Byte(FirstChar^);
3771 Inc(FirstChar);
3772 End;
3773
3774 vtPointer,
3775 vtPChar:
3776 Begin
3777 FirstChar := VArgs[ArgPos].VPChar;
3778 len := StrLen(FirstChar);
3779 End;
3780
3781 vtAnsiString:
3782 Begin
3783 FirstChar := VArgs[ArgPos].VPChar;
3784 len := Length(AnsiString(VArgs[ArgPos].VAnsiString));
3785 End;
3786 Else
3787 IllegalArg;
3788 End;
3789 Inc(ArgPos);
3790 End;
3791
3792 { Parse A Number from the format String. A '*' means:
3793 Get the Next Integer argument from the Open Array. }
3794
3795 Function ParseNum: LongInt;
3796 Begin
3797 If Fmt[FmtPos] = '*' Then Result := GetIntegerArg
3798 Else
3799 Begin
3800 Result := 0;
3801 While (Fmt[FmtPos] In ['0'..'9']) And (FmtPos < FmtLen) Do
3802 Begin
3803 Result := Result * 10 + Ord(Fmt[FmtPos]) - 48;
3804 Inc(FmtPos);
3805 End;
3806 End;
3807 End;
3808
3809 { Parse A whole format specifier. }
3810
3811 Function ParseFmtSpec: Char;
3812 Label
3813 LIndex, LColon, LMinus, LWidth, LPoint, LType;
3814 Begin
3815 Width := -1;
3816 Index := -1;
3817 Precision := -1;
3818 LeftAlign := False;
3819 ArgType := #0;
3820 C := Fmt[FmtPos];
3821
3822 LIndex:
3823
3824 If Not (C In ['0'..'9']) Then Goto LMinus;
3825 Width := ParseNum;
3826 If FmtPos >= FmtLen Then Exit;
3827 C := Fmt[FmtPos];
3828
3829 LColon:
3830
3831 If C <> ':' Then Goto LPoint;
3832 Index := Width;
3833 Width := -1;
3834 Inc(FmtPos);
3835 If FmtPos >= FmtLen Then Exit;
3836 C := Fmt[FmtPos];
3837
3838 LMinus:
3839
3840 If C <> '-' Then Goto LWidth;
3841 LeftAlign := True;
3842 Inc(FmtPos);
3843 If FmtPos >= FmtLen Then Exit;
3844 C := Fmt[FmtPos];
3845
3846 LWidth:
3847
3848 If Not (C In ['0'..'9']) Then Goto LPoint;
3849 Width := ParseNum;
3850 If FmtPos >= FmtLen Then Exit;
3851 C := Fmt[FmtPos];
3852
3853 LPoint:
3854
3855 If C <> '.' Then Goto LType;
3856 Inc(FmtPos);
3857 Precision := ParseNum;
3858 If FmtPos >= FmtLen Then Exit;
3859 C := Fmt[FmtPos];
3860
3861 LType:
3862
3863 Result := UpCase(C);
3864 ArgType := Result;
3865
3866 {WriteLn;
3867 WriteLn('Index:', Index, ' Align:', LeftAlign, ' Width:', Width, ' Prec: ', Precision, ' Type:', Result);
3868 WriteLn;}
3869
3870 Inc(FmtPos);
3871 End;
3872
3873 { Append something To the Result Buffer }
3874
3875 Procedure AppendStr(P: Pointer; Count: LongInt);
3876 Begin
3877 If BufLen - BufPos < Count Then Count := BufLen - BufPos;
3878 Move(P^, Buf[BufPos], Count);
3879 Inc(BufPos, Count);
3880 End;
3881
3882 Procedure AppendChar(C: Char; Count: LongInt);
3883 Begin
3884 If BufLen - BufPos < Count Then Count := BufLen - BufPos;
3885 FillChar(Buf[BufPos], Count, C);
3886 Inc(BufPos, Count);
3887 End;
3888
3889Begin
3890 FmtPos := 0;
3891 OldFmtPos := 0;
3892 BufPos := 0;
3893 ArgPos := 0;
3894
3895 High_Args := High(Args);
3896
3897 While (FmtPos < FmtLen) And (BufPos < BufLen) Do
3898 Begin
3899 C := Fmt[FmtPos];
3900 Inc(FmtPos);
3901 If C = '%' Then
3902 Begin
3903 C := ParseFmtSpec;
3904 If C = 'S' Then
3905 Begin
3906 GetStringArg(P, L);
3907 If (Precision > -1) And (Precision < L) Then L := Precision;
3908 End
3909 Else
3910 Begin
3911 Case C Of
3912 'D': Begin
3913 Str(GetIntegerArg, S);
3914 L := Length(S);
3915 If (Precision <> -1) And (L < Precision) Then
3916 Begin
3917 SetLength(S, Precision);
3918 Move(S[1], S[1 + Precision - L], L);
3919 FillChar(S[1], Precision - L, '0');
3920 End;
3921 End;
3922 'E': S := FloatToStrF(GetExtendedArg, ffExponent, Precision, 3);
3923 'F': S := FloatToStrF(GetExtendedArg, ffFixed, 9999, Precision);
3924 'G': S := FloatToStrF(GetExtendedArg, ffGeneral, Precision, 3);
3925 'N': S := FloatToStrF(GetExtendedArg, ffFixed, 9999, Precision);
3926 'M': S := FloatToStrF(GetExtendedArg, ffCurrency, 9999, Precision);
3927 'P': Begin
3928 L := LongInt(GetPointerArg);
3929 S := IntToHex(L Shr 16, 4) + ':' + IntToHex(L And $FFFF, 4);
3930 End;
3931 'X': Begin
3932 If Precision <> -1 Then S := IntToHex(GetIntegerArg, Precision)
3933 Else S := IntToHex(GetIntegerArg, 0);
3934 End;
3935 Else FmtLoadConvertError(SInvalidFormat, [C]);
3936 End;
3937 P := @S[1];
3938 L := Length(S);
3939 End;
3940
3941 { now P Points To the First Char To Append To our Result, L holds the
3942 Length Of the Text To Insert. If Width > L Then we have To pad our
3943 Text With spaces. }
3944
3945 If LeftAlign Then
3946 Begin
3947 AppendStr(P, L);
3948 If (Width > -1) And (L < Width) Then AppendChar(' ', Width - L );
3949 End
3950 Else
3951 Begin
3952 If (Width > -1) And (L < Width) Then AppendChar(' ', Width - L );
3953 AppendStr(P, L);
3954 End;
3955 End
3956 Else
3957 Begin
3958 { Ordinary character }
3959 Buf[BufPos] := C;
3960 Inc(BufPos);
3961 End;
3962 OldFmtPos := FmtPos;
3963 End;
3964 Result := BufPos;
3965End;
3966{$HINTS ON}
3967
3968
3969Function format(Const format: String; Const Args: Array Of Const): String;
3970Begin
3971 SetLength(Result, FormatBuf(Result[1], 255, format[1], Length(format), Args));
3972End;
3973
3974Procedure FmtStr(Var Result: String; Const format: String; Const Args: Array Of Const);
3975Begin
3976 SetLength(Result, FormatBuf(Result[1], 255, format[1], Length(format), Args));
3977End;
3978
3979Function StrFmt(Buffer, format: PChar; Const Args: Array Of Const): PChar;
3980Begin
3981 FormatBuf(Buffer, MaxLongInt, format, StrLen(format), Args);
3982 Result := Buffer;
3983End;
3984
3985Function StrLFmt(Buffer: PChar; MaxLen: Cardinal; format: PChar; Const Args: Array Of Const): PChar;
3986Begin
3987 FormatBuf(Buffer, MaxLen, format, StrLen(format), Args);
3988 Result := Buffer;
3989End;
3990
3991{ --- floating Point conversion --- }
3992
3993Function FloatToStr(Value: Extended): String;
3994Begin
3995 Result := FloatToStrF(Value, ffGeneral, 15, 0);
3996End;
3997
3998Function FloatToStrF(Value: Extended; format: TFloatFormat; Precision, Digits: Integer): String;
3999Var
4000 P: Integer;
4001 Negative, TooSmall, TooLarge: Boolean;
4002Begin
4003 Case format Of
4004
4005 ffGeneral:
4006
4007 Begin
4008 If (Precision = -1) Or (Precision > 15) Then Precision := 15;
4009 TooSmall := Abs(Value) < 0.00001;
4010 If Not TooSmall Then
4011 Begin
4012 Str(Value:0:999, Result);
4013 P := Pos('.', Result);
4014 Result[P] := DecimalSeparator;
4015 TooLarge := P > Precision + 1;
4016 End;
4017
4018 If TooSmall Or TooLarge Then
4019 Result := FloatToStrF(Value, ffExponent, Precision, Digits);
4020
4021 P := Length(Result);
4022 While Result[P] = '0' Do Dec(P);
4023 If Result[P] = DecimalSeparator Then Dec(P);
4024 SetLength(Result, P);
4025 End;
4026
4027 ffExponent:
4028
4029 Begin
4030 If (Precision = -1) Or (Precision > 15) Then Precision := 15;
4031 Str(Value:Precision + 8, Result);
4032 Result[3] := DecimalSeparator;
4033 If (Digits < 4) And (Result[Precision + 5] = '0') Then
4034 Begin
4035 Delete(Result, Precision + 5, 1);
4036 If (Digits < 3) And (Result[Precision + 5] = '0') Then
4037 Begin
4038 Delete(Result, Precision + 5, 1);
4039 If (Digits < 2) And (Result[Precision + 5] = '0') Then
4040 Begin
4041 Delete(Result, Precision + 5, 1);
4042 If (Digits < 1) And (Result[Precision + 5] = '0') Then Delete(Result, Precision + 3, 3);
4043 End;
4044 End;
4045 End;
4046 If Result[1] = ' ' Then Delete(Result, 1, 1);
4047 End;
4048
4049 ffFixed:
4050
4051 Begin
4052 If Digits = -1 Then Digits := 2
4053 Else If Digits > 15 Then Digits := 15;
4054 Str(Value:0:Digits, Result);
4055 If Result[1] = ' ' Then Delete(Result, 1, 1);
4056 P := Pos('.', Result);
4057 If P <> 0 Then Result[P] := DecimalSeparator;
4058 End;
4059
4060 ffNumber:
4061
4062 Begin
4063 If Digits = -1 Then Digits := 2
4064 Else If Digits > 15 Then Digits := 15;
4065 Str(Value:0:Digits, Result);
4066 If Result[1] = ' ' Then Delete(Result, 1, 1);
4067 P := Pos('.', Result);
4068 If P <> 0 Then Result[P] := DecimalSeparator;
4069 Dec(P, 3);
4070 While (P > 1) Do
4071 Begin
4072 If Result[P - 1] <> '-' Then Insert(ThousandSeparator, Result, P);
4073 Dec(P, 3);
4074 End;
4075 End;
4076
4077 ffCurrency:
4078
4079 Begin
4080 If Value < 0 Then
4081 Begin
4082 Negative := True;
4083 Value := -Value;
4084 End
4085 Else Negative := False;
4086
4087 If Digits = -1 Then Digits := CurrencyDecimals
4088 Else If Digits > 15 Then Digits := 15;
4089 Str(Value:0:Digits, Result);
4090 If Result[1] = ' ' Then Delete(Result, 1, 1);
4091 P := Pos('.', Result);
4092 If P <> 0 Then Result[P] := DecimalSeparator;
4093 Dec(P, 3);
4094 While (P > 1) Do
4095 Begin
4096 Insert(ThousandSeparator, Result, P);
4097 Dec(P, 3);
4098 End;
4099
4100 If Not Negative Then
4101 Begin
4102 Case CurrencyFormat Of
4103 0: Result := CurrencyString + Result;
4104 1: Result := Result + CurrencyString;
4105 2: Result := CurrencyString + ' ' + Result;
4106 3: Result := Result + ' ' + CurrencyString;
4107 End
4108 End
4109 Else
4110 Begin
4111 Case NegCurrFormat Of
4112 0: Result := '(' + CurrencyString + Result + ')';
4113 1: Result := '-' + CurrencyString + Result;
4114 2: Result := CurrencyString + '-' + Result;
4115 3: Result := CurrencyString + Result + '-';
4116 4: Result := '(' + Result + CurrencyString + ')';
4117 5: Result := '-' + Result + CurrencyString;
4118 6: Result := Result + '-' + CurrencyString;
4119 7: Result := Result + CurrencyString + '-';
4120 8: Result := '-' + Result + ' ' + CurrencyString;
4121 9: Result := '-' + CurrencyString + ' ' + Result;
4122 10: Result := CurrencyString + ' ' + Result + '-';
4123 End;
4124 End;
4125 End;
4126 End;
4127End;
4128
4129Function FloatToText(Buffer: PChar; Value: Extended; format: TFloatFormat; Precision, Digits: Integer): Integer;
4130Var
4131 Tmp: String[40];
4132Begin
4133 Tmp := FloatToStrF(Value, format, Precision, Digits);
4134 Result := Length(Tmp);
4135 Move(Tmp[1], Buffer[0], Result);
4136End;
4137
4138Function StrToFloat(Const S: String): Extended;
4139Var
4140 Error: Integer;
4141 Tmp: String;
4142 P: Integer;
4143Begin
4144 Tmp := S;
4145 P := Pos(DecimalSeparator, Tmp);
4146 If P <> 0 Then Tmp[P] := '.';
4147 Val(Tmp, Result, Error);
4148 If Error <> 0 Then FmtLoadConvertError(SInvalidFloat, [S]);
4149End;
4150
4151Function TextToFloat(Buffer: PChar; Var Value: Extended): Boolean;
4152Var
4153 Error: Integer;
4154 Tmp: String;
4155 P: Integer;
4156Begin
4157 Tmp := StrPas(Buffer);
4158 P := Pos(DecimalSeparator, Tmp);
4159 If P <> 0 Then Tmp[P] := '.';
4160 Val(Tmp, Value, Error);
4161 Result := (Error = 0);
4162End;
4163
4164Function FloatToTextFmt(Buffer: PChar; Value: Extended; format: PChar): Integer;
4165Var
4166 Digits: String[40]; { String Of Digits }
4167 Exponent: String[8]; { Exponent strin }
4168 FmtStart, FmtStop: PChar; { Start And End Of relevant part }
4169 { Of format String }
4170 ExpFmt, ExpSize: Integer; { Type And Length Of }
4171 { exponential format chosen }
4172 Placehold: Array[1..4] Of Integer; { Number Of placeholders In All }
4173 { four Sections }
4174 thousand: Boolean; { thousand separators? }
4175 UnexpectedDigits: Integer; { Number Of unexpected Digits that }
4176 { have To be inserted before the }
4177 { First placeholder. }
4178 DigitExponent: Integer; { Exponent Of First digit In }
4179 { Digits Array. }
4180
4181 { Find end of format section starting at P. False, if empty }
4182
4183 Function GetSectionEnd(Var P: PChar): Boolean;
4184 Var
4185 C: Char;
4186 SQ, DQ: Boolean;
4187 Begin
4188 Result := False;
4189 SQ := False;
4190 DQ := False;
4191 C := P[0];
4192 While (C <> #0) And ((C <> ';') Or SQ Or DQ) Do
4193 Begin
4194 Result := True;
4195 Case C Of
4196 #34: If Not SQ Then DQ := Not DQ;
4197 #39: If Not DQ Then SQ := Not SQ;
4198 End;
4199 Inc(P);
4200 C := P[0];
4201 End;
4202 End;
4203
4204 { Find start and end of format section to apply. If section doesn't exist,
4205 use section 1. If section 2 is used, the sign of value is ignored. }
4206
4207 Procedure GetSectionRange(section: Integer);
4208 Var
4209 Sec: Array[1..3] Of PChar;
4210 SecOk: Array[1..3] Of Boolean;
4211 Begin
4212 Sec[1] := format;
4213 SecOk[1] := GetSectionEnd(Sec[1]);
4214 If section > 1 Then
4215 Begin
4216 Sec[2] := Sec[1];
4217 If Sec[2][0] <> #0 Then Inc(Sec[2]);
4218 SecOk[2] := GetSectionEnd(Sec[2]);
4219 If section > 2 Then
4220 Begin
4221 Sec[3] := Sec[2];
4222 If Sec[3][0] <> #0 Then Inc(Sec[3]);
4223 SecOk[3] := GetSectionEnd(Sec[3]);
4224 End;
4225 End;
4226 If Not SecOk[1] Then FmtStart := Nil
4227 Else
4228 Begin
4229 If Not SecOk[section] Then section := 1
4230 Else If section = 2 Then Value := -Value; { Remove sign }
4231 If section = 1 Then FmtStart := format Else
4232 Begin
4233 FmtStart := Sec[section - 1];
4234 Inc(FmtStart);
4235 End;
4236 FmtStop := Sec[section];
4237 End;
4238 End;
4239
4240 { Find format section ranging from FmtStart to FmtStop. }
4241
4242 Procedure GetFormatOptions;
4243 Var
4244 Fmt: PChar;
4245 SQ, DQ: Boolean;
4246 area: Integer;
4247 Begin
4248 SQ := False;
4249 DQ := False;
4250 Fmt := FmtStart;
4251 ExpFmt := 0;
4252 area := 1;
4253 thousand := False;
4254 Placehold[1] := 0;
4255 Placehold[2] := 0;
4256 Placehold[3] := 0;
4257 Placehold[4] := 0;
4258
4259 While Fmt < FmtStop Do
4260 Begin
4261 Case Fmt[0] Of
4262 #34:
4263 Begin
4264 If Not SQ Then DQ := Not DQ;
4265 Inc(Fmt);
4266 End;
4267
4268 #39:
4269 Begin
4270 If Not DQ Then SQ := Not SQ;
4271 Inc(Fmt);
4272 End;
4273
4274 Else
4275 { This was 'if not SQ or DQ'. Looked wrong... }
4276 If Not SQ Or DQ Then
4277 Begin
4278 Case Fmt[0] Of
4279 '0':
4280 Begin
4281 Case area Of
4282 1:
4283 area := 2;
4284 4:
4285 Begin
4286 area := 3;
4287 Inc(Placehold[3], Placehold[4]);
4288 Placehold[4] := 0;
4289 End;
4290 End;
4291 Inc(Placehold[area]);
4292 Inc(Fmt);
4293 End;
4294
4295 '#':
4296 Begin
4297 If area = 3 Then area := 4;
4298 Inc(Placehold[area]);
4299 Inc(Fmt);
4300 End;
4301
4302 '.':
4303 Begin
4304 If area < 3 Then area := 3;
4305 Inc(Fmt);
4306 End;
4307
4308 ',':
4309 Begin
4310 thousand := True;
4311 Inc(Fmt);
4312 End;
4313
4314 'e', 'E':
4315 If ExpFmt = 0 Then
4316 Begin
4317 If Fmt[0] = 'E' Then ExpFmt := 1 Else ExpFmt := 3;
4318 Inc(Fmt);
4319 If Fmt < FmtStop Then
4320 Begin
4321 Case Fmt[0] Of
4322 '+':
4323 Begin
4324 End;
4325
4326 '-':
4327 Inc(ExpFmt);
4328
4329 Else
4330 ExpFmt := 0;
4331 End;
4332
4333 If ExpFmt <> 0 Then
4334 Begin
4335 Inc(Fmt);
4336 ExpSize := 0;
4337 While (Fmt < FmtStop) And (ExpSize < 4) And (Fmt[0] In ['0'..'9']) Do
4338 Begin
4339 Inc(ExpSize);
4340 Inc(Fmt);
4341 End;
4342 End;
4343 End;
4344 End
4345 Else Inc(Fmt);
4346
4347 Else { Case }
4348 Inc(Fmt);
4349 End; { Case }
4350 End; { Begin }
4351 End; { Case }
4352 End; { While .. Begin }
4353 End;
4354
4355 Procedure FloatToStr;
4356 Var
4357 I, J, Exp, Width, Decimals, DecimalPoint, len: Integer;
4358 Begin
4359 If ExpFmt = 0 Then
4360 Begin
4361 { Fixpoint }
4362 Decimals := Placehold[3] + Placehold[4];
4363 Width := Placehold[1] + Placehold[2] + Decimals;
4364
4365 If Decimals = 0 Then Str(Value: Width: 0, Digits)
4366 Else Str(Value: Width + 1: Decimals, Digits);
4367
4368 len := Length(Digits);
4369
4370 { Find the decimal point }
4371 If Decimals = 0 Then DecimalPoint := len + 1 Else DecimalPoint := len - Decimals;
4372
4373 { If value is very small, and no decimal places
4374 are desired, remove the leading 0. }
4375 If (Abs(Value) < 1) And (Placehold[2] = 0) Then
4376 Begin
4377 If Placehold[1] = 0 Then Delete(Digits, DecimalPoint - 1, 1)
4378 Else Digits[DecimalPoint - 1] := ' ';
4379 End;
4380
4381 { Convert optional zeroes to spaces. }
4382 I := len;
4383 J := DecimalPoint + Placehold[3];
4384 While (I > J) And (Digits[I] = '0') Do
4385 Begin
4386 Digits[I] := ' ';
4387 Dec(I);
4388 End;
4389
4390 { If integer value and no obligatory decimal
4391 places, remove decimal point. }
4392
4393 If (DecimalPoint < len) And (Digits[DecimalPoint + 1] = ' ') Then
4394 Digits[DecimalPoint] := ' ';
4395
4396 { Convert spaces left from obligatory decimal point to zeroes. }
4397
4398 I := DecimalPoint - Placehold[2];
4399 While (I < DecimalPoint) And (Digits[I] = ' ') Do
4400 Begin
4401 Digits[I] := '0';
4402 Inc(I);
4403 End;
4404
4405 Exp := 0;
4406 End
4407 Else
4408 Begin
4409 { Scientific: exactly <Width> Digits With <Precision> Decimals
4410 And adjusted Exponent. }
4411 If Placehold[1] + Placehold[2] = 0 Then Placehold[1] := 1;
4412
4413 Decimals := Placehold[3] + Placehold[4];
4414 Width := Placehold[1] + Placehold[2] + Decimals;
4415
4416 Str(Value: Width + 8, Digits);
4417
4418 //WriteLn('Digits: ', Digits);
4419
4420 { Find and cut out exponent. Always the
4421 last 6 characters in the string.
4422 -> 0000E+0000 }
4423
4424 I := Length(Digits) - 5;
4425
4426 Val(Copy(Digits, I + 1, 5), Exp, J);
4427
4428 //WriteLn('Exp: ', Exp);
4429
4430 Exp := Exp + 1 - (Placehold[1] + Placehold[2]);
4431 Delete(Digits, I, 6);
4432
4433 //WriteLn('Exp: ', Exp);
4434
4435 { Str() always returns at least one digit after the decimal point.
4436 If we don't want it, we have to remove it. }
4437 If (Decimals = 0) And (Placehold[1] + Placehold[2] <= 1) Then
4438 Begin
4439 If Digits[4] >= '5' Then
4440 Begin
4441 Inc(Digits[2]);
4442 If Digits[2] > '9' Then
4443 Begin
4444 Digits[2] := '1';
4445 Inc(Exp);
4446 End;
4447 End;
4448 Delete(Digits, 3, 2);
4449 DecimalPoint := Length(Digits) + 1;
4450 End
4451 Else
4452 Begin
4453 //WriteLn(Digits);
4454
4455 { Move decimal point at the desired position }
4456 Delete(Digits, 3, 1);
4457 DecimalPoint := 2 + Placehold[1] + Placehold[2];
4458 If Decimals <> 0 Then Insert('.', Digits, DecimalPoint);
4459 End;
4460
4461 //WriteLn(Digits);
4462
4463 { Convert optional zeroes to spaces. }
4464 I := Length(Digits);
4465 J := DecimalPoint + Placehold[3];
4466 While (I > J) And (Digits[I] = '0') Do
4467 Begin
4468 Digits[I] := ' ';
4469 Dec(I);
4470 End;
4471
4472 { If integer number and no obligatory decimal paces, remove decimal point }
4473
4474 If (DecimalPoint < Length(Digits)) And (Digits[DecimalPoint + 1] = ' ') Then
4475 Digits[DecimalPoint] := ' ';
4476
4477 If Digits[1] = ' ' Then
4478 Begin
4479 Delete(Digits, 1, 1);
4480 Dec(DecimalPoint);
4481 End;
4482
4483 { Calculate exponent string }
4484 Str(Abs(Exp), Exponent);
4485 While Length(Exponent) < ExpSize Do Insert('0', Exponent, 1);
4486 If Exp >= 0 Then
4487 Begin
4488 If ExpFmt In [1, 3] Then Insert('+', Exponent, 1);
4489 End
4490 Else Insert('-', Exponent, 1);
4491 If ExpFmt < 3 Then Insert('E', Exponent, 1) Else Insert('e', Exponent, 1);
4492 End;
4493
4494 DigitExponent := DecimalPoint - 2;
4495 If Digits[1] = '-' Then Dec(DigitExponent);
4496
4497 UnexpectedDigits := DecimalPoint - 1 - (Placehold[1] + Placehold[2]);
4498 End;
4499
4500 Function PutResult: LongInt;
4501 Var
4502 SQ, DQ: Boolean;
4503 Fmt, Buf: PChar;
4504 Dig, N: Integer;
4505 Begin
4506 SQ := False;
4507 DQ := False;
4508 Fmt := FmtStart;
4509 Buf := Buffer;
4510 Dig := 1;
4511
4512 //WriteLn('Putting result: ');
4513
4514 While Fmt < FmtStop Do
4515 Begin
4516 //Write(Fmt[0]);
4517
4518 Case Fmt[0] Of
4519 #34:
4520 Begin
4521 If Not SQ Then DQ := Not DQ;
4522 Inc(Fmt);
4523 End;
4524
4525 #39:
4526 Begin
4527 If Not DQ Then SQ := Not SQ;
4528 Inc(Fmt);
4529 End;
4530
4531 Else
4532
4533 If Not (SQ Or DQ) Then
4534 Begin
4535 Case Fmt[0] Of
4536 '0', '#', '.':
4537 Begin
4538 If (Dig = 1) And (UnexpectedDigits > 0) Then
4539 Begin
4540 { Everything unexpected is written before the first digit }
4541 For N := 1 To UnexpectedDigits Do
4542 Begin
4543 Buf[0] := Digits[N];
4544 Inc(Buf);
4545 If thousand And (Digits[N] <> '-') Then
4546 Begin
4547 If (DigitExponent Mod 3 = 0) And (DigitExponent > 0) Then
4548 Begin
4549 Buf[0] := ThousandSeparator;
4550 Inc(Buf);
4551 End;
4552 Dec(DigitExponent);
4553 End;
4554 End;
4555 Inc(Dig, UnexpectedDigits);
4556 End;
4557
4558 If Digits[Dig] <> ' ' Then
4559 Begin
4560 If Digits[Dig] = '.' Then Buf[0] := DecimalSeparator
4561 Else Buf[0] := Digits[Dig];
4562 Inc(Buf);
4563 If thousand And (DigitExponent Mod 3 = 0) And (DigitExponent > 0) Then
4564 Begin
4565 Buf[0] := ThousandSeparator;
4566 Inc(Buf);
4567 End;
4568 End;
4569 Inc(Dig);
4570 Dec(DigitExponent);
4571 Inc(Fmt);
4572 End;
4573
4574 'e', 'E':
4575 Begin
4576 If ExpFmt <> 0 Then
4577 Begin
4578 Inc(Fmt);
4579 If Fmt < FmtStop Then
4580 Begin
4581 If Fmt[0] In ['+', '-'] Then
4582 Begin
4583 Inc(Fmt, ExpSize);
4584
4585 //WriteLn('Exponent: ', Exponent);
4586
4587 For N := 1 To Length(Exponent) Do Buf[N - 1] := Exponent[N];
4588 Inc(Buf, Length(Exponent));
4589 ExpFmt := 0;
4590 End;
4591 Inc(Fmt);
4592 End;
4593 End
4594 Else
4595 Begin
4596 { No legal exponential format. Simply write
4597 the 'E' to the reult. }
4598 Buf[0] := Fmt[0];
4599 Inc(Buf);
4600 Inc(Fmt);
4601 End;
4602 End;
4603
4604 Else
4605 { Usual character }
4606 If Fmt[0] <> ',' Then
4607 Begin
4608 Buf[0] := Fmt[0];
4609 Inc(Buf);
4610 End;
4611 Inc(Fmt);
4612 End; { Case }
4613 End
4614
4615 Else { IF }
4616
4617 Begin
4618 { Character inside single or double quotes }
4619 Buf[0] := Fmt[0];
4620 Inc(Buf);
4621 Inc(Fmt);
4622 End;
4623 End; { Case }
4624 End; { While .. Begin }
4625
4626 //WriteLn;
4627
4628 Result := LongInt(Buf) - LongInt(Buffer);
4629 End;
4630
4631Begin
4632 If Value > 0 Then GetSectionRange(1)
4633 Else If Value < 0 Then GetSectionRange(2)
4634 Else GetSectionRange(3);
4635
4636 If FmtStart = Nil Then
4637 Begin
4638 //WriteLn('No format sections available.');
4639 Result := FloatToText(Buffer, Value, ffGeneral, 15, 4);
4640 End
4641 Else
4642 Begin
4643 GetFormatOptions;
4644 //WriteLn('Parsing complete');
4645 If (ExpFmt = 0) And (Abs(Value) >= 1E18) Then Result := FloatToText(Buffer, Value, ffGeneral, 15, 4)
4646 Else
4647 Begin
4648 FloatToStr;
4649 //WriteLn('FloatToStr() complete: "', Digits, '" / ', Exponent);
4650 //WriteLn('Unexpected digits: ', UnexpectedDigits);
4651 //WriteLn('DigitExponent: ', DigitExponent);
4652 Result := PutResult;
4653 //WriteLn('PutResult() complete');
4654 End;
4655 End;
4656End;
4657
4658
4659Function FormatFloat(Const format: String; Value: Extended): String;
4660Var
4661 Temp: cstring[128];
4662Begin
4663 Temp := format;
4664 SetLength(Result, FloatToTextFmt(@Result[1], Value, @Temp));
4665End;
4666
4667
4668Procedure FloatToDecimal(Var Result: TFloatRec; Value: Extended; Precision, Decimals: Integer);
4669Var
4670 Buffer: String[24];
4671 Error, N: Integer;
4672Begin
4673{ If Precision > 15 Then Precision := 15;
4674 If Decimals > 15 Then Decimals := 15; }
4675
4676 Str(Value:23, Buffer);
4677 {WriteLn('Buffer is: ', Buffer);}
4678
4679 Result.Negative := (Buffer[1] = '-');
4680 Val(Copy(Buffer, 19, 5), Result.Exponent, Error);
4681 Inc(Result. Exponent);
4682 {WriteLn('Exponent is: ', Result.Exponent);}
4683
4684 Result.Digits[0] := Buffer[2];
4685 Move(Buffer[4], Result.Digits[1], 14);
4686
4687 If Decimals + Result.Exponent < Precision Then N := Decimals + Result.Exponent
4688 Else N := Precision;
4689
4690 {WriteLn('Cut point is ', N);}
4691
4692 If N > 15 Then N := 15;
4693
4694 {WriteLn('That makes ', N, ' with our precision.');}
4695
4696 {WriteLn;}
4697
4698 If N = 0 Then
4699 Begin
4700 If Result.Digits[0] >= '5' Then
4701 Begin
4702 Result.Digits[0] := '1';
4703 Result.Digits[1] := #0;
4704 Inc(Result.Exponent);
4705 End
4706 Else Result.Digits[0] := #0;
4707 End
4708 Else If N > 0 Then
4709 Begin
4710 If Result.Digits[N] >= '5' Then
4711 Begin
4712 { Round up }
4713 Repeat
4714 Result.Digits[N] := #0;
4715 Dec(N);
4716 Inc(Result.Digits[N]);
4717 Until (N = 0) Or (Result.Digits[N] < ':');
4718 If Result.Digits[0] = ':' Then
4719 Begin
4720 Result.Digits[0] := '1';
4721 Inc(Result.Exponent);
4722 End;
4723 End
4724 Else
4725 Begin
4726 { Cut zeros }
4727 Result.Digits[N] := '0';
4728 While (Result.Digits[N] = '0') And (N > -1) Do
4729 Begin
4730 Result.Digits[N] := #0;
4731 Dec(N);
4732 End;
4733 End;
4734 End
4735 Else Result.Digits[0] := #0;
4736
4737 If Result.Digits[0] = #0 Then
4738 Begin
4739 { Zero has neither Exponent nor signum }
4740 Result.Exponent := 0;
4741 Result.Negative := False;
4742 End;
4743End;
4744
4745{ Time encoding And decoding }
4746
4747Procedure FastDiv(P, Q: LongWord; Var X, Y: LongInt); Assembler;
4748Asm
4749 MOV EAX, P;
4750 Xor EDX, EDX;
4751 Div DWord Ptr Q;
4752 MOV EBX, X;
4753 MOV [EBX], EAX;
4754 MOV EBX, Y;
4755 MOV [EBX], EDX;
4756End;
4757
4758Function _EncodeDate(Var date: TDateTime; Year, Month, Day: LongInt): Boolean;
4759Begin
4760 If (Year <= 9999) And (Month In [1..12]) And (Day In [1..31]) Then
4761 Begin
4762 If Month > 2 Then Dec (Month, 3)
4763 Else
4764 Begin
4765 Inc (Month, 9);
4766 Dec (Year);
4767 End;
4768 date:= (146097 * (Year Div 100)) Shr 2
4769 + (1461 * (Year Mod 100)) Shr 2
4770 + (153 * Month + 2) Div 5 + Day - 306;
4771 Result := True;
4772 End
4773 Else Result := False;
4774End;
4775
4776/*
4777Function _EncodeDate(Var date: TDateTime; Year, Month, Day: LongWord): Boolean;
4778Var
4779 LeapYear: Boolean;
4780Begin
4781 If (Year <= 9999) And (Month In [1..12]) And (Day In [1..31]) Then
4782 Begin
4783 LeapYear := (Year Mod 4 = 0) And Not (Year Mod 100 = 0) Or (Year Mod 400 = 0);
4784 Dec(Year);
4785 date := Year * 365 + Year Div 4 - Year Div 100 + Year Div 400
4786 + 1 + DaysPassed[LeapYear, Month] + Day - 1;
4787 Result := True;
4788 End
4789 Else Result := False;
4790End;
4791*/
4792
4793Function _EncodeTime(Var Time: TDateTime; Hour, Min, Sec, MSec: LongInt): Boolean;
4794Begin
4795 If (Hour < 24) And (Min < 60) And (Sec < 60) And (MSec < 1000) Then
4796 Begin
4797 Time := (((Hour * 60 + Min) * 60 + Sec) * 1000 + MSec) / MSecsPerDay;
4798 Result := True
4799 End
4800 Else Result := False;
4801End;
4802
4803Function EncodeDate(Year, Month, Day: Word): TDateTime;
4804Begin
4805 If Not _EncodeDate(Result, Year, Month, Day) Then
4806 FmtLoadConvertError(SDateEncodeError, [Year, Month, Day]);
4807End;
4808
4809Function EncodeTime(Hour, Min, Sec, MSec: Word): TDateTime;
4810Begin
4811 If Not _EncodeTime(Result, Hour, Min, Sec, MSec) Then
4812 FmtLoadConvertError(STimeEncodeError, [Hour, Min, Sec, MSec]);
4813End;
4814
4815Procedure DecodeDate(date: TDateTime; Var Year, Month, Day: Word);
4816Const
4817 Days400 = 146097;
4818 Days4 = 1461;
4819Var
4820 Y, M, D, Tmp1, Tmp2, Tmp3, Tmp4: LongInt;
4821Begin
4822 Tmp1 := Trunc (date) + 306;
4823 Tmp2 := 4 * Tmp1 - 1;
4824
4825 FastDiv(Tmp2, Days400, Tmp3, Tmp1);
4826
4827 Tmp2 := Tmp1 Shr 2;
4828 Tmp4 := 4 * Tmp2 + 3;
4829
4830 FastDiv(Tmp4, Days4, Tmp1, Tmp2);
4831
4832 Tmp2 := (Tmp2 + 4) Shr 2;
4833
4834 Y := 100 * Tmp3 + Tmp1;
4835 Tmp3 := 5 * Tmp2 - 3;
4836
4837 FastDiv(Tmp3, 153, M, Tmp2);
4838
4839 D := (Tmp2 + 5) Div 5;
4840 If M < 10 Then Inc (M, 3)
4841 Else
4842 Begin
4843 Dec (M, 9);
4844 Inc (Y);
4845 End;
4846
4847 Year := Y;
4848 Month := M;
4849 Day := D;
4850End;
4851
4852/*
4853Procedure DecodeDate(date: TDateTime; Var Year, Month, Day: Word);
4854Const
4855 Days400 = 146097;
4856 Days100 = 36524;
4857 Days4 = 1461;
4858Var
4859 cnt, DayNum: LongInt;
4860 LeapYear: Boolean;
4861Begin
4862 DayNum := Trunc(date);
4863
4864 Year := 1;
4865
4866 While DayNum > Days400 Do
4867 Begin
4868 Inc(Year, 400);
4869 Dec(DayNum, Days400);
4870 End;
4871
4872 cnt := 0;
4873 While (DayNum > Days100) And (cnt < 3) Do
4874 Begin
4875 Inc(Year, 100);
4876 Dec(DayNum, Days100);
4877 Inc(cnt);
4878 End;
4879
4880 While DayNum > Days4 Do
4881 Begin
4882 Inc(Year, 4);
4883 Dec(DayNum, Days4);
4884 End;
4885
4886 cnt := 0;
4887 While (DayNum > 365) And (cnt < 3) Do
4888 Begin
4889 Inc(Year);
4890 Dec(DayNum, 365);
4891 Inc(cnt);
4892 End;
4893
4894 LeapYear := (Year Mod 4 = 0) And Not (Year Mod 100 = 0) Or (Year Mod 400 = 0);
4895
4896 Month := 0;
4897 While DaysPassed[LeapYear, Month + 1] < DayNum Do
4898 Inc(Month);
4899
4900 Day := DayNum - DaysPassed[LeapYear, Month];
4901End;
4902*/
4903
4904Procedure DecodeTime(Time: TDateTime; Var Hour, Min, Sec, MSec: Word);
4905Begin
4906 Time := Frac(Time) * 24;
4907 Hour := Trunc(Time);
4908 Time := Frac(Time) * 60;
4909 Min := Trunc(Time);
4910 Time := Frac(Time) * 60;
4911 Sec := Trunc(Time);
4912 MSec := Trunc(Frac(Time) * 1000);
4913End;
4914
4915Function DayOfWeek(date: TDateTime): Integer;
4916Begin
4917 Result := (1 + Trunc(date)) Mod 7;
4918 If Result = 0 Then Result := 7;
4919End;
4920
4921Function date: TDateTime;
4922{$IFDEF OS2}
4923Var
4924 dt: DateTime;
4925{$ENDIF}
4926{$IFDEF Win95}
4927Var
4928 dt: SYSTEMTIME;
4929{$ENDIF}
4930Begin
4931 {$IFDEF OS2}
4932 DosGetDateTime (dt);
4933 date := EncodeDate(dt.Year, dt.Month, dt.Day);
4934 {$ENDIF}
4935 {$IFDEF Win95}
4936 GetLocalTime(dt);
4937 date := EncodeDate(dt.wYear, dt.wMonth, dt.wDay);
4938 {$ENDIF}
4939End;
4940
4941Function Time: TDateTime;
4942{$IFDEF OS2}
4943Var
4944 dt: DateTime;
4945{$ENDIF}
4946{$IFDEF Win95}
4947Var
4948 dt: SYSTEMTIME;
4949{$ENDIF}
4950Begin
4951 {$IFDEF OS2}
4952 DosGetDateTime (dt);
4953 Time := EncodeTime(dt.Hour, dt.Min, dt.Sec, dt.Hundredths * 10);
4954 {$ENDIF}
4955 {$IFDEF Win95}
4956 GetLocalTime(dt);
4957 Time := EncodeTime(dt.wHour, dt.wMinute, dt.wSecond, dt.wMilliSeconds * 10);
4958 {$ENDIF}
4959End;
4960
4961Function now: TDateTime;
4962{$IFDEF OS2}
4963Var
4964 dt: DateTime;
4965{$ENDIF}
4966{$IFDEF Win95}
4967Var
4968 dt: SYSTEMTIME;
4969{$ENDIF}
4970Begin
4971 {$IFDEF OS2}
4972 DosGetDateTime (dt);
4973 now := EncodeDate(dt.Year, dt.Month, dt.Day) + EncodeTime(dt.Hour, dt.Min, dt.Sec, dt.Hundredths * 10);
4974 {$ENDIF}
4975 {$IFDEF Win95}
4976 GetLocalTime(dt);
4977 now := EncodeDate(dt.wYear, dt.wMonth, dt.wDay) + EncodeTime(dt.wHour, dt.wMinute, dt.wSecond, dt.wMilliSeconds * 10);
4978 {$ENDIF}
4979End;
4980
4981{ --- date/Time To String conversion --- }
4982
4983Procedure DateTimeToString(Var Result: String; Const format: String; DateTime: TDateTime);
4984Var
4985 Year, Month, Day, Hour, Min, Sec, MSec, Hour12: Word;
4986 BeforeNoon: Boolean;
4987
4988 Procedure _DateTimeToString(Var Result: String; Const format: String; recursive: Boolean);
4989 { internal Function To Control recursion In format specifiers. Avoids
4990 stack overflow when format Strings contain Macros For other format
4991 Strings. }
4992
4993 Var
4994 Start, Count, Pos, len, LastHourPos, LastHourSize, Tmp: Integer;
4995 Token: Char;
4996 UseMinutes: Boolean;
4997
4998 Procedure AppendInt(I, Digits: Integer);
4999 Var
5000 S: String[5];
5001 P: Integer;
5002 Begin
5003 Str(I:Digits, S);
5004 P := 1;
5005 While S[P] = ' ' Do
5006 Begin
5007 S[P] := '0';
5008 Inc(P);
5009 End;
5010 AppendStr(Result, S);
5011 End;
5012
5013 Procedure AppendStr(Const S: String);
5014 Begin
5015 Insert(S, Result, Length(Result) + 1);
5016 End;
5017
5018 Function CountChar(C: Char; Max: Integer): Integer;
5019 Var
5020 Result: Integer;
5021 Begin
5022 Result := 1;
5023 While (Pos <= len) And (UpCase(format[Pos]) = C) And (Result < Max) Do
5024 Begin
5025 Inc(Pos);
5026 Inc(Result);
5027 End;
5028 CountChar := Result;
5029 End;
5030
5031 Function IsSubStr(Const S: String): Boolean;
5032 Begin
5033 IsSubStr := (uppercase(Copy(format, Pos, Length(S))) = S);
5034 End;
5035
5036 Procedure GetNextToken(BeforeNoon: Boolean);
5037 Begin
5038 Start := Pos;
5039 Token := UpCase(format[Pos]);
5040 Inc(Pos);
5041 Case Token Of
5042 #34,
5043 #39: Begin
5044 Inc(Start);
5045 While (Pos <= len) And (format[Pos] <> Token) Do Inc(Pos);
5046 Count := Pos - Start;
5047 If Pos < len Then Inc(Pos);
5048 Token := '$';
5049 End;
5050 'D': Count := CountChar('D', 6);
5051 'M': Count := CountChar('M', 4);
5052 'Y': Count := CountChar('Y', 4);
5053 'H',
5054 'N',
5055 'S',
5056 'T': Count := CountChar(Token, 2);
5057 'A': Begin
5058 If IsSubStr('MPM') Then
5059 Begin
5060 Inc(Pos, 3);
5061 Count := 0;
5062 End
5063 Else If IsSubStr('/P') Then
5064 Begin
5065 Inc(Pos, 2);
5066 If Not BeforeNoon Then Inc(Start, 2);
5067 Count := 1;
5068 End
5069 Else If IsSubStr('M/PM') Then
5070 Begin
5071 Inc(Pos, 4);
5072 If Not BeforeNoon Then Inc(Start, 3);
5073 Count := 2;
5074 End
5075 Else
5076 Begin
5077 Token := '$';
5078 Count := 1;
5079 End;
5080 End;
5081 'C',
5082 '/',
5083 ':': Begin
5084 { Nope }
5085 End;
5086 Else Begin
5087 Token := '$';
5088 Count := 1;
5089 While (Pos <= len) And Not (UpCase(format[Pos]) In
5090 [#34, #39, 'A', 'C', 'D', 'H', 'M', 'N', 'S', 'T', 'Y', ':', '/']) Do
5091 Begin
5092 Inc(Pos);
5093 Inc(Count);
5094 End;
5095 End;
5096 End;
5097
5098 If (Token = 'M') And UseMinutes Then Token := 'N';
5099
5100 Case Token Of
5101 'H': UseMinutes := True;
5102 'A', 'C', 'D', 'M', 'N', 'S', 'T', 'Y': UseMinutes := False;
5103 End;
5104 End;
5105
5106 Begin
5107 Pos := 1;
5108 len := Length(format);
5109 LastHourPos := 0;
5110 UseMinutes := False;
5111
5112 If len = 0 Then _DateTimeToString(Result, 'C', True)
5113 Else While (Pos <= len) Do
5114 Begin
5115 GetNextToken(BeforeNoon);
5116 // WriteLn('Token=', Token, ' Start=', Start, ' Count=', Count);
5117 Case Token Of
5118 'C': If recursive Then
5119 Begin
5120 _DateTimeToString(Result, ShortDateFormat, False);
5121 If (Hour + Min + Sec) > 0 Then
5122 Begin
5123 AppendStr(' ');
5124 _DateTimeToString(Result, LongTimeFormat, False);
5125 End;
5126 End
5127 Else AppendStr('C');
5128 'D': Case Count Of
5129 1: AppendInt(Day, 1);
5130 2: AppendInt(Day, 2);
5131 3: AppendStr(ShortDayNames[DayOfWeek(DateTime)]);
5132 4: AppendStr(LongDayNames[DayOfWeek(DateTime)]);
5133 5: If recursive Then _DateTimeToString(Result, ShortDateFormat, False)
5134 Else AppendStr('DDDDD');
5135 6: If recursive Then _DateTimeToString(Result, LongDateFormat, False)
5136 Else AppendStr('DDDDDD');
5137 End;
5138 'M': Case Count Of
5139 1: AppendInt(Month, 1);
5140 2: AppendInt(Month, 2);
5141 3: AppendStr(ShortMonthNames[Month]);
5142 4: AppendStr(LongMonthNames[Month]);
5143 End;
5144 'Y': Case Count Of
5145 1, 2: AppendInt(Year Mod 100, 2);
5146 3, 4: AppendInt(Year, 4);
5147 End;
5148 'H': Begin
5149 LastHourPos := Length(Result) + 1;
5150 LastHourSize := Count;
5151 AppendInt(Hour, Count);
5152 End;
5153 'N': AppendInt(Min, Count);
5154 'S': AppendInt(Sec, Count);
5155 'T': Case Count Of
5156 1: If recursive Then _DateTimeToString(Result, ShortTimeFormat, False)
5157 Else AppendStr('T');
5158 2: If recursive Then _DateTimeToString(Result, LongTimeFormat, False)
5159 Else AppendStr('TT');
5160 End;
5161 'A': Begin
5162 If LastHourPos <> 0 Then
5163 Begin
5164 If (LastHourSize = 1) And (Hour < 10) Then Tmp := 1
5165 Else Tmp := 2;
5166 Delete(Result, LastHourPos, Tmp);
5167 If (LastHourSize = 2) And (Hour12 < 10) Then
5168 Insert('0' + IntToStr(Hour12), Result, LastHourPos)
5169 Else Insert(IntToStr(Hour12), Result, LastHourPos);
5170 LastHourPos := 0;
5171 End;
5172 Case Count Of
5173 0: If BeforeNoon Then AppendStr(TimeAMString)
5174 Else AppendStr(TimePMString);
5175 1: AppendStr(format[Start]);
5176 2: AppendStr(format[Start] + format[Start + 1]);
5177 End
5178 End;
5179 '/': AppendStr(DateSeparator);
5180 ':': AppendStr(TimeSeparator);
5181 '$': AppendStr(Copy(format, Start, Count));
5182 End;
5183 End;
5184 End;
5185
5186Begin
5187 DateTime := DateTime + 5.79e-6; // avoid rounding problems
5188
5189 DecodeDate(DateTime, Year, Month, Day);
5190 DecodeTime(DateTime, Hour, Min, Sec, MSec);
5191
5192 If (Hour = 0) Or (Hour > 12) Then
5193 Begin
5194 If Hour = 0 Then Hour12 := 12
5195 Else Hour12 := Hour - 12;
5196 BeforeNoon := False;
5197 End
5198 Else
5199 Begin
5200 BeforeNoon := True;
5201 Hour12 := Hour;
5202 End;
5203 Result := '';
5204
5205 If Length(format) <> 0 Then _DateTimeToString(Result, format, True)
5206 Else _DateTimeToString(Result, 'C', True)
5207End;
5208
5209Function DateToStr(date: TDateTime): String;
5210Begin
5211 DateTimeToString(Result, ShortDateFormat, date);
5212End;
5213
5214Function TimeToStr(Time: TDateTime): String;
5215Begin
5216 DateTimeToString(Result, LongTimeFormat, Time);
5217End;
5218
5219Function DateTimeToStr(DateTime: TDateTime): String;
5220Begin
5221 DateTimeToString(Result, ShortDateFormat + ' ' + LongTimeFormat, DateTime);
5222End;
5223
5224Function FormatDateTime(Const format: String; DateTime: TDateTime): String;
5225Begin
5226 DateTimeToString(Result, format, DateTime);
5227End;
5228
5229{ --- String To date/Time conversions --- }
5230
5231Procedure IgnoreSpaces(Const S: String; Var Pos: Integer; len: Integer);
5232Begin
5233 While (Pos <= len) And (S[Pos] = ' ') Do Inc(Pos);
5234End;
5235
5236Function GetNumber(Var Num: Integer; Const S: String; Var Pos: Integer; len: Integer): Boolean;
5237Begin
5238 Result := False;
5239 Num := 0;
5240 IgnoreSpaces(S, Pos, len);
5241 While (Pos <= len) And (S[Pos] In ['0'..'9']) Do
5242 Begin
5243 Result := True;
5244 Num := Num * 10 + Ord(S[Pos]) - 48;
5245 Inc(Pos);
5246 End;
5247End;
5248
5249{$HINTS OFF}
5250Function CompareString(Const SubStr, S: String; Var Pos: Integer; len: Integer): Boolean;
5251Begin
5252 If CompareText(SubStr, Copy(S, 1, Length(SubStr))) = 0 Then
5253 Begin
5254 Result := True;
5255 Inc(Pos, Length(SubStr));
5256 End
5257 Else Result := False;
5258End;
5259{$HINTS ON}
5260
5261Function CompareChar(C: Char; S: String; Var Pos: Integer; len: Integer): Boolean;
5262Begin
5263 If (Pos <= len) And (UpCase(C) = UpCase(S[Pos])) Then
5264 Begin
5265 Result := True;
5266 Inc(Pos);
5267 End
5268 Else Result := False;
5269End;
5270
5271Function CutString(Var S: String; separator: Char): String;
5272Var
5273 P: Integer;
5274Begin
5275 P := Pos(separator, S);
5276 If P = 0 Then P := Length(S) + 1;
5277 Result := Copy(S, 1, P - 1);
5278 Delete(S, 1, P);
5279End;
5280
5281Function ParseDate(Var date: TDateTime; Const S: String; Var Pos: Integer; len: Integer): Boolean;
5282Var
5283 Head, Temp: String[15];
5284 N, Year, Month, Day: Integer;
5285 Number: Array[1..3] Of Integer;
5286 order: String[3];
5287
5288 Function GetCurrentYear: Integer;
5289 Var
5290 Y, M, D: Word;
5291 Begin
5292 DecodeDate(now, Y, M, D);
5293 Result := Y;
5294 End;
5295
5296Begin
5297 order := 'XXX';
5298
5299 Result := False;
5300
5301 If Not GetNumber(Number[1], S, Pos, len) Then Exit;
5302 If Not CompareChar(DateSeparator, S, Pos, len) Then Exit;
5303 If Not GetNumber(Number[2], S, Pos, len) Then Exit;
5304 If Not CompareChar(DateSeparator, S, Pos, len) Then Exit;
5305 If Not GetNumber(Number[3], S, Pos, len) Then Number[3] := -1;
5306
5307{ For N := 1 To 3 Do WriteLn(Number[N]); }
5308
5309 Temp := ShortDateFormat;
5310
5311 For N := 1 To 3 Do
5312 Begin
5313 Head := CutString(Temp, '/');
5314 If Length(Head) <> 0 Then order[N] := UpCase(Head[1]);
5315 End;
5316
5317 If order = 'MDY' Then
5318 Begin
5319 Month := Number[1];
5320 Day := Number[2];
5321 Year := Number[3];
5322 End
5323 Else If order = 'DMY' Then
5324 Begin
5325{ WriteLn('DMY'); }
5326 Day := Number[1];
5327 Month := Number[2];
5328 Year := Number[3];
5329 End
5330 Else If order = 'YMD' Then
5331 Begin
5332 If Number[3] = -1 Then
5333 Begin
5334 Year := -1;
5335 Month := Number[1];
5336 Day := Number[2];
5337 End
5338 Else
5339 Begin
5340 Year := Number[1];
5341 Month := Number[2];
5342 Day := Number[3];
5343 End;
5344 End;
5345
5346 If Year = -1 Then Year := GetCurrentYear
5347 Else If Year < 100 Then Inc(Year, 1900);
5348
5349 Result := True;
5350 Result := _EncodeDate(date, Year, Month, Day);
5351End;
5352
5353Function ParseTime(Var Time: TDateTime; Const S: String; Var Pos: Integer; len: Integer): Boolean;
5354Var
5355 Hour, Min, Sec: Integer;
5356Begin
5357 Result := False;
5358
5359 If Not GetNumber(Hour, S, Pos, len) Then Exit;
5360 If Not CompareChar(TimeSeparator, S, Pos, len) Then Exit;
5361 If Not GetNumber(Min, S, Pos, len) Then Exit;
5362 If CompareChar(TimeSeparator, S, Pos, len) And Not GetNumber(Sec, S, Pos, len) Then Exit;
5363
5364 IgnoreSpaces(S, Pos, len);
5365 If CompareChar('A', S, Pos, len) Then
5366 Begin
5367 CompareChar('M', S, Pos, len);
5368 If Hour = 12 Then Hour := 0;
5369 End
5370 Else If CompareChar('P', S, Pos, len) Then
5371 Begin
5372 CompareChar('M', S, Pos, len);
5373 If (Hour >= 1) And (Hour <= 11) Then Inc(Hour, 12);
5374 End;
5375
5376 Result := _EncodeTime(Time, Hour, Min, Sec, 0);
5377End;
5378
5379Function StrToDate(Const S: String): TDateTime;
5380Var
5381 Pos, len: Integer;
5382Begin
5383 Pos := 1;
5384 len := Length(S);
5385 If Not ParseDate(Result, S, Pos, len) Then FmtLoadConvertError(SInvalidDate, [S]);
5386End;
5387
5388Function StrToTime(Const S: String): TDateTime;
5389Var
5390 Pos, len: Integer;
5391Begin
5392 Pos := 1;
5393 len := Length(S);
5394 If Not ParseTime(Result, S, Pos, len) Then FmtLoadConvertError(SInvalidTime, [S]);
5395End;
5396
5397Function StrToDateTime(Const S: String): TDateTime;
5398Var
5399 Time: TDateTime;
5400 Pos, len: Integer;
5401Begin
5402 Pos := 1;
5403 len := Length(S);
5404 If Not ParseDate(Result, S, Pos, len) Then FmtLoadConvertError(SInvalidDateTime, [S]);
5405 If ParseTime(Time, S, Pos, len) Then Result := Result + Time;
5406End;
5407
5408{ --- Initialization File support --- }
5409
5410{$IFDEF GUI}
5411
5412Function GetProfileStr(Const Section, Entry, Default: String): String;
5413Var
5414 CDefault,OutBuf: cstring;
5415Begin
5416 CDefault := Default;
5417 {$IFDEF OS2}
5418 Fillchar(OutBuf, 255, 0); {sometimes the #0 character is not copied (cdp.ini)}
5419 PrfQueryProfileString(HINI_UserProfile, Section, Entry, Default, OutBuf, 255);
5420 Result := OutBuf;
5421 {$ENDIF}
5422 {$IFDEF Win95}
5423 If entry='' Then GetProfileString('USER',section,Default,CDefault,255)
5424 Else GetProfileString('USER',section,entry,CDefault,255);
5425 result:=CDefault;
5426 {$ENDIF}
5427End;
5428
5429{$HINTS OFF}
5430Function GetProfileChar(Const Section, Entry: String; Default: Char): Char;
5431Var
5432 InBuf, OutBuf: cstring[2];
5433Begin
5434 InBuf[0] := Default;
5435 InBuf[1] := #0;
5436 {$IFDEF OS2}
5437 PrfQueryProfileString(HINI_UserProfile,
5438 Section, Entry,
5439 InBuf, OutBuf, 2);
5440 Result := OutBuf[0];
5441 {$ENDIF}
5442 {$IFDEF Win95}
5443 GetProfileString('USER',section,InBuf,OutBuf,255);
5444 Result:= OutBuf[0];
5445 {$ENDIF}
5446End;
5447{$HINTS ON}
5448
5449Function GetProfileInt(Const Section, Entry: string; Default: Integer): Integer;
5450{$IFDEF Win95}
5451Var
5452 S: String;
5453 C: Integer;
5454{$ENDIF}
5455Begin
5456 {$IFDEF OS2}
5457 Result := PrfQueryProfileInt(HINI_UserProfile,Section, Entry,Default);
5458 {$ENDIF}
5459 {$IFDEF Win95}
5460 S:=GetProfileStr(section,entry,'');
5461 Val(S,Result,C);
5462 If C<>0 Then Result:=Default;
5463 {$ENDIF}
5464End;
5465
5466Procedure GetFormatSettings;
5467Const
5468 key = 'PM_National';
5469Var
5470 N: Integer;
5471Begin
5472 TimeAMString := GetProfileStr(key, 's1159', 'am');
5473 TimePMString := GetProfileStr(key, 's2359', 'pm');
5474 CurrencyString := GetProfileStr(key, 'sCurrency', '$');
5475 ThousandSeparator := GetProfileChar(key, 'sThousand', ',');
5476 DecimalSeparator := GetProfileChar(key, 'sDecimal', '.');
5477 DateSeparator := GetProfileChar(key, 'sDate', '/');
5478 TimeSeparator := GetProfileChar(key, 'sTime', ':');
5479 ListSeparator := GetProfileChar(key, 'sList', ';');
5480
5481 DateOrder := GetProfileInt(key, 'iDate', 0);
5482 Case DateOrder Of
5483 0: Begin
5484 ShortDateFormat := 'mm/dd/yyyy';
5485 LongDateFormat := 'dddd, mmmm d. yyyy';
5486 End;
5487 1: Begin
5488 ShortDateFormat := 'dd/mm/yyyy';
5489 LongDateFormat := 'dddd, d. mmmm yyyy';
5490 End;
5491 2: Begin
5492 ShortDateFormat := 'yyyy/mm/dd';
5493 LongDateFormat := 'dddd, yyyy mmmm d.';
5494 End;
5495 End;
5496
5497 CurrencyFormat := GetProfileInt(key, 'iCurrency', 0);
5498
5499 Case CurrencyFormat Of
5500 0: NegCurrFormat := 1;
5501 1: NegCurrFormat := 5;
5502 2: NegCurrFormat := 9;
5503 3: NegCurrFormat := 8;
5504 End;
5505
5506 CurrencyDecimals := GetProfileInt(key, 'iDigits', 2);
5507
5508 Case GetProfileInt(key, 'iLzero', 0) Of
5509 0: Begin
5510 ShortTimeFormat := 'h:mm';
5511 LongTimeFormat := 'h:mm:ss';
5512 End;
5513 1: Begin
5514 ShortTimeFormat := 'hh:mm';
5515 LongTimeFormat := 'hh:mm:ss';
5516 End;
5517 End;
5518
5519 If GetProfileInt(key, 'iTime', 0) = 0 Then
5520 Begin
5521 ShortTimeFormat := ShortTimeFormat + ' ampm';
5522 LongTimeFormat := LongTimeFormat + ' ampm';
5523 TwelveHours := True;
5524 End
5525 Else TwelveHours := False;
5526
5527 For N := 1 To 12 Do
5528 Begin
5529 ShortMonthNames[N] := LoadNLSStr(SShortMonthNames + N - 1);
5530 LongMonthNames[N] := LoadNLSStr(SLongMonthNames + N - 1);
5531 End;
5532
5533 For N := 1 To 7 Do
5534 Begin
5535 ShortDayNames[N] := LoadNLSStr(SShortDayNames + N - 1);
5536 LongDayNames[N] := LoadNLSStr(SLongDayNames + N - 1);
5537 End;
5538End;
5539
5540{$ELSE}
5541
5542Procedure GetFormatSettings; { VIO-only! }
5543Var
5544 cc: COUNTRYCODE;
5545 CI: COUNTRYINFO;
5546 L: LongInt;
5547Begin
5548 cc.country := 0;
5549 cc.codepage := 0;
5550 If DosQueryCtryInfo(SizeOf(CI), cc, CI, L) <> NO_ERROR Then Halt(255);
5551
5552 CurrencyString := CI.szCurrency;
5553 CurrencyFormat := CI.fsCurrencyFmt;
5554
5555 ThousandSeparator := CI.szThousandsSeparator[0];
5556 DecimalSeparator := CI.szDecimal[0];
5557 DateSeparator := CI.szDateSeparator[0];
5558 TimeSeparator := CI.szTimeSeparator[0];
5559 ListSeparator := CI.szDataSeparator[0];
5560 CurrencyDecimals := CI.cDecimalPlace;
5561
5562 Case CurrencyFormat Of
5563 0: NegCurrFormat := 1;
5564 1: NegCurrFormat := 5;
5565 2: NegCurrFormat := 9;
5566 3: NegCurrFormat := 8;
5567 End;
5568
5569 DateOrder := CI.fsDateFmt;
5570 Case DateOrder Of
5571 0: Begin
5572 ShortDateFormat := 'mm/dd/yyyy';
5573 LongDateFormat := 'dddd, mmmm d. yyyy';
5574 End;
5575 1: Begin
5576 ShortDateFormat := 'dd/mm/yyyy';
5577 LongDateFormat := 'dddd, d. mmmm yyyy';
5578 End;
5579 2: Begin
5580 ShortDateFormat := 'yyyy/mm/dd';
5581 LongDateFormat := 'dddd, yyyy mmmm d.';
5582 End;
5583 End;
5584
5585 Case CI.fsTimeFmt Of
5586 0: Begin
5587 ShortTimeFormat := 'hh:mm ampm';
5588 LongTimeFormat := 'hh:mm:ss ampm';
5589 TwelveHours := True;
5590 End;
5591 1: Begin
5592 ShortTimeFormat := 'hh:mm';
5593 LongTimeFormat := 'hh:mm:ss';
5594 TwelveHours := False;
5595 End;
5596 End;
5597
5598 DosQueryCollate(256, cc, CollatingSequence, L);
5599End;
5600
5601{$ENDIF}
5602
5603Function StringOfChars(CH: Char; Count: Integer): String;
5604Begin
5605 SetLength(Result, Count);
5606 FillChar(Result[1], Count, CH);
5607End;
5608
5609{Exception management}
5610Constructor Exception.CreateFmt(Const Msg:String;Const Args:Array Of Const);
5611Begin
5612 Inherited Create(format(Msg,Args));
5613End;
5614
5615Constructor Exception.CreateRes(Ident:Word);
5616Begin
5617 Inherited Create(LoadStr(Ident));
5618End;
5619
5620Constructor Exception.CreateResFmt(Ident:Word;Const Args:Array Of Const);
5621Begin
5622 Inherited Create(format(LoadStr(Ident),Args));
5623End;
5624
5625Constructor Exception.CreateResNLS(Ident:Word);
5626Begin
5627 Inherited Create(LoadNLSStr(Ident));
5628End;
5629
5630Constructor Exception.CreateResNLSFmt(Ident:Word;Const Args:Array Of Const);
5631Begin
5632 Inherited Create(format(LoadNLSStr(Ident),Args));
5633End;
5634
5635Constructor Exception.CreateHelp(Const Msg:String;AHelpContext:LongInt);
5636Begin
5637 Inherited Create(Msg);
5638 HelpContext:=AHelpContext;
5639End;
5640
5641Constructor Exception.CreateFmtHelp(Const Msg:String;Const Args:Array Of Const;AHelpContext:LongInt);
5642Begin
5643 Inherited Create(format(Msg,Args));
5644 HelpContext:=AHelpContext;
5645End;
5646
5647Constructor Exception.CreateResHelp(Ident:Word;AHelpContext:LongInt);
5648Begin
5649 Inherited Create(LoadStr(Ident));
5650 HelpContext:=AHelpContext;
5651End;
5652
5653Constructor Exception.CreateResFmtHelp(Ident:Word;Const Args:Array Of Const;AHelpContext:LongInt);
5654Begin
5655 Inherited Create(format(LoadStr(Ident),Args));
5656 HelpContext:=AHelpContext;
5657End;
5658
5659Constructor Exception.CreateResNLSHelp(Ident:Word;AHelpContext:LongInt);
5660Begin
5661 Inherited Create(LoadNLSStr(Ident));
5662 HelpContext:=AHelpContext;
5663End;
5664
5665Constructor Exception.CreateResNLSFmtHelp(Ident:Word;Const Args:Array Of Const;AHelpContext:LongInt);
5666Begin
5667 Inherited Create(format(LoadNLSStr(Ident),Args));
5668 HelpContext:=AHelpContext;
5669End;
5670
5671Var AH,AQ:LongWord;
5672
5673Begin
5674 {$IFDEF OS2}
5675 InitPM;
5676 {$ENDIF}
5677 SetCurrentLanguageTable('SIBYL_NLS_Default');
5678 GetFormatSettings;
5679End.
5680
5681{ -- date -- -- changes ----------------------------------------------
5682
5683 28-Feb-96 assume fmShareDenyNone, If no sharing Mode Is specified.
5684 added support For File locking.
5685 08-Mar-96 added lots Of comments. added resources And loading Of
5686 Error Messages And Month / Day Names.
5687 FIXED A bug In FormatStr.
5688 14-Apr-96 removed Some forgotten debugging Code.
5689 18-Apr-96 added windows-only AnsiLowerCase And AnsiCompareStr.
5690 FIXED A bug In DayOfWeek.
5691 Faster EncodeDate / DecodeDate.
5692 12-may-96 Error codes returned by File Open FUNCTIONs were always -1.
5693 24-may-96 added Trim, TrimLeft, TrimRight, And QuotedStr FUNCTIONs As
5694 In Delphi 2.0.
5695 11-Jun-96 bug In FloatToStrF, ffGeneral With values < 0.001 always used
5696 FIXED Point.
5697 27-Jul-96 removed SetLength, already declared In System Unit.
5698 27-Aug-96 added SysErrorMessage.
5699 26-Dec-96 FIXED Error In date encoding. changed numerous Parameters In
5700 API calls from LongInt To LongWord where ULONG was expected.
5701 27-Dec-96 added support For AnsiStrings As Open Array Parameters In
5702 String formatting FUNCTIONs.
5703 02-Feb-97 FIXED Some bugs:
5704 - FileWrite returned -1 ON Success instead Of ON failure.
5705 - DateTimeToFileDate didn't work With New Compiler.
5706 changed File access Mode For FileCreate To RD/WR/exclusive.
5707
5708
5709---------------------------
5710Bemerkungen fr J”rg: (nur der Form halber)
5711-
5712Function FileCreate
5713 fmOpenReadWrite Or fmShareExclusive
5714-
5715Function DateTimeToFileDate
5716 Result := (FileDate Shl 16) Or FILETIME;
5717
Note: See TracBrowser for help on using the repository browser.