daytime.sa
Generated by gen_html_sa_files from ICSI. Contact gomes@icsi.berkeley.edu for details
-------------------------> GNU Sather - sourcefile <-------------------------
-- Copyright (C) 2000 by K Hopper, University of Waikato, New Zealand --
-- This file is part of the GNU Sather library. It is free software; you may --
-- redistribute and/or modify it under the terms of the GNU Library General --
-- Public License (LGPL) as published by the Free Software Foundation; --
-- either version 2 of the license, or (at your option) any later version. --
-- This library is distributed in the hope that it will be useful, but --
-- WITHOUT ANY WARRANTY without even the implied warranty of MERCHANTABILITY --
-- or FITNESS FOR A PARTICULAR PURPOSE. See Doc/LGPL for more details. --
-- The license text is also available from: Free Software Foundation, Inc., --
-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --
--------------> Please email comments to <bug-sather@gnu.org> <--------------
immutable class CAL_DISPLAY_ORDERS < $ENUMS{CAL_DISPLAY_ORDERS}
immutable class CAL_DISPLAY_ORDERS < $ENUMS{CAL_DISPLAY_ORDERS} is
-- This class captures the notion of a suffix appended to a time to
-- indicate what kind of time -- morning or afternoon it is.
-- The corresponding strings are captured from the locale spec.
-- Version 1.0 Jun 97. Copyright K Hopper, U of Waikato
-- Development History
-- -------------------
-- Date Who By Detail
-- ---- ------ ------
-- 8 Jun 97 kh Original from ISO/IEC 14652
include EXACT_ENUM{CAL_DISPLAY_ORDERS} ;
private const val_count : CARD := 4 ;
-- The following constant 'routines' specify the enumeration values.
LR_TD : SAME is return enum(1) end ;
TD_LR : SAME is return enum(2) end ;
RL_TD : SAME is return enum(3) end ;
TD_RL : SAME is return enum(4) end ;
end ; -- CAL_DISPLAY_ORDERS
immutable class TIME_SUFFIX < $ENUMS{TIME_SUFFIX}
immutable class TIME_SUFFIX < $ENUMS{TIME_SUFFIX} is
-- This class captures the notion of a suffix appended to a time to
-- indicate what kind of time -- morning or afternoon it is.
-- The corresponding strings are captured from the locale spec.
-- Version 1.0 Jun 97. Copyright K Hopper, U of Waikato
-- Development History
-- -------------------
-- Date Who By Detail
-- ---- ------ ------
-- 8 Jun 97 kh Original from ISO/IEC 14652
include EXACT_ENUM{TIME_SUFFIX} ;
private const val_count : CARD := 2 ;
-- The following constant 'routines' specify the enumeration values.
Morning : SAME is return enum(1) end ;
Afternoon : SAME is return enum(2) end ;
end ; -- TIME_SUFFIX
immutable class DT_CODES < $ENUMS{DT_CODES}
immutable class DT_CODES < $ENUMS{DT_CODES} is
-- This class is an enumeration of all the date and time component
-- format values which are defined in the LC_TIME component of the POSIX
-- standard ISO/IEC 9945-2. Note that these are NOT culture-dependent
-- but ARE character encoding dependent!
--
-- The corresponding names in the common resources file
-- should be the ISO/IEC 9945-2 names specified for the indicated formats.
-- Note that these will be encoding dependent by the very bature or
-- the existence of that file produced on the computer system reading it.
--
-- The table in ISO/IEC 14652 gives the text string format codes and
-- a description of the semantics to be ascribed to that code in a date/time
-- formatting class. The prefix letters for some of these codes have the
-- following meanings
--
-- O - A numeric representation using non-Arabic glyphs
-- May apply to - d, e, H, I, m, M, U, w, W, y
--
-- E - A year property based on a non-Gregorian calendar base
-- May apply to - c, C, x, y, Y
--
-- Version 1.0 May 97. Copyright K Hopper, U of Waikato
-- Development History
-- -------------------
-- Date Who By Detail
-- ---- ------ ------
-- 8 May 97 kh Original from ISO/IEC 14652
include EXACT_ENUM{DT_CODES} ;
private const val_count : CARD := 34 ;
-- The following constant 'routines' specify the enumeration values.
ADay_Name : SAME is return enum(1) end ; -- a
Day_Name : SAME is return enum(2) end ; -- A
AMonth_Name : SAME is return enum(3) end ; -- b
Month_Name : SAME is return enum(4) end ; -- B
Full_DT : SAME is return enum(5) end ; -- c
Century : SAME is return enum(6) end ; -- C
Month_Day : SAME is return enum(7) end ; -- d
Numeric_Date : SAME is return enum(8) end ; -- D
Filled_Month_Day : SAME is return enum(9) end ; -- e
Weekday_Num : SAME is return enum(10) end ; -- f
ISO_Date : SAME is return enum(11) end ; -- F
Alt_AMonth_Name : SAME is return enum(12) end ; -- h
Hour : SAME is return enum(13) end ; -- H
Rel_Hour : SAME is return enum(14) end ; -- I
Year_Day : SAME is return enum(15) end ; -- j
Year_Month : SAME is return enum(16) end ; -- m
Minutes : SAME is return enum(17) end ; -- M
New_Line : SAME is return enum(18) end ; -- n
Am_Pm : SAME is return enum(19) end ; -- p
Rel_Time : SAME is return enum(20) end ; -- r
Seconds : SAME is return enum(21) end ; -- S
Tab : SAME is return enum(22) end ; -- t
Time : SAME is return enum(23) end ; -- T
Year_Sun_Week : SAME is return enum(24) end ; -- U
Week_Day : SAME is return enum(25) end ; -- w
Year_Mon_Week : SAME is return enum(26) end ; -- W
Local_Date : SAME is return enum(27) end ; -- x
Local_Time : SAME is return enum(28) end ; -- X
Century_Year : SAME is return enum(29) end ; -- y
Year : SAME is return enum(30) end ; -- Y
Time_Zone : SAME is return enum(31) end ; -- Z
Percent : SAME is return enum(32) end ; -- %
Era_Prefix : SAME is return enum(33) end ; -- E
Alternate_Prefix : SAME is return enum(34) end ; -- O
end ; -- DT_CODES
class DT_FMT < $BINARY
class DT_FMT < $BINARY is
-- This class is the descriptor to be used when converting and
-- formatting a date and/or a time value to a textual representation.
-- The format descriptor provides for an optional prefix string and then
-- pairs of component/string pairs for as many components as needed. Any of
-- the 'component' strings may be empty where two or more value components
-- are to be formatted adjacent to each other (without any space!).
-- Version 1.2 Nov 99. Copyright K Hopper, U of Waikato
-- Development History
-- -------------------
-- Date Who By Detail
-- ---- ------ ------
-- 22 May 97 kh Original design using ISO/IEC 14652 spec.
-- 22 Jul 98 kh Updated ISO standard and added $BINARY
-- 5 Nov 99 kh Made ISO I/O generic.
include ISO_FORMAT{SAME,DT_CODES} ;
private const Decimal_Chars : CARD := 10 ;
private us_date
pre ~ void(self)
post ((initial(modifiers.size) + 3) = modifiers.size)
and (modifiers.size = components.size)
and (separators.size + 1 = components.size)
is
-- This routine transforms a single format code into its individual
-- components for the US date kind of component.
sep : CODE_STR := CODE_STR::create(lib.Solidus) ;
modifiers := modifiers.push(void) ;
components := components.push(DT_CODES::Year_Month) ;
separators := separators.push(sep) ;
modifiers := modifiers.push(void) ;
components := components.push(DT_CODES::Month_Day) ;
separators := separators.push(sep) ;
modifiers := modifiers.push(void) ;
components := components.push(DT_CODES::Century_Year)
end ;
private iso_date
pre ~ void(self)
and ~void(lib)
post ((initial(modifiers.size) + 3) = modifiers.size)
and (modifiers.size = components.size)
and (separators.size + 1 = components.size)
is
-- This routine transforms a single format code into its individual
-- components for the date kind of component as defined in ISO 8601.
sep : CODE_STR := CODE_STR::create(lib.Minus_Sign) ;
modifiers := modifiers.push(void) ;
components := components.push(DT_CODES::Year) ;
separators := separators.push(sep) ;
modifiers := modifiers.push(void) ;
components := components.push(DT_CODES::Year_Month) ;
separators := separators.push(sep) ;
modifiers := modifiers.push(void) ;
components := components.push(DT_CODES::Month_Day)
end ;
private iso_time(
relative : BOOL
)
pre ~ void(self)
and ~void(lib)
post ((relative
and ((initial(modifiers.size) + 4) = modifiers.size)))
or (~relative
and ((initial(modifiers.size) + 3) = modifiers.size)
and (modifiers.size = components.size)
and ((separators.size + 1) = components.size))
is
-- This routine transforms a single format code into its individual
-- components for the international standard time component.
sep : CODE_STR := CODE_STR::create(lib.Colon) ;
modifiers := modifiers.push(void) ;
if relative then
components := components.push(DT_CODES::Rel_Hour)
else
components := components.push(DT_CODES::Hour)
end ;
separators := separators.push(sep) ;
modifiers := modifiers.push(void) ;
components := components.push(DT_CODES::Minutes) ;
separators := separators.push(sep) ;
modifiers := modifiers.push(void) ;
components := components.push(DT_CODES::Seconds) ;
if relative then
loc_space : CODE_STR := CODE_STR::create(lib.Space) ;
separators := separators.push(loc_space) ;
modifiers := modifiers.push(void) ;
components := components.push(DT_CODES::Am_Pm)
end
end ;
private do_special(
code : DT_CODES,
inout sep_str : CODE_STR,
out modifier : DT_CODES,
inout pushed : BOOL
) : BOOL is
-- This routine returns true if and only if the code argument has resulted
-- in any special action being taken, otherwise nothing has been done and
-- the creation routine below sets the appropriate list components.
modifier := void ; -- usually!
case code
when DT_CODES::Alternate_Prefix,
DT_CODES::Era_Prefix then
modifier := code ;
when DT_CODES::Numeric_Date then
if pushed then
separators := separators.push(sep_str) ;
sep_str := CODE_STR::create(lib)
end ;
us_date ;
pushed := true
when DT_CODES::ISO_Date then
if pushed then
separators := separators.push(sep_str) ;
sep_str := CODE_STR::create(lib)
end ;
iso_date ;
pushed := true
when DT_CODES::Local_Time,
DT_CODES::Rel_Time,
DT_CODES::Time then
if pushed then
separators := separators.push(sep_str) ;
sep_str := CODE_STR::create(lib)
end ;
iso_time(code = DT_CODES::Rel_Time) ;
pushed := true
when DT_CODES::Tab then
sep_str := sep_str.push(CHAR_CODE::create(
CONTROL_CODES::HORIZONTAL_TAB.card,lib))
when DT_CODES::New_Line then
sep_str := sep_str + lib.Line_Mark
else -- an ordinary formatting code!
return false
end ;
return true
end ;
private do_number(
num : CARD,
min_width : CARD,
lib : LIBCHARS,
alternate : BOOL,
zero_fill : BOOL
) : CODE_STR
pre ~void(self)
and ~void(lib)
and (min_width > 0)
post (result.size >= min_width)
is
-- This private routine converts a number to the appropriate
-- representation. If alternate is true then the characters come from
-- the cultural alternate digits, otherwise arabic digits. If zero_fill
-- is false then space-filling is done.
digit_cnt : CARD := Decimal_Chars ; -- default of ten!
filler : CHAR_CODE ;
cnt : CARD := min_width ;
val : CARD := num ;
res : CODE_STR := CODE_STR::create(lib) ;
if alternate then
digit_cnt := lib.alt_digits
end ;
if zero_fill then
if alternate then
filler := lib.alt_digit(0)[0].code
else
filler := lib.digit(0)
end
else
filler := lib.Space
end ;
if num >= digit_cnt then
if (digit_cnt > Decimal_Chars) then -- but is it 100?
if digit_cnt < 100 then -- use decimal placing
digit_cnt := 10
end
end
end ;
loop -- the digit string itself
if alternate then
res := res + lib.alt_digit(val % digit_cnt)[0].code
else
res := res + lib.digit(val % digit_cnt)
end ;
val := val / digit_cnt ;
if cnt > 0 then -- still less than given min width!
cnt := cnt - 1
end ;
until!(val = 0)
end ;
loop -- the fillers
(cnt / filler.lib.my_size).times! ;
res := res + filler
end ;
return res.reverse
end ;
private do_format(
date : DATES,
time : TIMES,
lib : LIBCHARS
) : CODE_STR
pre ~void(self)
and ~void(lib)
post ~void(result) -- and it is a valid date representation!
is
-- This private routine does formatting for all of the variant routines
-- which follow. Fundamentally it merely loops through all of the
-- components adding to the output string the relevant item and separator.
res : CODE_STR := CODE_STR::create(lib) ;
loop
modified : BOOL := ~modifiers.elt!.is_nil ;
loc_code : DT_CODES := components.elt! ;
case loc_code
when DT_CODES::ADay_Name then
res := res + CODE_STR::create(date.weekday.short_str)
when DT_CODES::Day_Name then
res := res + CODE_STR::create(date.weekday.str)
when DT_CODES::AMonth_Name then
res := res + CODE_STR::create(date.month.short_str)
when DT_CODES::Month_Name then
res := res + CODE_STR::create(date.month.str)
-- when DT_CODES::Full_DT then -- also Ec ?????
when DT_CODES::Century then --NOTE In future has two digits!
res := res + do_number(date.century,2,lib,modified,true)
when DT_CODES::Month_Day then
res := res + do_number(date.date,1,lib,modified,true)
-- when DT_CODES::Numeric_Date then -- Handled during building
when DT_CODES::Filled_Month_Day then
res := res + do_number(date.date,2,lib,modified,false)
when DT_CODES::Weekday_Num then
res := res + do_number(date.day_of_week,1,lib,modified,false)
-- when DT_CODES::ISO_Date then -- Handled during building
when DT_CODES::Alt_AMonth_Name then
res := res + CODE_STR::create(date.month.short_str)
when DT_CODES::Hour then
res := res + do_number(time.hour,2,lib,modified,true)
when DT_CODES::Rel_Hour then
loc_hour : CARD := time.hour ;
if loc_hour > 12 then
loc_hour := loc_hour - 12
end ;
res := res + do_number(loc_hour,2,lib,modified,false)
when DT_CODES::Year_Day then
res := res + do_number(date.day_in_year,3,lib,modified,true)
when DT_CODES::Year_Month then
res := res + do_number(date.month_number,2,lib,modified,true)
when DT_CODES::Minutes then
res := res + do_number(time.minute,2,lib,modified,true)
when DT_CODES::New_Line then
res := res + lib.Line_Mark
when DT_CODES::Am_Pm then
if time.hour >= 12 then
res := res + CODE_STR::create(TIME_SUFFIX::Afternoon.str)
else
res := res + CODE_STR::create(TIME_SUFFIX::Morning.str)
end
-- when DT_CODES::Rel_Time then -- Handled during building
when DT_CODES::Seconds then
res := res + do_number(time.second,2,lib,modified,true)
when DT_CODES::Tab then
res := res + CHAR_CODE::create(
CONTROL_CODES::HORIZONTAL_TAB.card,lib)
-- when DT_CODES::Time then -- Handled during building
when DT_CODES::Year_Sun_Week then
loc_week : CARD := date.week_in_year ;
if date.year_start_day = WEEKDAYS::Sunday then
loc_week := loc_week + 1
end ;
res := res + do_number(loc_week,2,lib,modified,true)
when DT_CODES::Week_Day then
res := res + CODE_STR::create(date.day_of_week.str)
when DT_CODES::Year_Mon_Week then
loc_week : CARD := date.week_in_year ;
if date.year_start_day = WEEKDAYS::Monday then
loc_week := loc_week + 1
end ;
res := res + do_number(loc_week,2,lib,modified,true)
-- when DT_CODES::Local_Date then
-- when DT_CODES::Local_Time then -- Handled during building
when DT_CODES::Century_Year then
res := res + do_number(date.year_this_century,2,
lib,modified,true)
when DT_CODES::Year then
res := res + do_number(date.year,4,lib,modified,true)
when DT_CODES::Time_Zone then
loc_stamp : TIME_STAMP := TIME_STAMP::create(date,time) ;
res := res + CODE_STR::create(
lib.culture.date_time.time_zone.str(loc_stamp,lib))
when DT_CODES::Percent then
res := res + lib.Percent
else -- error in cultural spec!
SYS_ERROR::create.error(self,
SYS_EXCEPT::Bad_Format,loc_code.card.str)
end ;
loc_str : CODE_STR := separators.elt! ;
if ~void(loc_str) then
res := res + loc_str
end
end ;
return res
end ;
fmt(
val : DATES,
lib : LIBCHARS
) : STR
pre ~void(self)
and ~void(lib)
and ~(val = DATES::null)
post ~void(result) -- and it is a valid date representation!
is
-- This routine produces a formatted version of the given date as a text
-- string representation.
loc_res : CODE_STR := do_format(val,TIMES::null,lib) ;
if void(prefix) then
return loc_res.tgt_str
else
return prefix.tgt_str + loc_res.tgt_str
end
end ;
fmt(
val : TIMES,
lib : LIBCHARS
) : STR
pre ~void(self)
and ~void(lib)
-- could be 'zero' and ~void(val)
post ~void(result) -- and it is a valid time representation!
is
-- This routine produces a formatted version of the given time as a text
-- string representation.
loc_res : CODE_STR := do_format(DATES::null,val,lib) ;
if void(prefix) then
return loc_res.tgt_str
else
return prefix.tgt_str + loc_res.tgt_str
end
end ;
fmt(
stamp : TIME_STAMP,
lib : LIBCHARS
) : STR
pre ~void(self)
and ~void(lib)
and ~(stamp = TIME_STAMP::create(0,0))
post ~void(result) -- and it is a valid date representation!
is
-- This routine produces a formatted version of the given date/time as
-- a text string representation.
loc_date : DATES := DATES::create(stamp) ;
loc_time : TIMES := TIMES::create(stamp) ;
loc_res : CODE_STR := do_format(loc_date,loc_time,lib) ;
if void(prefix) then
return loc_res.tgt_str
else
return prefix.tgt_str + loc_res.tgt_str
end
end ;
end ; -- DATE_FMT
class TEMPORAL
class TEMPORAL is
-- This class contains the numeric components of the cultural
-- description as specified in ISO/IEC 14652 (as amended).
--
-- WARNING READ THE FOLLOWING NOTE
--
-- Note that the alternate digits component of the ISO/IEC LC_TIME
-- specification is NOT included in this as it is/may be also used for
-- numbers and is therefore included in the class NUMBERS.
-- Version 1.0 Jun 98. Copyright K Hopper, U of Waikato
-- Development History
-- -------------------
-- Date Who By Detail
-- ---- ------ ------
-- 26 Jun 98 kh Original design from cultural compiler
readonly attr date : DT_FMT ;
readonly attr time : DT_FMT ;
readonly attr date_time : DT_FMT ;
readonly attr era_date : DT_FMT ;
readonly attr era : DT_FMT ;
readonly attr era_year : DT_FMT ;
readonly attr relative_time : DT_FMT ;
readonly attr week_day_count : CARD ; -- three values for 'week'
readonly attr first_day_in_week : WEEKDAYS ;
readonly attr first_week_contains : WEEKDAYS ;
readonly attr first_day_display : WEEKDAYS ;
readonly attr first_work_day : WEEKDAYS ;
readonly attr cal_dir : CAL_DISPLAY_ORDERS ;
private attr time_zones : FLIST{TIME_ZONE} ;
private attr current_zone : TIME_ZONE ;
build(
index : BIN_CURSOR,
lib : LIBCHARS
) : SAME
pre ~void(index)
and ~index.is_done
and ~void(lib)
post (void(result)
and index.is_done)
or ~void(result)
is
-- This routine creates an object of this kind from the binary string
-- attached to the given cursor providing that the string is long enough!
-- If not long enough then void is returned.
res : SAME := new ;
res.date := DT_FMT::read(index,lib) ;
if index.is_done then
return void
end ;
res.time := DT_FMT::read(index,lib) ;
if index.is_done then
return void
end ;
res.date_time := DT_FMT::read(index,lib) ;
if index.is_done then
return void
end ;
res.era_date := DT_FMT::read(index,lib) ;
if index.is_done then
return void
end ;
res.era := DT_FMT::read(index,lib) ;
if index.is_done then
return void
end ;
res.era_year := DT_FMT::read(index,lib) ;
if index.is_done then
return void
end ;
res.relative_time := DT_FMT::read(index,lib) ;
if index.is_done then
return void
end ;
res.week_day_count := index.get_item.card ;
if index.is_done then
return void
end ;
res.first_day_in_week := WEEKDAYS::build(index) ;
if index.is_done then
return void
end ;
res.first_week_contains := WEEKDAYS::build(index) ;
if index.is_done then
return void
end ;
res.first_day_display := WEEKDAYS::build(index) ;
if index.is_done then
return void
end ;
res.first_work_day := WEEKDAYS::build(index) ;
if index.is_done then
return void
end ;
res.cal_dir := CAL_DISPLAY_ORDERS::build(index) ;
if index.is_done then
return void
end ;
if BOOL::build(index) then
loc_cnt : CARD := index.get_item.card ;
if loc_cnt > 0 then
res.time_zones := FLIST{TIME_ZONE}::create ;
loop
loc_cnt.times! ;
res.time_zones := res.time_zones.push(
TIME_ZONE::build(index,lib)) ;
if index.is_done then
return void
end
end ;
res.current_zone := res.time_zones[0]
end
end ;
return res
end ;
build(
index : BIN_CURSOR
) : SAME
pre ~void(index)
and ~index.is_done
post (void(result)
and index.is_done)
or ~void(result)
is
-- This routine creates an object of this kind from the binary string
-- attached to the given cursor providing that the string is long enough!
-- If not long enough then void is returned.
return build(index,LIBCHARS::default)
end ;
time_zone : TIME_ZONE is
-- This routine returns the current time zone in use by this program.
-- Note that this may be void if no zones have been specified.
return current_zone
end ;
time_zone(
index : CARD
)
pre ~void(current_zone)
and (index < time_zones.size)
post true
is
-- This is the writer routine to set the indexed time zone as current
-- which will be returned by the corresponding reader routine until a
-- further change is made. Note that if no zones are specified then calls
-- to time_zone will result in no action being taken.
current_zone := time_zones[index]
end ;
binstr : BINSTR
pre ~void(self)
post ~void(result)
is
-- This routine returns a binary string representation of self.
res : BINSTR := BINSTR::create ;
if void(date) then
res := res + false.binstr
else
res := res + true.binstr + date.binstr
end ;
if void(time) then
res := res + false.binstr
else
res := res + true.binstr + time.binstr
end ;
if void(date_time) then
res := res + false.binstr
else
res := res + true.binstr + date_time.binstr
end ;
if void(era_date) then
res := res + false.binstr
else
res := res + true.binstr + era_date.binstr
end ;
if void(era) then
res := res + false.binstr
else
res := res + true.binstr + era.binstr
end ;
if void(era_year) then
res := res + false.binstr
else
res := res + true.binstr + era_year.binstr
end ;
if void(relative_time) then
res := res + false.binstr
else
res := res + true.binstr + relative_time.binstr
end ;
res := res + week_day_count.binstr +
first_day_in_week.binstr +
first_week_contains.binstr +
first_day_display.binstr +
first_work_day.binstr +
cal_dir.binstr ;
if void(time_zones) then
res := res + false.binstr
else
res := res + true.binstr + OCTET::create(time_zones.size) ;
loop
res := res + time_zones.elt!.binstr
end
end ;
return res
end ;
end ; -- TEMPORAL