home *** CD-ROM | disk | FTP | other *** search
-
- {*******************************************************}
- { }
- { Delphi Runtime Library }
- { System Utilities Unit }
- { }
- { Copyright (C) 1995,96 Borland International }
- { }
- {*******************************************************}
-
- unit SysUtils;
-
- {$H+}
-
- interface
-
- uses Windows;
-
- const
-
- { File open modes }
-
- fmOpenRead = $0000;
- fmOpenWrite = $0001;
- fmOpenReadWrite = $0002;
- fmShareCompat = $0000;
- fmShareExclusive = $0010;
- fmShareDenyWrite = $0020;
- fmShareDenyRead = $0030;
- fmShareDenyNone = $0040;
-
- { File attribute constants }
-
- faReadOnly = $00000001;
- faHidden = $00000002;
- faSysFile = $00000004;
- faVolumeID = $00000008;
- faDirectory = $00000010;
- faArchive = $00000020;
- faAnyFile = $0000003F;
-
- { File mode magic numbers }
-
- fmClosed = $D7B0;
- fmInput = $D7B1;
- fmOutput = $D7B2;
- fmInOut = $D7B3;
-
- { Seconds and milliseconds per day }
-
- SecsPerDay = 24 * 60 * 60;
- MSecsPerDay = SecsPerDay * 1000;
-
- { Days between 1/1/0001 and 12/31/1899 }
-
- DateDelta = 693594;
-
- type
-
- { Type conversion records }
-
- WordRec = packed record
- Lo, Hi: Byte;
- end;
-
- LongRec = packed record
- Lo, Hi: Word;
- end;
-
- TMethod = record
- Code, Data: Pointer;
- end;
-
- { General arrays }
-
- PByteArray = ^TByteArray;
- TByteArray = array[0..32767] of Byte;
-
- PWordArray = ^TWordArray;
- TWordArray = array[0..16383] of Word;
-
- { Generic procedure pointer }
-
- TProcedure = procedure;
-
- { Generic filename type }
-
- TFileName = string;
-
- { Search record used by FindFirst, FindNext, and FindClose }
-
- TSearchRec = record
- Time: Integer;
- Size: Integer;
- Attr: Integer;
- Name: TFileName;
- ExcludeAttr: Integer;
- FindHandle: THandle;
- FindData: TWin32FindData;
- end;
-
- { Typed-file and untyped-file record }
-
- TFileRec = record
- Handle: Integer;
- Mode: Integer;
- RecSize: Cardinal;
- Private: array[1..28] of Byte;
- UserData: array[1..32] of Byte;
- Name: array[0..259] of Char;
- end;
-
- { Text file record structure used for Text files }
-
- PTextBuf = ^TTextBuf;
- TTextBuf = array[0..127] of Char;
- TTextRec = record
- Handle: Integer;
- Mode: Integer;
- BufSize: Cardinal;
- BufPos: Cardinal;
- BufEnd: Cardinal;
- BufPtr: PChar;
- OpenFunc: Pointer;
- InOutFunc: Pointer;
- FlushFunc: Pointer;
- CloseFunc: Pointer;
- UserData: array[1..32] of Byte;
- Name: array[0..259] of Char;
- Buffer: TTextBuf;
- end;
-
- { FloatToText, FloatToTextFmt, TextToFloat, and FloatToDecimal type codes }
-
- TFloatValue = (fvExtended, fvCurrency);
-
- { FloatToText format codes }
-
- TFloatFormat = (ffGeneral, ffExponent, ffFixed, ffNumber, ffCurrency);
-
- { FloatToDecimal result record }
-
- TFloatRec = packed record
- Exponent: Smallint;
- Negative: Boolean;
- Digits: array[0..20] of Char;
- end;
-
- { Date and time record }
-
- TTimeStamp = record
- Time: Integer; { Number of milliseconds since midnight }
- Date: Integer; { One plus number of days since 1/1/0001 }
- end;
-
- { Exceptions }
-
- Exception = class(TObject)
- private
- FMessage: string;
- FHelpContext: Integer;
- public
- constructor Create(const Msg: string);
- constructor CreateFmt(const Msg: string; const Args: array of const);
- constructor CreateRes(Ident: Integer);
- constructor CreateResFmt(Ident: Integer; const Args: array of const);
- constructor CreateHelp(const Msg: string; AHelpContext: Integer);
- constructor CreateFmtHelp(const Msg: string; const Args: array of const;
- AHelpContext: Integer);
- constructor CreateResHelp(Ident: Integer; AHelpContext: Integer);
- constructor CreateResFmtHelp(Ident: Integer; const Args: array of const;
- AHelpContext: Integer);
- property HelpContext: Integer read FHelpContext write FHelpContext;
- property Message: string read FMessage write FMessage;
- end;
-
- ExceptClass = class of Exception;
-
- EAbort = class(Exception);
-
- EOutOfMemory = class(Exception)
- public
- destructor Destroy; override;
- procedure FreeInstance; override;
- end;
-
- EInOutError = class(Exception)
- public
- ErrorCode: Integer;
- end;
-
- EIntError = class(Exception);
- EDivByZero = class(EIntError);
- ERangeError = class(EIntError);
- EIntOverflow = class(EIntError);
-
- EMathError = class(Exception);
- EInvalidOp = class(EMathError);
- EZeroDivide = class(EMathError);
- EOverflow = class(EMathError);
- EUnderflow = class(EMathError);
-
- EInvalidPointer = class(Exception);
-
- EInvalidCast = class(Exception);
-
- EConvertError = class(Exception);
-
- EAccessViolation = class(Exception);
- EPrivilege = class(Exception);
- EStackOverflow = class(Exception);
- EControlC = class(Exception);
-
- EVariantError = class(Exception);
-
- EPropReadOnly = class(Exception);
- EPropWriteOnly = class(Exception);
-
- EExternalException = class(Exception)
- public
- ExceptionRecord: PExceptionRecord;
- end;
-
- const
-
- { Empty string and null string pointer. These constants are provided for
- backwards compatibility only. }
-
- EmptyStr: string = '';
- NullStr: PString = @EmptyStr;
-
- { Win32 platform identifier. This will be one of the following values:
-
- VER_PLATFORM_WIN32s
- VER_PLATFORM_WIN32_WINDOWS
- VER_PLATFORM_WIN32_NT
-
- See WINDOWS.PAS for the numerical values. }
-
- Win32Platform: Integer = 0;
-
- { Currency and date/time formatting options
-
- The initial values of these variables are fetched from the system registry
- using the GetLocaleInfo function in the Win32 API. The description of each
- variable specifies the LOCALE_XXXX constant used to fetch the initial
- value.
-
- CurrencyString - Defines the currency symbol used in floating-point to
- decimal conversions. The initial value is fetched from LOCALE_SCURRENCY.
-
- CurrencyFormat - Defines the currency symbol placement and separation
- used in floating-point to decimal conversions. Possible values are:
-
- 0 = '$1'
- 1 = '1$'
- 2 = '$ 1'
- 3 = '1 $'
-
- The initial value is fetched from LOCALE_ICURRENCY.
-
- NegCurrFormat - Defines the currency format for used in floating-point to
- decimal conversions of negative numbers. Possible values are:
-
- 0 = '($1)' 4 = '(1$)' 8 = '-1 $' 12 = '$ -1'
- 1 = '-$1' 5 = '-1$' 9 = '-$ 1' 13 = '1- $'
- 2 = '$-1' 6 = '1-$' 10 = '1 $-' 14 = '($ 1)'
- 3 = '$1-' 7 = '1$-' 11 = '$ 1-' 15 = '(1 $)'
-
- The initial value is fetched from LOCALE_INEGCURR.
-
- ThousandSeparator - The character used to separate thousands in numbers
- with more than three digits to the left of the decimal separator. The
- initial value is fetched from LOCALE_STHOUSAND.
-
- DecimalSeparator - The character used to separate the integer part from
- the fractional part of a number. The initial value is fetched from
- LOCALE_SDECIMAL.
-
- CurrencyDecimals - The number of digits to the right of the decimal point
- in a currency amount. The initial value is fetched from LOCALE_ICURRDIGITS.
-
- DateSeparator - The character used to separate the year, month, and day
- parts of a date value. The initial value is fetched from LOCATE_SDATE.
-
- ShortDateFormat - The format string used to convert a date value to a
- short string suitable for editing. For a complete description of date and
- time format strings, refer to the documentation for the FormatDate
- function. The short date format should only use the date separator
- character and the m, mm, d, dd, yy, and yyyy format specifiers. The
- initial value is fetched from LOCALE_SSHORTDATE.
-
- LongDateFormat - The format string used to convert a date value to a long
- string suitable for display but not for editing. For a complete description
- of date and time format strings, refer to the documentation for the
- FormatDate function. The initial value is fetched from LOCALE_SLONGDATE.
-
- TimeSeparator - The character used to separate the hour, minute, and
- second parts of a time value. The initial value is fetched from
- LOCALE_STIME.
-
- TimeAMString - The suffix string used for time values between 00:00 and
- 11:59 in 12-hour clock format. The initial value is fetched from
- LOCALE_S1159.
-
- TimePMString - The suffix string used for time values between 12:00 and
- 23:59 in 12-hour clock format. The initial value is fetched from
- LOCALE_S2359.
-
- ShortTimeFormat - The format string used to convert a time value to a
- short string with only hours and minutes. The default value is computed
- from LOCALE_ITIME and LOCALE_ITLZERO.
-
- LongTimeFormat - The format string used to convert a time value to a long
- string with hours, minutes, and seconds. The default value is computed
- from LOCALE_ITIME and LOCALE_ITLZERO.
-
- ShortMonthNames - Array of strings containing short month names. The mmm
- format specifier in a format string passed to FormatDate causes a short
- month name to be substituted. The default values are fecthed from the
- LOCALE_SABBREVMONTHNAME system locale entries.
-
- LongMonthNames - Array of strings containing long month names. The mmmm
- format specifier in a format string passed to FormatDate causes a long
- month name to be substituted. The default values are fecthed from the
- LOCALE_SMONTHNAME system locale entries.
-
- ShortDayNames - Array of strings containing short day names. The ddd
- format specifier in a format string passed to FormatDate causes a short
- day name to be substituted. The default values are fecthed from the
- LOCALE_SABBREVDAYNAME system locale entries.
-
- LongDayNames - Array of strings containing long day names. The dddd
- format specifier in a format string passed to FormatDate causes a long
- day name to be substituted. The default values are fecthed from the
- LOCALE_SDAYNAME system locale entries. }
-
- var
- CurrencyString: string;
- CurrencyFormat: Byte;
- NegCurrFormat: Byte;
- ThousandSeparator: Char;
- DecimalSeparator: Char;
- CurrencyDecimals: Byte;
- DateSeparator: Char;
- ShortDateFormat: string;
- LongDateFormat: string;
- TimeSeparator: Char;
- TimeAMString: string;
- TimePMString: string;
- ShortTimeFormat: string;
- LongTimeFormat: string;
- ShortMonthNames: array[1..12] of string;
- LongMonthNames: array[1..12] of string;
- ShortDayNames: array[1..7] of string;
- LongDayNames: array[1..7] of string;
-
- { Memory management routines }
-
- { AllocMem allocates a block of the given size on the heap. Each byte in
- the allocated buffer is set to zero. To dispose the buffer, use the
- FreeMem standard procedure. }
-
- function AllocMem(Size: Cardinal): Pointer;
-
- { Exit procedure handling }
-
- { AddExitProc adds the given procedure to the run-time library's exit
- procedure list. When an application terminates, its exit procedures are
- executed in reverse order of definition, i.e. the last procedure passed
- to AddExitProc is the first one to get executed upon termination. }
-
- procedure AddExitProc(Proc: TProcedure);
-
- { String handling routines }
-
- { NewStr allocates a string on the heap. NewStr is provided for backwards
- compatibility only. }
-
- function NewStr(const S: string): PString;
-
- { DisposeStr disposes a string pointer that was previously allocated using
- NewStr. DisposeStr is provided for backwards compatibility only. }
-
- procedure DisposeStr(P: PString);
-
- { AssignStr assigns a new dynamically allocated string to the given string
- pointer. AssignStr is provided for backwards compatibility only. }
-
- procedure AssignStr(var P: PString; const S: string);
-
- { AppendStr appends S to the end of Dest. AppendStr is provided for
- backwards compatibility only. Use "Dest := Dest + S" instead. }
-
- procedure AppendStr(var Dest: string; const S: string);
-
- { UpperCase converts all ASCII characters in the given string to upper case.
- The conversion affects only 7-bit ASCII characters between 'a' and 'z'. To
- convert 8-bit international characters, use AnsiUpperCase. }
-
- function UpperCase(const S: string): string;
-
- { UpperCase converts all ASCII characters in the given string to lower case.
- The conversion affects only 7-bit ASCII characters between 'A' and 'Z'. To
- convert 8-bit international characters, use AnsiLowerCase. }
-
- function LowerCase(const S: string): string;
-
- { CompareStr compares S1 to S2, with case-sensitivity. The return value is
- less than 0 if S1 < S2, 0 if S1 = S2, or greater than 0 if S1 > S2. The
- compare operation is based on the 8-bit ordinal value of each character
- and is not affected by the current Windows locale. }
-
- function CompareStr(const S1, S2: string): Integer;
-
- { CompareText compares S1 to S2, without case-sensitivity. The return value
- is the same as for CompareStr. The compare operation is based on the 8-bit
- ordinal value of each character, after converting 'a'..'z' to 'A'..'Z',
- and is not affected by the current Windows locale. }
-
- function CompareText(const S1, S2: string): Integer;
-
- { AnsiUpperCase converts all characters in the given string to upper case.
- The conversion uses the current Windows locale. }
-
- function AnsiUpperCase(const S: string): string;
-
- { AnsiLowerCase converts all characters in the given string to lower case.
- The conversion uses the current Windows locale. }
-
- function AnsiLowerCase(const S: string): string;
-
- { AnsiCompareStr compares S1 to S2, with case-sensitivity. The compare
- operation is controlled by the current Windows locale. The return value
- is the same as for CompareStr. }
-
- function AnsiCompareStr(const S1, S2: string): Integer;
-
- { AnsiCompareText compares S1 to S2, without case-sensitivity. The compare
- operation is controlled by the current Windows locale. The return value
- is the same as for CompareStr. }
-
- function AnsiCompareText(const S1, S2: string): Integer;
-
- { Trim trims leading and trailing spaces and control characters from the
- given string. }
-
- function Trim(const S: string): string;
-
- { TrimLeft trims leading spaces and control characters from the given
- string. }
-
- function TrimLeft(const S: string): string;
-
- { TrimRight trims trailing spaces and control characters from the given
- string. }
-
- function TrimRight(const S: string): string;
-
- { QuotedStr returns the given string as a quoted string. A single quote
- character is inserted at the beginning and the end of the string, and
- for each single quote character in the string, another one is added. }
-
- function QuotedStr(const S: string): string;
-
- { AdjustLineBreaks adjusts all line breaks in the given string to be true
- CR/LF sequences. The function changes any CR characters not followed by
- a LF and any LF characters not preceded by a CR into CR/LF pairs. }
-
- function AdjustLineBreaks(const S: string): string;
-
- { IsValidIdent returns true if the given string is a valid identifier. An
- identifier is defined as a character from the set ['A'..'Z', 'a'..'z', '_']
- followed by zero or more characters from the set ['A'..'Z', 'a'..'z',
- '0..'9', '_']. }
-
- function IsValidIdent(const Ident: string): Boolean;
-
- { IntToStr converts the given value to its decimal string representation. }
-
- function IntToStr(Value: Integer): string;
-
- { IntToHex converts the given value to a hexadecimal string representation
- with the minimum number of digits specified. }
-
- function IntToHex(Value: Integer; Digits: Integer): string;
-
- { StrToInt converts the given string to an integer value. If the string
- doesn't contain a valid value, an EConvertError exception is raised. }
-
- function StrToInt(const S: string): Integer;
-
- { StrToIntDef converts the given string to an integer value. If the string
- doesn't contain a valid value, the value given by Default is returned. }
-
- function StrToIntDef(const S: string; Default: Integer): Integer;
-
- { LoadStr loads the string resource given by Ident from the application's
- executable file. If the string resource does not exist, an empty string
- is returned. }
-
- function LoadStr(Ident: Integer): string;
-
- { LoadStr loads the string resource given by Ident from the application's
- executable file, and uses it as the format string in a call to the
- Format function with the given arguments. }
-
- function FmtLoadStr(Ident: Integer; const Args: array of const): string;
-
- { File management routines }
-
- { FileOpen opens the specified file using the specified access mode. The
- access mode value is constructed by OR-ing one of the fmOpenXXXX constants
- with one of the fmShareXXXX constants. If the return value is positive,
- the function was successful and the value is the file handle of the opened
- file. A return value of -1 indicates that an error occurred. }
-
- function FileOpen(const FileName: string; Mode: Integer): Integer;
-
- { FileCreate creates a new file by the specified name. If the return value
- is positive, the function was successful and the value is the file handle
- of the new file. A return value of -1 indicates that an error occurred. }
-
- function FileCreate(const FileName: string): Integer;
-
- { FileRead reads Count bytes from the file given by Handle into the buffer
- specified by Buffer. The return value is the number of bytes actually
- read; it is less than Count if the end of the file was reached. The return
- value is -1 if an error occurred. }
-
- function FileRead(Handle: Integer; var Buffer; Count: Integer): Integer;
-
- { FileWrite writes Count bytes to the file given by Handle from the buffer
- specified by Buffer. The return value is the number of bytes actually
- written, or -1 if an error occurred. }
-
- function FileWrite(Handle: Integer; const Buffer; Count: Integer): Integer;
-
- { FileSeek changes the current position of the file given by Handle to be
- Offset bytes relative to the point given by Origin. Origin = 0 means that
- Offset is relative to the beginning of the file, Origin = 1 means that
- Offset is relative to the current position, and Origin = 2 means that
- Offset is relative to the end of the file. The return value is the new
- current position, relative to the beginning of the file, or -1 if an error
- occurred. }
-
- function FileSeek(Handle, Offset, Origin: Integer): Integer;
-
- { FileClose closes the specified file. }
-
- procedure FileClose(Handle: Integer);
-
- { FileAge returns the date-and-time stamp of the specified file. The return
- value can be converted to a TDateTime value using the FileDateToDateTime
- function. The return value is -1 if the file does not exist. }
-
- function FileAge(const FileName: string): Integer;
-
- { FileExists returns a boolean value that indicates whether the specified
- file exists. }
-
- function FileExists(const FileName: string): Boolean;
-
- { FindFirst searches the directory given by Path for the first entry that
- matches the filename given by Path and the attributes given by Attr. The
- result is returned in the search record given by SearchRec. The return
- value is zero if the function was successful. Otherwise the return value
- is a Windows error code. FindFirst is typically used in conjunction with
- FindNext and FindClose as follows:
-
- Result := FindFirst(Path, Attr, SearchRec);
- while Result = 0 do
- begin
- ProcessSearchRec(SearchRec);
- Result := FindNext(SearchRec);
- end;
- FindClose(SearchRec);
-
- where ProcessSearchRec represents user-defined code that processes the
- information in a search record. }
-
- function FindFirst(const Path: string; Attr: Integer;
- var F: TSearchRec): Integer;
-
- { FindNext returs the next entry that matches the name and attributes
- specified in a previous call to FindFirst. The search record must be one
- that was passed to FindFirst. The return value is zero if the function was
- successful. Otherwise the return value is a Windows error code. }
-
- function FindNext(var F: TSearchRec): Integer;
-
- { FindClose terminates a FindFirst/FindNext sequence. FindClose does nothing
- in the 16-bit version of Windows, but is required in the 32-bit version,
- so for maximum portability every FindFirst/FindNext sequence should end
- with a call to FindClose. }
-
- procedure FindClose(var F: TSearchRec);
-
- { FileGetDate returns the DOS date-and-time stamp of the file given by
- Handle. The return value is -1 if the handle is invalid. The
- FileDateToDateTime function can be used to convert the returned value to
- a TDateTime value. }
-
- function FileGetDate(Handle: Integer): Integer;
-
- { FileSetDate sets the DOS date-and-time stamp of the file given by Handle
- to the value given by Age. The DateTimeToFileDate function can be used to
- convert a TDateTime value to a DOS date-and-time stamp. The return value
- is zero if the function was successful. Otherwise the return value is a
- Windows error code. }
-
- function FileSetDate(Handle: Integer; Age: Integer): Integer;
-
- { FileGetAttr returns the file attributes of the file given by FileName. The
- attributes can be examined by AND-ing with the faXXXX constants defined
- above. A return value of -1 indicates that an error occurred. }
-
- function FileGetAttr(const FileName: string): Integer;
-
- { FileSetAttr sets the file attributes of the file given by FileName to the
- value given by Attr. The attribute value is formed by OR-ing the
- appropriate faXXXX constants. The return value is zero if the function was
- successful. Otherwise the return value is a Windows error code. }
-
- function FileSetAttr(const FileName: string; Attr: Integer): Integer;
-
- { DeleteFile deletes the file given by FileName. The return value is True if
- the file was successfully deleted, or False if an error occurred. }
-
- function DeleteFile(const FileName: string): Boolean;
-
- { RenameFile renames the file given by OldName to the name given by NewName.
- The return value is True if the file was successfully renamed, or False if
- an error occurred. }
-
- function RenameFile(const OldName, NewName: string): Boolean;
-
- { ChangeFileExt changes the extension of a filename. FileName specifies a
- filename with or without an extension, and Extension specifies the new
- extension for the filename. The new extension can be a an empty string or
- a period followed by up to three characters. }
-
- function ChangeFileExt(const FileName, Extension: string): string;
-
- { ExtractFilePath extracts the drive and directory parts of the given
- filename. The resulting string is the rightmost characters of FileName,
- up to and including the colon or backslash that separates the path
- information from the name and extension. The resulting string is empty
- if FileName contains no drive and directory parts. }
-
- function ExtractFilePath(const FileName: string): string;
-
- { ExtractFileDir extracts the drive and directory parts of the given
- filename. The resulting string is a directory name suitable for passing
- to SetCurrentDir, CreateDir, etc. The resulting string is empty if
- FileName contains no drive and directory parts. }
-
- function ExtractFileDir(const FileName: string): string;
-
- { ExtractFileDrive extracts the drive part of the given filename. For
- filenames with drive letters, the resulting string is '<drive>:'.
- For filenames with a UNC path, the resulting string is in the form
- '\\<servername>\<sharename>'. If the given path contains neither
- style of filename, the result is an empty string. }
-
- function ExtractFileDrive(const FileName: string): string;
-
- { ExtractFileName extracts the name and extension parts of the given
- filename. The resulting string is the leftmost characters of FileName,
- starting with the first character after the colon or backslash that
- separates the path information from the name and extension. The resulting
- string is equal to FileName if FileName contains no drive and directory
- parts. }
-
- function ExtractFileName(const FileName: string): string;
-
- { ExtractFileExt extracts the extension part of the given filename. The
- resulting string includes the period character that separates the name
- and extension parts. The resulting string is empty if the given filename
- has no extension. }
-
- function ExtractFileExt(const FileName: string): string;
-
- { ExpandFileName expands the given filename to a fully qualified filename.
- The resulting string consists of a drive letter, a colon, a root relative
- directory path, and a filename. Embedded '.' and '..' directory references
- are removed. }
-
- function ExpandFileName(const FileName: string): string;
-
- { ExpandUNCFileName expands the given filename to a fully qualified filename.
- This function is the same as ExpandFileName except that it will return the
- drive portion of the filename in the format '\\<servername>\<sharename> if
- that drive is actually a network resource instead of a local resource.
- Like ExpandFileName, embedded '.' and '..' directory references are
- removed. }
-
- function ExpandUNCFileName(const FileName: string): string;
-
- { FileSearch searches for the file given by Name in the list of directories
- given by DirList. The directory paths in DirList must be separated by
- semicolons. The search always starts with the current directory of the
- current drive. The returned value is a concatenation of one of the
- directory paths and the filename, or an empty string if the file could not
- be located. }
-
- function FileSearch(const Name, DirList: string): string;
-
- { DiskFree returns the number of free bytes on the specified drive number,
- where 0 = Current, 1 = A, 2 = B, etc. DiskFree returns -1 if the drive
- number is invalid. }
-
- function DiskFree(Drive: Byte): Integer;
-
- { DiskSize returns the size in bytes of the specified drive number, where
- 0 = Current, 1 = A, 2 = B, etc. DiskSize returns -1 if the drive number
- is invalid. }
-
- function DiskSize(Drive: Byte): Integer;
-
- { FileDateToDateTime converts a DOS date-and-time value to a TDateTime
- value. The FileAge, FileGetDate, and FileSetDate routines operate on DOS
- date-and-time values, and the Time field of a TSearchRec used by the
- FindFirst and FindNext functions contains a DOS date-and-time value. }
-
- function FileDateToDateTime(FileDate: Integer): TDateTime;
-
- { DateTimeToFileDate converts a TDateTime value to a DOS date-and-time
- value. The FileAge, FileGetDate, and FileSetDate routines operate on DOS
- date-and-time values, and the Time field of a TSearchRec used by the
- FindFirst and FindNext functions contains a DOS date-and-time value. }
-
- function DateTimeToFileDate(DateTime: TDateTime): Integer;
-
- { GetCurrentDir returns the current directory. }
-
- function GetCurrentDir: string;
-
- { SetCurrentDir sets the current directory. The return value is True if
- the current directory was successfully changed, or False if an error
- occurred. }
-
- function SetCurrentDir(const Dir: string): Boolean;
-
- { CreateDir creates a new directory. The return value is True if a new
- directory was successfully created, or False if an error occurred. }
-
- function CreateDir(const Dir: string): Boolean;
-
- { RemoveDir deletes an existing empty directory. The return value is
- True if the directory was successfully deleted, or False if an error
- occurred. }
-
- function RemoveDir(const Dir: string): Boolean;
-
- { PChar routines }
-
- { StrLen returns the number of characters in Str, not counting the null
- terminator. }
-
- function StrLen(Str: PChar): Cardinal;
-
- { StrEnd returns a pointer to the null character that terminates Str. }
-
- function StrEnd(Str: PChar): PChar;
-
- { StrMove copies exactly Count characters from Source to Dest and returns
- Dest. Source and Dest may overlap. }
-
- function StrMove(Dest, Source: PChar; Count: Cardinal): PChar;
-
- { StrCopy copies Source to Dest and returns Dest. }
-
- function StrCopy(Dest, Source: PChar): PChar;
-
- { StrECopy copies Source to Dest and returns StrEnd(Dest). }
-
- function StrECopy(Dest, Source: PChar): PChar;
-
- { StrLCopy copies at most MaxLen characters from Source to Dest and
- returns Dest. }
-
- function StrLCopy(Dest, Source: PChar; MaxLen: Cardinal): PChar;
-
- { StrPCopy copies the Pascal style string Source into Dest and
- returns Dest. }
-
- function StrPCopy(Dest: PChar; const Source: string): PChar;
-
- { StrPLCopy copies at most MaxLen characters from the Pascal style string
- Source into Dest and returns Dest. }
-
- function StrPLCopy(Dest: PChar; const Source: string;
- MaxLen: Cardinal): PChar;
-
- { StrCat appends a copy of Source to the end of Dest and returns Dest. }
-
- function StrCat(Dest, Source: PChar): PChar;
-
- { StrLCat appends at most MaxLen - StrLen(Dest) characters from Source to
- the end of Dest, and returns Dest. }
-
- function StrLCat(Dest, Source: PChar; MaxLen: Cardinal): PChar;
-
- { StrComp compares Str1 to Str2. The return value is less than 0 if
- Str1 < Str2, 0 if Str1 = Str2, or greater than 0 if Str1 > Str2. }
-
- function StrComp(Str1, Str2: PChar): Integer;
-
- { StrIComp compares Str1 to Str2, without case sensitivity. The return
- value is the same as StrComp. }
-
- function StrIComp(Str1, Str2: PChar): Integer;
-
- { StrLComp compares Str1 to Str2, for a maximum length of MaxLen
- characters. The return value is the same as StrComp. }
-
- function StrLComp(Str1, Str2: PChar; MaxLen: Cardinal): Integer;
-
- { StrLIComp compares Str1 to Str2, for a maximum length of MaxLen
- characters, without case sensitivity. The return value is the same
- as StrComp. }
-
- function StrLIComp(Str1, Str2: PChar; MaxLen: Cardinal): Integer;
-
- { StrScan returns a pointer to the first occurrence of Chr in Str. If Chr
- does not occur in Str, StrScan returns NIL. The null terminator is
- considered to be part of the string. }
-
- function StrScan(Str: PChar; Chr: Char): PChar;
-
- { StrRScan returns a pointer to the last occurrence of Chr in Str. If Chr
- does not occur in Str, StrRScan returns NIL. The null terminator is
- considered to be part of the string. }
-
- function StrRScan(Str: PChar; Chr: Char): PChar;
-
- { StrPos returns a pointer to the first occurrence of Str2 in Str1. If
- Str2 does not occur in Str1, StrPos returns NIL. }
-
- function StrPos(Str1, Str2: PChar): PChar;
-
- { StrUpper converts Str to upper case and returns Str. }
-
- function StrUpper(Str: PChar): PChar;
-
- { StrLower converts Str to lower case and returns Str. }
-
- function StrLower(Str: PChar): PChar;
-
- { StrPas converts Str to a Pascal style string. This function is provided
- for backwards compatibility only. To convert a null terminated string to
- a Pascal style string, use a type cast or an assignment. }
-
- function StrPas(Str: PChar): string;
-
- { StrAlloc allocates a buffer of the given size on the heap. The size of
- the allocated buffer is encoded in a four byte header that immediately
- preceeds the buffer. To dispose the buffer, use StrDispose. }
-
- function StrAlloc(Size: Cardinal): PChar;
-
- { StrBufSize returns the allocated size of the given buffer, not including
- the two byte header. }
-
- function StrBufSize(Str: PChar): Cardinal;
-
- { StrNew allocates a copy of Str on the heap. If Str is NIL, StrNew returns
- NIL and doesn't allocate any heap space. Otherwise, StrNew makes a
- duplicate of Str, obtaining space with a call to the StrAlloc function,
- and returns a pointer to the duplicated string. To dispose the string,
- use StrDispose. }
-
- function StrNew(Str: PChar): PChar;
-
- { StrDispose disposes a string that was previously allocated with StrAlloc
- or StrNew. If Str is NIL, StrDispose does nothing. }
-
- procedure StrDispose(Str: PChar);
-
- { String formatting routines }
-
- { The Format routine formats the argument list given by the Args parameter
- using the format string given by the Format parameter.
-
- Format strings contain two types of objects--plain characters and format
- specifiers. Plain characters are copied verbatim to the resulting string.
- Format specifiers fetch arguments from the argument list and apply
- formatting to them.
-
- Format specifiers have the following form:
-
- "%" [index ":"] ["-"] [width] ["." prec] type
-
- A format specifier begins with a % character. After the % come the
- following, in this order:
-
- - an optional argument index specifier, [index ":"]
- - an optional left-justification indicator, ["-"]
- - an optional width specifier, [width]
- - an optional precision specifier, ["." prec]
- - the conversion type character, type
-
- The following conversion characters are supported:
-
- d Decimal. The argument must be an integer value. The value is converted
- to a string of decimal digits. If the format string contains a precision
- specifier, it indicates that the resulting string must contain at least
- the specified number of digits; if the value has less digits, the
- resulting string is left-padded with zeros.
-
- e Scientific. The argument must be a floating-point value. The value is
- converted to a string of the form "-d.ddd...E+ddd". The resulting
- string starts with a minus sign if the number is negative, and one digit
- always precedes the decimal point. The total number of digits in the
- resulting string (including the one before the decimal point) is given
- by the precision specifer in the format string--a default precision of
- 15 is assumed if no precision specifer is present. The "E" exponent
- character in the resulting string is always followed by a plus or minus
- sign and at least three digits.
-
- f Fixed. The argument must be a floating-point value. The value is
- converted to a string of the form "-ddd.ddd...". The resulting string
- starts with a minus sign if the number is negative. The number of digits
- after the decimal point is given by the precision specifier in the
- format string--a default of 2 decimal digits is assumed if no precision
- specifier is present.
-
- g General. The argument must be a floating-point value. The value is
- converted to the shortest possible decimal string using fixed or
- scientific format. The number of significant digits in the resulting
- string is given by the precision specifier in the format string--a
- default precision of 15 is assumed if no precision specifier is present.
- Trailing zeros are removed from the resulting string, and a decimal
- point appears only if necessary. The resulting string uses fixed point
- format if the number of digits to the left of the decimal point in the
- value is less than or equal to the specified precision, and if the
- value is greater than or equal to 0.00001. Otherwise the resulting
- string uses scientific format.
-
- n Number. The argument must be a floating-point value. The value is
- converted to a string of the form "-d,ddd,ddd.ddd...". The "n" format
- corresponds to the "f" format, except that the resulting string
- contains thousand separators.
-
- m Money. The argument must be a floating-point value. The value is
- converted to a string that represents a currency amount. The conversion
- is controlled by the CurrencyString, CurrencyFormat, NegCurrFormat,
- ThousandSeparator, DecimalSeparator, and CurrencyDecimals global
- variables, all of which are initialized from the Currency Format in
- the International section of the Windows Control Panel. If the format
- string contains a precision specifier, it overrides the value given
- by the CurrencyDecimals global variable.
-
- p Pointer. The argument must be a pointer value. The value is converted
- to a string of the form "XXXX:YYYY" where XXXX and YYYY are the
- segment and offset parts of the pointer expressed as four hexadecimal
- digits.
-
- s String. The argument must be a character, a string, or a PChar value.
- The string or character is inserted in place of the format specifier.
- The precision specifier, if present in the format string, specifies the
- maximum length of the resulting string. If the argument is a string
- that is longer than this maximum, the string is truncated.
-
- x Hexadecimal. The argument must be an integer value. The value is
- converted to a string of hexadecimal digits. If the format string
- contains a precision specifier, it indicates that the resulting string
- must contain at least the specified number of digits; if the value has
- less digits, the resulting string is left-padded with zeros.
-
- Conversion characters may be specified in upper case as well as in lower
- case--both produce the same results.
-
- For all floating-point formats, the actual characters used as decimal and
- thousand separators are obtained from the DecimalSeparator and
- ThousandSeparator global variables.
-
- Index, width, and precision specifiers can be specified directly using
- decimal digit string (for example "%10d"), or indirectly using an asterisk
- charcater (for example "%*.*f"). When using an asterisk, the next argument
- in the argument list (which must be an integer value) becomes the value
- that is actually used. For example "Format('%*.*f', [8, 2, 123.456])" is
- the same as "Format('%8.2f', [123.456])".
-
- A width specifier sets the minimum field width for a conversion. If the
- resulting string is shorter than the minimum field width, it is padded
- with blanks to increase the field width. The default is to right-justify
- the result by adding blanks in front of the value, but if the format
- specifier contains a left-justification indicator (a "-" character
- preceding the width specifier), the result is left-justified by adding
- blanks after the value.
-
- An index specifier sets the current argument list index to the specified
- value. The index of the first argument in the argument list is 0. Using
- index specifiers, it is possible to format the same argument multiple
- times. For example "Format('%d %d %0:d %d', [10, 20])" produces the string
- '10 20 10 20'.
-
- The Format function can be combined with other formatting functions. For
- example
-
- S := Format('Your total was %s on %s', [
- FormatFloat('$#,##0.00;;zero', Total),
- FormatDateTime('mm/dd/yy', Date)]);
-
- which uses the FormatFloat and FormatDateTime functions to customize the
- format beyond what is possible with Format. }
-
- function Format(const Format: string; const Args: array of const): string;
-
- { FmtStr formats the argument list given by Args using the format string
- given by Format into the string variable given by Result. For further
- details, see the description of the Format function. }
-
- procedure FmtStr(var Result: string; const Format: string;
- const Args: array of const);
-
- { StrFmt formats the argument list given by Args using the format string
- given by Format into the buffer given by Buffer. It is up to the caller to
- ensure that Buffer is large enough for the resulting string. The returned
- value is Buffer. For further details, see the description of the Format
- function. }
-
- function StrFmt(Buffer, Format: PChar; const Args: array of const): PChar;
-
- { StrFmt formats the argument list given by Args using the format string
- given by Format into the buffer given by Buffer. The resulting string will
- contain no more than MaxLen characters, not including the null terminator.
- The returned value is Buffer. For further details, see the description of
- the Format function. }
-
- function StrLFmt(Buffer: PChar; MaxLen: Cardinal; Format: PChar;
- const Args: array of const): PChar;
-
- { FormatBuf formats the argument list given by Args using the format string
- given by Format and FmtLen into the buffer given by Buffer and BufLen.
- The Format parameter is a reference to a buffer containing FmtLen
- characters, and the Buffer parameter is a reference to a buffer of BufLen
- characters. The returned value is the number of characters actually stored
- in Buffer. The returned value is always less than or equal to BufLen. For
- further details, see the description of the Format function. }
-
- function FormatBuf(var Buffer; BufLen: Cardinal; const Format;
- FmtLen: Cardinal; const Args: array of const): Cardinal;
-
- { Floating point conversion routines }
-
- { FloatToStr converts the floating-point value given by Value to its string
- representation. The conversion uses general number format with 15
- significant digits. For further details, see the description of the
- FloatToStrF function. }
-
- function FloatToStr(Value: Extended): string;
-
- { CurrToStr converts the currency value given by Value to its string
- representation. The conversion uses general number format. For further
- details, see the description of the CurrToStrF function. }
-
- function CurrToStr(Value: Currency): string;
-
- { FloatToStrF converts the floating-point value given by Value to its string
- representation. The Format parameter controls the format of the resulting
- string. The Precision parameter specifies the precision of the given value.
- It should be 7 or less for values of type Single, 15 or less for values of
- type Double, and 18 or less for values of type Extended. The meaning of the
- Digits parameter depends on the particular format selected.
-
- The possible values of the Format parameter, and the meaning of each, are
- described below.
-
- ffGeneral - General number format. The value is converted to the shortest
- possible decimal string using fixed or scientific format. Trailing zeros
- are removed from the resulting string, and a decimal point appears only
- if necessary. The resulting string uses fixed point format if the number
- of digits to the left of the decimal point in the value is less than or
- equal to the specified precision, and if the value is greater than or
- equal to 0.00001. Otherwise the resulting string uses scientific format,
- and the Digits parameter specifies the minimum number of digits in the
- exponent (between 0 and 4).
-
- ffExponent - Scientific format. The value is converted to a string of the
- form "-d.ddd...E+dddd". The resulting string starts with a minus sign if
- the number is negative, and one digit always precedes the decimal point.
- The total number of digits in the resulting string (including the one
- before the decimal point) is given by the Precision parameter. The "E"
- exponent character in the resulting string is always followed by a plus
- or minus sign and up to four digits. The Digits parameter specifies the
- minimum number of digits in the exponent (between 0 and 4).
-
- ffFixed - Fixed point format. The value is converted to a string of the
- form "-ddd.ddd...". The resulting string starts with a minus sign if the
- number is negative, and at least one digit always precedes the decimal
- point. The number of digits after the decimal point is given by the Digits
- parameter--it must be between 0 and 18. If the number of digits to the
- left of the decimal point is greater than the specified precision, the
- resulting value will use scientific format.
-
- ffNumber - Number format. The value is converted to a string of the form
- "-d,ddd,ddd.ddd...". The ffNumber format corresponds to the ffFixed format,
- except that the resulting string contains thousand separators.
-
- ffCurrency - Currency format. The value is converted to a string that
- represents a currency amount. The conversion is controlled by the
- CurrencyString, CurrencyFormat, NegCurrFormat, ThousandSeparator, and
- DecimalSeparator global variables, all of which are initialized from the
- Currency Format in the International section of the Windows Control Panel.
- The number of digits after the decimal point is given by the Digits
- parameter--it must be between 0 and 18.
-
- For all formats, the actual characters used as decimal and thousand
- separators are obtained from the DecimalSeparator and ThousandSeparator
- global variables.
-
- If the given value is a NAN (not-a-number), the resulting string is 'NAN'.
- If the given value is positive infinity, the resulting string is 'INF'. If
- the given value is negative infinity, the resulting string is '-INF'. }
-
- function FloatToStrF(Value: Extended; Format: TFloatFormat;
- Precision, Digits: Integer): string;
-
- { CurrToStrF converts the currency value given by Value to its string
- representation. A call to CurrToStrF corresponds to a call to
- FloatToStrF with an implied precision of 19 digits. }
-
- function CurrToStrF(Value: Currency; Format: TFloatFormat;
- Digits: Integer): string;
-
- { FloatToText converts the given floating-point value to its decimal
- representation using the specified format, precision, and digits. The
- Value parameter must be a variable of type Extended or Currency, as
- indicated by the ValueType parameter. The resulting string of characters
- is stored in the given buffer, and the returned value is the number of
- characters stored. The resulting string is not null-terminated. For
- further details, see the description of the FloatToStrF function. }
-
- function FloatToText(Buffer: PChar; const Value; ValueType: TFloatValue;
- Format: TFloatFormat; Precision, Digits: Integer): Integer;
-
- { FormatFloat formats the floating-point value given by Value using the
- format string given by Format. The following format specifiers are
- supported in the format string:
-
- 0 Digit placeholder. If the value being formatted has a digit in the
- position where the '0' appears in the format string, then that digit
- is copied to the output string. Otherwise, a '0' is stored in that
- position in the output string.
-
- # Digit placeholder. If the value being formatted has a digit in the
- position where the '#' appears in the format string, then that digit
- is copied to the output string. Otherwise, nothing is stored in that
- position in the output string.
-
- . Decimal point. The first '.' character in the format string
- determines the location of the decimal separator in the formatted
- value; any additional '.' characters are ignored. The actual
- character used as a the decimal separator in the output string is
- determined by the DecimalSeparator global variable. The default value
- of DecimalSeparator is specified in the Number Format of the
- International section in the Windows Control Panel.
-
- , Thousand separator. If the format string contains one or more ','
- characters, the output will have thousand separators inserted between
- each group of three digits to the left of the decimal point. The
- placement and number of ',' characters in the format string does not
- affect the output, except to indicate that thousand separators are
- wanted. The actual character used as a the thousand separator in the
- output is determined by the ThousandSeparator global variable. The
- default value of ThousandSeparator is specified in the Number Format
- of the International section in the Windows Control Panel.
-
- E+ Scientific notation. If any of the strings 'E+', 'E-', 'e+', or 'e-'
- E- are contained in the format string, the number is formatted using
- e+ scientific notation. A group of up to four '0' characters can
- e- immediately follow the 'E+', 'E-', 'e+', or 'e-' to determine the
- minimum number of digits in the exponent. The 'E+' and 'e+' formats
- cause a plus sign to be output for positive exponents and a minus
- sign to be output for negative exponents. The 'E-' and 'e-' formats
- output a sign character only for negative exponents.
-
- 'xx' Characters enclosed in single or double quotes are output as-is, and
- "xx" do not affect formatting.
-
- ; Separates sections for positive, negative, and zero numbers in the
- format string.
-
- The locations of the leftmost '0' before the decimal point in the format
- string and the rightmost '0' after the decimal point in the format string
- determine the range of digits that are always present in the output string.
-
- The number being formatted is always rounded to as many decimal places as
- there are digit placeholders ('0' or '#') to the right of the decimal
- point. If the format string contains no decimal point, the value being
- formatted is rounded to the nearest whole number.
-
- If the number being formatted has more digits to the left of the decimal
- separator than there are digit placeholders to the left of the '.'
- character in the format string, the extra digits are output before the
- first digit placeholder.
-
- To allow different formats for positive, negative, and zero values, the
- format string can contain between one and three sections separated by
- semicolons.
-
- One section - The format string applies to all values.
-
- Two sections - The first section applies to positive values and zeros, and
- the second section applies to negative values.
-
- Three sections - The first section applies to positive values, the second
- applies to negative values, and the third applies to zeros.
-
- If the section for negative values or the section for zero values is empty,
- that is if there is nothing between the semicolons that delimit the
- section, the section for positive values is used instead.
-
- If the section for positive values is empty, or if the entire format string
- is empty, the value is formatted using general floating-point formatting
- with 15 significant digits, corresponding to a call to FloatToStrF with
- the ffGeneral format. General floating-point formatting is also used if
- the value has more than 18 digits to the left of the decimal point and
- the format string does not specify scientific notation.
-
- The table below shows some sample formats and the results produced when
- the formats are applied to different values:
-
- Format string 1234 -1234 0.5 0
- -----------------------------------------------------------------------
- 1234 -1234 0.5 0
- 0 1234 -1234 1 0
- 0.00 1234.00 -1234.00 0.50 0.00
- #.## 1234 -1234 .5
- #,##0.00 1,234.00 -1,234.00 0.50 0.00
- #,##0.00;(#,##0.00) 1,234.00 (1,234.00) 0.50 0.00
- #,##0.00;;Zero 1,234.00 -1,234.00 0.50 Zero
- 0.000E+00 1.234E+03 -1.234E+03 5.000E-01 0.000E+00
- #.###E-0 1.234E3 -1.234E3 5E-1 0E0
- ----------------------------------------------------------------------- }
-
- function FormatFloat(const Format: string; Value: Extended): string;
-
- { FormatCurr formats the currency value given by Value using the format
- string given by Format. For further details, see the description of the
- FormatFloat function. }
-
- function FormatCurr(const Format: string; Value: Currency): string;
-
- { FloatToTextFmt converts the given floating-point value to its decimal
- representation using the specified format. The Value parameter must be a
- variable of type Extended or Currency, as indicated by the ValueType
- parameter. The resulting string of characters is stored in the given
- buffer, and the returned value is the number of characters stored. The
- resulting string is not null-terminated. For further details, see the
- description of the FormatFloat function. }
-
- function FloatToTextFmt(Buffer: PChar; const Value; ValueType: TFloatValue;
- Format: PChar): Integer;
-
- { StrToFloat converts the given string to a floating-point value. The string
- must consist of an optional sign (+ or -), a string of digits with an
- optional decimal point, and an optional 'E' or 'e' followed by a signed
- integer. Leading and trailing blanks in the string are ignored. The
- DecimalSeparator global variable defines the character that must be used
- as a decimal point. Thousand separators and currency symbols are not
- allowed in the string. If the string doesn't contain a valid value, an
- EConvertError exception is raised. }
-
- function StrToFloat(const S: string): Extended;
-
- { StrToCurr converts the given string to a currency value. For further
- details, see the description of the StrToFloat function. }
-
- function StrToCurr(const S: string): Currency;
-
- { TextToFloat converts the null-terminated string given by Buffer to a
- floating-point value which is returned in the variable given by Value.
- The Value parameter must be a variable of type Extended or Currency, as
- indicated by the ValueType parameter. The return value is True if the
- conversion was successful, or False if the string is not a valid
- floating-point value. For further details, see the description of the
- StrToFloat function. }
-
- function TextToFloat(Buffer: PChar; var Value;
- ValueType: TFloatValue): Boolean;
-
- { FloatToDecimal converts a floating-point value to a decimal representation
- that is suited for further formatting. The Value parameter must be a
- variable of type Extended or Currency, as indicated by the ValueType
- parameter. For values of type Extended, the Precision parameter specifies
- the requested number of significant digits in the result--the allowed range
- is 1..18. For values of type Currency, the Precision parameter is ignored,
- and the implied precision of the conversion is 19 digits. The Decimals
- parameter specifies the requested maximum number of digits to the left of
- the decimal point in the result. Precision and Decimals together control
- how the result is rounded. To produce a result that always has a given
- number of significant digits regardless of the magnitude of the number,
- specify 9999 for the Decimals parameter. The result of the conversion is
- stored in the specified TFloatRec record as follows:
-
- Exponent - Contains the magnitude of the number, i.e. the number of
- significant digits to the right of the decimal point. The Exponent field
- is negative if the absolute value of the number is less than one. If the
- number is a NAN (not-a-number), Exponent is set to -32768. If the number
- is INF or -INF (positive or negative infinity), Exponent is set to 32767.
-
- Negative - True if the number is negative, False if the number is zero
- or positive.
-
- Digits - Contains up to 18 (for type Extended) or 19 (for type Currency)
- significant digits followed by a null terminator. The implied decimal
- point (if any) is not stored in Digits. Trailing zeros are removed, and
- if the resulting number is zero, NAN, or INF, Digits contains nothing but
- the null terminator. }
-
- procedure FloatToDecimal(var Result: TFloatRec; const Value;
- ValueType: TFloatValue; Precision, Decimals: Integer);
-
- { Date/time support routines }
-
- function DateTimeToTimeStamp(DateTime: TDateTime): TTimeStamp;
-
- function TimeStampToDateTime(const TimeStamp: TTimeStamp): TDateTime;
- function MSecsToTimeStamp(MSecs: Comp): TTimeStamp;
- function TimeStampToMSecs(const TimeStamp: TTimeStamp): Comp;
-
- { EncodeDate encodes the given year, month, and day into a TDateTime value.
- The year must be between 1 and 9999, the month must be between 1 and 12,
- and the day must be between 1 and N, where N is the number of days in the
- specified month. If the specified values are not within range, an
- EConvertError exception is raised. The resulting value is the number of
- days between 12/30/1899 and the given date. }
-
- function EncodeDate(Year, Month, Day: Word): TDateTime;
-
- { EncodeTime encodes the given hour, minute, second, and millisecond into a
- TDateTime value. The hour must be between 0 and 23, the minute must be
- between 0 and 59, the second must be between 0 and 59, and the millisecond
- must be between 0 and 999. If the specified values are not within range, an
- EConvertError exception is raised. The resulting value is a number between
- 0 (inclusive) and 1 (not inclusive) that indicates the fractional part of
- a day given by the specified time. The value 0 corresponds to midnight,
- 0.5 corresponds to noon, 0.75 corresponds to 6:00 pm, etc. }
-
- function EncodeTime(Hour, Min, Sec, MSec: Word): TDateTime;
-
- { DecodeDate decodes the integral (date) part of the given TDateTime value
- into its corresponding year, month, and day. If the given TDateTime value
- is less than or equal to zero, the year, month, and day return parameters
- are all set to zero. }
-
- procedure DecodeDate(Date: TDateTime; var Year, Month, Day: Word);
-
- { DecodeTime decodes the fractional (time) part of the given TDateTime value
- into its corresponding hour, minute, second, and millisecond. }
-
- procedure DecodeTime(Time: TDateTime; var Hour, Min, Sec, MSec: Word);
-
- { DayOfWeek returns the day of the week of the given date. The result is an
- integer between 1 and 7, corresponding to Sunday through Saturday. }
-
- function DayOfWeek(Date: TDateTime): Integer;
-
- { Date returns the current date. }
-
- function Date: TDateTime;
-
- { Time returns the current time. }
-
- function Time: TDateTime;
-
- { Now returns the current date and time, corresponding to Date + Time. }
-
- function Now: TDateTime;
-
- { DateToStr converts the date part of the given TDateTime value to a string.
- The conversion uses the format specified by the ShortDateFormat global
- variable. }
-
- function DateToStr(Date: TDateTime): string;
-
- { TimeToStr converts the time part of the given TDateTime value to a string.
- The conversion uses the format specified by the LongTimeFormat global
- variable. }
-
- function TimeToStr(Time: TDateTime): string;
-
- { DateTimeToStr converts the given date and time to a string. The resulting
- string consists of a date and time formatted using the ShortDateFormat and
- LongTimeFormat global variables. Time information is included in the
- resulting string only if the fractional part of the given date and time
- value is non-zero. }
-
- function DateTimeToStr(DateTime: TDateTime): string;
-
- { StrToDate converts the given string to a date value. The string must
- consist of two or three numbers, separated by the character defined by
- the DateSeparator global variable. The order for month, day, and year is
- determined by the ShortDateFormat global variable--possible combinations
- are m/d/y, d/m/y, and y/m/d. If the string contains only two numbers, it
- is interpreted as a date (m/d or d/m) in the current year. Year values
- between 0 and 99 are assumed to be in the current century. If the given
- string does not contain a valid date, an EConvertError exception is
- raised. }
-
- function StrToDate(const S: string): TDateTime;
-
- { StrToTime converts the given string to a time value. The string must
- consist of two or three numbers, separated by the character defined by
- the TimeSeparator global variable, optionally followed by an AM or PM
- indicator. The numbers represent hour, minute, and (optionally) second,
- in that order. If the time is followed by AM or PM, it is assumed to be
- in 12-hour clock format. If no AM or PM indicator is included, the time
- is assumed to be in 24-hour clock format. If the given string does not
- contain a valid time, an EConvertError exception is raised. }
-
- function StrToTime(const S: string): TDateTime;
-
- { StrToDateTime converts the given string to a date and time value. The
- string must contain a date optionally followed by a time. The date and
- time parts of the string must follow the formats described for the
- StrToDate and StrToTime functions. }
-
- function StrToDateTime(const S: string): TDateTime;
-
- { FormatDateTime formats the date-and-time value given by DateTime using the
- format given by Format. The following format specifiers are supported:
-
- c Displays the date using the format given by the ShortDateFormat
- global variable, followed by the time using the format given by
- the LongTimeFormat global variable. The time is not displayed if
- the fractional part of the DateTime value is zero.
-
- d Displays the day as a number without a leading zero (1-31).
-
- dd Displays the day as a number with a leading zero (01-31).
-
- ddd Displays the day as an abbreviation (Sun-Sat) using the strings
- given by the ShortDayNames global variable.
-
- dddd Displays the day as a full name (Sunday-Saturday) using the strings
- given by the LongDayNames global variable.
-
- ddddd Displays the date using the format given by the ShortDateFormat
- global variable.
-
- dddddd Displays the date using the format given by the LongDateFormat
- global variable.
-
- m Displays the month as a number without a leading zero (1-12). If
- the m specifier immediately follows an h or hh specifier, the
- minute rather than the month is displayed.
-
- mm Displays the month as a number with a leading zero (01-12). If
- the mm specifier immediately follows an h or hh specifier, the
- minute rather than the month is displayed.
-
- mmm Displays the month as an abbreviation (Jan-Dec) using the strings
- given by the ShortMonthNames global variable.
-
- mmmm Displays the month as a full name (January-December) using the
- strings given by the LongMonthNames global variable.
-
- yy Displays the year as a two-digit number (00-99).
-
- yyyy Displays the year as a four-digit number (0000-9999).
-
- h Displays the hour without a leading zero (0-23).
-
- hh Displays the hour with a leading zero (00-23).
-
- n Displays the minute without a leading zero (0-59).
-
- nn Displays the minute with a leading zero (00-59).
-
- s Displays the second without a leading zero (0-59).
-
- ss Displays the second with a leading zero (00-59).
-
- t Displays the time using the format given by the ShortTimeFormat
- global variable.
-
- tt Displays the time using the format given by the LongTimeFormat
- global variable.
-
- am/pm Uses the 12-hour clock for the preceding h or hh specifier, and
- displays 'am' for any hour before noon, and 'pm' for any hour
- after noon. The am/pm specifier can use lower, upper, or mixed
- case, and the result is displayed accordingly.
-
- a/p Uses the 12-hour clock for the preceding h or hh specifier, and
- displays 'a' for any hour before noon, and 'p' for any hour after
- noon. The a/p specifier can use lower, upper, or mixed case, and
- the result is displayed accordingly.
-
- ampm Uses the 12-hour clock for the preceding h or hh specifier, and
- displays the contents of the TimeAMString global variable for any
- hour before noon, and the contents of the TimePMString global
- variable for any hour after noon.
-
- / Displays the date separator character given by the DateSeparator
- global variable.
-
- : Displays the time separator character given by the TimeSeparator
- global variable.
-
- 'xx' Characters enclosed in single or double quotes are displayed as-is,
- "xx" and do not affect formatting.
-
- Format specifiers may be written in upper case as well as in lower case
- letters--both produce the same result.
-
- If the string given by the Format parameter is empty, the date and time
- value is formatted as if a 'c' format specifier had been given.
-
- The following example:
-
- S := FormatDateTime('"The meeting is on" dddd, mmmm d, yyyy, ' +
- '"at" hh:mm AM/PM', StrToDateTime('2/15/95 10:30am'));
-
- assigns 'The meeting is on Wednesday, February 15, 1995 at 10:30 AM' to
- the string variable S. }
-
- function FormatDateTime(const Format: string; DateTime: TDateTime): string;
-
- { DateTimeToString converts the date and time value given by DateTime using
- the format string given by Format into the string variable given by Result.
- For further details, see the description of the FormatDateTime function. }
-
- procedure DateTimeToString(var Result: string; const Format: string;
- DateTime: TDateTime);
-
- { System error messages }
-
- function SysErrorMessage(ErrorCode: Integer): string;
-
- { Initialization file support }
-
- function GetLocaleStr(Locale, LocaleType: Integer; const Default: string): string;
- function GetLocaleChar(Locale, LocaleType: Integer; Default: Char): Char;
-
- { GetFormatSettings resets all date and number format variables to their
- default values. }
-
- procedure GetFormatSettings;
-
- { Exception handling routines }
-
- function ExceptObject: TObject;
- function ExceptAddr: Pointer;
-
- procedure ShowException(ExceptObject: TObject; ExceptAddr: Pointer);
-
- procedure Abort;
-
- procedure OutOfMemoryError;
-
- procedure Beep;
-
- implementation
-
- {$R SYSUTILS.RES}
-
- {$I SYSUTILS.INC}
-
- { Utility routines }
-
- procedure DivMod(Dividend: Integer; Divisor: Word;
- var Result, Remainder: Word);
- asm
- PUSH EBX
- MOV EBX,EDX
- MOV EDX,EAX
- SHR EDX,16
- DIV BX
- MOV EBX,Remainder
- MOV [ECX],AX
- MOV [EBX],DX
- POP EBX
- end;
-
- procedure ConvertError(Ident: Integer);
- begin
- raise EConvertError.CreateRes(Ident);
- end;
-
- procedure ConvertErrorFmt(Ident: Integer; const Args: array of const);
- begin
- raise EConvertError.CreateResFmt(Ident, Args);
- end;
-
- { Memory management routines }
-
- function AllocMem(Size: Cardinal): Pointer;
- begin
- GetMem(Result, Size);
- FillChar(Result^, Size, 0);
- end;
-
- { Exit procedure handling }
-
- type
- PExitProcInfo = ^TExitProcInfo;
- TExitProcInfo = record
- Next: PExitProcInfo;
- SaveExit: Pointer;
- Proc: TProcedure;
- end;
-
- const
- ExitProcList: PExitProcInfo = nil;
-
- procedure DoExitProc; far;
- var
- P: PExitProcInfo;
- Proc: TProcedure;
- begin
- P := ExitProcList;
- ExitProcList := P^.Next;
- ExitProc := P^.SaveExit;
- Proc := P^.Proc;
- Dispose(P);
- Proc;
- end;
-
- procedure AddExitProc(Proc: TProcedure);
- var
- P: PExitProcInfo;
- begin
- New(P);
- P^.Next := ExitProcList;
- P^.SaveExit := ExitProc;
- P^.Proc := Proc;
- ExitProcList := P;
- ExitProc := @DoExitProc;
- end;
-
- { String handling routines }
-
- function NewStr(const S: string): PString;
- begin
- if S = '' then Result := NullStr else
- begin
- New(Result);
- Result^ := S;
- end;
- end;
-
- procedure DisposeStr(P: PString);
- begin
- if (P <> nil) and (P^ <> '') then Dispose(P);
- end;
-
- procedure AssignStr(var P: PString; const S: string);
- var
- Temp: PString;
- begin
- Temp := P;
- P := NewStr(S);
- DisposeStr(Temp);
- end;
-
- procedure AppendStr(var Dest: string; const S: string);
- begin
- Dest := Dest + S;
- end;
-
- function UpperCase(const S: string): string;
- var
- Ch: Char;
- L: Integer;
- Source, Dest: PChar;
- begin
- L := Length(S);
- SetLength(Result, L);
- Source := Pointer(S);
- Dest := Pointer(Result);
- while L <> 0 do
- begin
- Ch := Source^;
- if (Ch >= 'a') and (Ch <= 'z') then Dec(Ch, 32);
- Dest^ := Ch;
- Inc(Source);
- Inc(Dest);
- Dec(L);
- end;
- end;
-
- function LowerCase(const S: string): string;
- var
- Ch: Char;
- L: Integer;
- Source, Dest: PChar;
- begin
- L := Length(S);
- SetLength(Result, L);
- Source := Pointer(S);
- Dest := Pointer(Result);
- while L <> 0 do
- begin
- Ch := Source^;
- if (Ch >= 'A') and (Ch <= 'Z') then Inc(Ch, 32);
- Dest^ := Ch;
- Inc(Source);
- Inc(Dest);
- Dec(L);
- end;
- end;
-
- function CompareStr(const S1, S2: string): Integer; assembler;
- asm
- PUSH ESI
- PUSH EDI
- MOV ESI,EAX
- MOV EDI,EDX
- OR EAX,EAX
- JE @@1
- MOV EAX,[EAX-4]
- @@1: OR EDX,EDX
- JE @@2
- MOV EDX,[EDX-4]
- @@2: MOV ECX,EAX
- CMP ECX,EDX
- JBE @@3
- MOV ECX,EDX
- @@3: CMP ECX,ECX
- REPE CMPSB
- JE @@4
- MOVZX EAX,BYTE PTR [ESI-1]
- MOVZX EDX,BYTE PTR [EDI-1]
- @@4: SUB EAX,EDX
- POP EDI
- POP ESI
- end;
-
- function CompareText(const S1, S2: string): Integer; assembler;
- asm
- PUSH ESI
- PUSH EDI
- PUSH EBX
- MOV ESI,EAX
- MOV EDI,EDX
- OR EAX,EAX
- JE @@0
- MOV EAX,[EAX-4]
- @@0: OR EDX,EDX
- JE @@1
- MOV EDX,[EDX-4]
- @@1: MOV ECX,EAX
- CMP ECX,EDX
- JBE @@2
- MOV ECX,EDX
- @@2: CMP ECX,ECX
- @@3: REPE CMPSB
- JE @@6
- MOV BL,BYTE PTR [ESI-1]
- CMP BL,'a'
- JB @@4
- CMP BL,'z'
- JA @@4
- SUB BL,20H
- @@4: MOV BH,BYTE PTR [EDI-1]
- CMP BH,'a'
- JB @@5
- CMP BH,'z'
- JA @@5
- SUB BH,20H
- @@5: CMP BL,BH
- JE @@3
- MOVZX EAX,BL
- MOVZX EDX,BH
- @@6: SUB EAX,EDX
- POP EBX
- POP EDI
- POP ESI
- end;
-
- function AnsiUpperCase(const S: string): string;
- var
- Len: Integer;
- begin
- Len := Length(S);
- SetString(Result, PChar(S), Len);
- CharUpperBuff(Pointer(Result), Len);
- end;
-
- function AnsiLowerCase(const S: string): string;
- var
- Len: Integer;
- begin
- Len := Length(S);
- SetString(Result, PChar(S), Len);
- CharLowerBuff(Pointer(Result), Len);
- end;
-
- function AnsiCompareStr(const S1, S2: string): Integer;
- begin
- Result := CompareString(LOCALE_USER_DEFAULT, 0, PChar(S1), Length(S1),
- PChar(S2), Length(S2)) - 2;
- end;
-
- function AnsiCompareText(const S1, S2: string): Integer;
- begin
- Result := CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE,
- PChar(S1), Length(S1), PChar(S2), Length(S2)) - 2;
- end;
-
- function Trim(const S: string): string;
- var
- I, L: Integer;
- begin
- L := Length(S);
- I := 1;
- while (I <= L) and (S[I] <= ' ') do Inc(I);
- if I > L then Result := '' else
- begin
- while S[L] <= ' ' do Dec(L);
- Result := Copy(S, I, L - I + 1);
- end;
- end;
-
- function TrimLeft(const S: string): string;
- var
- I, L: Integer;
- begin
- L := Length(S);
- I := 1;
- while (I <= L) and (S[I] <= ' ') do Inc(I);
- Result := Copy(S, I, Maxint);
- end;
-
- function TrimRight(const S: string): string;
- var
- I: Integer;
- begin
- I := Length(S);
- while (I > 0) and (S[I] <= ' ') do Dec(I);
- Result := Copy(S, 1, I);
- end;
-
- function QuotedStr(const S: string): string;
- var
- I: Integer;
- begin
- Result := S;
- for I := Length(Result) downto 1 do
- if Result[I] = '''' then Insert('''', Result, I);
- Result := '''' + Result + '''';
- end;
-
- function AdjustLineBreaks(const S: string): string;
- var
- Source, SourceEnd, Dest: PChar;
- Extra: Integer;
- begin
- Source := Pointer(S);
- SourceEnd := Source + Length(S);
- Extra := 0;
- while Source < SourceEnd do
- begin
- case Source^ of
- #10:
- Inc(Extra);
- #13:
- if Source[1] = #10 then Inc(Source) else Inc(Extra);
- end;
- Inc(Source);
- end;
- if Extra = 0 then Result := S else
- begin
- Source := Pointer(S);
- SetString(Result, nil, SourceEnd - Source + Extra);
- Dest := Pointer(Result);
- while Source < SourceEnd do
- case Source^ of
- #10:
- begin
- Dest^ := #13;
- Inc(Dest);
- Dest^ := #10;
- Inc(Dest);
- Inc(Source);
- end;
- #13:
- begin
- Dest^ := #13;
- Inc(Dest);
- Dest^ := #10;
- Inc(Dest);
- Inc(Source);
- if Source^ = #10 then Inc(Source);
- end;
- else
- Dest^ := Source^;
- Inc(Dest);
- Inc(Source);
- end;
- end;
- end;
-
- function IsValidIdent(const Ident: string): Boolean;
- const
- Alpha = ['A'..'Z', 'a'..'z', '_'];
- AlphaNumeric = Alpha + ['0'..'9'];
- var
- I: Integer;
- begin
- Result := False;
- if (Length(Ident) = 0) or not (Ident[1] in Alpha) then Exit;
- for I := 2 to Length(Ident) do if not (Ident[I] in AlphaNumeric) then Exit;
- Result := True;
- end;
-
- function IntToStr(Value: Integer): string;
- begin
- FmtStr(Result, '%d', [Value]);
- end;
-
- function IntToHex(Value: Integer; Digits: Integer): string;
- begin
- FmtStr(Result, '%.*x', [Digits, Value]);
- end;
-
- function StrToInt(const S: string): Integer;
- var
- E: Integer;
- begin
- Val(S, Result, E);
- if E <> 0 then ConvertErrorFmt(SInvalidInteger, [S]);
- end;
-
- function StrToIntDef(const S: string; Default: Integer): Integer;
- var
- E: Integer;
- begin
- Val(S, Result, E);
- if E <> 0 then Result := Default;
- end;
-
- function LoadStr(Ident: Integer): string;
- var
- Buffer: array[0..1023] of Char;
- begin
- SetString(Result, Buffer, LoadString(HInstance, Ident, Buffer,
- SizeOf(Buffer)));
- end;
-
- function FmtLoadStr(Ident: Integer; const Args: array of const): string;
- begin
- FmtStr(Result, LoadStr(Ident), Args);
- end;
-
- { File management routines }
-
- function FileOpen(const FileName: string; Mode: Integer): Integer;
- const
- AccessMode: array[0..2] of Integer = (
- GENERIC_READ,
- GENERIC_WRITE,
- GENERIC_READ or GENERIC_WRITE);
- ShareMode: array[0..4] of Integer = (
- 0,
- 0,
- FILE_SHARE_READ,
- FILE_SHARE_WRITE,
- FILE_SHARE_READ or FILE_SHARE_WRITE);
- begin
- Result := CreateFile(PChar(FileName), AccessMode[Mode and 3],
- ShareMode[(Mode and $F0) shr 4], nil, OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, 0);
- end;
-
- function FileCreate(const FileName: string): Integer;
- begin
- Result := CreateFile(PChar(FileName), GENERIC_READ or GENERIC_WRITE,
- 0, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
- end;
-
- function FileRead(Handle: Integer; var Buffer; Count: Integer): Integer;
- begin
- if not ReadFile(Handle, Buffer, Count, Result, nil) then Result := -1;
- end;
-
- function FileWrite(Handle: Integer; const Buffer; Count: Integer): Integer;
- begin
- if not WriteFile(Handle, Buffer, Count, Result, nil) then Result := -1;
- end;
-
- function FileSeek(Handle, Offset, Origin: Integer): Integer;
- begin
- Result := SetFilePointer(Handle, Offset, nil, Origin);
- end;
-
- procedure FileClose(Handle: Integer);
- begin
- CloseHandle(Handle);
- end;
-
- function FileAge(const FileName: string): Integer;
- var
- Handle: THandle;
- FindData: TWin32FindData;
- LocalFileTime: TFileTime;
- begin
- Handle := FindFirstFile(PChar(FileName), FindData);
- if Handle <> INVALID_HANDLE_VALUE then
- begin
- Windows.FindClose(Handle);
- if (FindData.dwFileAttributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then
- begin
- FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime);
- if FileTimeToDosDateTime(LocalFileTime, LongRec(Result).Hi,
- LongRec(Result).Lo) then Exit;
- end;
- end;
- Result := -1;
- end;
-
- function FileExists(const FileName: string): Boolean;
- begin
- Result := FileAge(FileName) <> -1;
- end;
-
- function FileGetDate(Handle: Integer): Integer;
- var
- FileTime, LocalFileTime: TFileTime;
- begin
- if GetFileTime(Handle, nil, nil, @FileTime) and
- FileTimeToLocalFileTime(FileTime, LocalFileTime) and
- FileTimeToDosDateTime(LocalFileTime, LongRec(Result).Hi,
- LongRec(Result).Lo) then Exit;
- Result := -1;
- end;
-
- function FileSetDate(Handle: Integer; Age: Integer): Integer;
- var
- LocalFileTime, FileTime: TFileTime;
- begin
- Result := 0;
- if DosDateTimeToFileTime(LongRec(Age).Hi, LongRec(Age).Lo, LocalFileTime) and
- LocalFileTimeToFileTime(LocalFileTime, FileTime) and
- SetFileTime(Handle, nil, nil, @FileTime) then Exit;
- Result := GetLastError;
- end;
-
- function FileGetAttr(const FileName: string): Integer;
- begin
- Result := GetFileAttributes(PChar(FileName));
- end;
-
- function FileSetAttr(const FileName: string; Attr: Integer): Integer;
- begin
- Result := 0;
- if not SetFileAttributes(PChar(FileName), Attr) then
- Result := GetLastError;
- end;
-
- function FindMatchingFile(var F: TSearchRec): Integer;
- var
- LocalFileTime: TFileTime;
- begin
- with F do
- begin
- while FindData.dwFileAttributes and ExcludeAttr <> 0 do
- if not FindNextFile(FindHandle, FindData) then
- begin
- Result := GetLastError;
- Exit;
- end;
- FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime);
- FileTimeToDosDateTime(LocalFileTime, LongRec(Time).Hi,
- LongRec(Time).Lo);
- Size := FindData.nFileSizeLow;
- Attr := FindData.dwFileAttributes;
- Name := FindData.cFileName;
- end;
- Result := 0;
- end;
-
- function FindFirst(const Path: string; Attr: Integer;
- var F: TSearchRec): Integer;
- const
- faSpecial = faHidden or faSysFile or faVolumeID or faDirectory;
- begin
- F.ExcludeAttr := not Attr and faSpecial;
- F.FindHandle := FindFirstFile(PChar(Path), F.FindData);
- if F.FindHandle <> INVALID_HANDLE_VALUE then
- begin
- Result := FindMatchingFile(F);
- if Result <> 0 then FindClose(F);
- end else
- Result := GetLastError;
- end;
-
- function FindNext(var F: TSearchRec): Integer;
- begin
- if FindNextFile(F.FindHandle, F.FindData) then
- Result := FindMatchingFile(F) else
- Result := GetLastError;
- end;
-
- procedure FindClose(var F: TSearchRec);
- begin
- if F.FindHandle <> INVALID_HANDLE_VALUE then
- Windows.FindClose(F.FindHandle);
- end;
-
- function DeleteFile(const FileName: string): Boolean;
- begin
- Result := Windows.DeleteFile(PChar(FileName));
- end;
-
- function RenameFile(const OldName, NewName: string): Boolean;
- begin
- Result := MoveFile(PChar(OldName), PChar(NewName));
- end;
-
- function ChangeFileExt(const FileName, Extension: string): string;
- var
- I: Integer;
- begin
- I := Length(FileName);
- while (I > 0) and not (FileName[I] in ['.', '\', ':']) do Dec(I);
- if (I = 0) or (FileName[I] <> '.') then I := MaxInt;
- Result := Copy(FileName, 1, I - 1) + Extension;
- end;
-
- function ExtractFilePath(const FileName: string): string;
- var
- I: Integer;
- begin
- I := Length(FileName);
- while (I > 0) and not (FileName[I] in ['\', ':']) do Dec(I);
- Result := Copy(FileName, 1, I);
- end;
-
- function ExtractFileDir(const FileName: string): string;
- var
- I: Integer;
- begin
- I := Length(FileName);
- while (I > 0) and not (FileName[I] in ['\', ':']) do Dec(I);
- if (I > 1) and (FileName[I] = '\') and
- not (FileName[I - 1] in ['\', ':']) then Dec(I);
- Result := Copy(FileName, 1, I);
- end;
-
- function ExtractFileDrive(const FileName: string): string;
- var
- I, J: Integer;
- begin
- if (Length(FileName) >= 2) and (FileName[2] = ':') then
- Result := Copy(FileName, 1, 2)
- else if (Length(FileName) >= 2) and (FileName[1] = '\') and
- (FileName[2] = '\') then
- begin
- J := 0;
- I := 3;
- While (I < Length(FileName)) and (J < 2) do
- begin
- if FileName[I] = '\' then Inc(J);
- if J < 2 then Inc(I);
- end;
- if FileName[I] = '\' then Dec(I);
- Result := Copy(FileName, 1, I);
- end else Result := '';
- end;
-
- function ExtractFileName(const FileName: string): string;
- var
- I: Integer;
- begin
- I := Length(FileName);
- while (I > 0) and not (FileName[I] in ['\', ':']) do Dec(I);
- Result := Copy(FileName, I + 1, 255);
- end;
-
- function ExtractFileExt(const FileName: string): string;
- var
- I: Integer;
- begin
- I := Length(FileName);
- while (I > 0) and not (FileName[I] in ['.', '\', ':']) do Dec(I);
- if (I > 0) and (FileName[I] = '.') then
- Result := Copy(FileName, I, 255) else
- Result := '';
- end;
-
- function ExpandFileName(const FileName: string): string;
- var
- FName: PChar;
- Buffer: array[0..MAX_PATH - 1] of Char;
- begin
- SetString(Result, Buffer, GetFullPathName(PChar(FileName), SizeOf(Buffer),
- Buffer, FName));
- end;
-
- function GetUniversalName(const FileName: string): string;
- type
- PNetResourceArray = ^TNetResourceArray;
- TNetResourceArray = array[0..MaxInt div SizeOf(TNetResource) - 1] of TNetResource;
- var
- I, Count, BufSize, Size, NetResult: Integer;
- Drive: Char;
- NetHandle: THandle;
- NetResources: PNetResourceArray;
- RemoteNameInfo: array[0..1023] of Byte;
- begin
- Result := FileName;
- if Win32Platform <> VER_PLATFORM_WIN32_WINDOWS then
- begin
- Size := SizeOf(RemoteNameInfo);
- if WNetGetUniversalName(PChar(FileName), UNIVERSAL_NAME_INFO_LEVEL,
- @RemoteNameInfo, Size) <> NO_ERROR then Exit;
- Result := PRemoteNameInfo(@RemoteNameInfo).lpUniversalName;
- end else
- begin
- { The following works around a bug in WNetGetUniversalName under Windows 95 }
- Drive := UpCase(FileName[1]);
- if (Drive < 'A') or (Drive > 'Z') or (Length(FileName) < 3) or
- (FileName[2] <> ':') or (FileName[3] <> '\') then
- Exit;
- if WNetOpenEnum(RESOURCE_CONNECTED, RESOURCETYPE_DISK, 0, nil,
- NetHandle) <> NO_ERROR then Exit;
- try
- BufSize := 50 * SizeOf(TNetResource);
- GetMem(NetResources, BufSize);
- try
- while True do
- begin
- Count := -1;
- Size := BufSize;
- NetResult := WNetEnumResource(NetHandle, Count, NetResources, Size);
- if NetResult = ERROR_MORE_DATA then
- begin
- BufSize := Size;
- ReallocMem(NetResources, BufSize);
- Continue;
- end;
- if NetResult <> NO_ERROR then Exit;
- for I := 0 to Count - 1 do
- with NetResources^[I] do
- if (lpLocalName <> nil) and (Drive = UpCase(lpLocalName[0])) then
- begin
- Result := lpRemoteName + Copy(FileName, 3, Length(FileName) - 2);
- Exit;
- end;
- end;
- finally
- FreeMem(NetResources, BufSize);
- end;
- finally
- WNetCloseEnum(NetHandle);
- end;
- end;
- end;
-
- function ExpandUNCFileName(const FileName: string): string;
- begin
- { First get the local resource version of the file name }
- Result := ExpandFileName(FileName);
- if (Length(Result) >= 3) and (Result[2] = ':') and (Upcase(Result[1]) >= 'A')
- and (Upcase(Result[1]) <= 'Z') then
- Result := GetUniversalName(Result);
- end;
-
- function FileSearch(const Name, DirList: string): string;
- var
- I, P, L: Integer;
- begin
- Result := Name;
- P := 1;
- L := Length(DirList);
- while True do
- begin
- if FileExists(Result) then Exit;
- while (P <= L) and (DirList[P] = ';') do Inc(P);
- if P > L then Break;
- I := P;
- while (P <= L) and (DirList[P] <> ';') do Inc(P);
- Result := Copy(DirList, I, P - I);
- if not (DirList[P - 1] in [':', '\']) then Result := Result + '\';
- Result := Result + Name;
- end;
- Result := '';
- end;
-
- function DiskFree(Drive: Byte): Integer;
- var
- RootPath: array[0..4] of Char;
- RootPtr: PChar;
- SectorsPerCluster,
- BytesPerSector,
- FreeClusters,
- TotalClusters: Integer;
- begin
- RootPtr := nil;
- if Drive > 0 then
- begin
- StrCopy(RootPath, 'A:\');
- RootPath[0] := Char(Drive + $40);
- RootPtr := RootPath;
- end;
- if GetDiskFreeSpace(RootPtr, SectorsPerCluster, BytesPerSector,
- FreeClusters, TotalClusters) then
- Result := SectorsPerCluster * BytesPerSector * FreeClusters
- else Result := -1;
- end;
-
- function DiskSize(Drive: Byte): Integer;
- var
- RootPath: array[0..4] of Char;
- RootPtr: PChar;
- SectorsPerCluster,
- BytesPerSector,
- FreeClusters,
- TotalClusters: Integer;
- begin
- RootPtr := nil;
- if Drive > 0 then
- begin
- StrCopy(RootPath, 'A:\');
- RootPath[0] := Char(Drive + $40);
- RootPtr := RootPath;
- end;
- if GetDiskFreeSpace(RootPtr, SectorsPerCluster, BytesPerSector,
- FreeClusters, TotalClusters) then
- Result := SectorsPerCluster * BytesPerSector * TotalClusters
- else Result := -1;
- end;
-
- function FileDateToDateTime(FileDate: Integer): TDateTime;
- begin
- Result :=
- EncodeDate(
- LongRec(FileDate).Hi shr 9 + 1980,
- LongRec(FileDate).Hi shr 5 and 15,
- LongRec(FileDate).Hi and 31) +
- EncodeTime(
- LongRec(FileDate).Lo shr 11,
- LongRec(FileDate).Lo shr 5 and 63,
- LongRec(FileDate).Lo and 31 shl 1, 0);
- end;
-
- function DateTimeToFileDate(DateTime: TDateTime): Integer;
- var
- Year, Month, Day, Hour, Min, Sec, MSec: Word;
- begin
- DecodeDate(DateTime, Year, Month, Day);
- if (Year < 1980) or (Year > 2099) then Result := 0 else
- begin
- DecodeTime(DateTime, Hour, Min, Sec, MSec);
- LongRec(Result).Lo := (Sec shr 1) or (Min shl 5) or (Hour shl 11);
- LongRec(Result).Hi := Day or (Month shl 5) or ((Year - 1980) shl 9);
- end;
- end;
-
- function GetCurrentDir: string;
- var
- Buffer: array[0..MAX_PATH - 1] of Char;
- begin
- SetString(Result, Buffer, GetCurrentDirectory(SizeOf(Buffer), Buffer));
- end;
-
- function SetCurrentDir(const Dir: string): Boolean;
- begin
- Result := SetCurrentDirectory(PChar(Dir));
- end;
-
- function CreateDir(const Dir: string): Boolean;
- begin
- Result := CreateDirectory(PChar(Dir), nil);
- end;
-
- function RemoveDir(const Dir: string): Boolean;
- begin
- Result := RemoveDirectory(PChar(Dir));
- end;
-
- { PChar routines }
-
- function StrLen(Str: PChar): Cardinal; assembler;
- asm
- MOV EDX,EDI
- MOV EDI,EAX
- MOV ECX,0FFFFFFFFH
- XOR AL,AL
- REPNE SCASB
- MOV EAX,0FFFFFFFEH
- SUB EAX,ECX
- MOV EDI,EDX
- end;
-
- function StrEnd(Str: PChar): PChar; assembler;
- asm
- MOV EDX,EDI
- MOV EDI,EAX
- MOV ECX,0FFFFFFFFH
- XOR AL,AL
- REPNE SCASB
- LEA EAX,[EDI-1]
- MOV EDI,EDX
- end;
-
- function StrMove(Dest, Source: PChar; Count: Cardinal): PChar; assembler;
- asm
- PUSH ESI
- PUSH EDI
- MOV ESI,EDX
- MOV EDI,EAX
- MOV EDX,ECX
- CMP EDI,ESI
- JG @@1
- JE @@2
- SHR ECX,2
- REP MOVSD
- MOV ECX,EDX
- AND ECX,3
- REP MOVSB
- JMP @@2
- @@1: LEA ESI,[ESI+ECX-1]
- LEA EDI,[EDI+ECX-1]
- AND ECX,3
- STD
- REP MOVSB
- SUB ESI,3
- SUB EDI,3
- MOV ECX,EDX
- SHR ECX,2
- REP MOVSD
- CLD
- @@2: POP EDI
- POP ESI
- end;
-
- function StrCopy(Dest, Source: PChar): PChar; assembler;
- asm
- PUSH EDI
- PUSH ESI
- MOV ESI,EAX
- MOV EDI,EDX
- MOV ECX,0FFFFFFFFH
- XOR AL,AL
- REPNE SCASB
- NOT ECX
- MOV EDI,ESI
- MOV ESI,EDX
- MOV EDX,ECX
- MOV EAX,EDI
- SHR ECX,2
- REP MOVSD
- MOV ECX,EDX
- AND ECX,3
- REP MOVSB
- POP ESI
- POP EDI
- end;
-
- function StrECopy(Dest, Source: PChar): PChar; assembler;
- asm
- PUSH EDI
- PUSH ESI
- MOV ESI,EAX
- MOV EDI,EDX
- MOV ECX,0FFFFFFFFH
- XOR AL,AL
- REPNE SCASB
- NOT ECX
- MOV EDI,ESI
- MOV ESI,EDX
- MOV EDX,ECX
- SHR ECX,2
- REP MOVSD
- MOV ECX,EDX
- AND ECX,3
- REP MOVSB
- LEA EAX,[EDI-1]
- POP ESI
- POP EDI
- end;
-
- function StrLCopy(Dest, Source: PChar; MaxLen: Cardinal): PChar; assembler;
- asm
- PUSH EDI
- PUSH ESI
- PUSH EBX
- MOV ESI,EAX
- MOV EDI,EDX
- MOV EBX,ECX
- XOR AL,AL
- TEST ECX,ECX
- JZ @@1
- REPNE SCASB
- JNE @@1
- INC ECX
- @@1: SUB EBX,ECX
- MOV EDI,ESI
- MOV ESI,EDX
- MOV EDX,EDI
- MOV ECX,EBX
- SHR ECX,2
- REP MOVSD
- MOV ECX,EBX
- AND ECX,3
- REP MOVSB
- STOSB
- MOV EAX,EDX
- POP EBX
- POP ESI
- POP EDI
- end;
-
- function StrPCopy(Dest: PChar; const Source: string): PChar;
- begin
- Result := StrLCopy(Dest, PChar(Source), 255);
- end;
-
- function StrPLCopy(Dest: PChar; const Source: string;
- MaxLen: Cardinal): PChar;
- begin
- Result := StrLCopy(Dest, PChar(Source), MaxLen);
- end;
-
- function StrCat(Dest, Source: PChar): PChar;
- begin
- StrCopy(StrEnd(Dest), Source);
- Result := Dest;
- end;
-
- function StrLCat(Dest, Source: PChar; MaxLen: Cardinal): PChar; assembler;
- asm
- PUSH EDI
- PUSH ESI
- PUSH EBX
- MOV EDI,Dest
- MOV ESI,Source
- MOV EBX,MaxLen
- CALL StrEnd
- MOV ECX,EDI
- ADD ECX,EBX
- SUB ECX,EAX
- JBE @@1
- MOV EDX,ESI
- CALL StrLCopy
- @@1: MOV EAX,EDI
- POP EBX
- POP ESI
- POP EDI
- end;
-
- function StrComp(Str1, Str2: PChar): Integer; assembler;
- asm
- PUSH EDI
- PUSH ESI
- MOV EDI,EDX
- MOV ESI,EAX
- MOV ECX,0FFFFFFFFH
- XOR EAX,EAX
- REPNE SCASB
- NOT ECX
- MOV EDI,EDX
- XOR EDX,EDX
- REPE CMPSB
- MOV AL,[ESI-1]
- MOV DL,[EDI-1]
- SUB EAX,EDX
- POP ESI
- POP EDI
- end;
-
- function StrIComp(Str1, Str2: PChar): Integer; assembler;
- asm
- PUSH EDI
- PUSH ESI
- MOV EDI,EDX
- MOV ESI,EAX
- MOV ECX,0FFFFFFFFH
- XOR EAX,EAX
- REPNE SCASB
- NOT ECX
- MOV EDI,EDX
- XOR EDX,EDX
- @@1: REPE CMPSB
- JE @@4
- MOV AL,[ESI-1]
- CMP AL,'a'
- JB @@2
- CMP AL,'z'
- JA @@2
- SUB AL,20H
- @@2: MOV DL,[EDI-1]
- CMP DL,'a'
- JB @@3
- CMP DL,'z'
- JA @@3
- SUB DL,20H
- @@3: SUB EAX,EDX
- JE @@1
- @@4: POP ESI
- POP EDI
- end;
-
- function StrLComp(Str1, Str2: PChar; MaxLen: Cardinal): Integer; assembler;
- asm
- PUSH EDI
- PUSH ESI
- PUSH EBX
- MOV EDI,EDX
- MOV ESI,EAX
- MOV EBX,ECX
- XOR EAX,EAX
- OR ECX,ECX
- JE @@1
- REPNE SCASB
- SUB EBX,ECX
- MOV ECX,EBX
- MOV EDI,EDX
- XOR EDX,EDX
- REPE CMPSB
- MOV AL,[ESI-1]
- MOV DL,[EDI-1]
- SUB EAX,EDX
- @@1: POP EBX
- POP ESI
- POP EDI
- end;
-
- function StrLIComp(Str1, Str2: PChar; MaxLen: Cardinal): Integer; assembler;
- asm
- PUSH EDI
- PUSH ESI
- PUSH EBX
- MOV EDI,EDX
- MOV ESI,EAX
- MOV EBX,ECX
- XOR EAX,EAX
- OR ECX,ECX
- JE @@4
- REPNE SCASB
- SUB EBX,ECX
- MOV ECX,EBX
- MOV EDI,EDX
- XOR EDX,EDX
- @@1: REPE CMPSB
- JE @@4
- MOV AL,[ESI-1]
- CMP AL,'a'
- JB @@2
- CMP AL,'z'
- JA @@2
- SUB AL,20H
- @@2: MOV DL,[EDI-1]
- CMP DL,'a'
- JB @@3
- CMP DL,'z'
- JA @@3
- SUB DL,20H
- @@3: SUB EAX,EDX
- JE @@1
- @@4: POP EBX
- POP ESI
- POP EDI
- end;
-
- function StrScan(Str: PChar; Chr: Char): PChar; assembler;
- asm
- PUSH EDI
- PUSH EAX
- MOV EDI,Str
- MOV ECX,0FFFFFFFFH
- XOR AL,AL
- REPNE SCASB
- NOT ECX
- POP EDI
- MOV AL,Chr
- REPNE SCASB
- MOV EAX,0
- JNE @@1
- MOV EAX,EDI
- DEC EAX
- @@1: POP EDI
- end;
-
- function StrRScan(Str: PChar; Chr: Char): PChar; assembler;
- asm
- PUSH EDI
- MOV EDI,Str
- MOV ECX,0FFFFFFFFH
- XOR AL,AL
- REPNE SCASB
- NOT ECX
- STD
- DEC EDI
- MOV AL,Chr
- REPNE SCASB
- MOV EAX,0
- JNE @@1
- MOV EAX,EDI
- INC EAX
- @@1: CLD
- POP EDI
- end;
-
- function StrPos(Str1, Str2: PChar): PChar; assembler;
- asm
- PUSH EDI
- PUSH ESI
- PUSH EBX
- MOV EBX,EAX
- MOV EDI,EDX
- XOR AL,AL
- MOV ECX,0FFFFFFFFH
- REPNE SCASB
- NOT ECX
- DEC ECX
- JE @@2
- MOV ESI,ECX
- MOV EDI,EBX
- MOV ECX,0FFFFFFFFH
- REPNE SCASB
- NOT ECX
- SUB ECX,ESI
- JBE @@2
- MOV EDI,EBX
- LEA EBX,[ESI-1]
- @@1: MOV ESI,EDX
- LODSB
- REPNE SCASB
- JNE @@2
- MOV EAX,ECX
- PUSH EDI
- MOV ECX,EBX
- REPE CMPSB
- POP EDI
- MOV ECX,EAX
- JNE @@1
- LEA EAX,[EDI-1]
- JMP @@3
- @@2: XOR EAX,EAX
- @@3: POP EBX
- POP ESI
- POP EDI
- end;
-
- function StrUpper(Str: PChar): PChar; assembler;
- asm
- PUSH ESI
- MOV ESI,Str
- MOV EDX,Str
- @@1: LODSB
- OR AL,AL
- JE @@2
- CMP AL,'a'
- JB @@1
- CMP AL,'z'
- JA @@1
- SUB AL,20H
- MOV [ESI-1],AL
- JMP @@1
- @@2: XCHG EAX,EDX
- POP ESI
- end;
-
- function StrLower(Str: PChar): PChar; assembler;
- asm
- PUSH ESI
- MOV ESI,Str
- MOV EDX,Str
- @@1: LODSB
- OR AL,AL
- JE @@2
- CMP AL,'A'
- JB @@1
- CMP AL,'Z'
- JA @@1
- ADD AL,20H
- MOV [ESI-1],AL
- JMP @@1
- @@2: XCHG EAX,EDX
- POP ESI
- end;
-
- function StrPas(Str: PChar): string;
- begin
- Result := Str;
- end;
-
- function StrAlloc(Size: Cardinal): PChar;
- begin
- Inc(Size, SizeOf(Cardinal));
- GetMem(Result, Size);
- Cardinal(Pointer(Result)^) := Size;
- Inc(Result, SizeOf(Cardinal));
- end;
-
- function StrBufSize(Str: PChar): Cardinal;
- begin
- Dec(Str, SizeOf(Cardinal));
- Result := Cardinal(Pointer(Str)^) - SizeOf(Cardinal);
- end;
-
- function StrNew(Str: PChar): PChar;
- var
- Size: Cardinal;
- begin
- if Str = nil then Result := nil else
- begin
- Size := StrLen(Str) + 1;
- Result := StrMove(StrAlloc(Size), Str, Size);
- end;
- end;
-
- procedure StrDispose(Str: PChar);
- begin
- if Str <> nil then
- begin
- Dec(Str, SizeOf(Cardinal));
- FreeMem(Str, Cardinal(Pointer(Str)^));
- end;
- end;
-
- { String formatting routines }
-
- procedure FormatError(ErrorCode: Integer; Format: PChar; FmtLen: Cardinal);
- var
- Buffer: array[0..31] of Char;
- begin
- if FmtLen > 31 then FmtLen := 31;
- StrMove(Buffer, Format, FmtLen);
- Buffer[FmtLen] := #0;
- ConvertErrorFmt(SInvalidFormat + ErrorCode, [PChar(@Buffer)]);
- end;
-
- procedure FormatVarToStr(var S: string; const V: Variant);
- begin
- S := V;
- end;
-
- procedure FormatClearStr(var S: string);
- begin
- S := '';
- end;
-
- function FormatBuf(var Buffer; BufLen: Cardinal; const Format;
- FmtLen: Cardinal; const Args: array of const): Cardinal;
- const
- C10000: Single = 10000;
- var
- ArgIndex, Width, Prec: Integer;
- BufferOrg, FormatOrg, FormatPtr, TempStr: PChar;
- JustFlag: Byte;
- StrBuf: array[0..39] of Char;
- asm
- PUSH EBX
- PUSH ESI
- PUSH EDI
- MOV EDI,EAX
- MOV ESI,ECX
- ADD ECX,FmtLen
- MOV BufferOrg,EDI
- XOR EAX,EAX
- MOV ArgIndex,EAX
- MOV TempStr,EAX
-
- @Loop:
- OR EDX,EDX
- JE @Done
-
- @NextChar:
- CMP ESI,ECX
- JE @Done
- LODSB
- CMP AL,'%'
- JE @Format
-
- @StoreChar:
- STOSB
- DEC EDX
- JNE @NextChar
-
- @Done:
- MOV EAX,EDI
- SUB EAX,BufferOrg
- JMP @Exit
-
- @Format:
- CMP ESI,ECX
- JE @Done
- LODSB
- CMP AL,'%'
- JE @StoreChar
- LEA EBX,[ESI-2]
- MOV FormatOrg,EBX
- @A0: MOV JustFlag,AL
- CMP AL,'-'
- JNE @A1
- CMP ESI,ECX
- JE @Done
- LODSB
- @A1: CALL @Specifier
- CMP AL,':'
- JNE @A2
- MOV ArgIndex,EBX
- CMP ESI,ECX
- JE @Done
- LODSB
- JMP @A0
- @A2: MOV Width,EBX
- MOV EBX,-1
- CMP AL,'.'
- JNE @A3
- CMP ESI,ECX
- JE @Done
- LODSB
- CALL @Specifier
- @A3: MOV Prec,EBX
- MOV FormatPtr,ESI
- PUSH ECX
- PUSH EDX
- CALL @Convert
- POP EDX
- MOV EBX,Width
- SUB EBX,ECX
- JAE @A4
- XOR EBX,EBX
- @A4: CMP JustFlag,'-'
- JNE @A6
- SUB EDX,ECX
- JAE @A5
- ADD ECX,EDX
- XOR EDX,EDX
- @A5: REP MOVSB
- @A6: XCHG EBX,ECX
- SUB EDX,ECX
- JAE @A7
- ADD ECX,EDX
- XOR EDX,EDX
- @A7: MOV AL,' '
- REP STOSB
- XCHG EBX,ECX
- SUB EDX,ECX
- JAE @A8
- ADD ECX,EDX
- XOR EDX,EDX
- @A8: REP MOVSB
- CMP TempStr,0
- JE @A9
- PUSH EDX
- LEA EAX,TempStr
- CALL FormatClearStr
- POP EDX
- @A9: POP ECX
- MOV ESI,FormatPtr
- JMP @Loop
-
- @Specifier:
- XOR EBX,EBX
- CMP AL,'*'
- JE @B3
- @B1: CMP AL,'0'
- JB @B5
- CMP AL,'9'
- JA @B5
- IMUL EBX,EBX,10
- SUB AL,'0'
- MOVZX EAX,AL
- ADD EBX,EAX
- CMP ESI,ECX
- JE @B2
- LODSB
- JMP @B1
- @B2: POP EAX
- JMP @Done
- @B3: MOV EAX,ArgIndex
- CMP EAX,Args.Integer[-4]
- JA @B4
- INC ArgIndex
- MOV EBX,Args
- CMP [EBX+EAX*8].Byte[4],vtInteger
- MOV EBX,[EBX+EAX*8]
- JE @B4
- XOR EBX,EBX
- @B4: CMP ESI,ECX
- JE @B2
- LODSB
- @B5: RET
-
- @Convert:
- AND AL,0DFH
- MOV CL,AL
- MOV EAX,1
- MOV EBX,ArgIndex
- CMP EBX,Args.Integer[-4]
- JA @ErrorExit
- INC ArgIndex
- MOV ESI,Args
- LEA ESI,[ESI+EBX*8]
- MOV EAX,[ESI].Integer[0]
- MOVZX EBX,[ESI].Byte[4]
- JMP @CvtVector.Pointer[EBX*4]
-
- @CvtVector:
- DD @CvtInteger
- DD @CvtBoolean
- DD @CvtChar
- DD @CvtExtended
- DD @CvtShortStr
- DD @CvtPointer
- DD @CvtPChar
- DD @CvtObject
- DD @CvtClass
- DD @CvtWideChar
- DD @CvtPWideChar
- DD @CvtAnsiStr
- DD @CvtCurrency
- DD @CvtVariant
-
- @CvtBoolean:
- @CvtObject:
- @CvtClass:
- @CvtWideChar:
- @CvtPWideChar:
- @CvtError:
- XOR EAX,EAX
-
- @ErrorExit:
- MOV EDX,FormatOrg
- MOV ECX,FormatPtr
- SUB ECX,EDX
- CALL FormatError
-
- @CvtInteger:
- CMP CL,'D'
- JE @C1
- CMP CL,'U'
- JE @C2
- CMP CL,'X'
- JNE @CvtError
- MOV ECX,16
- JMP @CvtLong
- @C1: OR EAX,EAX
- JNS @C2
- NEG EAX
- CALL @C2
- MOV AL,'-'
- INC ECX
- DEC ESI
- MOV [ESI],AL
- RET
- @C2: MOV ECX,10
-
- @CvtLong:
- LEA ESI,StrBuf[16]
- @D1: XOR EDX,EDX
- DIV ECX
- ADD DL,'0'
- CMP DL,'0'+10
- JB @D2
- ADD DL,'A'-'0'-10
- @D2: DEC ESI
- MOV [ESI],DL
- OR EAX,EAX
- JNE @D1
- LEA ECX,StrBuf[16]
- SUB ECX,ESI
- MOV EDX,Prec
- CMP EDX,16
- JB @D3
- RET
- @D3: SUB EDX,ECX
- JBE @D5
- ADD ECX,EDX
- MOV AL,'0'
- @D4: DEC ESI
- MOV [ESI],AL
- DEC EDX
- JNE @D4
- @D5: RET
-
- @CvtChar:
- CMP CL,'S'
- JNE @CvtError
- MOV ECX,1
- RET
-
- @CvtVariant:
- CMP CL,'S'
- JNE @CvtError
- CMP [EAX].TVarData.VType,varNull
- JBE @CvtEmptyStr
- MOV EDX,EAX
- LEA EAX,TempStr
- CALL FormatVarToStr
- MOV ESI,TempStr
- JMP @CvtStrRef
-
- @CvtEmptyStr:
- XOR ECX,ECX
- RET
-
- @CvtShortStr:
- CMP CL,'S'
- JNE @CvtError
- MOV ESI,EAX
- LODSB
- MOVZX ECX,AL
- JMP @CvtStrLen
-
- @CvtAnsiStr:
- CMP CL,'S'
- JNE @CvtError
- MOV ESI,EAX
-
- @CvtStrRef:
- OR ESI,ESI
- JE @CvtEmptyStr
- MOV ECX,[ESI-4]
-
- @CvtStrLen:
- CMP ECX,Prec
- JA @E1
- RET
- @E1: MOV ECX,Prec
- RET
-
- @CvtPChar:
- CMP CL,'S'
- JNE @CvtError
- MOV ESI,EAX
- PUSH EDI
- MOV EDI,EAX
- XOR AL,AL
- MOV ECX,Prec
- JECXZ @F1
- REPNE SCASB
- JNE @F1
- DEC EDI
- @F1: MOV ECX,EDI
- SUB ECX,ESI
- POP EDI
- RET
-
- @CvtPointer:
- CMP CL,'P'
- JNE @CvtError
- MOV Prec,8
- MOV ECX,16
- JMP @CvtLong
-
- @CvtCurrency:
- MOV BH,fvCurrency
- JMP @CvtFloat
-
- @CvtExtended:
- MOV BH,fvExtended
-
- @CvtFloat:
- MOV ESI,EAX
- MOV BL,ffGeneral
- CMP CL,'G'
- JE @G2
- MOV BL,ffExponent
- CMP CL,'E'
- JE @G2
- MOV BL,ffFixed
- CMP CL,'F'
- JE @G1
- MOV BL,ffNumber
- CMP CL,'N'
- JE @G1
- CMP CL,'M'
- JNE @CvtError
- MOV BL,ffCurrency
- @G1: MOV EAX,18
- MOV EDX,Prec
- CMP EDX,EAX
- JBE @G3
- MOV EDX,2
- CMP CL,'M'
- JNE @G3
- MOVZX EDX,CurrencyDecimals
- JMP @G3
- @G2: MOV EAX,Prec
- MOV EDX,3
- CMP EAX,18
- JBE @G3
- MOV EAX,15
- @G3: PUSH EBX
- PUSH EAX
- PUSH EDX
- LEA EAX,StrBuf
- MOV EDX,ESI
- MOVZX ECX,BH
- CALL FloatToText
- MOV ECX,EAX
- LEA ESI,StrBuf
- RET
-
- @Exit:
- POP EDI
- POP ESI
- POP EBX
- end;
-
- function StrFmt(Buffer, Format: PChar; const Args: array of const): PChar;
- begin
- Buffer[FormatBuf(Buffer^, MaxInt, Format^, StrLen(Format), Args)] := #0;
- Result := Buffer;
- end;
-
- function StrLFmt(Buffer: PChar; MaxLen: Cardinal; Format: PChar;
- const Args: array of const): PChar;
- begin
- Buffer[FormatBuf(Buffer^, MaxLen, Format^, StrLen(Format), Args)] := #0;
- Result := Buffer;
- end;
-
- function Format(const Format: string; const Args: array of const): string;
- begin
- FmtStr(Result, Format, Args);
- end;
-
- procedure FmtStr(var Result: string; const Format: string;
- const Args: array of const);
- var
- Len: Integer;
- Buffer: array[0..4097] of Char;
- begin
- Len := FormatBuf(Buffer, SizeOf(Buffer) - 1, Pointer(Format)^,
- Length(Format), Args);
- if Len = SizeOf(Buffer) - 1 then ConvertError(SResultTooLong);
- SetString(Result, Buffer, Len);
- end;
-
- { Floating point conversion routines }
-
- {$L FFMT.OBJ}
-
- procedure FloatToDecimal(var Result: TFloatRec; const Value;
- ValueType: TFloatValue; Precision, Decimals: Integer); external;
-
- function FloatToText(Buffer: PChar; const Value; ValueType: TFloatValue;
- Format: TFloatFormat; Precision, Digits: Integer): Integer; external;
-
- function FloatToTextFmt(Buffer: PChar; const Value; ValueType: TFloatValue;
- Format: PChar): Integer; external;
-
- function TextToFloat(Buffer: PChar; var Value;
- ValueType: TFloatValue): Boolean; external;
-
- function FloatToStr(Value: Extended): string;
- var
- Buffer: array[0..63] of Char;
- begin
- SetString(Result, Buffer, FloatToText(Buffer, Value, fvExtended,
- ffGeneral, 15, 0));
- end;
-
- function CurrToStr(Value: Currency): string;
- var
- Buffer: array[0..63] of Char;
- begin
- SetString(Result, Buffer, FloatToText(Buffer, Value, fvCurrency,
- ffGeneral, 0, 0));
- end;
-
- function FloatToStrF(Value: Extended; Format: TFloatFormat;
- Precision, Digits: Integer): string;
- var
- Buffer: array[0..63] of Char;
- begin
- SetString(Result, Buffer, FloatToText(Buffer, Value, fvExtended,
- Format, Precision, Digits));
- end;
-
- function CurrToStrF(Value: Currency; Format: TFloatFormat;
- Digits: Integer): string;
- var
- Buffer: array[0..63] of Char;
- begin
- SetString(Result, Buffer, FloatToText(Buffer, Value, fvCurrency,
- Format, 0, Digits));
- end;
-
- function FormatFloat(const Format: string; Value: Extended): string;
- var
- Buffer: array[0..255] of Char;
- begin
- if Length(Format) > SizeOf(Buffer) - 32 then ConvertError(SFormatTooLong);
- SetString(Result, Buffer, FloatToTextFmt(Buffer, Value, fvExtended,
- PChar(Format)));
- end;
-
- function FormatCurr(const Format: string; Value: Currency): string;
- var
- Buffer: array[0..255] of Char;
- begin
- if Length(Format) > SizeOf(Buffer) - 32 then ConvertError(SFormatTooLong);
- SetString(Result, Buffer, FloatToTextFmt(Buffer, Value, fvCurrency,
- PChar(Format)));
- end;
-
- function StrToFloat(const S: string): Extended;
- begin
- if not TextToFloat(PChar(S), Result, fvExtended) then
- ConvertErrorFmt(SInvalidFloat, [S]);
- end;
-
- function StrToCurr(const S: string): Currency;
- begin
- if not TextToFloat(PChar(S), Result, fvCurrency) then
- ConvertErrorFmt(SInvalidFloat, [S]);
- end;
-
- { Date/time support routines }
-
- type
- PDayTable = ^TDayTable;
- TDayTable = array[1..12] of Word;
-
- const
- FMSecsPerDay: Single = MSecsPerDay;
- IMSecsPerDay: Integer = MSecsPerDay;
-
- function DateTimeToTimeStamp(DateTime: TDateTime): TTimeStamp;
- asm
- MOV ECX,EAX
- FLD DateTime
- FMUL FMSecsPerDay
- SUB ESP,8
- FISTP QWORD PTR [ESP]
- FWAIT
- POP EAX
- POP EDX
- OR EDX,EDX
- JNS @@1
- NEG EDX
- NEG EAX
- SBB EDX,0
- DIV IMSecsPerDay
- NEG EAX
- JMP @@2
- @@1: DIV IMSecsPerDay
- @@2: ADD EAX,DateDelta
- MOV [ECX].TTimeStamp.Time,EDX
- MOV [ECX].TTimeStamp.Date,EAX
- end;
-
- function TimeStampToDateTime(const TimeStamp: TTimeStamp): TDateTime;
- asm
- MOV ECX,[EAX].TTimeStamp.Time
- MOV EAX,[EAX].TTimeStamp.Date
- SUB EAX,DateDelta
- IMUL IMSecsPerDay
- OR EDX,EDX
- JNS @@1
- SUB EAX,ECX
- SBB EDX,0
- JMP @@2
- @@1: ADD EAX,ECX
- ADC EDX,0
- @@2: PUSH EDX
- PUSH EAX
- FILD QWORD PTR [ESP]
- FDIV FMSecsPerDay
- ADD ESP,8
- end;
-
- function MSecsToTimeStamp(MSecs: Comp): TTimeStamp;
- asm
- MOV ECX,EAX
- MOV EAX,MSecs.Integer[0]
- MOV EDX,MSecs.Integer[4]
- DIV IMSecsPerDay
- MOV [ECX].TTimeStamp.Time,EDX
- MOV [ECX].TTimeStamp.Date,EAX
- end;
-
- function TimeStampToMSecs(const TimeStamp: TTimeStamp): Comp;
- asm
- FILD [EAX].TTimeStamp.Date
- FMUL FMSecsPerDay
- FIADD [EAX].TTimeStamp.Time
- end;
-
- { Time encoding and decoding }
-
- function DoEncodeTime(Hour, Min, Sec, MSec: Word; var Time: TDateTime): Boolean;
- begin
- Result := False;
- if (Hour < 24) and (Min < 60) and (Sec < 60) and (MSec < 1000) then
- begin
- Time := (Hour * 3600000 + Min * 60000 + Sec * 1000 + MSec) / MSecsPerDay;
- Result := True;
- end;
- end;
-
- function EncodeTime(Hour, Min, Sec, MSec: Word): TDateTime;
- begin
- if not DoEncodeTime(Hour, Min, Sec, MSec, Result) then
- ConvertError(STimeEncodeError);
- end;
-
- procedure DecodeTime(Time: TDateTime; var Hour, Min, Sec, MSec: Word);
- var
- MinCount, MSecCount: Word;
- begin
- DivMod(DateTimeToTimeStamp(Time).Time, 60000, MinCount, MSecCount);
- DivMod(MinCount, 60, Hour, Min);
- DivMod(MSecCount, 1000, Sec, MSec);
- end;
-
- { Date encoding and decoding }
-
- function IsLeapYear(Year: Word): Boolean;
- begin
- Result := (Year mod 4 = 0) and ((Year mod 100 <> 0) or (Year mod 400 = 0));
- end;
-
- function GetDayTable(Year: Word): PDayTable;
- const
- DayTable1: TDayTable = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
- DayTable2: TDayTable = (31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
- DayTables: array[Boolean] of PDayTable = (@DayTable1, @DayTable2);
- begin
- Result := DayTables[IsLeapYear(Year)];
- end;
-
- function DoEncodeDate(Year, Month, Day: Word; var Date: TDateTime): Boolean;
- var
- I: Integer;
- DayTable: PDayTable;
- begin
- Result := False;
- DayTable := GetDayTable(Year);
- if (Year >= 1) and (Year <= 9999) and (Month >= 1) and (Month <= 12) and
- (Day >= 1) and (Day <= DayTable^[Month]) then
- begin
- for I := 1 to Month - 1 do Inc(Day, DayTable^[I]);
- I := Year - 1;
- Date := I * 365 + I div 4 - I div 100 + I div 400 + Day - DateDelta;
- Result := True;
- end;
- end;
-
- function EncodeDate(Year, Month, Day: Word): TDateTime;
- begin
- if not DoEncodeDate(Year, Month, Day, Result) then
- ConvertError(SDateEncodeError);
- end;
-
- procedure DecodeDate(Date: TDateTime; var Year, Month, Day: Word);
- const
- D1 = 365;
- D4 = D1 * 4 + 1;
- D100 = D4 * 25 - 1;
- D400 = D100 * 4 + 1;
- var
- Y, M, D, I: Word;
- T: Integer;
- DayTable: PDayTable;
- begin
- T := DateTimeToTimeStamp(Date).Date;
- if T <= 0 then
- begin
- Year := 0;
- Month := 0;
- Day := 0;
- end else
- begin
- Dec(T);
- Y := 1;
- while T >= D400 do
- begin
- Dec(T, D400);
- Inc(Y, 400);
- end;
- DivMod(T, D100, I, D);
- if I = 4 then
- begin
- Dec(I);
- Inc(D, D100);
- end;
- Inc(Y, I * 100);
- DivMod(D, D4, I, D);
- Inc(Y, I * 4);
- DivMod(D, D1, I, D);
- if I = 4 then
- begin
- Dec(I);
- Inc(D, D1);
- end;
- Inc(Y, I);
- DayTable := GetDayTable(Y);
- M := 1;
- while True do
- begin
- I := DayTable^[M];
- if D < I then Break;
- Dec(D, I);
- Inc(M);
- end;
- Year := Y;
- Month := M;
- Day := D + 1;
- end;
- end;
-
- function DayOfWeek(Date: TDateTime): Integer;
- begin
- Result := DateTimeToTimeStamp(Date).Date mod 7 + 1;
- end;
-
- function Date: TDateTime;
- var
- SystemTime: TSystemTime;
- begin
- GetLocalTime(SystemTime);
- with SystemTime do Result := EncodeDate(wYear, wMonth, wDay);
- end;
-
- function Time: TDateTime;
- var
- SystemTime: TSystemTime;
- begin
- GetLocalTime(SystemTime);
- with SystemTime do
- Result := EncodeTime(wHour, wMinute, wSecond, wMilliSeconds);
- end;
-
- function Now: TDateTime;
- begin
- Result := Date + Time;
- end;
-
- function CurrentYear: Word;
- var
- SystemTime: TSystemTime;
- begin
- GetLocalTime(SystemTime);
- Result := SystemTime.wYear;
- end;
-
- { Date/time to string conversions }
-
- procedure DateTimeToString(var Result: string; const Format: string;
- DateTime: TDateTime);
- var
- BufPos, AppendLevel: Integer;
- Buffer: array[0..255] of Char;
-
- procedure AppendChars(P: PChar; Count: Integer);
- var
- N: Integer;
- begin
- N := SizeOf(Buffer) - BufPos;
- if N > Count then N := Count;
- if N <> 0 then Move(P[0], Buffer[BufPos], N);
- Inc(BufPos, N);
- end;
-
- procedure AppendString(const S: string);
- begin
- AppendChars(Pointer(S), Length(S));
- end;
-
- procedure AppendNumber(Number, Digits: Integer);
- const
- Format: array[0..3] of Char = '%.*d';
- var
- NumBuf: array[0..15] of Char;
- begin
- AppendChars(NumBuf, FormatBuf(NumBuf, SizeOf(NumBuf), Format,
- SizeOf(Format), [Digits, Number]));
- end;
-
- procedure AppendFormat(Format: PChar);
- var
- Starter, Token, LastToken: Char;
- DateDecoded, TimeDecoded, LastWasHour, Use12HourClock,
- BetweenQuotes: Boolean;
- P: PChar;
- Count: Integer;
- Year, Month, Day, Hour, Min, Sec, MSec, H: Word;
-
- procedure GetCount;
- var
- P: PChar;
- begin
- P := Format;
- while Format^ = Starter do Inc(Format);
- Count := Format - P + 1;
- end;
-
- procedure GetDate;
- begin
- if not DateDecoded then
- begin
- DecodeDate(DateTime, Year, Month, Day);
- DateDecoded := True;
- end;
- end;
-
- procedure GetTime;
- begin
- if not TimeDecoded then
- begin
- DecodeTime(DateTime, Hour, Min, Sec, MSec);
- TimeDecoded := True;
- end;
- end;
-
- begin
- if (Format <> nil) and (AppendLevel < 2) then
- begin
- Inc(AppendLevel);
- LastToken := ' ';
- DateDecoded := False;
- TimeDecoded := False;
- while Format^ <> #0 do
- begin
- Starter := Format^;
- Inc(Format);
- Token := Starter;
- if Token in ['a'..'z'] then Dec(Token, 32);
- if Token in ['A'..'Z'] then
- begin
- if (Token = 'M') and (LastToken = 'H') then Token := 'N';
- LastToken := Token;
- end;
- case Token of
- 'Y':
- begin
- GetCount;
- GetDate;
- if Count <= 2 then
- AppendNumber(Year mod 100, 2) else
- AppendNumber(Year, 4);
- end;
- 'M':
- begin
- GetCount;
- GetDate;
- case Count of
- 1, 2: AppendNumber(Month, Count);
- 3: AppendString(ShortMonthNames[Month]);
- else
- AppendString(LongMonthNames[Month]);
- end;
- end;
- 'D':
- begin
- GetCount;
- case Count of
- 1, 2:
- begin
- GetDate;
- AppendNumber(Day, Count);
- end;
- 3: AppendString(ShortDayNames[DayOfWeek(DateTime)]);
- 4: AppendString(LongDayNames[DayOfWeek(DateTime)]);
- 5: AppendFormat(Pointer(ShortDateFormat));
- else
- AppendFormat(Pointer(LongDateFormat));
- end;
- end;
- 'H':
- begin
- GetCount;
- GetTime;
- Use12HourClock := False;
- BetweenQuotes := False;
- P := Format;
- while P^ <> #0 do
- begin
- case P^ of
- 'A', 'a':
- if not BetweenQuotes then
- begin
- Use12HourClock := True;
- Break;
- end;
- 'H', 'h':
- Break;
- '''', '"': BetweenQuotes := not BetweenQuotes;
- end;
- Inc(P);
- end;
- H := Hour;
- if Use12HourClock then
- if H = 0 then H := 12 else if H > 12 then Dec(H, 12);
- if Count > 2 then Count := 2;
- AppendNumber(H, Count);
- end;
- 'N':
- begin
- GetCount;
- GetTime;
- if Count > 2 then Count := 2;
- AppendNumber(Min, Count);
- end;
- 'S':
- begin
- GetCount;
- GetTime;
- if Count > 2 then Count := 2;
- AppendNumber(Sec, Count);
- end;
- 'T':
- begin
- GetCount;
- if Count = 1 then
- AppendFormat(Pointer(ShortTimeFormat)) else
- AppendFormat(Pointer(LongTimeFormat));
- end;
- 'A':
- begin
- GetTime;
- P := Format - 1;
- if StrLIComp(P, 'AM/PM', 5) = 0 then
- begin
- if Hour >= 12 then Inc(P, 3);
- AppendChars(P, 2);
- Inc(Format, 4);
- end else
- if StrLIComp(P, 'A/P', 3) = 0 then
- begin
- if Hour >= 12 then Inc(P, 2);
- AppendChars(P, 1);
- Inc(Format, 2);
- end else
- if StrLIComp(P, 'AMPM', 4) = 0 then
- begin
- if Hour < 12 then
- AppendString(TimeAMString) else
- AppendString(TimePMString);
- Inc(Format, 3);
- end else
- AppendChars(@Starter, 1);
- end;
- 'C':
- begin
- GetCount;
- AppendFormat(Pointer(ShortDateFormat));
- GetTime;
- if (Hour <> 0) or (Min <> 0) or (Sec <> 0) then
- begin
- AppendChars(' ', 1);
- AppendFormat(Pointer(LongTimeFormat));
- end;
- end;
- '/':
- AppendChars(@DateSeparator, 1);
- ':':
- AppendChars(@TimeSeparator, 1);
- '''', '"':
- begin
- P := Format;
- while (Format^ <> #0) and (Format^ <> Starter) do Inc(Format);
- AppendChars(P, Format - P);
- if Format^ <> #0 then Inc(Format);
- end;
- else
- AppendChars(@Starter, 1);
- end;
- end;
- Dec(AppendLevel);
- end;
- end;
-
- begin
- BufPos := 0;
- AppendLevel := 0;
- if Format <> '' then AppendFormat(Pointer(Format)) else AppendFormat('C');
- SetString(Result, Buffer, BufPos);
- end;
-
- function DateToStr(Date: TDateTime): string;
- begin
- DateTimeToString(Result, ShortDateFormat, Date);
- end;
-
- function TimeToStr(Time: TDateTime): string;
- begin
- DateTimeToString(Result, LongTimeFormat, Time);
- end;
-
- function DateTimeToStr(DateTime: TDateTime): string;
- begin
- DateTimeToString(Result, '', DateTime);
- end;
-
- function FormatDateTime(const Format: string; DateTime: TDateTime): string;
- begin
- DateTimeToString(Result, Format, DateTime);
- end;
-
- { String to date/time conversions }
-
- type
- TDateOrder = (doMDY, doDMY, doYMD);
-
- procedure ScanBlanks(const S: string; var Pos: Integer);
- var
- I: Integer;
- begin
- I := Pos;
- while (I <= Length(S)) and (S[I] = ' ') do Inc(I);
- Pos := I;
- end;
-
- function ScanNumber(const S: string; var Pos: Integer;
- var Number: Word): Boolean;
- var
- I: Integer;
- N: Word;
- begin
- Result := False;
- ScanBlanks(S, Pos);
- I := Pos;
- N := 0;
- while (I <= Length(S)) and (S[I] in ['0'..'9']) and (N < 1000) do
- begin
- N := N * 10 + (Ord(S[I]) - Ord('0'));
- Inc(I);
- end;
- if I > Pos then
- begin
- Pos := I;
- Number := N;
- Result := True;
- end;
- end;
-
- function ScanString(const S: string; var Pos: Integer;
- const Symbol: string): Boolean;
- begin
- Result := False;
- if Symbol <> '' then
- begin
- ScanBlanks(S, Pos);
- if AnsiCompareText(Symbol, Copy(S, Pos, Length(Symbol))) = 0 then
- begin
- Inc(Pos, Length(Symbol));
- Result := True;
- end;
- end;
- end;
-
- function ScanChar(const S: string; var Pos: Integer; Ch: Char): Boolean;
- begin
- Result := False;
- ScanBlanks(S, Pos);
- if (Pos <= Length(S)) and (S[Pos] = Ch) then
- begin
- Inc(Pos);
- Result := True;
- end;
- end;
-
- function GetDateOrder(const DateFormat: string): TDateOrder;
- var
- I: Integer;
- begin
- I := 1;
- while I <= Length(DateFormat) do
- begin
- case Chr(Ord(DateFormat[I]) and $DF) of
- 'Y': Result := doYMD;
- 'M': Result := doMDY;
- 'D': Result := doDMY;
- else
- Inc(I);
- Continue;
- end;
- Exit;
- end;
- Result := doMDY;
- end;
-
- function ScanDate(const S: string; var Pos: Integer;
- var Date: TDateTime): Boolean;
- var
- DateOrder: TDateOrder;
- I: Integer;
- N1, N2, N3, Y, M, D: Word;
- begin
- Result := False;
- DateOrder := GetDateOrder(ShortDateFormat);
- if not (ScanNumber(S, Pos, N1) and ScanChar(S, Pos, DateSeparator) and
- ScanNumber(S, Pos, N2)) then Exit;
- if ScanChar(S, Pos, DateSeparator) then
- begin
- if not ScanNumber(S, Pos, N3) then Exit;
- case DateOrder of
- doMDY: begin Y := N3; M := N1; D := N2; end;
- doDMY: begin Y := N3; M := N2; D := N1; end;
- doYMD: begin Y := N1; M := N2; D := N3; end;
- end;
- if Y <= 99 then Inc(Y, CurrentYear div 100 * 100);
- end else
- begin
- Y := CurrentYear;
- if DateOrder = doDMY then
- begin
- D := N1; M := N2;
- end else
- begin
- M := N1; D := N2;
- end;
- end;
- ScanChar(S, Pos, DateSeparator);
- ScanBlanks(S, Pos);
- Result := DoEncodeDate(Y, M, D, Date);
- end;
-
- function ScanTime(const S: string; var Pos: Integer;
- var Time: TDateTime): Boolean;
- var
- BaseHour: Integer;
- Hour, Min, Sec: Word;
- begin
- Result := False;
- if not ScanNumber(S, Pos, Hour) then Exit;
- Min := 0;
- if ScanChar(S, Pos, TimeSeparator) then
- if not ScanNumber(S, Pos, Min) then Exit;
- Sec := 0;
- if ScanChar(S, Pos, TimeSeparator) then
- if not ScanNumber(S, Pos, Sec) then Exit;
- BaseHour := -1;
- if ScanString(S, Pos, TimeAMString) or ScanString(S, Pos, 'AM') then
- BaseHour := 0
- else
- if ScanString(S, Pos, TimePMString) or ScanString(S, Pos, 'PM') then
- BaseHour := 12;
- if BaseHour >= 0 then
- begin
- if (Hour = 0) or (Hour > 12) then Exit;
- if Hour = 12 then Hour := 0;
- Inc(Hour, BaseHour);
- end;
- ScanBlanks(S, Pos);
- Result := DoEncodeTime(Hour, Min, Sec, 0, Time);
- end;
-
- function StrToDate(const S: string): TDateTime;
- var
- Pos: Integer;
- begin
- Pos := 1;
- if not ScanDate(S, Pos, Result) or (Pos <= Length(S)) then
- ConvertErrorFmt(SInvalidDate, [S]);
- end;
-
- function StrToTime(const S: string): TDateTime;
- var
- Pos: Integer;
- begin
- Pos := 1;
- if not ScanTime(S, Pos, Result) or (Pos <= Length(S)) then
- ConvertErrorFmt(SInvalidTime, [S]);
- end;
-
- function StrToDateTime(const S: string): TDateTime;
- var
- Pos: Integer;
- Date, Time: TDateTime;
- begin
- Pos := 1;
- Time := 0;
- if not ScanDate(S, Pos, Date) or not ((Pos > Length(S)) or
- ScanTime(S, Pos, Time)) then
- ConvertErrorFmt(SInvalidDateTime, [S]);
- if Date >= 0 then
- Result := Date + Time else
- Result := Date - Time;
- end;
-
- { System error messages }
-
- function SysErrorMessage(ErrorCode: Integer): string;
- var
- Len: Integer;
- Buffer: array[0..255] of Char;
- begin
- Len := FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or
- FORMAT_MESSAGE_ARGUMENT_ARRAY, nil, ErrorCode, 0, Buffer,
- SizeOf(Buffer), nil);
- while (Len > 0) and (Buffer[Len - 1] in [#0..#32, '.']) do Dec(Len);
- SetString(Result, Buffer, Len);
- end;
-
- { Initialization file support }
-
- function GetLocaleStr(Locale, LocaleType: Integer; const Default: string): string;
- var
- L: Integer;
- Buffer: array[0..255] of Char;
- begin
- L := GetLocaleInfo(Locale, LocaleType, Buffer, SizeOf(Buffer));
- if L > 0 then SetString(Result, Buffer, L - 1) else Result := Default;
- end;
-
- function GetLocaleChar(Locale, LocaleType: Integer; Default: Char): Char;
- var
- Buffer: array[0..1] of Char;
- begin
- if GetLocaleInfo(Locale, LocaleType, Buffer, 2) > 0 then
- Result := Buffer[0] else
- Result := Default;
- end;
-
- procedure GetMonthDayNames;
- var
- I, Day: Integer;
- DefaultLCID: LCID;
- begin
- DefaultLCID := GetSystemDefaultLCID;
- for I := 1 to 12 do
- begin
- ShortMonthNames[I] := GetLocaleStr(DefaultLCID, LOCALE_SABBREVMONTHNAME1 + I - 1,
- LoadStr(I + (SShortMonthNames - 1)));
- LongMonthNames[I] := GetLocaleStr(DefaultLCID, LOCALE_SMONTHNAME1 + I - 1,
- LoadStr(I + (SLongMonthNames - 1)));
- end;
- for I := 1 to 7 do
- begin
- Day := (I + 5) mod 7;
- ShortDayNames[I] := GetLocaleStr(DefaultLCID, LOCALE_SABBREVDAYNAME1 + Day,
- LoadStr(I + (SShortDayNames - 1)));
- LongDayNames[I] := GetLocaleStr(DefaultLCID, LOCALE_SDAYNAME1 + Day,
- LoadStr(I + (SLongDayNames - 1)));
- end;
- end;
-
- procedure GetFormatSettings;
- var
- HourFormat, TimePostfix: string;
- DefaultLCID: LCID;
- begin
- DefaultLCID := GetSystemDefaultLCID;
- CurrencyString := GetLocaleStr(DefaultLCID, LOCALE_SCURRENCY, '');
- CurrencyFormat := StrToIntDef(GetLocaleStr(DefaultLCID, LOCALE_ICURRENCY, '0'), 0);
- NegCurrFormat := StrToIntDef(GetLocaleStr(DefaultLCID, LOCALE_INEGCURR, '0'), 0);
- ThousandSeparator := GetLocaleChar(DefaultLCID, LOCALE_STHOUSAND, ',');
- DecimalSeparator := GetLocaleChar(DefaultLCID, LOCALE_SDECIMAL, '.');
- CurrencyDecimals := StrToIntDef(GetLocaleStr(DefaultLCID, LOCALE_ICURRDIGITS, '0'), 0);
- DateSeparator := GetLocaleChar(DefaultLCID, LOCALE_SDATE, '/');
- ShortDateFormat := GetLocaleStr(DefaultLCID, LOCALE_SSHORTDATE, 'm/d/yy');
- LongDateFormat := GetLocaleStr(DefaultLCID, LOCALE_SLONGDATE, 'mmmm d, yyyy');
- TimeSeparator := GetLocaleChar(DefaultLCID, LOCALE_STIME, ':');
- TimeAMString := GetLocaleStr(DefaultLCID, LOCALE_S1159, 'am');
- TimePMString := GetLocaleStr(DefaultLCID, LOCALE_S2359, 'pm');
- if StrToIntDef(GetLocaleStr(DefaultLCID, LOCALE_ITLZERO, '0'), 0) = 0 then
- HourFormat := 'h' else
- HourFormat := 'hh';
- if StrToIntDef(GetLocaleStr(DefaultLCID, LOCALE_ITIME, '0'), 0) = 0 then
- TimePostfix := ' AMPM' else
- TimePostfix := '';
- ShortTimeFormat := HourFormat + ':mm' + TimePostfix;
- LongTimeFormat := HourFormat + ':mm:ss' + TimePostfix;
- end;
-
- { Exception handling routines }
-
- var
- OutOfMemory: EOutOfMemory;
-
- type
- PRaiseFrame = ^TRaiseFrame;
- TRaiseFrame = record
- NextRaise: PRaiseFrame;
- ExceptAddr: Pointer;
- ExceptObject: TObject;
- ExceptionRecord: PExceptionRecord;
- end;
-
- { Return current exception object }
-
- function ExceptObject: TObject;
- begin
- if RaiseList <> nil then
- Result := PRaiseFrame(RaiseList)^.ExceptObject else
- Result := nil;
- end;
-
- { Return current exception address }
-
- function ExceptAddr: Pointer;
- begin
- if RaiseList <> nil then
- Result := PRaiseFrame(RaiseList)^.ExceptAddr else
- Result := nil;
- end;
-
- { Convert physical address to logical address }
-
- function ConvertAddr(Address: Pointer): Pointer; assembler;
- asm
- TEST EAX,EAX { Always convert nil to nil }
- JE @@1
- SUB EAX,OFFSET TextStart
- @@1:
- end;
-
- { Display exception message box }
-
- procedure ShowException(ExceptObject: TObject; ExceptAddr: Pointer);
- var
- MsgPtr: PChar;
- MsgEnd: PChar;
- MsgLen: Integer;
- ModuleName: array[0..63] of Char;
- Temp: array[0..63] of Char;
- Buffer: array[0..255] of Char;
- begin
- GetModuleFileName(HInstance, Buffer, SizeOf(Buffer));
- StrLCopy(ModuleName, StrRScan(Buffer, '\') + 1, SizeOf(ModuleName) - 1);
- MsgPtr := '';
- MsgEnd := '';
- if ExceptObject is Exception then
- begin
- MsgPtr := PChar(Exception(ExceptObject).Message);
- MsgLen := StrLen(MsgPtr);
- if (MsgLen <> 0) and (MsgPtr[MsgLen - 1] <> '.') then MsgEnd := '.';
- end;
- LoadString(HInstance, SException, Temp, SizeOf(Temp));
- StrFmt(Buffer, Temp, [ExceptObject.ClassName, ModuleName,
- ConvertAddr(ExceptAddr), MsgPtr, MsgEnd]);
- LoadString(HInstance, SExceptTitle, Temp, SizeOf(Temp));
- if IsConsole then
- WriteLn(Buffer)
- else
- MessageBox(0, Buffer, Temp, MB_OK or MB_ICONSTOP or MB_TASKMODAL);
- end;
-
- { Raise abort exception }
-
- procedure Abort;
-
- function ReturnAddr: Pointer;
- asm
- MOV EAX,[ESP+4]
- end;
-
- begin
- raise EAbort.CreateRes(SOperationAborted) at ReturnAddr;
- end;
-
- { Raise out of memory exception }
-
- procedure OutOfMemoryError;
- begin
- raise OutOfMemory;
- end;
-
- { Exception class }
-
- constructor Exception.Create(const Msg: string);
- begin
- FMessage := Msg;
- end;
-
- constructor Exception.CreateFmt(const Msg: string;
- const Args: array of const);
- begin
- FMessage := Format(Msg, Args);
- end;
-
- constructor Exception.CreateRes(Ident: Integer);
- begin
- FMessage := LoadStr(Ident);
- end;
-
- constructor Exception.CreateResFmt(Ident: Integer;
- const Args: array of const);
- begin
- FMessage := Format(LoadStr(Ident), Args);
- end;
-
- constructor Exception.CreateHelp(const Msg: string; AHelpContext: Integer);
- begin
- FMessage := Msg;
- FHelpContext := AHelpContext;
- end;
-
- constructor Exception.CreateFmtHelp(const Msg: string; const Args: array of const;
- AHelpContext: Integer);
- begin
- FMessage := Format(Msg, Args);
- FHelpContext := AHelpContext;
- end;
-
- constructor Exception.CreateResHelp(Ident: Integer; AHelpContext: Integer);
- begin
- FMessage := LoadStr(Ident);
- FHelpContext := AHelpContext;
- end;
-
- constructor Exception.CreateResFmtHelp(Ident: Integer;
- const Args: array of const;
- AHelpContext: Integer);
- begin
- FMessage := Format(LoadStr(Ident), Args);
- FHelpContext := AHelpContext;
- end;
-
- { EOutOfMemory class }
-
- destructor EOutOfMemory.Destroy;
- begin
- end;
-
- procedure EOutOfMemory.FreeInstance;
- begin
- end;
-
- { Create I/O exception }
-
- function CreateInOutError: EInOutError;
- type
- TErrorRec = record
- Code: Integer;
- Ident: Integer;
- end;
- const
- ErrorMap: array[0..6] of TErrorRec = (
- (Code: 2; Ident: SFileNotFound),
- (Code: 3; Ident: SInvalidFilename),
- (Code: 4; Ident: STooManyOpenFiles),
- (Code: 5; Ident: SAccessDenied),
- (Code: 100; Ident: SEndOfFile),
- (Code: 101; Ident: SDiskFull),
- (Code: 106; Ident: SInvalidInput));
- var
- I: Integer;
- begin
- I := Low(ErrorMap);
- while (I <= High(ErrorMap)) and (ErrorMap[I].Code <> InOutRes) do Inc(I);
- if I <= High(ErrorMap) then
- Result := EInOutError.CreateRes(ErrorMap[I].Ident) else
- Result := EInOutError.CreateResFmt(SInOutError, [InOutRes]);
- Result.ErrorCode := InOutRes;
- InOutRes := 0;
- end;
-
- { RTL error handler }
-
- type
- TExceptRec = record
- EClass: ExceptClass;
- EIdent: Integer;
- end;
-
- const
- ExceptMap: array[2..21] of TExceptRec = (
- (EClass: EInvalidPointer; EIdent: SInvalidPointer),
- (EClass: EDivByZero; EIdent: SDivByZero),
- (EClass: ERangeError; EIdent: SRangeError),
- (EClass: EIntOverflow; EIdent: SIntOverflow),
- (EClass: EInvalidOp; EIdent: SInvalidOp),
- (EClass: EZeroDivide; EIdent: SZeroDivide),
- (EClass: EOverflow; EIdent: SOverflow),
- (EClass: EUnderflow; EIdent: SUnderflow),
- (EClass: EInvalidCast; EIdent: SInvalidCast),
- (EClass: EAccessViolation; EIdent: SAccessViolation),
- (EClass: EPrivilege; EIdent: SPrivilege),
- (EClass: EControlC; EIdent: SControlC),
- (EClass: EStackOverflow; EIdent: SStackOverflow),
- (EClass: EVariantError; EIdent: SInvalidVarCast),
- (EClass: EVariantError; EIdent: SInvalidVarOp),
- (EClass: EVariantError; EIdent: SDispatchError),
- (EClass: EVariantError; EIdent: SVarArrayCreate),
- (EClass: EVariantError; EIdent: SVarNotArray),
- (EClass: EVariantError; EIdent: SVarArrayBounds),
- (EClass: EExternalException; EIdent: SExternalException));
-
- procedure ErrorHandler(ErrorCode: Integer; ErrorAddr: Pointer);
- var
- E: Exception;
- begin
- case ErrorCode of
- 1: E := OutOfMemory;
- 2..20: with ExceptMap[ErrorCode] do E := EClass.CreateRes(EIdent);
- else
- E := CreateInOutError;
- end;
- raise E at ErrorAddr;
- end;
-
- function MapException(P: PExceptionRecord):Byte;
- begin
- case P.ExceptionCode of
- STATUS_INTEGER_DIVIDE_BY_ZERO: Result := 3;
- STATUS_ARRAY_BOUNDS_EXCEEDED: Result := 4;
- STATUS_INTEGER_OVERFLOW: Result := 5;
- STATUS_FLOAT_INEXACT_RESULT,
- STATUS_FLOAT_INVALID_OPERATION,
- STATUS_FLOAT_STACK_CHECK: Result := 6;
- STATUS_FLOAT_DIVIDE_BY_ZERO: Result := 7;
- STATUS_FLOAT_OVERFLOW: Result := 8;
- STATUS_FLOAT_UNDERFLOW,
- STATUS_FLOAT_DENORMAL_OPERAND: Result := 9;
- STATUS_ACCESS_VIOLATION: Result := 11;
- STATUS_PRIVILEGED_INSTRUCTION: Result := 12;
- STATUS_CONTROL_C_EXIT: Result := 13;
- STATUS_STACK_OVERFLOW: Result := 14;
- else Result := 21;
- end;
- end;
-
- function GetExceptionClass(P: PExceptionRecord):ExceptClass;
- var
- ErrorCode: Byte;
- begin
- ErrorCode := MapException(P);
- Result := ExceptMap[ErrorCode].EClass;
- end;
-
- function GetExceptionObject(P: PExceptionRecord):Exception;
- var
- ErrorCode: Integer;
- AccessOp: Integer; // string ID indicating the access type READ or WRITE
- AccessAddress: Pointer;
- begin
- ErrorCode := MapException(P);
- case ErrorCode of
- 3..10,12..20:
- with ExceptMap[ErrorCode] do Result := EClass.CreateRes(EIdent);
- 11:
- begin
- with P^ do
- begin
- if ExceptionInformation[0] = 0 then
- AccessOp := sReadAccess
- else AccessOp := sWriteAccess;
- AccessAddress := Pointer(ExceptionInformation[1]);
- Result := EAccessViolation.CreateResFmt(sAccessViolation,
- [ExceptionAddress, LoadStr(AccessOp), AccessAddress]);
- end;
- end;
- else
- Result := EExternalException.CreateResFmt(SExternalException,
- [P.ExceptionCode]);
- EExternalException(Result).ExceptionRecord := P;
- end;
- end;
-
- { RTL exception handler }
-
- procedure ExceptHandler(ExceptObject: TObject; ExceptAddr: Pointer); far;
- begin
- ShowException(ExceptObject, ExceptAddr);
- Halt(1);
- end;
-
- procedure InitExceptions;
- begin
- OutOfMemory := EOutOfMemory.CreateRes(SOutOfMemory);
- ErrorProc := @ErrorHandler;
- ExceptProc := @ExceptHandler;
- ExceptionClass := Exception;
- ExceptClsProc := @GetExceptionClass;
- ExceptObjProc := @GetExceptionObject;
- end;
-
- procedure InitPlatformId;
- var
- OSVersionInfo: TOSVersionInfo;
- begin
- OSVersionInfo.dwOSVersionInfoSize := SizeOf(OSVersionInfo);
- if GetVersionEx(OSVersionInfo) then
- Win32Platform := OSVersionInfo.dwPLatformId;
- end;
-
- procedure Beep;
- begin
- MessageBeep(0);
- end;
-
- begin
- InitExceptions;
- GetMonthDayNames;
- GetFormatSettings;
- InitPLatformId;
- end.
-
-