lazarus-ccr/components/orpheus/ovcintl.pas
2007-01-16 02:17:08 +00:00

1652 lines
48 KiB
ObjectPascal

{*********************************************************}
{* OVCINTL.PAS 4.06 *}
{*********************************************************}
{* ***** BEGIN LICENSE BLOCK ***** *}
{* Version: MPL 1.1 *}
{* *}
{* The contents of this file are subject to the Mozilla Public License *}
{* Version 1.1 (the "License"); you may not use this file except in *}
{* compliance with the License. You may obtain a copy of the License at *}
{* http://www.mozilla.org/MPL/ *}
{* *}
{* Software distributed under the License is distributed on an "AS IS" basis, *}
{* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License *}
{* for the specific language governing rights and limitations under the *}
{* License. *}
{* *}
{* The Original Code is TurboPower Orpheus *}
{* *}
{* The Initial Developer of the Original Code is TurboPower Software *}
{* *}
{* Portions created by TurboPower Software Inc. are Copyright (C)1995-2002 *}
{* TurboPower Software Inc. All Rights Reserved. *}
{* *}
{* Contributor(s): *}
{* *}
{* ***** END LICENSE BLOCK ***** *}
{$I OVC.INC}
{$B-} {Complete Boolean Evaluation}
{$I+} {Input/Output-Checking}
{$P+} {Open Parameters}
{$T-} {Typed @ Operator}
{.W-} {Windows Stack Frame}
{$X+} {Extended Syntax}
unit ovcintl;
{-International date/time support class}
interface
uses
{$IFNDEF LCL} Windows, Messages, {$ELSE} LclIntf, LMessages, LclType, MyMisc, {$ENDIF}
Registry, Classes, Forms, SysUtils, OvcConst, OvcData, OvcStr, OvcDate;
type
TCurrencySt = array[0..5] of AnsiChar;
{.Z+}
TIntlData = packed record
{substitution strings for semi-literal mask characters}
CurrencyLtStr : TCurrencySt; {corresponding string for 'c'}
CurrencyRtStr : TCurrencySt; {corresponding string for 'C'}
DecimalChar : AnsiChar; {character used for decimal point}
CommaChar : AnsiChar; {character used for comma}
{format specifiers for currency masks}
CurrDigits : Byte; {number of dec places in currency}
SlashChar : AnsiChar; {date seperator}
{characters that represent boolean values}
TrueChar : AnsiChar;
FalseChar : AnsiChar;
YesChar : AnsiChar;
NoChar : AnsiChar;
end;
{.Z-}
type
TOvcIntlSup = class(TObject)
{.Z+}
protected {private}
FAutoUpdate : Boolean; {true to reset settings when win.ini changes}
{substitution strings for semi-literal mask characters}
FCurrencyLtStr : TCurrencySt; {corresponding string for 'c'}
FCurrencyRtStr : TCurrencySt; {corresponding string for 'C'}
FDecimalChar : AnsiChar; {character used for decimal point}
{general international settings}
FCommaChar : AnsiChar; {character used for comma}
FCurrencyDigits : Byte; {number of dec places in currency}
FListChar : AnsiChar; {list serarater}
FSlashChar : AnsiChar; {character used to separate dates}
{characters that represent boolean values}
FTrueChar : AnsiChar;
FFalseChar : AnsiChar;
FYesChar : AnsiChar;
FNoChar : AnsiChar;
{event variables}
FOnWinIniChange : TNotifyEvent; {notify of win.ini changes}
{internal working variables}
intlHandle : hWnd; {our window handle}
w1159 : array[0..5] of AnsiChar;
w2359 : array[0..5] of AnsiChar;
wColonChar : AnsiChar;
wCountry : PAnsiChar;
wCurrencyForm : Byte;
wldSub1 : array[0..5] of AnsiChar;
wldSub2 : array[0..5] of AnsiChar;
wldSub3 : array[0..5] of AnsiChar;
wLongDate : array[0..39] of AnsiChar;
wNegCurrencyForm : Byte;
wShortDate : array[0..29] of AnsiChar;
wTLZero : Boolean;
w12Hour : Boolean;
{property methods}
function GetCountry : string;
function GetCurrencyLtStr : string;
function GetCurrencyRtStr : string;
procedure SetAutoUpdate(Value : Boolean);
procedure SetCurrencyLtStr(const Value : string);
procedure SetCurrencyRtStr(const Value : string);
{internal methods}
procedure isExtractFromPicture(Picture, S : PAnsiChar; Ch : AnsiChar;
var I : Integer; Blank, Default : Integer);
procedure isIntlWndProc(var Msg : TMessage);
function isMaskCharCount(P : PAnsiChar; MC : AnsiChar) : Word;
procedure isMergeIntoPicture(Picture : PAnsiChar; Ch : AnsiChar; I : Integer);
procedure isMergePictureSt(Picture, P : PAnsiChar; MC : AnsiChar; SP : PAnsiChar);
procedure isPackResult(Picture, S : PAnsiChar);
procedure isSubstChar(Picture : PAnsiChar; OldCh, NewCh : AnsiChar);
procedure isSubstCharSim(P : PAnsiChar; OC, NC : AnsiChar);
function isTimeToTimeStringPrim(Dest, Picture : PAnsiChar; T : TStTime;
Pack : Boolean; t1159, t2359 : PAnsiChar) : PAnsiChar;
public
constructor Create;
destructor Destroy;
override;
{.Z-}
function CurrentDateString(const Picture : string;
Pack : Boolean) : string;
{.Z+}
function CurrentDatePChar(Dest : PAnsiChar; Picture : PAnsiChar;
Pack : Boolean) : PAnsiChar;
{-returns today's date as a string of the specified form}
{.Z-}
function CurrentTimeString(const Picture : string; Pack : Boolean) : string;
{.Z+}
function CurrentTimePChar(Dest : PAnsiChar; Picture : PAnsiChar; Pack : Boolean) : PAnsiChar;
{-returns current time as a string of the specified form}
{.Z-}
function DateToDateString(const Picture : string; Julian : TStDate;
Pack : Boolean) : string;
{.Z+}
function DateToDatePChar(Dest : PAnsiChar; Picture : PAnsiChar; Julian : TStDate;
Pack : Boolean) : PAnsiChar;
{.Z-}
{-convert Julian to a string of the form indicated by Picture}
function DateStringToDMY(const Picture, S : string; var Day, Month, Year : Integer;
Epoch : Integer) : Boolean;
{.Z+}
function DatePCharToDMY(Picture, S : PAnsiChar; var Day, Month, Year : Integer;
Epoch : Integer) : Boolean;
{.Z-}
{-extract day, month, and year from S, returning true if string is valid}
function DateStringIsBlank(const Picture, S : string) : Boolean;
{.Z+}
function DatePCharIsBlank(Picture, S : PAnsiChar) : Boolean;
{.Z-}
{-return True if the month, day, and year in S are all blank}
function DateStringToDate(const Picture, S : string; Epoch : Integer) : TStDate;
{.Z+}
function DatePCharToDate(Picture, S : PAnsiChar; Epoch : Integer) : TStDate;
{.Z-}
{-convert St, a string of the form indicated by Picture, to a julian date. Picture and St must be of equal lengths}
function DayOfWeekToString(WeekDay : TDayType) : string;
{.Z+}
function DayOfWeekToPChar(Dest : PAnsiChar; WeekDay : TDayType) : PAnsiChar;
{.Z-}
{-return a string for the specified day of the week}
function DMYtoDateString(const Picture : string;
Day, Month, Year : Integer; Pack : Boolean; Epoch : Integer) : string;
{.Z+}
function DMYtoDatePChar(Dest : PAnsiChar; Picture : PAnsiChar;
Day, Month, Year : Integer; Pack : Boolean; Epoch : Integer) : PAnsiChar;
{.Z-}
{-merge the month, day, and year into the picture}
function InternationalCurrency(FormChar : AnsiChar; MaxDigits : Byte; Float,
AddCommas, IsNumeric : Boolean) : string;
{.Z+}
function InternationalCurrencyPChar(Dest : PAnsiChar; FormChar : AnsiChar;
MaxDigits : Byte; Float,
AddCommas, IsNumeric : Boolean) : PAnsiChar;
{.Z-}
{-return a picture mask for a currency string, based on Windows' intl info}
function InternationalDate(ForceCentury : Boolean) : string;
{.Z+}
function InternationalDatePChar(Dest : PAnsiChar; ForceCentury : Boolean) : PAnsiChar;
{.Z-}
{-return a picture mask for a short date string, based on Windows' international information}
function InternationalLongDate(ShortNames : Boolean; ExcludeDOW : Boolean) : string;
{.Z+}
function InternationalLongDatePChar(Dest : PAnsiChar; ShortNames : Boolean; ExcludeDOW : Boolean) : PAnsiChar;
{.Z-}
{-return a picture mask for a date string, based on Windows' international information}
function InternationalTime(ShowSeconds : Boolean) : string;
{.Z+}
function InternationalTimePChar(Dest : PAnsiChar; ShowSeconds : Boolean) : PAnsiChar;
{.Z-}
{-return a picture mask for a time string, based on Windows' international information}
function MonthStringToMonth(const S : string; Width : Byte) : Byte;
{.Z+}
function MonthPCharToMonth(S : PAnsiChar; Width : Byte) : Byte;
{.Z-}
{-Convert the month name in S to a month (1..12)}
function MonthToString(Month : Integer) : string;
{.Z+}
function MonthToPChar(Dest : PAnsiChar; Month : Integer) : PAnsiChar;
{.Z-}
{return month name as a string for Month}
procedure ResetInternationalInfo;
{-read string resources and update internal info to match Windows'}
function TimeStringToHMS(const Picture, S : string; var Hour, Minute, Second : Integer) : Boolean;
{.Z+}
function TimePCharToHMS(Picture, S : PAnsiChar; var Hour, Minute, Second : Integer) : Boolean;
{.Z-}
{-extract Hours, Minutes, Seconds from St, returning true if string is valid}
function TimeStringToTime(const Picture, S : string) : TStTime;
{.Z+}
function TimePCharToTime(Picture, S : PAnsiChar) : TStTime;
{.Z-}
{-convert S, a string of the form indicated by Picture, to a Time variable}
function TimeToTimeString(const Picture : string; T : TStTime; Pack : Boolean) : string;
{.Z+}
function TimeToTimePChar(Dest : PAnsiChar; Picture : PAnsiChar; T : TStTime; Pack : Boolean) : PAnsiChar;
{.Z-}
{-convert T to a string of the form indicated by Picture}
function TimeToAmPmString(const Picture : string; T : TStTime; Pack : Boolean) : string;
{.Z+}
function TimeToAmPmPChar(Dest : PAnsiChar; Picture : PAnsiChar; T : TStTime; Pack : Boolean) : PAnsiChar;
{.Z-}
{-convert T to a string of the form indicated by Picture. Times are always displayed in am/pm format.}
property AutoUpdate : Boolean
read FAutoUpdate write SetAutoUpdate;
property CurrencyLtStr : string
read GetCurrencyLtStr write SetCurrencyLtStr;
property CurrencyRtStr : string
read GetCurrencyRtStr write SetCurrencyRtStr;
property DecimalChar : AnsiChar
read FDecimalChar write FDecimalChar;
property CommaChar : AnsiChar
read FCommaChar write FCommaChar;
property Country : string
read GetCountry;
property CurrencyDigits : Byte
read FCurrencyDigits write FCurrencyDigits;
property ListChar : AnsiChar
read FListChar write FListChar;
property SlashChar : AnsiChar
read FSlashChar write FSlashChar;
property TrueChar : AnsiChar
read FTrueChar write FTrueChar;
property FalseChar : AnsiChar
read FFalseChar write FFalseChar;
property YesChar : AnsiChar
read FYesChar write FYesChar;
property NoChar : AnsiChar
read FNoChar write FNoChar;
property OnWinIniChange : TNotifyEvent
read FOnWinIniChange write FOnWinIniChange;
end;
const
DefaultIntlData : TIntlData = (
{substitution strings for semi-literal mask characters}
CurrencyLtStr : '$'; {corresponding string for 'c'}
CurrencyRtStr : ''; {corresponding string for 'C'}
DecimalChar : '.'; {character used for decimal point}
CommaChar : ','; {character used for comma}
{format specifiers for currency masks}
CurrDigits : 2; {number of dec places in currency}
SlashChar : '/'; {date seperator}
{characters that represent boolean values}
TrueChar : 'T';
FalseChar : 'F';
YesChar : 'Y';
NoChar : 'N');
var
{global default international support object}
OvcIntlSup : TOvcIntlSup;
implementation
{*** Inline routines ***}
{$IFDEF NoAsm}
function GetMaxWord(A, B : Word) : Word;
begin
if A >= B then
Result := A
else
Result := B;
end;
{$ELSE}
function GetMaxWord(A, B : Word) : Word; register;
{-Return the greater of A and B}
asm
and eax,0FFFFH {faster than movzx }
and edx,0FFFFH {faster than movzx }
cmp eax,edx {compare A and B }
jae @@001 {done if ax is greater or equal }
mov eax,edx {dx is larger, set result }
@@001:
end;
{$ENDIF}
{*** TOvcIntlSup ***}
constructor TOvcIntlSup.Create;
begin
inherited Create;
FAutoUpdate := False;
{substitution strings for semi-literal mask characters}
StrCopy(FCurrencyLtStr, DefaultIntlData.CurrencyLtStr);
StrCopy(FCurrencyRtStr, DefaultIntlData.CurrencyRtStr);
FDecimalChar := DefaultIntlData.DecimalChar;
FCommaChar := DefaultIntlData.CommaChar;
{format specifiers for currency masks}
FCurrencyDigits := DefaultIntlData.CurrDigits;
FSlashChar := DefaultIntlData.SlashChar;
{characters that represent boolean values}
FTrueChar := DefaultIntlData.TrueChar;
FFalseChar := DefaultIntlData.FalseChar;
FYesChar := DefaultIntlData.YesChar;
FNoChar := DefaultIntlData.NoChar;
{get windows international information}
ResetInternationalInfo;
end;
function TOvcIntlSup.CurrentDateString(const Picture : string;
Pack : Boolean) : string;
{-returns today's date as a string of the specified form}
begin
Result := DateToDateString(Picture, CurrentDate, Pack);
end;
function TOvcIntlSup.CurrentDatePChar(Dest : PAnsiChar; Picture : PAnsiChar;
Pack : Boolean) : PAnsiChar;
{-returns today's date as a string of the specified form}
begin
Result := DateToDatePChar(Dest, Picture, CurrentDate, Pack);
end;
function TOvcIntlSup.CurrentTimeString(const Picture : string; Pack : Boolean) : string;
{-returns current time as a string of the specified form}
begin
Result := TimeToTimeString(Picture, CurrentTime, Pack);
end;
function TOvcIntlSup.CurrentTimePChar(Dest : PAnsiChar; Picture : PAnsiChar; Pack : Boolean) : PAnsiChar;
{-returns current time as a string of the specified form}
begin
Result := TimeToTimePChar(Dest, Picture, CurrentTime, Pack);
end;
function TOvcIntlSup.DateStringIsBlank(const Picture, S : string) : Boolean;
{-return True if the month, day, and year in S are all blank}
var
Buf1 : array[0..255] of AnsiChar;
Buf2 : array[0..255] of AnsiChar;
begin
StrPCopy(Buf1, Picture);
StrPCopy(Buf2, S);
Result := DatePCharIsBlank(Buf1, Buf2);
end;
function TOvcIntlSup.DatePCharIsBlank(Picture, S : PAnsiChar) : Boolean;
{-return True if the month, day, and year in S are all blank}
var
M, D, Y : Integer;
begin
isExtractFromPicture(Picture, S, pmMonthName, M, -2, 0);
if M = 0 then
isExtractFromPicture(Picture, S, pmMonth, M, -2, -2);
isExtractFromPicture(Picture, S, pmDay, D, -2, -2);
isExtractFromPicture(Picture, S, pmYear, Y, -2, -2);
Result := (M = -2) and (D = -2) and (Y = -2);
end;
function TOvcIntlSup.DateStringToDate(const Picture, S : string; Epoch : Integer) : TStDate;
{-convert St, a string of the form indicated by Picture, to a julian date.
Picture and St must be of equal lengths}
var
Buf1 : array[0..255] of AnsiChar;
Buf2 : array[0..255] of AnsiChar;
begin
StrPCopy(Buf1, Picture);
StrPCopy(Buf2, S);
Result := DatePCharToDate(Buf1, Buf2, Epoch);
end;
function TOvcIntlSup.DatePCharToDate(Picture, S : PAnsiChar; Epoch : Integer) : TStDate;
{-convert St, a string of the form indicated by Picture, to a julian date.
Picture and St must be of equal lengths}
var
Month, Day, Year : Integer;
begin
{extract day, month, year from St}
if DatePCharToDMY(Picture, S, Day, Month, Year, Epoch) then
{convert to julian date}
Result := DMYtoStDate(Day, Month, Year, Epoch)
else
Result := BadDate;
end;
function TOvcIntlSup.DateStringToDMY(const Picture, S : string; var Day, Month, Year : Integer;
Epoch : Integer) : Boolean;
{-extract day, month, and year from S, returning true if string is valid}
var
Buf1 : array[0..255] of AnsiChar;
Buf2 : array[0..255] of AnsiChar;
begin
StrPCopy(Buf1, Picture);
StrPCopy(Buf2, S);
Result := DatePCharToDMY(Buf1, Buf2, Day, Month, Year, Epoch);
end;
function TOvcIntlSup.DatePCharToDMY(Picture, S : PAnsiChar; var Day, Month, Year : Integer;
Epoch : Integer) : Boolean;
{-extract day, month, and year from S, returning true if string is valid}
begin
Result := False;
if StrLen(Picture) <> StrLen(S) then
Exit;
isExtractFromPicture(Picture, S, pmMonthName, Month, -1, 0);
if Month = 0 then
isExtractFromPicture(Picture, S, pmMonth, Month, -1, DefaultMonth);
isExtractFromPicture(Picture, S, pmDay, Day, -1, 1);
isExtractFromPicture(Picture, S, pmYear, Year, -1, DefaultYear);
Result := ValidDate(Day, Month, Year, Epoch);
end;
function TOvcIntlSup.DateToDateString(const Picture : string;
Julian : TStDate; Pack : Boolean) : string;
{-convert Julian to a string of the form indicated by Picture}
var
Buf1 : array[0..255] of AnsiChar;
Buf2 : array[0..255] of AnsiChar;
begin
StrPCopy(Buf1, Picture);
Result := StrPas(DateToDatePChar(Buf2, Buf1, Julian, Pack));
end;
function TOvcIntlSup.DateToDatePChar(Dest : PAnsiChar; Picture : PAnsiChar;
Julian : TStDate; Pack : Boolean) : PAnsiChar;
{-convert Julian to a string of the form indicated by Picture}
var
Month, Day, Year : Integer;
begin
Move(Picture[0], Dest[0], StrLen(Picture)+1);
if Julian = BadDate then begin
{map picture characters to spaces}
isSubstChar(Dest, pmMonth, ' ');
isSubstChar(Dest, pmMonthName, ' ');
isSubstChar(Dest, pmDay, ' ');
isSubstChar(Dest, pmYear, ' ');
isSubstChar(Dest, pmWeekDay, ' ');
isMergePictureSt(Picture, Dest, pmLongDateSub1, wldSub1);
isMergePictureSt(Picture, Dest, pmLongDateSub2, wldSub2);
isMergePictureSt(Picture, Dest, pmLongDateSub3, wldSub3);
{map slashes}
isSubstChar(Dest, pmDateSlash, SlashChar);
Result := Dest;
end else begin
{convert Julian to day/month/year}
StDateToDMY(Julian, Day, Month, Year);
{merge the month, day, and year into the picture}
Result := DMYtoDatePChar(Dest, Picture, Day, Month, Year, Pack, 0);
end;
end;
function TOvcIntlSup.DayOfWeekToString(WeekDay : TDayType) : string;
{-return the day of the week specified by WeekDay as a string. Will
honor the international names as specified in the INI file.}
begin
Result := LongDayNames[Ord(WeekDay)+1];
end;
function TOvcIntlSup.DayOfWeekToPChar(Dest : PAnsiChar; WeekDay : TDayType) : PAnsiChar;
{-return the day of the week specified by WeekDay as a string in Dest. Will
honor the international names as specified in the INI file.}
begin
Result := Dest;
StrPCopy(Dest, LongDayNames[Ord(WeekDay)+1]);
end;
destructor TOvcIntlSup.Destroy;
begin
{$IFNDEF LCL}
if intlHandle <> 0 then
{$IFDEF VERSION6}
Classes.DeallocateHWnd(intlHandle);
{$ELSE}
DeallocateHWnd(intlHandle);
{$ENDIF}
{$ENDIF}
StrDispose(wCountry);
inherited Destroy;
end;
function TOvcIntlSup.DMYtoDateString(const Picture : string; Day, Month,
Year : Integer; Pack : Boolean; Epoch : Integer) : string;
{-merge the month, day, and year into the picture}
var
Buf1 : array[0..255] of AnsiChar;
Buf2 : array[0..255] of AnsiChar;
begin
StrPCopy(Buf1, Picture);
Result := StrPas(DMYtoDatePChar(Buf2, Buf1, Day, Month, Year, Pack, Epoch));
end;
function TOvcIntlSup.DMYtoDatePChar(Dest : PAnsiChar; Picture : PAnsiChar; Day, Month,
Year : Integer; Pack : Boolean; Epoch : Integer) : PAnsiChar;
{-merge the month, day, and year into the picture}
var
DOW : Integer;
EpochCent : Integer;
begin
Move(Picture[0], Dest[0], StrLen(Picture)+1);
EpochCent := (Epoch div 100)*100;
if Word(Year) < 100 then begin
if Year < (Epoch mod 100) then
Inc(Year, EpochCent + 100)
else
Inc(Year, EpochCent)
end;
DOW := Integer(DayOfWeekDMY(Day, Month, Year, Epoch));
isMergeIntoPicture(Dest, pmMonth, Month);
isMergeIntoPicture(Dest, pmDay, Day);
isMergeIntoPicture(Dest, pmYear, Year);
isMergeIntoPicture(Dest, pmMonthName, Month);
isMergeIntoPicture(Dest, pmWeekDay, DOW);
{map slashes}
isSubstChar(Dest, pmDateSlash, SlashChar);
isMergePictureSt(Picture, Dest, pmLongDateSub1, wldSub1);
isMergePictureSt(Picture, Dest, pmLongDateSub2, wldSub2);
isMergePictureSt(Picture, Dest, pmLongDateSub3, wldSub3);
if Pack then
isPackResult(Picture, Dest);
Result := Dest;
end;
function TOvcIntlSup.GetCountry : string;
{-return the country setting}
begin
Result := StrPas(wCountry);
end;
function TOvcIntlSup.GetCurrencyLtStr : string;
begin
Result := StrPas(FCurrencyLtStr);
end;
function TOvcIntlSup.GetCurrencyRtStr : string;
begin
Result := StrPas(FCurrencyRtStr);
end;
function TOvcIntlSup.InternationalCurrency(FormChar : AnsiChar; MaxDigits : Byte; Float,
AddCommas, IsNumeric : Boolean) : string;
{-Return a picture mask for a currency string, based on Windows' intl info}
var
Buf1 : array[0..255] of AnsiChar;
begin
Result := StrPas(InternationalCurrencyPChar(Buf1, FormChar, MaxDigits,
Float, AddCommas, IsNumeric));
end;
function TOvcIntlSup.InternationalCurrencyPChar(Dest : PAnsiChar; FormChar : AnsiChar;
MaxDigits : Byte; Float, AddCommas, IsNumeric : Boolean) : PAnsiChar;
{-Return a picture mask for a currency string, based on Windows' intl info}
const
NP : array[0..1] of AnsiChar = pmNegParens+#0;
NH : array[0..1] of AnsiChar = pmNegHere+#0;
var
CLSlen, DLen, I, J : Word;
Tmp : array[0..10] of AnsiChar;
begin
Dest[0] := #0;
Result := Dest;
if (MaxDigits = 0) then
Exit;
{initialize Dest with the numeric part of the string to left of decimal point}
I := Pred(MaxDigits) div 3 ;
J := Word(MaxDigits)+(I*Ord(AddCommas));
if J > 247 then
DLen := 247
else
DLen := J;
FillChar(Dest[0], DLen, FormChar);
Dest[DLen] := #0;
if AddCommas then begin
{insert commas at appropriate points}
J := 0;
for I := DLen-1 downto 0 do
if J < 3 then
Inc(J)
else begin
Dest[I] := pmComma;
J := 0;
end;
end;
{add in the decimals}
if CurrencyDigits > 0 then begin
Dest[DLen] := pmDecimalPt;
FillChar(Dest[DLen+1], CurrencyDigits, FormChar);
Inc(DLen, CurrencyDigits+1);
Dest[DLen] := #0;
end;
{do we need a minus before the currency symbol}
if (wNegCurrencyForm = 6) then
StrCat(Dest, NH);
{see if we can do a floating currency symbol}
if Float then
Float := not Odd(wCurrencyForm);
{plug in the picture characters for the currency symbol}
CLSlen := StrLen(FCurrencyLtStr);
if Float then
StrStInsertPrim(Dest, CharStrPChar(Tmp, pmFloatDollar, CLSlen), 0)
else if not Odd(wCurrencyForm) then
StrStInsertPrim(Dest, CharStrPChar(Tmp, pmCurrencyLt, CLSlen), 0)
else
StrCat(Dest, CharStrPChar(Tmp, pmCurrencyRt, StrLen(FCurrencyRtStr)));
{plug in special minus characters}
if IsNumeric then
case wNegCurrencyForm of
0, 4 :
StrCat(Dest, NP);
3, 7, 10 :
if Odd(wCurrencyForm) then
StrCat(Dest, NH);
end;
end;
function TOvcIntlSup.InternationalDate(ForceCentury : Boolean) : string;
{-return a picture mask for a short date string, based on Windows' international information}
var
Buf : array[0..255] of AnsiChar;
begin
InternationalDatePChar(Buf, ForceCentury);
Result := StrPas(Buf);
end;
function TOvcIntlSup.InternationalDatePChar(Dest : PAnsiChar;
ForceCentury : Boolean) : PAnsiChar;
{-return a picture mask for a date string, based on Windows' int'l info}
procedure FixMask(MC : AnsiChar; DL : Integer);
var
I : Cardinal;
J, AL : Word;
MCT : AnsiChar;
Found : Boolean;
begin
{find number of matching characters}
MCT := MC;
Found := StrChPos(Dest, MC, I);
if not Found then begin
MCT := UpCase(MC);
Found := StrChPos(Dest, MCT, I);
end;
if not Found then
Exit;
{pad substring to desired length}
AL := isMaskCharCount(Dest, MCT);
if AL < DL then
for J := 1 to DL-AL do
StrChInsertPrim(Dest, MCT, I);
if MC <> pmYear then
{choose blank/zero padding}
case AL of
1 : if MCT = MC then
isSubstCharSim(Dest, MCT, UpCase(MCT));
2 : if MCT <> MC then
isSubstCharSim(Dest, MCT, MC);
end;
end;
begin
{copy Windows mask into our var}
StrCopy(Dest, wShortDate);
{if single Day marker, make double}
FixMask(pmDay, 2);
{if single Month marker, make double}
FixMask(pmMonth, 2);
{force yyyy if desired}
FixMask(pmYear, 2 shl Ord(ForceCentury));
Result := Dest;
end;
function TOvcIntlSup.InternationalLongDate(ShortNames : Boolean; ExcludeDOW : Boolean) : string;
{-return a picture mask for a date string, based on Windows' int'l info}
var
Buf : array[0..255] of AnsiChar;
begin
Result := StrPas(InternationalLongDatePChar(Buf, ShortNames, ExcludeDOW));
end;
function TOvcIntlSup.InternationalLongDatePChar(Dest : PAnsiChar; ShortNames : Boolean;
ExcludeDOW : Boolean) : PAnsiChar;
{-return a picture mask for a date string, based on Windows' int'l info}
var
I : Cardinal;
WC : Word;
Temp : array[0..80] of AnsiChar;
Stop : Boolean;
function LongestMonthName : Word;
var
I : Word;
begin
Result := 0;
for I := 1 to 12 do
Result := GetMaxWord(Result, Length(LongMonthNames[I]));
end;
function LongestDayName : Word;
var
D : TDayType;
begin
Result := 0;
for D := Sunday to Saturday do
Result := GetMaxWord(Result, Length(LongDayNames[Ord(D)+1]));
end;
procedure FixMask(MC : AnsiChar; DL : Integer);
var
I : Cardinal;
J, AL : Word;
MCT : AnsiChar;
Found : Boolean;
begin
{find first matching mask character}
MCT := MC;
Found := StrChPos(Temp, MC, I);
if not Found then begin
MCT := UpCase(MC);
Found := StrChPos(Temp, MCT, I);
end;
if not Found then
Exit;
{pad substring to desired length}
AL := isMaskCharCount(Temp, MCT);
if AL < DL then begin
for J := 1 to DL-AL do
StrChInsertPrim(Temp, MCT, I);
end else if (AL > DL) then
StrStDeletePrim(Temp, I, AL-DL);
if MC <> pmYear then
{choose blank/zero padding}
case AL of
1 : if MCT = MC then
isSubstCharSim(Temp, MCT, UpCase(MCT));
2 : if MCT <> MC then
isSubstCharSim(Temp, MCT, MC);
end;
end;
begin
{copy Windows mask into temporary var}
StrCopy(Temp, wLongDate);
if ExcludeDOW then begin
{remove day-of-week and any junk that follows}
if StrChPos(Temp, pmWeekDay, I) then begin
WC := 1;
Stop := False;
repeat
case LoCaseChar(Temp[I+WC]) of
#0, pmMonth, pmDay, pmYear, pmMonthName : Stop := True;
else
Inc(WC);
end;
until Stop;
StrStDeletePrim(Temp, I, WC);
end;
end else if ShortNames then
FixMask(pmWeekDay, 3)
else if isMaskCharCount(Temp, pmWeekday) = 4 then
FixMask(pmWeekDay, LongestDayName);
{fix month names}
if ShortNames then
FixMask(pmMonthName, 3)
else if isMaskCharCount(Temp, pmMonthName) = 4 then
FixMask(pmMonthName, LongestMonthName);
{if single Day marker, make double}
FixMask(pmDay, 2);
{if single Month marker, make double}
FixMask(pmMonth, 2);
{force yyyy}
FixMask(pmYear, 4);
{copy result into Dest}
StrCopy(Dest, Temp);
Result := Dest;
end;
function TOvcIntlSup.InternationalTime(ShowSeconds : Boolean) : string;
{-return a picture mask for a time string, based on Windows' int'l info}
var
Buf : array[0..255] of AnsiChar;
begin
Result := StrPas(InternationalTimePChar(Buf, ShowSeconds));
end;
function TOvcIntlSup.InternationalTimePChar(Dest : PAnsiChar; ShowSeconds : Boolean) : PAnsiChar;
{-return a picture mask for a time string, based on Windows' int'l info}
var
SL, ML : Word;
S : array[0..20] of AnsiChar;
begin
{format the default string}
StrCopy(S, 'hh:mm:ss');
if not wTLZero then
S[0] := pmHourU;
{show seconds?}
if not ShowSeconds then
S[5] := #0;
{handle international AM/PM markers}
if w12Hour then begin
ML := GetMaxWord(StrLen(@w1159), StrLen(@w2359));
if (ML <> 0) then begin
SL := StrLen(S);
S[SL] := ' ';
FillChar(S[SL+1], ML, pmAmPm);
S[SL+ML+1] := #0;
end;
end;
StrCopy(Dest, S);
Result := Dest;
end;
procedure TOvcIntlSup.isIntlWndProc(var Msg : TMessage);
{-window procedure to catch WM_WININICHANGE messages}
begin
with Msg do
if AutoUpdate and (Msg = WM_WININICHANGE) then
try
if Assigned(FOnWinIniChange) then
FOnWinIniChange(Self)
else
ResetInternationalInfo;
except
Application.HandleException(Self);
end
else
Result := DefWindowProc(intlHandle, Msg, wParam, lParam);
end;
procedure TOvcIntlSup.isExtractFromPicture(Picture, S : PAnsiChar;
Ch : AnsiChar; var I : Integer;
Blank, Default : Integer);
{-extract the value of the subfield specified by Ch from S and return in
I. I will be set to -1 in case of an error, Blank if the subfield exists
in Picture but is empty, Default if the subfield doesn't exist in
Picture.}
var
PTmp : Array[0..20] of AnsiChar;
J, K, W : Cardinal;
Code : Integer;
Found,
UpFound : Boolean;
begin
{find the start of the subfield}
I := Default;
Found := StrChPos(Picture, Ch, J);
Ch := UpCaseChar(Ch);
UpFound := StrChPos(Picture, Ch, K);
if not Found or (UpFound and (K < J)) then begin
J := K;
Found := UpFound;
end;
if not Found or (StrLen(S) <> StrLen(Picture)) then
Exit;
{extract the substring}
PTmp[0] := #0;
W := 0;
K := 0;
while (UpCaseChar(Picture[J]) = Ch) and (J < StrLen(Picture)) do begin
if S[J] <> ' ' then begin
PTmp[k] := S[J];
Inc(K);
PTmp[k] := #0;
end;
Inc(J);
Inc(W);
end;
if StrLen(PTmp) = 0 then
I := Blank
else if Ch = pmMonthNameU then begin
I := MonthPCharToMonth(PTmp, W);
if I = 0 then
I := -1;
end else begin
{convert to a value}
Val(PTmp, I, Code);
if Code <> 0 then
I := -1;
end;
end;
function TOvcIntlSup.isMaskCharCount(P : PAnsiChar; MC : AnsiChar) : Word;
{-return the number of mask characters (MC) in P}
var
I : Cardinal;
begin
if StrChPos(P, MC, I) then begin
Result := 1;
while P[I+Result] = MC do
Inc(Result);
end else
Result := 0;
end;
procedure TOvcIntlSup.isMergePictureSt(Picture, P : PAnsiChar; MC : AnsiChar; SP : PAnsiChar);
var
I, J : Cardinal;
begin
if not StrChPos(Picture, MC, I) then
Exit;
J := 0;
while Picture[I] = MC do begin
if SP[J] = #0 then
P[I] := ' '
else begin
P[I] := SP[J];
Inc(J);
end;
Inc(I);
end;
end;
procedure TOvcIntlSup.isMergeIntoPicture(Picture : PAnsiChar; Ch : AnsiChar;
I : Integer);
{-merge I into location in Picture indicated by format character Ch}
var
Tmp : string[MaxDateLen];
TLen : Byte absolute Tmp;
J : Cardinal;
K, L : Word;
UCh, CPJ, CTI : AnsiChar;
Done : Boolean;
begin
{find the start of the subfield}
UCh := UpCaseChar(Ch);
if not StrChPos(Picture, Ch, J) then
if not StrChPos(Picture, UCh, J) then
Exit;
{find the end of the subfield}
K := J;
while (J < StrLen(Picture)) and (UpCaseChar(Picture[J]) = UCh) do
Inc(J);
Dec(J);
if (UCh = pmWeekDayU) or (UCh = pmMonthNameU) then begin
if UCh = pmWeekDayU then
case I of
Ord(Sunday)..Ord(Saturday) :
Tmp := LongDayNames[I+1];
else
Tmp := '';
end
else
case I of
1..12 :
Tmp := LongMonthNames[I];
else
Tmp := '';
end;
K := Succ(J-K);
if K > TLen then
FillChar(Tmp[TLen+1], K-TLen, ' ');
TLen := K;
end else
{convert I to a string}
Str(I:MaxDateLen, Tmp);
{now merge}
L := TLen;
Done := False;
CPJ := Picture[J];
while (UpCaseChar(CPJ) = UCh) and not Done do begin
CTI := Tmp[L];
if (UCh = pmMonthNameU) or (UCh = pmWeekDayU) then begin
case CPJ of
pmMonthNameU, pmWeekDayU :
CTI := UpCaseChar(CTI);
end;
end
{change spaces to 0's if desired}
else if (CPJ >= 'a') and (CTI = ' ') then
CTI := '0';
Picture[J] := CTI;
Done := (J = 0) or (L = 0);
if not Done then begin
Dec(J);
Dec(L);
end;
CPJ := Picture[J];
end;
end;
procedure TOvcIntlSup.isPackResult(Picture, S : PAnsiChar);
{-remove unnecessary blanks from S}
var
Temp : array[0..80] of AnsiChar;
I, J : Integer;
begin
FillChar(Temp, SizeOf(Temp), #0);
I := 0;
J := 0;
while Picture[I] <> #0 do begin
case Picture[I] of
pmMonthU, pmDayU, pmMonthName, pmMonthNameU, pmWeekDay,
pmWeekDayU, pmHourU, {pmMinU,} pmSecondU :
if S[I] <> ' ' then begin
Temp[J] := S[I];
Inc(J);
end;
pmAmPm :
if S[I] <> ' ' then begin
Temp[J] := S[I];
Inc(J);
end
else if (I > 0) and (Picture[I-1] = ' ') then begin
Dec(J);
Temp[J] := #0;
end;
else
Temp[J] := S[I];
Inc(J);
end;
Inc(I);
end;
StrCopy(S, Temp);
end;
procedure TOvcIntlSup.isSubstChar(Picture : PAnsiChar; OldCh, NewCh : AnsiChar);
{-replace all instances of OldCh in Picture with NewCh}
var
I : Byte;
UpCh : AnsiChar;
Temp : Cardinal;
begin
UpCh := UpCaseChar(OldCh);
if StrChPos(Picture, OldCh, Temp) or
StrChPos(Picture, UpCh, Temp) then
for I := 0 to StrLen(Picture)-1 do
if UpCaseChar(Picture[I]) = UpCh then
Picture[I] := NewCh;
end;
procedure TOvcIntlSup.isSubstCharSim(P : PAnsiChar; OC, NC : AnsiChar);
begin
while P^ <> #0 do begin
if P^ = OC then
P^ := NC;
Inc(P);
end;
end;
function TOvcIntlSup.isTimeToTimeStringPrim(Dest, Picture : PAnsiChar;
T : TStTime; Pack : Boolean;
t1159, t2359 : PAnsiChar) : PAnsiChar;
{-convert T to a string of the form indicated by Picture}
var
I : Word;
Hours : Byte;
Minutes : Byte;
Seconds : Byte;
P : PAnsiChar;
TPos : Cardinal;
Found : Boolean;
begin
{merge the hours, minutes, and seconds into the picture}
StTimeToHMS(T, Hours, Minutes, Seconds);
StrCopy(Dest, Picture);
P := nil;
{check for TimeOnly}
Found := StrChPos(Dest, pmAmPm, TPos);
if Found then begin
if (Hours >= 12) then
P := t2359
else
P := t1159;
if (t1159[0] <> #0) and (t2359[0] <> #0) then begin
{adjust hours}
case Hours of
0 : Hours := 12;
13..23 : Dec(Hours, 12);
end;
end;
end;
if T = BadTime then begin
{map picture characters to spaces}
isSubstChar(Dest, pmHour, ' ');
isSubstChar(Dest, pmMinute, ' ');
isSubstChar(Dest, pmSecond, ' ');
end else begin
{merge the numbers into the picture}
isMergeIntoPicture(Dest, pmHour, Hours);
isMergeIntoPicture(Dest, pmMinute, Minutes);
isMergeIntoPicture(Dest, pmSecond, Seconds);
end;
{map colons}
isSubstChar(Dest, pmTimeColon, wColonChar);
{plug in AM/PM string if appropriate}
if Found then begin
if (t1159[0] = #0) and (t2359[0] = #0) then
isSubstCharSim(@Dest[TPos], pmAmPm, ' ')
else if (T = BadTime) and (t1159[0] = #0) then
isSubstCharSim(@Dest[TPos], pmAmPm, ' ')
else begin
I := 0;
while (Dest[TPos] = pmAmPm) and (P[I] <> #0) do begin
Dest[TPos] := P[I];
Inc(I);
Inc(TPos);
end;
end;
end;
if Pack and (T <> BadTime) then
isPackResult(Picture, Dest);
Result := Dest;
end;
function TOvcIntlSup.MonthStringToMonth(const S : string; Width : Byte) : Byte;
{-Convert the month name in MSt to a month (1..12)}
var
I : Word;
Mt : string[MaxDateLen];
MLen : Byte absolute Mt;
St : string[MaxDateLen];
SLen : Byte absolute St;
begin
Result := 0;
Mt := AnsiUpperCase(S);
if Width > MLen then
FillChar(Mt[MLen+1], Width-MLen, ' ');
MLen := Width;
for I := 1 to 12 do begin
St := AnsiUpperCase(LongMonthNames[I]);
if Width > SLen then
FillChar(St[SLen+1], Width-SLen, ' ');
SLen := Width;
if Mt = St then begin
Result := I;
Break;
end;
end;
end;
function TOvcIntlSup.MonthPCharToMonth(S : PAnsiChar; Width : Byte) : Byte;
{-convert the month name in S to a month (1..12)}
var
I : Word;
Mt : string[MaxDateLen];
MLen : Byte absolute Mt;
St : string[MaxDateLen];
SLen : Byte absolute St;
begin
Result := 0;
Mt := AnsiUpperCase(StrPas(S));
if Width > MLen then
FillChar(Mt[MLen+1], Width-MLen, ' ');
MLen := Width;
for I := 1 to 12 do begin
St := AnsiUpperCase(LongMonthNames[I]);
if Width > SLen then
FillChar(St[SLen+1], Width-SLen, ' ');
SLen := Width;
if Mt = St then begin
Result := I;
Break;
end;
end;
end;
function TOvcIntlSup.MonthToString(Month : Integer) : string;
{-return month name as a string for Month}
begin
if (Month >= 1) and (Month <= 12) then
Result := LongMonthNames[Month]
else
Result := '';
end;
function TOvcIntlSup.MonthToPChar(Dest : PAnsiChar; Month : Integer) : PAnsiChar;
{-return month name as a string for Month}
begin
Result := Dest;
if (Month >= 1) and (Month <= 12) then
StrPCopy(Dest, LongMonthNames[Month])
else
Dest[0] := #0;
end;
procedure TOvcIntlSup.ResetInternationalInfo;
{-read Window's international information and string resources}
var
S : string;
I : Cardinal;
Buf : array[0..255] of AnsiChar;
R : TRegistry;
procedure GetIntlString(S, Def, Buf : PAnsiChar; Size : Word);
begin
GetProfileString('intl', S, Def, Buf, Size);
end;
function GetIntlChar(S, Def : PAnsiChar) : AnsiChar;
var
B : array[0..5] of AnsiChar;
begin
GetIntlString(S, Def, B, SizeOf(B));
Result := B[0];
if (Result = #0) then
Result := Def[0];
end;
procedure ExtractSubString(SubChar : AnsiChar; Dest : PAnsiChar);
var
I, Temp : Cardinal;
L : Word;
begin
FillChar(Dest^, SizeOf(wldSub1), 0);
if not StrChPos(wLongDate, '''', I) then
Exit;
{delete the first quote}
StrChDeletePrim(wLongDate, I);
{assure that there is another quote}
if not StrChPos(wLongDate, '''', Temp) then
Exit;
{copy substring into Dest, replace substring with SubChar}
L := 0;
while wLongDate[I] <> '''' do
if L < SizeOf(wldSub1) then begin
Dest[L] := wLongDate[I];
Inc(L);
wLongDate[I] := SubChar;
Inc(I);
end else
StrChDeletePrim(wLongDate, I);
{delete the second quote}
StrChDeletePrim(wLongDate, I);
end;
begin
FDecimalChar := GetIntlChar('sDecimal',
@DefaultIntlData.DecimalChar);
FCommaChar := GetIntlChar('sThousand',
@DefaultIntlData.CommaChar);
FCurrencyDigits := GetProfileInt('intl', 'iCurrDigits',
DefaultIntlData.CurrDigits);
if (FCommaChar = FDecimalChar) then begin
FDecimalChar := DefaultIntlData.DecimalChar;
FCommaChar := DefaultIntlData.CommaChar;
end;
wNegCurrencyForm := GetProfileInt('intl', 'iNegCurr', 0);
FListChar := GetIntlChar('sList', ',');
GetIntlString('sCountry', '', Buf, SizeOf(Buf));
wCountry := StrNew(Buf);
GetIntlString('sCurrency', DefaultIntlData.CurrencyLtStr,
FCurrencyLtStr, SizeOf(FCurrencyLtStr));
StrCopy(FCurrencyRtStr, FCurrencyLtStr);
wCurrencyForm := GetProfileInt('intl', 'iCurrency', 0);
case wCurrencyForm of
0 : {};
1 : {};
2 : StrCat(FCurrencyLtStr, ' ');
3 : StrChInsertPrim(FCurrencyRtStr, ' ', 0);
end;
wTLZero := GetProfileInt('intl', 'iTLZero', 0) <> 0;
w12Hour := LongTimeFormat[Length(LongTimeFormat)] = 'M';
wColonChar := GetIntlChar('sTTime', ':');
FSlashChar := GetIntlChar('sDate', @DefaultIntlData.SlashChar);
GetIntlString('s1159', 'AM', w1159, SizeOf(w1159));
GetIntlString('s2359', 'PM', w2359, SizeOf(w2359));
{get short date mask and fix it up}
{$IFDEF MSWINDOWS}
R := TRegistry.Create;
try
R.RootKey := HKEY_CURRENT_USER;
if R.OpenKey('Control Panel\International', False) then begin
try
if R.ValueExists('sShortDate') then
StrPCopy(wShortDate, R.ReadString('sShortDate'))
else
GetIntlString('sShortDate', 'MM/dd/yy',
wShortDate, SizeOf(wShortDate));
finally
R.CloseKey;
end;
end else
GetIntlString('sShortDate', 'MM/dd/yy',
wShortDate, SizeOf(wShortDate));
finally
R.Free;
end;
{$ELSE}
GetIntlString('sShortDate', 'MM/dd/yy',
wShortDate, SizeOf(wShortDate));
{$ENDIF}
I := 0;
while wShortDate[I] <> #0 do begin
if wShortDate[I] = SlashChar then
wShortDate[I] := '/';
Inc(I);
end;
{get long date mask and fix it up}
GetIntlString('sLongDate', 'dddd, MMMM dd, yyyy',
wLongDate, SizeOf(wLongDate));
ExtractSubString(pmLongDateSub1, wldSub1);
ExtractSubString(pmLongDateSub2, wldSub2);
ExtractSubString(pmLongDateSub3, wldSub3);
{replace ddd/dddd with www/wwww}
if StrStPos(wLongDate, 'ddd', I) then
while wLongDate[I] = 'd' do begin
wLongDate[I] := 'w';
Inc(I);
end;
{replace MMM/MMMM with nnn/nnnn}
if StrStPos(wShortDate, 'MMM', I) then
while wShortDate[I] = 'M' do begin
wShortDate[I] := 'n';
Inc(I);
end;
{replace MMM/MMMM with nnn/nnnn}
if StrStPos(wLongDate, 'MMM', I) then
while wLongDate[I] = 'M' do begin
wLongDate[I] := 'n';
Inc(I);
end;
{deal with oddities concerning . and ,}
I := 0;
while wLongDate[I] <> #0 do begin
case wLongDate[I] of
'.', ',' :
if wLongDate[I+1] <> ' ' then begin
StrChInsertPrim(wLongDate, ' ', I+1);
Inc(I);
end;
end;
Inc(I);
end;
{get Y/N and T/F values}
S := GetOrphStr(SCYes);
if Length(S) = 1 then
YesChar := S[1];
S := GetOrphStr(SCNo);
if Length(S) = 1 then
NoChar := S[1];
S := GetOrphStr(SCTrue);
if Length(S) = 1 then
TrueChar := S[1];
S := GetOrphStr(SCFalse);
if Length(S) = 1 then
FalseChar := S[1];
end;
procedure TOvcIntlSup.SetAutoUpdate(Value : Boolean);
{-set the AutoUpdate option}
begin
if Value <> FAutoUpdate then begin
FAutoUpdate := Value;
// AllocateHWnd not available in LCL to create non-visual window that
// responds to messages sent to control. But not needed?
{$IFNDEF LCL}
if FAutoUpdate then
{allocate our window handle}
{$IFDEF VERSION6}
intlHandle := Classes.AllocateHWnd(isIntlWndProc)
{$ELSE}
intlHandle := AllocateHWnd(isIntlWndProc)
{$ENDIF}
else begin
{deallocate our window handle}
if intlHandle <> 0 then
{$IFDEF VERSION6}
Classes.DeallocateHWnd(intlHandle);
{$ELSE}
DeallocateHWnd(intlHandle);
{$ENDIF}
intlHandle := 0;
end;
{$ENDIF}
end;
end;
procedure TOvcIntlSup.SetCurrencyLtStr(const Value : string);
begin
StrPLCopy(FCurrencyLtStr, Value, SizeOf(FCurrencyLtStr)-1);
end;
procedure TOvcIntlSup.SetCurrencyRtStr(const Value : string);
begin
StrPLCopy(FCurrencyRtStr, Value, SizeOf(FCurrencyRtStr)-1);
end;
function TOvcIntlSup.TimeStringToHMS(const Picture, S : string;
var Hour, Minute, Second : Integer) : Boolean;
{-extract Hours, Minutes, Seconds from St, returning true if string is valid}
var
Buf1 : array[0..255] of AnsiChar;
Buf2 : array[0..255] of AnsiChar;
begin
StrPCopy(Buf1, Picture);
StrPCopy(Buf2, S);
Result := TimePCharToHMS(Buf1, Buf2, Hour, Minute, Second);
end;
function TOvcIntlSup.TimePCharToHMS(Picture, S : PAnsiChar;
var Hour, Minute, Second : Integer) : Boolean;
{-extract Hours, Minutes, Seconds from St, returning true if string is valid}
var
I, J : Cardinal;
Tmp,
t1159,
t2359 : array[0..20] of AnsiChar;
begin
Result := False;
if StrLen(Picture) <> StrLen(S) then
Exit;
{extract hours, minutes, seconds from St}
isExtractFromPicture(Picture, S, pmHour, Hour, -1, 0);
isExtractFromPicture(Picture, S, pmMinute, Minute, -1, 0);
isExtractFromPicture(Picture, S, pmSecond, Second, -1, 0);
if (Hour = -1) or (Minute = -1) or (Second = -1) then begin
Result := False;
Exit;
end;
{check for TimeOnly}
if StrChPos(Picture, pmAmPm, I) and (w1159[0] <> #0)
and (w2359[0] <> #0) then begin
Tmp[0] := #0;
J := 0;
while Picture[I] = pmAmPm do begin
Tmp[J] := S[I];
Inc(J);
Inc(I);
end;
Tmp[J] := #0;
TrimTrailPrimPChar(Tmp);
StrCopy(t1159, w1159);
t1159[J] := #0;
StrCopy(t2359, w2359);
t2359[J] := #0;
if (Tmp[0] = #0) then
Hour := -1
else if StrIComp(Tmp, t2359) = 0 then begin
if (Hour < 12) then
Inc(Hour, 12)
else if (Hour = 0) or (Hour > 12) then
{force BadTime}
Hour := -1;
end else if StrIComp(Tmp, t1159) = 0 then begin
if Hour = 12 then
Hour := 0
else if (Hour = 0) or (Hour > 12) then
{force BadTime}
Hour := -1;
end else
{force BadTime}
Hour := -1;
end;
Result := ValidTime(Hour, Minute, Second);
end;
function TOvcIntlSup.TimeToAmPmString(const Picture : string; T : TStTime; Pack : Boolean) : string;
{-convert T to a string of the form indicated by Picture. Times are always displayed in am/pm format.}
var
Buf1 : array[0..255] of AnsiChar;
Buf2 : array[0..255] of AnsiChar;
begin
StrPCopy(Buf1, Picture);
Result := StrPas(TimeToAmPmPChar(Buf2, Buf1, T, Pack));
end;
function TOvcIntlSup.TimeToAmPmPChar(Dest : PAnsiChar; Picture : PAnsiChar; T : TStTime; Pack : Boolean) : PAnsiChar;
{-convert T to a string of the form indicated by Picture. Times are always displayed in am/pm format.}
const
t1159 = 'AM'#0;
t2359 = 'PM'#0;
var
PLen : Byte;
Temp : Cardinal;
begin
Move(Picture[0], Dest[0], StrLen(Picture)+1);
if not StrChPos(Dest, pmAmPm, Temp) then begin
PLen := StrLen(Dest);
Dest[PLen] := pmAmPm;
Dest[PLen+1] := #0;
end;
Result := isTimeToTimeStringPrim(Dest, Dest, T, Pack, t1159, t2359);
end;
function TOvcIntlSup.TimeStringToTime(const Picture, S : string) : TStTime;
{-convert S, a string of the form indicated by Picture, to a Time variable}
var
Buf1 : array[0..255] of AnsiChar;
Buf2 : array[0..255] of AnsiChar;
begin
StrPCopy(Buf1, Picture);
StrPCopy(Buf2, S);
Result := TimePCharToTime(Buf1, Buf2);
end;
function TOvcIntlSup.TimePCharToTime(Picture, S : PAnsiChar) : TStTime;
{-convert S, a string of the form indicated by Picture, to a Time variable}
var
Hours, Minutes, Seconds : Integer;
begin
if TimePCharToHMS(Picture, S, Hours, Minutes, Seconds) then
Result := HMStoStTime(Hours, Minutes, Seconds)
else
Result := BadTime;
end;
function TOvcIntlSup.TimeToTimeString(const Picture : string; T : TStTime; Pack : Boolean) : string;
{-convert T to a string of the form indicated by Picture}
var
Buf1 : array[0..255] of AnsiChar;
Buf2 : array[0..255] of AnsiChar;
begin
StrPCopy(Buf1, Picture);
Result := StrPas(TimeToTimePChar(Buf2, Buf1, T, Pack));
end;
function TOvcIntlSup.TimeToTimePChar(Dest : PAnsiChar; Picture : PAnsiChar; T : TStTime; Pack : Boolean) : PAnsiChar;
{-convert T to a string of the form indicated by Picture}
begin
Result := isTimeToTimeStringPrim(Dest, Picture, T, Pack, w1159, w2359);
end;
procedure DestroyGlobalIntlSup; far;
begin
OvcIntlSup.Free;
end;
initialization
{create instance of default user data class}
OvcIntlSup := TOvcIntlSup.Create;
finalization
DestroyGlobalIntlSup;
end.