mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-01-01 11:29:27 +00:00
0ba83392d4
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
3378 lines
109 KiB
Plaintext
3378 lines
109 KiB
Plaintext
;
|
|
; File: ScriptMgrUtilDate.a (formerly SMgrUtilDate.a)
|
|
;
|
|
; Contains: Script Manager date/time utilities
|
|
;
|
|
; Written by: MED Mark Davis
|
|
; JLT
|
|
; LDC Lee Collins
|
|
; PKE Peter Edberg
|
|
;
|
|
; Copyright: © 1987-1992 by Apple Computer, Inc. All rights reserved.
|
|
;
|
|
; This file is used in these builds: ROM, disk
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM5> 11/12/92 PN Get rid of ³ 020 conditionals for ROM builds
|
|
; <SM4> 11/6/92 SWC Changed PackMacs.a->Packages.a.
|
|
; <15> 6/12/92 FM remove MacsBug symbols and obsolete smgrKeepMacsBugSymbols
|
|
; conditional. Replaced long divisions w/ a macro that uses a
|
|
; divu.l instruction for 020 cpus and a subroutine otherwise.
|
|
; Removed if 0 then code from division routine.
|
|
; <14> 4/30/92 FM Remove conditional smgrUsesStdExit
|
|
; <13> 3/16/92 csd #1017570,<gbm>:
|
|
; Removed the MoveHHi call on the itl0 and itl1 resources to avoid
|
|
; System heap fragmentation.
|
|
; <12> 2/19/91 PKE smb,#DTS FT: ToggleDate trashes one word past the end of its
|
|
; ÒVAR lSecs: LongDateTimeÓ parameter (reported by a developer).
|
|
; <11> 2/15/91 PKE JSM,#54736: Redo conditionals to move change <10> to Post 7.0.
|
|
; Object compare identical to <9>.
|
|
; <10> 1/28/91 JH PKE,#54736: Changed InitDateCache so that the date separators
|
|
; are now part of the cache. Then fixed String2Date to use these
|
|
; separators and not be quite so forgiving about allowed
|
|
; separators. Now if a separator is used that is not part of the
|
|
; cache before a number is found the routine returns invalid date.
|
|
; If a non-cached separator is found after a number the routine
|
|
; continues, but a warning result is returned. Also changed
|
|
; ValidLong so that it won't allow numbers > 32768.
|
|
; <9> 9/14/90 BG Removed <8>. 040s are now behaving more reliably.
|
|
; <8> 7/17/90 BG Added EclipseNOPs for flakey 040s.
|
|
; <7> 7/5/90 PKE NEEDED FOR SIXPACK: Rearranged InitDateCache to fix old problem:
|
|
; itl0 and itl1 may be purged before we try to use them.
|
|
; <6> 6/1/90 PKE Just cleaned up some comments, formatting, and superfluous
|
|
; definitions.
|
|
; <5> 5/5/90 PKE Updated 3 previously overlooked ÔSysVersÕ symbols to
|
|
; ((smgrSysVers >= $605) OR (smgrROMVers >= 2)) so we can build
|
|
; with new ScriptPriv.a.
|
|
; <4> 4/10/90 PKE Deleted conditionalized definitions of forRom, SysVers and
|
|
; TestScriptManager. Fixed tabs. Replaced local definition of
|
|
; _FixDiv with include of FixMath.a. Used smgrSysVers,
|
|
; smgrROMVers, and smgrUseStdExit symbols instead of SysVers and
|
|
; buildLevel. Removed remaining MacsBug symbols for 7.0.
|
|
; <3> 3/4/90 PKE Changed _UprText to _UpperText to match new Traps.a.
|
|
; <2> 2/22/90 PKE Replaced obsolete _LwrStringToUpr opword with _UprText. Updated
|
|
; header to BBS format.
|
|
; <1> 12/18/89 CCH Adding for the first time into BBS. Changed include 'inc.sum.a'
|
|
; to load 'StandardEqu.d'. Updated file name references.
|
|
;
|
|
; (BBS versions above, EASE versions below:)
|
|
; <2.5> 11/6/89 PKE NEEDED FOR 6.0.5!! (since 2.4 change is conditionalized for 7.0,
|
|
; the file can be used as is, except that you might need to add
|
|
; back the load 'nEqu.d') -Bug fixes for InitDateCache and
|
|
; String2Date needed for HyperCard. InitDateCache: Fixed CopyArray
|
|
; to use correct register (A4) for source pointer, and to
|
|
; initialize all relevant bytes of length register (D0).
|
|
; String2Date: if first relevant (i.e., day or month name) alpha
|
|
; token is a month name, we now search the day name list if we
|
|
; find another alpha token (fixes BRC #54946). Rearranged Cache
|
|
; structure to fix invalid use of month/day name index. Note that
|
|
; the invalid index use in String2Date happened to work before
|
|
; because of the incorrect source pointer use in CopyArray, but it
|
|
; was incomprehensible.
|
|
; <2.4> 9/18/89 PKE Replace _GetScript call in InitDateCache with direct access to
|
|
; ScriptRecord, since we may not have GetScript yet; this is also
|
|
; an optimization.
|
|
; <2.3> 8/26/89 PKE Cleaned up some conditionals, moved a comment.
|
|
; <2.2> 8/22/89 SES Removed references to nFiles.
|
|
; <2.1> 6/30/89 PKE NEEDED FOR AURORA: Use OPWORD _LwrStringToUpr for LwrString with
|
|
; uppercase function; use _LwrStringToUpr instead of UprString in
|
|
; ToggleDate (ToggleDate may now move memory, but the 2.0
|
|
; documentation didn't indicate whether or not it moved memory).
|
|
; For ROMs on 020 or greater machines, get rid of LongDiv and move
|
|
; divs.l inline. Use constant NoonHr for 12 where appropriate.
|
|
; (all of these changes from code review).
|
|
; <2.0> 6/23/89 PKE In String2Date, change conditionals so Lee's heuristic for dates
|
|
; near the beginning or end of the century is used for 7.0 as well
|
|
; as ROM; skip definition of buildLevel (done in ScriptPriv.a).
|
|
; <1.9> 6/13/89 PKE (ROM & 7.0 only) Fix bug introduced by 1.6 below: In
|
|
; InitDateCache, lock itl0 & itl1 around direct or indirect calls
|
|
; to Block2String, which now calls LwrString and can move memory.
|
|
; <1.8> 6/9/89 PKE Fix InitDateCache bug that could trash random memory (BRC
|
|
; #50472).
|
|
; <1.7> 6/4/89 PKE Modify ValidDate and ToggleDate to check genCdevRangeBit flag
|
|
; and restrict valid dates to the Gregorian range 1920-2019 (or
|
|
; equivalent range in another calendar), as in General CDEV. Note:
|
|
; these changes were originally checked in on 5/25/89 as version
|
|
; 1.6, but the EASE version list didn't get updated. Consequently,
|
|
; (1) that version couldn't be checked out, and (2) the next
|
|
; checkout/checkin sequence resulted in the new version 1.6 below,
|
|
; which didn't have these changes.
|
|
; <1.6> 5/30/89 PKE (New ROMs & System 7.0 only) Replace UprString calls in routines
|
|
; that already move memory with calls to enhanced LwrString for
|
|
; localizable uppercasing.
|
|
; <1.5> 5/2/89 PKE Change CPU test in LongDiv to work properly for 68030 (BRC
|
|
; 35696); for ROM, replace test with conditionals that select the
|
|
; right code.
|
|
; <1.4> 4/7/89 PKE Modified ValidDate to compare LongDateRec fields from pm to era
|
|
; (was from era to weekOfYear, but undocumented): fixes the "2/29"
|
|
; problem in ToggleDate. Eliminated the ValidDate code
|
|
; (ROM/BigBang only) restricting hour to 0-11 if twelveHourBit
|
|
; set; check pm field instead, so hour will always be 0-23.
|
|
; Modified ToggleDate to mask out togFlags bits for LongDateRec
|
|
; fields it can't deal with; to place tighter restrictions on
|
|
; toggling by char in numeric fields (only $30-$39 and $b0-$b9
|
|
; allowed); and to handle 12-hour time in various ways with the
|
|
; addition of 3 flag bits. Fixed bug in LongSecs2Date for negative
|
|
; LongSecs.
|
|
; <1.3> 2/21/89 PKE Replaced with RomProj version, which already had system and Rom
|
|
; sources merged.
|
|
; (EASE ROMproj history below)
|
|
; <1.5> 2/21/89 PKE Fix up includes: always use include 'inc.sum.a'.
|
|
; <1.4> 2/14/89 PKE Updated to use MPW 3.0 final ScriptEqu.a equate names
|
|
; <1.3> 2/3/89 PKE Merged with current system sources (CCH's 01/16/1989 merge of
|
|
; 6.0.3 and 7.0 sources, done in RES.sys:smgr)
|
|
; <1.2> 11/14/88 PKE Synchronize EASE and Projector
|
|
; <1.1> 11/11/88 CCH Fixed Header.
|
|
; <1.0> 11/9/88 CCH Adding to EASE.
|
|
; (old EASE ROMproj history below)
|
|
; <1.8> 10/27/88 LDC Mods by Carl Hewitt and Brian McGhie in the process of putting
|
|
; Script Manager in ROM
|
|
; (EASE SYSproj history below)
|
|
; <1.2> 2/14/89 PKE Updated to use MPW 3.0 final ScriptEqu.a equates
|
|
; <1.1> 1/16/89 CCH Merged 6.0.3 final sources into 7.0.
|
|
; <1.0> 11/16/88 CCH Added to EASE.
|
|
; (pre-EASE history below)
|
|
; 10/12/88 ldc removed longDay, etc.
|
|
; 10/10/88 ldc include 'inc.sum.d'
|
|
; 9/30/88 ldc Added check for 12 hour time using #12HourBit in ValidDate
|
|
; 9/27/88 ldc Changed heuristic for determining when input year less than 100
|
|
; belongs in previous, current or next century
|
|
; 7/25/88 ldc Changed error equ names per Keithen
|
|
; 5/19/88 ldc Standardized routine exits
|
|
; * above changes for ROM or buildLevel >= 2 *
|
|
; 2/22/88 med Use token length instead of abbrevLen for matching months,
|
|
; daysOfWeek
|
|
; 2/22/88 med Use MatchString for time testing.
|
|
; 1/13/88 med Added LongDiv routine for 64/32 -> r32,q32
|
|
; 1/13/88 med Changed LongDateTime to type Comp throughout
|
|
; 1/12/88 med Changed String2Date, Date2String to use LongDateRec, ValidDate
|
|
; 1/12/88 med Added dispatch for ValidDate, added field flag bits
|
|
; 1/11/88 med Fix BC
|
|
; 1/11/88 med Fix day of week if divs overflow
|
|
; 1/11/88 med Fix range bug (<1600) with Long dates
|
|
; 1/5/88 med Major revamp of String2Time and Time2String for compression
|
|
; 1/4/88 med Statements were outside of With TBlock
|
|
; 11/21/87 med Asm adds extra bytes to front of dc.x
|
|
; 11/20/87 med dy100 to big as divisor, must hack around, misc fixes
|
|
; 11/17/87 med Added c version of LongDate2Secs, LongSecs2Date; started
|
|
; assemblyizing
|
|
; 9/2/87 med Check for white space as separator
|
|
; 8/25/87 med Added check for 12AM
|
|
; 8/24/87 med Stop getting time if time string is found OR (not AND) 3
|
|
; elements
|
|
; 8/24/87 med DayFound was missing (a6).
|
|
; 8/24/87 med Caught case of null string.
|
|
; 8/22/87 med Added fix for 24:xx:xx time
|
|
; 8/22/87 med Added test for alternate space
|
|
; 8/22/87 med Removed seconds parameter entirely, since it never would work
|
|
; right
|
|
; 8/22/87 med Removed use of A5 as temp register. Not a wise idea, Jim
|
|
; 8/21/87 med Stash seconds in var paramter in String2Date, String2Time
|
|
; 8/21/87 med Added header and minor changes to resourcize the procedures
|
|
; 8/11/87 JLT String2Date/Time only affects date/time fields in var
|
|
; DateTimeRec parameter
|
|
; 8/10/87 JLT Speeded up Compare and MatchString
|
|
; 8/10/87 JLT Told Tokenizer to return strings and wrote faster ValidLong
|
|
; routine
|
|
; 8/9/87 JLT Replaced trap calls with JSR's
|
|
; 8/9/87 JLT Wrote InitCache to do pre-initialization of String2Date and
|
|
; String2Time
|
|
; 8/8/87 JLT LongSecstoDate is written
|
|
; 8/7/87 JLT String2Date and String2Time return number of seconds, and
|
|
; location of string were date/time stopped
|
|
; 8/5/87 JLT Errors and warning codes added to String2Date and String2Time
|
|
; 7/29/87 JLT String2Date routine written
|
|
; 7/28/87 JLT String2Time routine written
|
|
; 7/23/87 JLT Compare, Block2String and MatchString modified to have no var
|
|
; parameters
|
|
; 7/22/87 JLT Block2String modified to not to load in leading spaces, length
|
|
; bug fixed
|
|
; 7/20/87 JLT Final version of PortionText done
|
|
; 7/13/87 JLT Portion Text written
|
|
; 7/1/87 JLT Final version of GetNeighborhood and SearchText is reached
|
|
; 6/30/87 JLT GetNeighborhood; SearchText now calls GetNeighborhood
|
|
; 6/29/87 JLT SearchText
|
|
; 6/20/87 MD ConvertTable written
|
|
; 6/20/87 MD Compare, Block2String and MatchString support routines written
|
|
; for pascal String2Date
|
|
;___________________________________________________________________________________________________
|
|
; To Do:
|
|
; eyeballing algorithm could speed up calendar calculations
|
|
;___________________________________________________________________________________________________
|
|
PRINT OFF ; jh, <10>
|
|
|
|
IF &type('CPU')='UNDEFINED' THEN ; <06/30/89 pke>
|
|
CPU: equ 0 ; <06/30/89 pke>
|
|
ENDIF ; <06/30/89 pke>
|
|
|
|
load 'StandardEqu.d'
|
|
include 'ScriptPriv.a'
|
|
include 'SANEMacs.a'
|
|
include 'Packages.a'
|
|
FixMathNonPortable equ 1 ; We require Mac Plus or newer <4>
|
|
include 'FixMath.a' ; to get _FixDiv <4>
|
|
import StdUnlink
|
|
|
|
|
|
PRINT ON
|
|
|
|
FixCacheAndStr2Date equ 0 ; do for 7.1 & new ROMs <11>
|
|
;FixCacheAndStr2Date equ ((smgrSysVers >= $710) OR (smgrROMVers >= 2)) ; do for 7.1 & new ROMs <11>
|
|
|
|
; Assorted In-line constants
|
|
|
|
secsInDay equ 86400 ; seconds in one day
|
|
maxDate equ $CE ; max date range is $0000,00EA,D380,0000
|
|
minDate equ -$EB ; these correspond to -30000,30000
|
|
NoonHr equ 12
|
|
|
|
genCdevRangeLo equ 504921600 ; secs for 1920-Jan-01 00:00:00
|
|
genCdevRangeHi equ $DA319179 ; =3660681599, secs for 2019-Dec-31 23:59:59
|
|
|
|
;____________________________________________________________
|
|
; Long division macro macro. For 020 machines we can use an instruction
|
|
; for efficiency.
|
|
|
|
macro
|
|
LongDiv
|
|
|
|
machine mc68020
|
|
divs.l d2,d0:d1 ; do it
|
|
|
|
endm
|
|
|
|
|
|
|
|
|
|
proc
|
|
export MonthStarts,LeapStarts,secsInDayX,maxOldDate,maxVal
|
|
|
|
mLimit equ 1000 ; limit for searching
|
|
|
|
MonthStarts dc.w 0,31,59,90,120,151,181,212,243,273,304,334,mLimit
|
|
LeapStarts dc.w 0,31,60,91,121,152,182,213,244,274,305,335,mLimit
|
|
secsInDayHack dc.x "86400.0"
|
|
secsInDayX equ *-10 ; skip first two byts--asm bug <11/21/87med>
|
|
maxDateHack dc.x "4294967295.0"
|
|
maxOldDate equ *-10
|
|
maxVal dc.w 0,150,13,35,24,60,60,7,400,60
|
|
endproc
|
|
|
|
;============================================================
|
|
; FUNCTION ValidDate (VAR date : LongDateRec;
|
|
; flags: Longint;
|
|
; var newSecs: LongDateTime,
|
|
; selector: Longint): DateField;
|
|
; LABEL
|
|
; 999;
|
|
; VAR
|
|
; i: DateField;
|
|
; dateTime2: LongDateRec;
|
|
;============================================================
|
|
ValidDate proc export
|
|
|
|
ValidDateRec record {oldA6},decr
|
|
resultSize equ 2
|
|
result ds.w 1 ; DateField
|
|
argSize equ *-8
|
|
date ds.l 1 ; @LongDateREc
|
|
flags ds.l 1 ; long
|
|
newSecs ds.l 1 ; @newSecs
|
|
selector ds.l 1 ; long
|
|
return ds.l 1
|
|
oldA6 ds.l 1
|
|
dateTime2 ds LongDateRec
|
|
localFrame equ *
|
|
endr
|
|
|
|
rResult equ d3
|
|
rNewSecs equ a2
|
|
rDateTime2 equ a3
|
|
rDate equ a4
|
|
|
|
ValidDateRegs reg rResult/rNewSecs/rDateTime2/rDate
|
|
|
|
with ValidDateRec,LongDateRec,LongDateField
|
|
import maxOldDate
|
|
|
|
CheckSelector
|
|
link a6,#localFrame
|
|
movem.l ValidDateRegs,-(sp) ; save regs
|
|
|
|
; pea procName
|
|
; _DebugStr
|
|
|
|
; ValidDate := yearField; {assume bad}
|
|
; LongDate2Secs(date, newSecs);
|
|
; if (BAnd(oldDateFlag,flags) <> 0) then
|
|
; if ((newSecs < 0) or (newSecs > maxOldDate)) then goto 999;
|
|
|
|
move.w #yearField,rResult ; assume bad
|
|
move.l newSecs(a6),rNewSecs ; arg
|
|
lea dateTime2(a6),rDateTime2 ; reg arg
|
|
move.l date(a6),rDate ; ditto
|
|
|
|
move.l rDate,-(sp) ; pass @date
|
|
move.l rNewSecs,-(sp) ; pass @newSecs
|
|
_LongDate2Secs ; get values in array
|
|
move.l flags(a6),d0 ; get flags for testing
|
|
btst.l #smallDateBit,d0 ; limited version?
|
|
beq.s @InRange ; no, skip test
|
|
tst.l (rNewSecs) ; negative? (high long <> 0 => quad used
|
|
bne.s @ValidExit ; yes, bail
|
|
|
|
btst.l #genCdevRangeBit,d0 ; limited to 1920-2019?
|
|
beq.s @InRange ; if not, skip following test
|
|
cmp.l #genCdevRangeLo,4(rNewSecs) ; before 1920?
|
|
bcs.s @ValidExit ; bail if so
|
|
cmp.l #genCdevRangeHi,4(rNewSecs) ; after 2019?
|
|
bhi.s @ValidExit ; bail if so
|
|
|
|
@InRange
|
|
; LongSecs2Date(newSecs, dateTime2);
|
|
|
|
move.l rNewSecs,-(sp) ; pass @newSecs
|
|
move.l rDateTime2,-(sp) ; pass @dateTime2 for loading
|
|
_LongSecs2Date ; call
|
|
|
|
; FOR i := eraField TO secondField DO
|
|
; IF date.list[i] <> dateTime2.list[i] THEN
|
|
; BEGIN
|
|
; ValidDate := i;
|
|
; GOTO 999;
|
|
; END;
|
|
; ValidDate := validDateFields;
|
|
|
|
move.l flags(a6),d2 ; get flags for testing <1/11/88med>
|
|
move.w #validDateFields,rResult ; assume ok
|
|
|
|
; Go from end to beginning
|
|
|
|
adda.l #pm+2,rDate ; -(rDate) will start with pm field
|
|
adda.l #pm+2,rDateTime2 ; -(rDateTime2) starts with pm field
|
|
move.l #pmField,d1 ; counter & bit mask index
|
|
@ValidLoop
|
|
move.w -(rDateTime2),d0 ;
|
|
cmp.w -(rDate),d0 ; same?
|
|
dbne d1,@ValidLoop ; loop until not equal
|
|
beq.s @ValidExit ; ok, exit
|
|
btst d1,d2 ; field bit on? <1/11/88med>
|
|
dbne d1,@ValidLoop ; loop until set <1/11/88med>
|
|
beq.s @ValidExit ; bit not set, done <1/11/88med>
|
|
move.w d1,rResult ; now return bad field number
|
|
|
|
|
|
;999 :
|
|
@ValidExit
|
|
move.w rResult,result(a6) ; return result
|
|
movem.l (sp)+,ValidDateRegs ; restore registers to their original value
|
|
checkA6 ; check stack
|
|
|
|
move.w #argSize, d0 ; for StdUnlink
|
|
bra StdUnlink ; standard exit
|
|
|
|
endWith
|
|
endProc
|
|
|
|
;{============================================================
|
|
; ToggleDate Code
|
|
; ============================================================}
|
|
; const
|
|
; validDateFields = -1;
|
|
; maxOldDate = 4294967295.0;
|
|
;============================================================
|
|
; ToggleResults = (toggleUndefined, {function undefined}
|
|
; toggleOk, {worked ok}
|
|
; toggleBadField, {field not supported}
|
|
; toggleBadDelta, {delta = -1/1}
|
|
; toggleUnknown {unknown error}
|
|
; {others later: use r-});
|
|
;
|
|
;
|
|
;============================================================
|
|
;
|
|
; Function ToggleDate ( VAR mySecs: LongDateTime;
|
|
; field: DateField;
|
|
; delta: DateDelta;
|
|
; ch: Integer;
|
|
; params: TogglePB;
|
|
; selector:Longint): ToggleResults;
|
|
; LABEL
|
|
; 777,888,900,999;
|
|
; VAR
|
|
; dateTime0,
|
|
; dateTime1,
|
|
;; maxVal: LongDateRec;
|
|
; newDate: LongDateTime;
|
|
;; succField,
|
|
; badField: DateField;
|
|
;; j,
|
|
; baseValue,
|
|
; hundreds: Integer;
|
|
; rtPtr: ^ResType;
|
|
; myLong: Longint;
|
|
; tempStr: Str255;
|
|
; curChar: Char;
|
|
;
|
|
; BEGIN
|
|
;============================================================
|
|
|
|
ToggleDate proc export
|
|
|
|
ToggleDateRec record {oldA6},decr
|
|
resultSize equ 2
|
|
funcResult ds.w 1
|
|
argSize equ *-8
|
|
mySecsPtr ds.l 1
|
|
field ds.w 1
|
|
delta ds.w 1
|
|
ch ds.w 1
|
|
paramsPtr ds.l 1
|
|
selector ds.l 1
|
|
return ds.l 1
|
|
oldA6 ds.l 1
|
|
dateTime0 ds LongDateRec
|
|
dateTime1 ds LongDateRec
|
|
dateTime2 ds LongDateRec
|
|
newDate ds LongDateTime
|
|
myTogFlags ds.l 1 ; modified copy of togFlags
|
|
localFrame equ *
|
|
endr
|
|
|
|
rDateFieldPtr equ a2
|
|
rDateSuccPtr equ a3
|
|
rMaxValPtr equ a4
|
|
|
|
rDelta equ d3
|
|
rField equ d4
|
|
rCounter equ d5
|
|
rBaseValue equ d5 ; doesn't overlap
|
|
rChar equ d6
|
|
rHundreds equ d7
|
|
|
|
ToggleDateRegs reg a2-a4/d3-d7
|
|
|
|
with ToggleDateRec,LongDateRec,LongDateField,ToggleResults,TogglePB
|
|
import maxOldDate,maxVal
|
|
|
|
CheckSelector
|
|
link a6,#localFrame
|
|
movem.l ToggleDateRegs,-(sp) ; save regs
|
|
|
|
; pea procName
|
|
; _DebugStr
|
|
|
|
move.b delta(a6),rDelta ; get delta
|
|
ext.w rDelta ; wordize
|
|
clr.l rField ; wordize
|
|
move.b field(a6),rField ; get field
|
|
move.w rField,d0 ; temp for field
|
|
add.w d0,d0 ; double for internal use
|
|
lea dateTime0(a6,d0.w),rDateFieldPtr ; date field poitner
|
|
lea maxVal,rMaxValPtr ; maxval table
|
|
|
|
move.l paramsPtr(a6),a0 ; paramsPtr^
|
|
move.l togFlags(a0),d0 ; get copy of togFlags
|
|
andi.w #$07F,d0 ; mask out bits for LongDateRec
|
|
; fields we can't deal withÉ
|
|
btst.l #togDelta12HourBit,d0 ; but if 12-hour range for delta
|
|
beq.s @doneForcePmBit ; (no -skip)
|
|
ori.w #$400,d0 ; then force pm bit on
|
|
@doneForcePmBit ; finished adjusting togFlags
|
|
move.l d0,myTogFlags(a6) ; save for ValidDate calls
|
|
|
|
move.l mySecsPtr(a6),-(sp) ; pass @mySecs
|
|
pea dateTime0(a6) ; pass @dateTime0
|
|
_LongSecs2Date
|
|
|
|
; ToggleDate := toggleBadDelta; {assume bad}
|
|
; if (delta < -1) or (delta > 1) then goto 999;
|
|
|
|
tst.w dateTime0.era(a6) ; BC? <1/11/88med>
|
|
blt UnknownError ; out of range
|
|
|
|
move.w #toggleErr3,funcResult(a6) ; assume out-of-range error
|
|
move.l myTogFlags(a6),d0 ; get flags
|
|
btst.l #smallDateBit,d0 ; 1904-2040 range desired?
|
|
beq.s @doneTogRangeCheck ; if not, skip these tests
|
|
move.l mySecsPtr(a6),a0 ; get ptr to longSecs
|
|
tst.l (a0) ; is high longword used?
|
|
bne ToggleExit ; if so, bail
|
|
btst.l #genCdevRangeBit,d0 ; 1920-2019 range desired?
|
|
beq.s @doneTogRangeCheck ; if not, skip year adjustment
|
|
; force year (in any calendar) into range equivalent to Gregorian 1920-2019
|
|
cmp.l #genCdevRangeLo,4(a0) ; before 1920?
|
|
bcs.s @togRangeLow ; if so, go fix
|
|
cmp.l #genCdevRangeHi,4(a0) ; after 2019?
|
|
bls.s @doneTogRangeCheck ; if not, we're done adjusting
|
|
sub.w #100,dateTime0.year(a6) ; after 2019, sub 100 from year
|
|
bra.s @doneTogRangeCheck
|
|
@togRangeLow:
|
|
add.w #100,dateTime0.year(a6) ; before 1920, add 100 to year
|
|
@doneTogRangeCheck:
|
|
|
|
move.w #toggleBadDelta,funcResult(a6) ; assume bad
|
|
move.w rDelta,d0 ; temp for compare
|
|
sub.w #1,d0 ; > 1?
|
|
bgt.s @ToggleExit3 ; yes, bail
|
|
add.w #2,d0 ; < -1 ?
|
|
blt.s @ToggleExit3 ; yes? bail
|
|
|
|
;
|
|
; if (field = pmField) then if (delta <> 0) then begin
|
|
; LongSecs2Date(mySecs, dateTime0); ****
|
|
; dateTime0.hour := (dateTime0.hour+12) mod 24;
|
|
; LongDate2Secs(dateTime0,mySecs);
|
|
; goto 900;
|
|
; end;
|
|
|
|
move.w #toggleBadField,funcResult(a6) ; assume bad
|
|
cmp.w #pmField,rField ; special case?
|
|
bne.s @NotSpecialPM ; no, skip
|
|
tst.w rDelta ; zero? (tested above)
|
|
beq.s @FieldRangeOk ; skip special if so
|
|
bra SwapAmPm ; invertpm, exit
|
|
@ToggleExit3
|
|
bra ToggleExit ; for long skip & jump
|
|
@NotSpecialPM
|
|
|
|
; ToggleDate := toggleBadField; {assume bad}
|
|
; if ((field < yearField) or (field > secondField)) then goto 999;
|
|
|
|
cmp.w #yearField,rField ; out of range?
|
|
blt.s @ToggleExit3 ; bail
|
|
cmp.w #secondField,rField ; out of range?
|
|
bgt.s @ToggleExit3 ; bail
|
|
@FieldRangeOk
|
|
|
|
; WITH maxVal DO ****
|
|
; BEGIN
|
|
; year := 150;
|
|
; {if (BAnd(oldDateFlag,params.flags) = 0) then year := 10000;}
|
|
; month := 13;
|
|
; day := 35;
|
|
; hour := 24;
|
|
; minute := 60;
|
|
; second := 60;
|
|
; dayOfWeek := 7;
|
|
; dayOfYear := 400;
|
|
; weekOfYear := 60;
|
|
; END;
|
|
; LongSecs2Date(mySecs, dateTime0); ****
|
|
|
|
|
|
; if delta = 0 then begin {character type-in}
|
|
; curChar := char(ch);
|
|
; if field = pmField then begin
|
|
; with params do
|
|
; if dateTime0.hour < 12
|
|
; then rtPtr := @pmChars
|
|
; else rtPtr := @amChars;
|
|
|
|
tst.w rDelta ; zero, character typeing?
|
|
bne NoCharInput ; no, skip
|
|
move.w #toggleBadChar,funcResult(a6) ; assume bad
|
|
lea ch(a6),a0 ; ptr
|
|
move.l #2,d0 ; length
|
|
|
|
_UpperText ; _LwrString with uppercase function <3>
|
|
move.w (a0),rChar ; copy
|
|
beq.s @ToggleExit3 ; skip null
|
|
cmp.w #pmField,rField ; special case
|
|
bne.s @NoSpecPM2 ; no, skip
|
|
move.l paramsPtr(a6),a0 ; params
|
|
add.w #pmChars,a0 ; right pointer
|
|
cmp.w #NoonHr,dateTime0.hour(a6) ; am?
|
|
blt.s @1 ; no, skip
|
|
add.w #amChars-pmChars,a0 ; now pm
|
|
@1
|
|
|
|
; for j := 1 to 4 do
|
|
; if rtPtr^[j] = curChar then begin
|
|
; dateTime0.hour := (dateTime0.hour+12) mod 24;
|
|
; LongDate2Secs(dateTime0,mySecs);
|
|
; goto 900;
|
|
; end
|
|
; end;
|
|
|
|
; NOTE THAT THE FOLLOWING ASSUMES CHARS ARE 1 BYTE !!!
|
|
move.l #3,d1 ; dbra
|
|
@MatchLoop
|
|
cmp.b (a0)+,rChar ; got match?
|
|
dbeq d1,@MatchLoop ; no, skip
|
|
beq SwapAmPm ; swap if equal
|
|
|
|
@NoSpecPM2
|
|
|
|
; myLong := BAnd(ord(curChar),$F);
|
|
; {StringToNum(tempStr,myLong); so we are international!}
|
|
; baseValue := dateTime0.list[field];
|
|
; hundreds := baseValue - (baseValue mod 100);
|
|
|
|
move.w #toggleBadNum,funcResult(a6) ; assume bad
|
|
|
|
; NOTE THAT THE FOLLOWING MAKES NON-INTERNATIONAL ASSUMPTIONS ABOUT DIGIT CODES !!!
|
|
|
|
cmp.w #$FF,rChar ; too big?
|
|
bhi ToggleExit2 ; yes, bail
|
|
andi.w #$7F,rChar ; move $b0-$b9 to $30-$39
|
|
cmp.w #$30,rChar ; too small?
|
|
blo ToggleExit2 ; yes, bail
|
|
cmp.w #$39,rChar ; too big?
|
|
bhi ToggleExit2 ; yes, bail
|
|
and.b #$F,rChar ; get numeric value of digit
|
|
|
|
move.w (rDateFieldPtr),rBaseValue ; get base value
|
|
|
|
; if toggling hours in twelve-hour mode, convert hour (0-23) to 12-hour range (1-12)
|
|
cmp.w #hourField,rField ; toggling hours?
|
|
bne.s @doneHourShiftDown ; skip if not
|
|
move.l myTogFlags(a6),d1 ;
|
|
btst.l #togChar12HourBit,d1 ; 12-hour mode?
|
|
beq.s @doneHourShiftDown ; skip if not
|
|
btst.l #togCharZCycleBit,d1 ; zero-cycle?
|
|
beq.s @hourShiftDown0 ; if not, 0 & 12 are special
|
|
cmp.w #NoonHr,rBaseValue ;
|
|
blt.s @doneHourShiftDown ;
|
|
sub.w #NoonHr,rBaseValue ;
|
|
bra.s @doneHourShiftDown ;
|
|
@hourShiftDown0 ;
|
|
cmp.w #NoonHr,rBaseValue ; hour <= 12?
|
|
ble.s @hourShiftDown1 ; if so, go test for hour=0
|
|
sub.w #NoonHr,rBaseValue ; otherwise, hour -= 12
|
|
bra.s @doneHourShiftDown ;
|
|
@hourShiftDown1
|
|
tst.w rBaseValue ; hour = 0?
|
|
bne.s @doneHourShiftDown ; skip if not
|
|
move.l #NoonHr,rBaseValue ; if so, hour = 12
|
|
@doneHourShiftDown ;
|
|
|
|
move.w rBaseValue,d1 ; copy
|
|
ext.l d1 ; longize
|
|
divs #100,d1 ; get remainder
|
|
swap d1 ; now here
|
|
move.w rBaseValue,rHundreds ; copy
|
|
sub.w d1,rHundreds ; e.g. 1967 -> 1900
|
|
sub.w rHundreds,rBaseValue ; 1967 -> 67
|
|
bge.s @CharRightSign ; positive?
|
|
neg.w rChar ; no, fix
|
|
@CharRightSign
|
|
|
|
; while true do begin
|
|
; baseValue := (baseValue * 10) mod 100;
|
|
; dateTime0.list[field] := hundreds + baseValue + myLong;
|
|
; if ValidDate(dateTime0, params.flags, newDate) = validDateFields
|
|
; then goto 888;
|
|
; if (baseValue = 0) then begin
|
|
; if (myLong = 0) then goto 777;
|
|
; baseValue := myLong;
|
|
; myLong := 0;
|
|
; end;
|
|
; end;
|
|
; end;
|
|
|
|
@NumLoop
|
|
muls #10,rBaseValue ; * 10
|
|
cmp.w #100,rBaseValue ; > 100?
|
|
blt.s @BaseOk ; skip if ok
|
|
divs #100,rBaseValue ; mod 100
|
|
swap rBaseValue ; now mod
|
|
@BaseOk
|
|
move.w rHundreds,d0 ; hundreds
|
|
add.w rBaseValue,d0 ; base
|
|
add.w rChar,d0 ; char value
|
|
|
|
; if toggling hours in twelve-hour mode, convert time back to 12-hour range.
|
|
cmp.w #hourField,rField ; toggling hours?
|
|
bne.s @doneHourShiftUp ; skip if not
|
|
move.l myTogFlags(a6),d1 ;
|
|
btst.l #togChar12HourBit,d1 ; 12-hour mode?
|
|
beq.s @doneHourShiftUp ; skip if not
|
|
; process 12-hour time
|
|
btst.l #togCharZCycleBit,d1 ; zero-cycle (0..11) time?
|
|
beq.s @hourShiftUp0 ; if not, go do 12,1..11 time
|
|
; process 0..11 time
|
|
cmp.w #NoonHr,d0 ; check bounds
|
|
bge.s @hourShiftUpErr ; if bad, set err
|
|
tst.w dateTime0.pm(a6) ; am/pm?
|
|
beq.s @doneHourShiftUp ; if am, done
|
|
add.w #NoonHr,d0 ; if pm, shift up
|
|
bra.s @doneHourShiftUp ;
|
|
@hourShiftUp0 ; process 12,1..11 time
|
|
tst.w d0 ; check lo bounds
|
|
beq.s @hourShiftUpErr ; if =0, bad
|
|
tst.w dateTime0.pm(a6) ; am/pm?
|
|
beq.s @hourShiftUp1 ; if am, go fix hour=12
|
|
; pm
|
|
cmp.w #NoonHr,d0 ; check hour
|
|
beq.s @doneHourShiftUp ; if hour=12, leave alone.
|
|
bgt.s @hourShiftUpErr ; if hour>12, err (needed?)
|
|
add.w #NoonHr,d0 ; otherwise, add 12
|
|
bra.s @doneHourShiftUp ;
|
|
@hourShiftUp1 ; am
|
|
cmp.w #NoonHr,d0 ; check hour
|
|
bgt.s @hourShiftUpErr ; if >12, err
|
|
blt.s @doneHourShiftUp ; if <12, done
|
|
clr.w d0 ; otherwise, set hour=0
|
|
bra.s @doneHourShiftUp ;
|
|
@hourShiftUpErr ; error handling
|
|
move.w #-1,d0 ; make an err
|
|
@doneHourShiftUp ;
|
|
|
|
move.w d0,(rDateFieldPtr) ; set date time record
|
|
bsr xValidDate ; is it ok?
|
|
blt SetNewDate ; yes, done
|
|
|
|
cmp.w #yearField,rField ; toggling years?
|
|
bne.s @doneTogYearAdjust ; no, skip this stuff
|
|
move.l myTogFlags(a6),d0 ; get flags
|
|
btst.l #smallDateBit,d0 ; 1904-2040 range desired?
|
|
beq.s @doneTogYearAdjust ; if not, skip these tests
|
|
btst.l #genCdevRangeBit,d0 ; 1920-2019 range desired?
|
|
beq.s @doneTogYearAdjust ; if not, skip these tests
|
|
tst.l newDate(a6) ; check high longword
|
|
bmi.s @togAdjustUp ; if year < 1904, go fix
|
|
bne.s @togAdjustDown ; if year > 2040, go fix
|
|
; now check low longword for 1920-2019 range
|
|
cmp.l #genCdevRangeLo,newDate+4(a6) ; year < 1920?
|
|
bcs.s @togAdjustUp ; if so, go fix
|
|
cmp.l #genCdevRangeHi,newDate+4(a6) ; year > 2019?
|
|
bls.s @doneTogYearAdjust ; if not, we're done adjusting
|
|
@togAdjustDown:
|
|
sub.w #100,(rDateFieldPtr) ; after 2019, sub 100 from year
|
|
bra.s @togRecheckValid
|
|
@togAdjustUp:
|
|
add.w #100,(rDateFieldPtr) ; before 1920, add 100 to year
|
|
@togRecheckValid:
|
|
bsr.s xValidDate ; is it ok?
|
|
blt SetNewDate ; yes, done
|
|
@doneTogYearAdjust:
|
|
|
|
tst.w rBaseValue ; base empty?
|
|
IF FixCacheAndStr2Date THEN ; <10><11>
|
|
bne @NumLoop ; no, continue <1-8-91,jh> .w added here
|
|
ELSE ; <10>
|
|
bne.s @NumLoop ; no, continue
|
|
ENDIF ; <10>
|
|
tst.w rChar ; char empty?
|
|
beq.s ToggleExit2 ; done, bail
|
|
move.w rChar,rBaseValue ; set it
|
|
clr.w rChar ; signal done next time
|
|
IF FixCacheAndStr2Date THEN ; <10><11>
|
|
bra @NumLoop ; done <1-8-91, jh> changed to .w
|
|
ELSE ; <10>
|
|
bra.s @NumLoop ; done
|
|
ENDIF ; <10>
|
|
|
|
;----------
|
|
ToggleExit2
|
|
bra ToggleExit ; done
|
|
;----------
|
|
SwapAmPm
|
|
move.w dateTime0.hour(a6),d0 ; get value
|
|
sub.w #12,d0 ; day/night swap
|
|
bge.s @1 ; ok
|
|
add.w #24,d0 ; now ok
|
|
@1
|
|
move.w d0,dateTime0.hour(a6) ; fix
|
|
pea dateTime0(a6) ; pass @dateTime0
|
|
move.l mySecsPtr(a6),-(sp) ; pass @mySecs
|
|
_LongDate2Secs
|
|
bra ReturnOk ; exit.
|
|
|
|
;----------
|
|
xValidDate
|
|
clr.w -(sp) ; allocate return
|
|
pea dateTime0(a6) ; pass @datetime0
|
|
|
|
move.l myTogFlags(a6),-(sp) ; pass adjusted togFlags
|
|
|
|
pea newDate(a6) ; pass @newDate
|
|
_ValidDate ; call it
|
|
move.w (sp)+,d0 ; pop result
|
|
rts
|
|
;----------
|
|
; note: don't care about speed, just space
|
|
|
|
CopyDate0to1
|
|
lea dateTime0(a6),a0 ; source
|
|
lea dateTime1(a6),a1 ; dest
|
|
CopyDateA0toA1
|
|
move.w #LongDateRecSize/2-1,d0 ; dbra counter
|
|
CopyDateLoop
|
|
move.w (a0)+,(a1)+ ; copy
|
|
dbra d0,CopyDateLoop ; until done
|
|
rts
|
|
|
|
;----------
|
|
NoCharInput
|
|
|
|
; datetime1 := dateTime0;
|
|
; dateTime0.list[field] := dateTime0.list[field] + delta;
|
|
; badField := ValidDate(dateTime0, params.flags, newDate);
|
|
; if badField = validDateFields then goto 888;
|
|
|
|
bsr.s CopyDate0to1 ; copy over
|
|
add.w rDelta,(rDateFieldPtr) ; add delta
|
|
bsr.s xValidDate ; is it ok?
|
|
blt.s SetNewDate ; yes, done
|
|
|
|
; IF badField >= field THEN {try finer field}
|
|
; BEGIN
|
|
; succField := succ(field);
|
|
; FOR j := 1 TO maxVal.list[succField] DO
|
|
; BEGIN
|
|
; dateTime0.list[succField] := dateTime0.list[succField] - 1;
|
|
; IF ValidDate(dateTime0, params.flags, newDate) = validDateFields THEN
|
|
; GOTO 888;
|
|
; END;
|
|
; END;
|
|
|
|
cmp.w #pmField,d0 ; If bad field is pm,
|
|
bne.s @donePmAdjust ;
|
|
move.w #hourField,d0 ; say that it is hour instead
|
|
@donePmAdjust
|
|
|
|
cmp.w rField,d0 ;
|
|
ble.s @NoFiner ; badfield<=field, don't try finer
|
|
add.w d0,d0 ; word offset for bad field
|
|
lea dateTime0(a6,d0.w),rDateSuccPtr ; pointer to bad field
|
|
move.w 0(rMaxValPtr,d0.w),rCounter ; get maximum value
|
|
|
|
@FinerLoop
|
|
sub.w #1,(rDateSuccPtr) ; drop
|
|
bsr.s xValidDate ; is it ok?
|
|
dblt rCounter,@FinerLoop ; til done
|
|
blt.s SetNewDate ; yes, exit
|
|
|
|
@NoFiner
|
|
|
|
; dateTime0 := dateTime1;
|
|
; if delta < 0
|
|
; then dateTime0.list[field] := dateTime0.list[field] + maxVal.list[field]
|
|
; else dateTime0.list[field] := dateTime0.list[field] - maxVal.list[field];
|
|
|
|
lea dateTime1(a6),a0 ; source
|
|
lea dateTime0(a6),a1 ; dest
|
|
bsr.s CopyDateA0toA1 ; date0 := date1
|
|
move.w rField,d0 ; double for word array
|
|
add.w d0,d0 ; double
|
|
move.w 0(rMaxValPtr,d0),rCounter ; get value
|
|
move.w rCounter,d0 ; temp value for adding
|
|
tst.w rDelta ; <0?
|
|
blt.s @DeltaNegative ; yes, d0 ok
|
|
neg d0 ; reverse
|
|
@DeltaNegative
|
|
add.w d0,(rDateFieldPtr) ; bump the other direction
|
|
|
|
; for j := 0 to maxVal.List[field] do begin
|
|
; dateTime0.list[field] := dateTime0.list[field] + delta;
|
|
; if ValidDate(dateTime0, params.flags, newDate) = validDateFields then goto 888;
|
|
; end;
|
|
|
|
@BackwardsLoop
|
|
add.w rDelta,(rDateFieldPtr) ; bump
|
|
bsr.s xValidDate ; is it ok?
|
|
dblt rCounter,@BackwardsLoop ; yes, exit
|
|
blt.s SetNewDate ; with correct date from ValidDate
|
|
|
|
; Couldn't deal with it. bail
|
|
;777:
|
|
; ToggleDate := toggleUnknown;
|
|
; goto 999;
|
|
|
|
UnknownError
|
|
moveq #toggleUnknown,d0 ; unknown error
|
|
bra.s ToggleResult ; bail
|
|
|
|
SetNewDate
|
|
;888:
|
|
; mySecs := newDate;
|
|
|
|
lea newDate(a6),a0 ; source
|
|
move.l mySecsPtr(a6),a1 ; dest
|
|
move.w #4-1,d0 ; word count, -1 for dbra <12>
|
|
bsr.s CopyDateLoop ; copy date
|
|
|
|
;900:
|
|
; ToggleDate := toggleOk;
|
|
|
|
ReturnOk
|
|
moveq #toggleOk,d0 ; good return
|
|
ToggleResult
|
|
move.w d0,funcResult(a6) ; return result
|
|
;999:
|
|
; END;
|
|
;;999 :
|
|
ToggleExit
|
|
movem.l (sp)+,ToggleDateRegs ; restore registers to their original value
|
|
checkA6 ; check stack
|
|
|
|
move #argSize, d0 ; for StdUnlink
|
|
bra StdUnlink ; standard exit
|
|
|
|
endWith
|
|
endProc
|
|
|
|
;============================================================================
|
|
; LongDate Tables & equates
|
|
;============================================================================
|
|
|
|
;typedef short YearStarts[13];
|
|
;typedef double LongDate;
|
|
|
|
dy400 equ 146097 ; days in quadcentury
|
|
dy100 equ 36524 ; days in non-leap century--must be even!
|
|
dy4 equ 1461 ; days in quad year
|
|
dy1 equ 365 ; days in non-leap year
|
|
dy2001 equ 35430 ; days between jan1,1904 and jan1,2001
|
|
sd1 equ 86400 ; seconds in day
|
|
dow2001 equ 1 ; day of week for Jan 1,2001
|
|
|
|
;============================================================================
|
|
;pascal void LongDate2Secs (longDate, longSecs, selector)
|
|
; LongDateRec* longDate;
|
|
; LongDate* longSecs;
|
|
; long selector;
|
|
; register long days, years, secs, months;
|
|
; register short leapYear = 0;
|
|
;============================================================================
|
|
|
|
LongDate2Secs proc export
|
|
|
|
LD2SRec record {oldA6},decr
|
|
resultSize equ 0
|
|
argSize equ *-8
|
|
longDate ds.l 1
|
|
longSecs ds.l 1
|
|
selector ds.l 1
|
|
argBottom equ *
|
|
return ds.l 1
|
|
oldA6 ds.l 1
|
|
mulDest ds LongDateTime
|
|
leapYear ds.w 1
|
|
srcLong ds.l 1
|
|
localFrame equ *
|
|
endr
|
|
|
|
RD2SRegs reg a2/d3-d7
|
|
|
|
; d3 years
|
|
; d4 months
|
|
; d5 days
|
|
; d6 secs
|
|
; d7 temp
|
|
|
|
with LD2SRec,LongDateRec
|
|
import MonthStarts,LeapStarts
|
|
|
|
CheckSelector
|
|
link a6,#localFrame
|
|
movem.l RD2SRegs,-(sp) ; save regs
|
|
|
|
; pea procName
|
|
; _DebugStr
|
|
|
|
; initial values
|
|
|
|
; years = longDate->year - 2001;
|
|
; months = longDate->month-1;
|
|
; days = 0;
|
|
; secs = longDate->second + (longDate->minute + longDate->hour * 60) * (long) 60;
|
|
|
|
move.l longDate(a6),a2 ; longDatePtr
|
|
|
|
; add BC <1/11/88med>
|
|
|
|
lea longDateRec.era(a2),a0 ; for unloading <1/11/88med>
|
|
move.w (a0)+,d1 ; get era
|
|
move.w (a0)+,d3 ; year
|
|
tst.w d1 ; era < 0?
|
|
bge.s @EraAD ; no, skip
|
|
sub.w #1,d3 ; no year zero
|
|
neg.w d3 ; now negative
|
|
@EraAd
|
|
sub.w #2001,d3 ; - 2001
|
|
move.w (a0)+,d4 ; months
|
|
add.w #2,a0 ; skip day, for later
|
|
sub.w #1,d4 ; - 1
|
|
clr.l d5 ; days = 0
|
|
move.w (a0)+,d6 ; hour
|
|
muls #60,d6 ; * 60 (word: don't worry about overflow)
|
|
add.w (a0)+,d6 ; minute
|
|
muls #60,d6 ; * 60 (long)
|
|
move.w (a0)+,d1 ; second
|
|
ext.l d1 ; extend to add to long
|
|
add.l d1,d6 ; value for seconds
|
|
clr.b leapYear(a6) ; leapyear = 0
|
|
|
|
; if (months > 11)
|
|
; { years += (months / 12);
|
|
; months %= 12;
|
|
; }
|
|
|
|
move.w #12,d7 ; comparison value
|
|
cmp.w d7,d4 ; turn 12+ months into years
|
|
blo.s @MonthsOk ; bail if ok already
|
|
ext.l d4 ; longize for divide
|
|
divs d7,d4 ; mod & div
|
|
add.w d4,d3 ; years = years + div
|
|
swap d4 ; months = mod
|
|
tst.w d4 ; mod negative?
|
|
bge.s @MonthsOk ; if rem < 0 then mod = mod + divisor, div = div - 1
|
|
sub.w #1,d3 ; div = div - 1
|
|
add.w d7,d4 ; mod = mod + divisor
|
|
@MonthsOk
|
|
|
|
; if (years >= 400 | years <= -400)
|
|
; { days += dy400 * (years / 400);
|
|
; years %= 400;
|
|
; }
|
|
; if (years < 0)
|
|
; { years += 400;
|
|
; days -= dy400;
|
|
; }
|
|
; if (years == 399) leapYear += 2;
|
|
|
|
move.w #400,d7 ; comparison value
|
|
cmp.w d7,d3 ; year out of bounds?
|
|
blo.s @YearsPositive ; no, continue
|
|
bgt.s @YearBig400 ; too big (otherwise negative)
|
|
move.w d7,d0 ; d0=400
|
|
add.w d3,d0 ; d3 < -400?
|
|
bge.s @YearNegative ; no, continue
|
|
@YearBig400
|
|
ext.l d3 ; long for divide
|
|
divs d7,d3 ; get mod & quo
|
|
move.w d3,d1 ; divisor
|
|
swap d3 ; years = rem
|
|
ext.l d1 ; longize
|
|
move.l d1,-(sp) ; pass it
|
|
move.l #dy400,-(sp) ; pass it
|
|
pea mulDest(a6) ; pass address of result
|
|
_LongMul
|
|
add.l mulDest+4(a6),d5 ; days +=
|
|
@YearOk400
|
|
tst.w d3 ; < 0?
|
|
bge.s @YearsPositive ; no, skip <1/11/88med>
|
|
@YearNegative
|
|
add.w d7,d3 ; fix years
|
|
sub.l #dy400,d5 ; fix days
|
|
@YearsPositive
|
|
subq.w #1,d7 ; get last year in cycle
|
|
cmp.w d7,d3 ; at last year?
|
|
bne.s @LeapOk400 ; no, skip
|
|
move.b #2,leapYear(a6) ; leapyear += 2
|
|
@LeapOk400
|
|
|
|
; years and months now guaranteed to be positive!
|
|
; if (years >= 100)
|
|
; { days += dy100 * (years / 100);
|
|
; years %= 100;
|
|
; }
|
|
; if (years == 99) leapYear -= 1;
|
|
|
|
move.w #100,d7 ; comparison value
|
|
cmp.w d7,d3 ; year out of bounds?
|
|
blo.s @YearOk100 ; no, continue
|
|
ext.l d3 ; long for divide
|
|
divu d7,d3 ; get mod & quo
|
|
move.w d3,d1 ; divisor
|
|
swap d3 ; years = rem
|
|
mulu #dy100/2,d1 ; partial multiply, since it is too big
|
|
asl.l #1,d1 ; rest of the way
|
|
add.l d1,d5 ; days +=
|
|
@YearOk100
|
|
subq.w #1,d7 ; get last year in cycle
|
|
cmp.w d7,d3 ; at last year?
|
|
bne.s @LeapOk100 ; no, skip
|
|
sub.b #1,leapYear(a6) ; leapyear -= 1
|
|
@LeapOk100
|
|
|
|
; if (years >= 4)
|
|
; { days += dy4 * (years / 4);
|
|
; years %= 4;
|
|
; }
|
|
; if (years == 3) leapYear += 1;
|
|
|
|
moveq #4,d7 ; comparison value
|
|
cmp.w d7,d3 ; year out of bounds?
|
|
blo.s @YearOk4 ; no, continue
|
|
ext.l d3 ; longize for divide
|
|
divu d7,d3 ; get mod & quo
|
|
move.w d3,d1 ; quotient
|
|
swap d3 ; years = rem
|
|
mulu #dy4,d1 ; quick mul
|
|
add.l d1,d5 ; days +=
|
|
@YearOk4
|
|
subq.w #1,d7 ; get last year in cycle
|
|
cmp.w d7,d3 ; at last year?
|
|
bne.s @LeapOk4 ; no, skip
|
|
add.b #1,leapYear(a6) ; leapyear += 1
|
|
@LeapOk4
|
|
|
|
; days += years * d1;
|
|
|
|
mulu #dy1,d3 ; quick mul, dont need d3
|
|
add.l d3,d5 ; days +=
|
|
|
|
; days += MonthStarts[months];
|
|
; if (leapYear > 0)
|
|
; { if (months > 1)
|
|
; { days += 1;
|
|
; }
|
|
; }
|
|
|
|
lea MonthStarts,a0 ; get months array
|
|
tst.b leapYear(a6) ; leap?
|
|
ble.s @LeapOk ; no
|
|
lea LeapStarts,a0 ; adjust
|
|
@LeapOk
|
|
add.w d4,d4 ; for word offset
|
|
clr.l d0 ; longize
|
|
move.w 0(a0,d4.w),d0 ; get days in year
|
|
add.l d0,d5 ; add days in year
|
|
|
|
; if (longDate->day !=0) days += longDate->day;
|
|
; else if (longDate->dayOfYear != 0) days += longDate->dayOfYear;
|
|
; else
|
|
; { temp = (days - dow2001) % 7;
|
|
; if (temp < 0) temp += 7;
|
|
; days += (longDate->weekOfYear - 1) * 7 - temp + longDate->dayOfWeek + 1;
|
|
; }
|
|
; days += d2001 - 1;
|
|
|
|
move.w day(a2),d0 ; get day
|
|
bne.s @GotDay ; ok, skip
|
|
move.w dayOfYear(a2),d0 ; get day of year
|
|
bne.s @GotDay ; ok, skip
|
|
move.w weekOfYear(a2),d0 ; get week of year
|
|
sub.w #1,d0 ; make zero based
|
|
muls #7,d0 ; get days
|
|
move.l d5,d1 ; get days to year
|
|
sub.l #dow2001,d1 ; normalize for year 2001
|
|
divs #7,d1 ; get first day of year
|
|
swap d1 ; d1 = (d5-dow2001) % 7
|
|
tst.w d1 ; negative (rem)
|
|
bge.s @1 ; no, ok
|
|
add.w #7,d1 ; rem -> mod
|
|
@1
|
|
sub.w d1,d0 ; remove first day
|
|
add.w dayOfWeek(a2),d0 ; add day of week
|
|
add.w #1,d0 ; make 1 based (soon to be removed)
|
|
|
|
@GotDay
|
|
ext.l d0 ; normal
|
|
add.l #dy2001-1,d0 ; adjust
|
|
add.l d0,d5 ; now in days
|
|
|
|
; *longSecs = secs + days * secsInDayX;
|
|
|
|
move.l d5,-(sp) ; pass days
|
|
move.l #secsInDay,-(sp) ; pass secs in day
|
|
move.l longSecs(a6),-(sp) ; pass dest address
|
|
_LongMul
|
|
|
|
clr.l d1 ; for foolish addx syntax
|
|
move.l longSecs(a6),a0 ; addr of result
|
|
move.l (a0)+,d0 ; get high
|
|
add.l d6,(a0) ; add to low part
|
|
addx.l d1,d0 ; add to high part
|
|
move.l d0,-(a0) ; stick back in
|
|
|
|
IF 0 THEN
|
|
lea srcLong(a6),a1 ; address of source
|
|
move.l a1,-(sp) ; pass source address
|
|
move.l d5,(a1) ; source = long days
|
|
lea secsInDayX,a0 ; constant
|
|
move.l longSecs(a6),a1 ; dst address
|
|
move.l a1,-(sp) ; pass address
|
|
move.l (a0)+,(a1)+ ; copy
|
|
move.l (a0)+,(a1)+ ; copy
|
|
move.w (a0)+,(a1)+ ; copy
|
|
FMULL ; dst = source * dest
|
|
|
|
lea srcLong(a6),a1 ; address of source
|
|
move.l a1,-(sp) ; pass source address
|
|
move.l d6,(a1) ; source = secs
|
|
move.l longSecs(a6),-(sp) ; pass dst address
|
|
FADDL ; dst2 = extended
|
|
ENDIF
|
|
|
|
; done, so exit gracefully
|
|
|
|
movem.l (sp)+,RD2SRegs ; restore registers to their original value
|
|
checkA6 ; check stack
|
|
|
|
move.w #argSize, d0 ; for StdUnlink
|
|
bra StdUnlink ; Standard exit
|
|
|
|
endWith
|
|
endProc
|
|
|
|
|
|
|
|
;============================================================================
|
|
;pascal void LongSecs2Date (longSecs, longDate, selector)
|
|
; LongDate* longSecs;
|
|
; LongDateRec* longDate;
|
|
; long selector;
|
|
;============================================================================
|
|
|
|
LongSecs2Date proc export
|
|
|
|
LS2DRec record {oldA6},decr
|
|
resultSize equ 0
|
|
argSize equ *-8
|
|
longSecs ds.l 1
|
|
longDate ds.l 1
|
|
selector ds.l 1
|
|
return ds.l 1
|
|
oldA6 ds.l 1
|
|
fExt ds.x 1
|
|
fLong ds.l 1
|
|
mulDest ds LongDateTime
|
|
localFrame equ *
|
|
endr
|
|
|
|
; a2 LongDatePtr
|
|
; d3 years
|
|
; d4 leapyear
|
|
; d5 days
|
|
; d6 secs
|
|
; d7 temp
|
|
|
|
; leapyear contains 3 bits:
|
|
; bit 0: not end of century
|
|
; bit 1: end of quadcentury
|
|
; bit 2: end of quadyear
|
|
; so the year is a leap year if leapyear > 4: (qy + (qc or nc))
|
|
|
|
RS2DRegs reg a2/d3-d7
|
|
|
|
with LS2DRec,LongDateRec
|
|
import MonthStarts,LeapStarts,secsInDayX
|
|
|
|
CheckSelector
|
|
link a6,#localFrame
|
|
movem.l RS2DRegs,-(sp) ; save regs
|
|
|
|
; pea procName ; save
|
|
; _DebugStr
|
|
|
|
; initial values
|
|
; register long days, years, secs, dow, i, temp;
|
|
; register short leapYear = 1;
|
|
; register YearStarts*
|
|
; myStarts;
|
|
;
|
|
; days = *longSecs / secsInDayX;
|
|
; secs = *longSecs - secsInDayX * days;
|
|
|
|
move.l longDate(a6),a2 ; longDatePtr
|
|
moveq #1,d4 ; leapyear = 1
|
|
|
|
; divide a sixty-four by a 32 and produce quotient and remainder in d5, d6
|
|
|
|
move.l longSecs(a6),a0 ; get @source
|
|
move.l (a0)+,d0 ; get top
|
|
move.l (a0)+,d1 ; get bottom
|
|
cmp.l #maxDate,d0 ; too big?
|
|
blo.s @DateInRange ; no, keep going
|
|
bge.s @OutOfRangeDate ; fix
|
|
cmp.l #minDate,d0 ; now try bottom <was d2, fixed 4/07/89 pke>
|
|
bge.s @DateInRange ; ok, continue
|
|
@OutOfRangeDate
|
|
clr.l d0 ; assume zero date, cant help it
|
|
clr.l d1 ; ditto (just drop through, don't care about performance)
|
|
@DateInRange
|
|
move.l #secsInDay,d2 ; divisor
|
|
|
|
|
|
LongDiv ; results in rd1,qd0
|
|
|
|
|
|
move.l d1,d5 ; get quotient
|
|
move.l d0,d6 ; get remainder
|
|
|
|
; if secs < 0 then secs = secs + secsInDayX, days = days - 1;
|
|
|
|
bge.s @SecsPlus ; no, continue
|
|
add.l #sd1,d6 ; secs +
|
|
sub.l #1,d5 ; days -
|
|
@SecsPlus
|
|
|
|
; dow = (days + 5) % 7;
|
|
; if (dow < 0) dow += 7;
|
|
; longDate->dayOfWeek = dow+1;
|
|
|
|
move.l d5,d0 ; temp d0
|
|
add.l #5,d0 ; +5
|
|
divs #7,d0 ; (d5+5)/7
|
|
bvc.s @Mod7Ok ; mod ok, skip
|
|
|
|
; fix days if overflow <1/11/88med>
|
|
|
|
divs #16807,d0 ; divide by large power of 7
|
|
swap d0 ; get modulo
|
|
ext.l d0 ; longize
|
|
divs #7,d0 ; (d5+5)/7
|
|
@Mod7Ok
|
|
swap d0 ; modulo
|
|
tst.w d0 ; <0?
|
|
bge.s @DofWPlus ; skip if not
|
|
add.w #7,d0 ; fix
|
|
@DofWPlus
|
|
add.w #1,d0 ; make 1 based
|
|
lea dayOfWeek(a2),a0 ; for walking through array
|
|
move.w d0,(a0) ; set day of week
|
|
|
|
; longDate->second = secs % 60;
|
|
; secs /= 60;
|
|
; longDate->minute = secs % 60;
|
|
; longDate->hour = secs / 60;
|
|
|
|
move.w #60,d0 ; common factor
|
|
divu d0,d6 ; /60
|
|
swap d6 ; modulo
|
|
move.w d6,-(a0) ; save seconds in record
|
|
clr.w d6 ; longize for after swap <11/23/87med>
|
|
swap d6 ; recover divisor
|
|
divu d0,d6 ; /60
|
|
move.w d6,d0 ; save quo
|
|
swap d6 ; modulo
|
|
move.w d6,-(a0) ; save minutes in record
|
|
move.w d0,-(a0) ; save hours in record
|
|
lea pm(a2),a0 ; for storing
|
|
cmp.w #NoonHr,d0 ; am/pm?
|
|
sge d0 ; set bottom byte
|
|
neg.b d0 ; top byte already zero
|
|
move.w d0,(a0)+ ; set pm state
|
|
clr.l (a0)+ ; clear ldReserved
|
|
|
|
; days = days - dy2001;
|
|
; years = 0;
|
|
|
|
sub.l #dy2001,d5 ; normalize
|
|
clr.l d3 ; years = 0
|
|
|
|
; if (days >= dy400 | days <= -400)
|
|
; { years += 400 * (days / dy400);
|
|
; days %= dy400;
|
|
; }
|
|
; if (days < 0)
|
|
; { days += dy400;
|
|
; years -= 400;
|
|
; }
|
|
|
|
move.l #dy400,d7 ; temp comparison value
|
|
cmp.l d7,d5 ; in range?
|
|
blo.s @In400Range ; yes, skip
|
|
bgt.s @Adjust400 ; no, adjust
|
|
move.l d7,d0 ; temp
|
|
add.l d5,d0 ; > dy400?
|
|
bge.s @Adjust400Neg ; yes, just fix negation
|
|
@Adjust400
|
|
move.l d7,d2 ; divisor
|
|
move.l d5,d1 ; dividend
|
|
slt d0 ; now extend long to quad
|
|
ext.w d0 ; more
|
|
ext.l d0 ; and more
|
|
|
|
LongDiv ; results in rd1,qd0
|
|
|
|
muls #400,d1 ; get years = quotient * 400
|
|
add.l d1,d3 ; add in
|
|
move.l d0,d5 ; set remainder
|
|
|
|
; tst.l d5 ; remainder negative?
|
|
bge.s @In400Range ; no, continue
|
|
@Adjust400Neg
|
|
add.l #dy400,d5 ; bump up
|
|
sub.l #400,d3 ; fix years
|
|
@In400Range
|
|
|
|
; days are now safely positive
|
|
; temp = 0;
|
|
; if (days > dy100)
|
|
; { temp += 100 * (days / dy100);
|
|
; days %= dy100;
|
|
; if (temp == 400)
|
|
; { temp -= 100;
|
|
; days += d100;
|
|
; }
|
|
; }
|
|
; if (temp == 300) leapYear += 2;
|
|
|
|
; note: d5 is long from above.
|
|
clr.w d0 ; temp years
|
|
move.l #dy100,d7 ; comparison value
|
|
cmp.l d7,d5 ; in range?
|
|
blt.s @InRange100 ; yes, skip
|
|
move.l d5,d1 ; days
|
|
divu #dy100,d5 ; days/dy100
|
|
move.w d5,d0 ; quotient
|
|
clr.w d5 ; longize for after swap
|
|
swap d5 ; remainder=modulo
|
|
mulu #100,d0 ; 100 * (days / dy100)- don't need to add
|
|
cmp.w #300,d0 ; (years are word) leap?
|
|
blt.s @InRange100 ; no, continue
|
|
beq.s @Leap100 ; too big
|
|
sub.l #100,d0 ; back one century
|
|
add.l #dy100,d5 ; bump days up
|
|
@Leap100
|
|
add.b #2,d4 ; bump flag up
|
|
@InRange100
|
|
add.w d0,d3 ; add in to days <11/20/87med>
|
|
|
|
; years +=temp; ****
|
|
; temp = 4 * (days / dy4); ****
|
|
; days %= dy4;
|
|
; if (temp == 96) leapYear -= 1;
|
|
; years += temp;
|
|
|
|
; don't test for range of 4 years, very unlikely
|
|
; note: d5 is long from above. Do NOT sign extend.
|
|
divu #dy4,d5 ; div days
|
|
move.w d5,d0 ; quo
|
|
asl.w #2,d0 ; *4
|
|
swap d5 ; rem=mod
|
|
cmp.w #96,d0 ; end of cycle?
|
|
bne.s @InRange4 ; no, skip
|
|
sub.b #1,d4 ; bump down, at end
|
|
@InRange4
|
|
add.l d0,d3 ; years +=
|
|
|
|
; temp = (days / d1);
|
|
; days %= d1;
|
|
; if (temp < 3)
|
|
; { leapYear += 4;
|
|
; if (temp == 4)
|
|
; { temp -= 1;
|
|
; days += d1;
|
|
; }
|
|
; }
|
|
; years += temp;
|
|
|
|
ext.l d5 ; for division
|
|
divu #dy1,d5 ; get number of years in 4 yr cycle
|
|
move.w d5,d0 ; temp = quo
|
|
swap d5 ; days = remainder
|
|
cmp.w #3,d0 ; leap year?
|
|
blt.s @InRange1 ; no, skip
|
|
beq.s @Leap1 ; yes, simple case
|
|
sub.w #1,d0 ; back up a year
|
|
add.w #dy1,d5 ; correct days
|
|
@Leap1
|
|
add.b #4,d4 ; possible leap year
|
|
@InRange1
|
|
add.w d0,d3 ; years
|
|
|
|
; longDate->dayOfYear = days+1;
|
|
; {algorithm changed in asm!}
|
|
; temp = (days - longDate->dayOfWeek) % 7;
|
|
; if (temp < 0) temp += 7;
|
|
; longDate->weekOfYear = (days + temp - longDate->dayOfWeek) / 7 + 1;
|
|
; longDate->era = 0; /* for now */
|
|
|
|
move.w d5,d0 ; get days in year
|
|
add.w #1,d0 ; one-based
|
|
move.w d0,dayOfYear(a2) ; save
|
|
|
|
move.w d5,d1 ; days
|
|
ext.l d1 ; prepare to di(vid)e
|
|
divu #7,d1 ; days are unsigned
|
|
move.w d1,d0 ; save weeks
|
|
swap d1 ; get quo=rem for unsigned
|
|
cmp.w dayOfWeek(a2),d1 ; if remainder day <= day of week, add 1
|
|
blt.s @WeekOk ; ow bail (dow is 1 based, so < )
|
|
add.w #1,d0 ; fix
|
|
@WeekOk
|
|
add.w #1,d0 ; make 1 based
|
|
|
|
move.w d0,weekOfYear(a2) ; save
|
|
|
|
; if (leapYear > 4)
|
|
; {
|
|
; for (i = 0; LeapStarts[i] <= days; ++i);
|
|
; days -= LeapStarts[i-1];
|
|
; }
|
|
; else
|
|
; {
|
|
; for (i = 0; MonthStarts[i] <= days; ++i);
|
|
; days -= MonthStarts[i-1];
|
|
; }
|
|
|
|
lea MonthStarts,a0 ; assume not leap
|
|
cmp.b #4,d4 ; leap?
|
|
ble.s @ArrayOk ; no, continue
|
|
lea LeapStarts,a0 ; fix
|
|
@ArrayOk
|
|
|
|
move.l #-1,d0 ; init month
|
|
@FindMonthLoop
|
|
add.w #1,d0 ; inc month
|
|
cmp.w (a0)+,d5 ; in range yet?
|
|
bge.s @FindMonthLoop ; no, keep going (d5 limited, must terminate)
|
|
|
|
; longDate->year = years + 2001;
|
|
; longDate->month = i;
|
|
; longDate->day = days+1;
|
|
|
|
; add BC <1/11/88med>
|
|
|
|
lea era(a2),a1 ; for loading <1/11/88med>
|
|
clr.w d1 ; assume AD <1/11/88med>
|
|
add.w #2001,d3 ; add offset <11/20/87med>
|
|
bgt.s @EraOK ; skip if AD (> 0) <1/11/88med>
|
|
moveq #-1,d1 ; set BCq <1/11/88med>
|
|
neg d3 ; now positive (BC) <1/11/88med>
|
|
add.w #1,d3 ; no year zero
|
|
@EraOk
|
|
move.w d1,(a1)+ ; set era <1/11/88med>
|
|
move.w d3,(a1)+ ; set year
|
|
move.w d0,(a1)+ ; set month
|
|
sub.w -4(a0),d5 ; days in month (zero based
|
|
add.w #1,d5 ; now 1 based
|
|
move.w d5,(a1)+ ; day, and we are done
|
|
|
|
; done, so exit gracefully
|
|
|
|
movem.l (sp)+,RS2DRegs ; restore registers to their original value
|
|
checkA6 ; check stack
|
|
|
|
move.w #argSize, d0 ; for StdUnlink
|
|
bra StdUnlink ; standard exit
|
|
|
|
endWith
|
|
endProc
|
|
|
|
;============================================================================
|
|
; String & Date conversions
|
|
;============================================================================
|
|
|
|
WhiteSpace EQU 1 ; token number for white space
|
|
AlphaToken EQU 4 ; token number for string
|
|
NumericToken EQU 5 ; token number for number
|
|
AltNumericToken equ $B ; alternate token type for numbers <9/2/87med>
|
|
NonAlphNumToken EQU 16 ; token numbers starting here correspond to non-alpha numeric tokens
|
|
NilToken EQU $7F ; token number for nil
|
|
MaxTokens EQU 32 ; number of tokens for which there is space
|
|
|
|
omdy EQU 0 ; date order constants
|
|
odmy EQU 1
|
|
oymd EQU 2
|
|
omyd EQU 3
|
|
odym EQU 4
|
|
oydm EQU 5
|
|
|
|
; long date order constants defined in PackMacs.a <10/12/88ldc>
|
|
|
|
invalidPart EQU $80000000
|
|
|
|
Str15 EQU 16 ; length of string[15]
|
|
IF FixCacheAndStr2Date THEN ; <10><11>
|
|
Str4 EQU 5 ; length of string[4] added for more space-efficient cache <1-8-91jh><10>
|
|
Str8 EQU 9 ; length of string[8] ditto <1-8-91jh><10>
|
|
ENDIF ; <10>
|
|
DayMonthLen equ 15 ; length of days and months
|
|
IF FixCacheAndStr2Date THEN ; <10><11>
|
|
TimeLen equ 4 ; length of time strings
|
|
ELSE
|
|
TimeLen equ 15 ; length of time strings
|
|
ENDIF
|
|
NumDays EQU 7 ; length of various arrays
|
|
NumMonths EQU 12
|
|
IF FixCacheAndStr2Date THEN ; <10><11>
|
|
NumTimeStrings equ 4
|
|
ELSE
|
|
NumTimeStrings equ 3 ; number of time strings
|
|
ENDIF
|
|
DayList EQU NumDays*Str15
|
|
MonthList EQU NumMonths*Str15
|
|
NumStrBytes EQU 300
|
|
|
|
IF FixCacheAndStr2Date THEN ; <10><11>
|
|
;;-------BEGIN <1-8-90, jh> equates for extend itl1
|
|
; new itl1 extensions
|
|
itl1Version equ localRtn+2
|
|
itl1Format equ itl1Version+2
|
|
calendarcode equ itl1Format+2
|
|
extraDaysOffset equ calendarcode+2
|
|
extraDaysLength equ extraDaysOffset+4
|
|
extraMonthsOffset equ extraDaysLength+4
|
|
extraMonthsLength equ extraMonthsOffset+4
|
|
abbrevDaysOffset equ extraMonthsLength+4
|
|
abbrevDaysLength equ abbrevDaysOffset+4
|
|
abbrevMonthsOffset equ abbrevDaysLength+4
|
|
abbrevMonthsLength equ abbrevMonthsOffset+4
|
|
extraSepsOffset equ abbrevMonthsLength+4
|
|
extraSepsLength equ extraSepsOffset+4
|
|
; For any of the above offsets there will be data down here in all cases this
|
|
; data will have the STR# format (i.e. word for string count followed by an
|
|
; array of pstring)
|
|
|
|
extformatkey equ $A89F
|
|
maxExtraSeps equ 10 ; count of extra seps in cache, must be at least 1!! <10>
|
|
IF maxExtraSeps<1 THEN ; <10>
|
|
aerror &concat('maxExtraSeps wrong: ',&i2s(maxExtraSeps)) ; <10>
|
|
ENDIF ; <10>
|
|
itl1stCount equ 4 ; 0..4 st's in itl1
|
|
|
|
;;-----------END <1-8-91, jh> equates for extended itl1
|
|
ENDIF ; <10>
|
|
|
|
monthReplace EQU 0 ; offsets to CvtTable
|
|
reorder EQU 18
|
|
theYear EQU 0 ; offset to elements of arrays in CvtTable.reorder
|
|
theMonth EQU 1
|
|
theDay EQU 2
|
|
|
|
|
|
IF 0 THEN ; already defined
|
|
tokenOK EQU 0 ; tokenizer result constants
|
|
tokenOverflow EQU 1
|
|
stringOverflow EQU 2
|
|
badDelim EQU 3
|
|
unknownToken EQU 4
|
|
|
|
TokenRec RECORD 0,INCR ;
|
|
theToken ds.w 1 ; TokenType
|
|
position ds.l 1 ; Ptr into original source
|
|
length ds.l 1 ; length of text in original source
|
|
stringPosition ds.l 1 ; StringPtr to copy of identifier
|
|
tokenRecSize equ *
|
|
ENDR
|
|
|
|
tokenBlock RECORD 0
|
|
source DS.L 1
|
|
sourceLength DS.L 1
|
|
tokenList DS.L 1
|
|
tokenLength DS.L 1
|
|
tokenCount DS.L 1
|
|
stringList DS.L 1
|
|
stringLength DS.L 1
|
|
stringCount DS.L 1
|
|
doString DS.B 1
|
|
doAppend DS.B 1
|
|
doAlphaNumeric DS.B 1
|
|
doNest DS.B 1
|
|
leftDelims DS.W 4
|
|
rightDelims DS.W 4
|
|
leftComment DS.W 4
|
|
rightComment DS.W 4
|
|
escapeCode DS.W 1
|
|
ENDR
|
|
ENDIF
|
|
|
|
;========================IMPORTANT NOTE,POTENTIAL DANGER===================================
|
|
;
|
|
; The Data structure below is actually 6 bytes longer than the size of a
|
|
; DateCacheRecord. Initially, I fixed it so that the Record fit within 512 bytes
|
|
; but that change forced very large patches to String2Date and String2Time in the
|
|
; aurora and esprit ROMs.
|
|
;
|
|
; Since these patches were large and required a fair amount of change to ScriptMgrROMPatch.a
|
|
; we rethought fixing the cache so that it fit into 512 bytes and instead opted
|
|
; for keeping the fields in identical offsets.
|
|
;
|
|
; This is not as bad as it sounds (although it is bad, let there be no doubt about that)
|
|
; since the last 32 bytes of a tokenBlock are reserved and at this time (7.0 and earlier)
|
|
; are neither read from nor written to. For that reason, the fact that the declaration
|
|
; below is 6 bytes longer than the memory provided for it is only a forgiveable bit
|
|
; of forgetfulness.
|
|
;
|
|
; However, do NOT read or write any values past the itlResource field of the token block.
|
|
; And do NOT do what inside mac and the published headers say to do which is zero out
|
|
; the last 32 bytes of the token block. Doing that will TRASH memory. DON'T DO IT.
|
|
;========================================================================================
|
|
|
|
Cache RECORD 0
|
|
version ds.w 1
|
|
CurrentDate DS LongDateRec
|
|
BaseDate DS LongDateRec
|
|
theDays DS.B DayList
|
|
theMonths DS.B MonthList
|
|
|
|
IF FixCacheAndStr2Date THEN ; <10><11>
|
|
theEveStr DS.B Str4 ;use new string definitions to make room for altseps
|
|
theMornStr DS.B Str4 ;
|
|
the24hrAMStr DS.B Str4 ;
|
|
the24hrPMStr DS.B Str4 ;
|
|
countAltSeps DS.W 1 ;number of separator tokens <1-8-91, jh>
|
|
AltSeps DS.W maxExtraSeps ;contains an array of separator tokens <1-8-91, jh>
|
|
filler DS.B 6
|
|
ELSE ; <10>
|
|
theEveStr DS.B Str15
|
|
theMornStr DS.B Str15
|
|
the24hrStr DS.B Str15
|
|
ENDIF ; <10>
|
|
theTimeSep DS.W 1
|
|
theDateSep DS.W 1
|
|
theDateOrder DS.b 1
|
|
longDateOrder ds.b 1
|
|
theAbbrLen DS.W 1
|
|
TBlock DS tokenBlock
|
|
CacheSize equ *
|
|
theTimeStrings equ theEveStr
|
|
ENDR
|
|
|
|
MaxInteger equ $00008000 ; <10>
|
|
|
|
;============================================================================
|
|
; Utility Routines
|
|
;============================================================================
|
|
|
|
;======================================================================
|
|
; Function ValidLong(aStr: Str255): Longint; <2.5>
|
|
; Input stringPtr: ptr in A0
|
|
; Output theLong ($80000000 if invalid) in D0
|
|
; returns a valid longint, positive. Number sets status register
|
|
;======================================================================
|
|
|
|
|
|
ValidLong proc export
|
|
|
|
movem.l d3/d4,-(sp)
|
|
move.l #$80000000,d0 ; assume bad
|
|
clr.l d4
|
|
move.b (A0)+,d4 ; get length
|
|
ble.s @BailValid ; bail if not there
|
|
|
|
clr.l d1 ; longize
|
|
move.b (a0)+,d1 ; new value
|
|
sub.b #'0',d1 ; adjust
|
|
subq.b #1,D4 ; adjust string length
|
|
|
|
move.l d1,d2 ; initialize total
|
|
bra.s @FastEntry ; enter loop in middle
|
|
|
|
@FastPathLoop
|
|
; multiply by 10
|
|
|
|
add.l d2,d2 ; double
|
|
move.l d2,d3 ; save copy
|
|
lsl.l #2,d2 ; now * 8
|
|
add.l d3,d2 ; now * 10, at a cost of 6+4+12+6=28 10x = 2x + 4á2x
|
|
add.l d1,d2 ; accumulate
|
|
@FastEntry
|
|
move.b (a0)+,d1 ; new value
|
|
sub.b #'0',d1 ; adjust
|
|
dbra d4,@FastPathLoop ; yes, continue
|
|
|
|
@DoneFastPath
|
|
IF FixCacheAndStr2Date THEN ; <10><11>
|
|
|
|
cmp.l #MaxInteger,d2 ; is it greater than 32768?
|
|
bhi.s @BailValid ; yes, so it is too high, bail
|
|
|
|
ENDIF ; <10>
|
|
move.l d2,d0 ; return result and set status register
|
|
|
|
@BailValid
|
|
tst.l d0
|
|
@Exit
|
|
movem.l (sp)+,d3/d4
|
|
rts
|
|
endProc
|
|
|
|
|
|
;======================================================================
|
|
; Procedure Block2String
|
|
; Input textPtr: ptr in A0
|
|
; textLen: word in D0
|
|
; var dstStr: strNN in A1 ; not necessarily Str15 <10>
|
|
; leadSpaces: boolean in D1
|
|
; altSpace: byte in d2 <8/22/87med>
|
|
; Function Copy text to pascal string, stopping at null byte,
|
|
; stripping leading spaces, and uppercasing <1/5/88med>
|
|
; Uses A0-1,D0-2
|
|
;======================================================================
|
|
Block2String proc export
|
|
move.l d3,-(sp) ; save d3 <8/22/87med>
|
|
move.l a1,-(sp) ; save destination string for later <1/5/88med>
|
|
move.b d2,d3 ; use for alternate space <8/22/87med>
|
|
move.b d1,d2 ; move lead spaces into d2
|
|
|
|
; pin length
|
|
clr.l d1 ; assume zero
|
|
tst.l d0 ; length 0 or negative?
|
|
ble.s @QuickExit ; exit now
|
|
not.b d1 ; d2 = 255
|
|
cmp.l d1,d0 ; too big?
|
|
ble.s @NoPin ; no, keep going (catches negatives)
|
|
move.l d1,d0 ; pin at value
|
|
@NoPin
|
|
move.l a1,-(sp) ; save length position
|
|
move.l d0,d1 ; save length
|
|
add.l #1,a1 ; skip length for now
|
|
tst.b d2 ; discard leading spaces?
|
|
beq.b @CopySpaces ; no, copy everything
|
|
bra.b @DiscardSpaces ; yes, discard leading spaces
|
|
|
|
@DSLoopStart
|
|
subq.b #1,d1 ; found leading space, resultant string will be shorter by 1
|
|
@DiscardSpaces
|
|
move.b (a0)+,d2 ; get next character
|
|
cmp.b #' ',d2 ; is it a space
|
|
beq.s @1 ; keep looping <8/22/87med>
|
|
cmp.b d3,d2 ; alternate space? <8/22/87med>
|
|
@1
|
|
dbne d0,@DSLoopStart ; if yes, and we haven't exhausted string, loop
|
|
beq.b @QuickExit ; whoops! string was all spaces, return null string.
|
|
tst.b d2 ; set status register to current character
|
|
bne.b @LoopEnd ; copy string.
|
|
|
|
@CopySpaces
|
|
move.b (a0)+,d2 ; get byte
|
|
bra.s @LoopEnd ; dbra setting
|
|
@CopyBytes
|
|
move.b d2,(a1)+ ; copy
|
|
move.b (a0)+,d2 ; get byte
|
|
@LoopEnd
|
|
dbeq d0,@CopyBytes ; copy
|
|
bne.b @SkipZero ; continue if not null
|
|
sub.b d0,d1 ; readjust length as null was found
|
|
@SkipZero
|
|
; fix length, exit
|
|
move.l (sp)+,a1 ; recover length
|
|
@QuickExit
|
|
move.b d1,(a1) ; set it
|
|
|
|
move.l (sp)+,a0 ; restore string address
|
|
CLR.L D0
|
|
MOVE.B (A0)+,D0 ; UprString wants textPtr and length in D0. Get it from
|
|
; string and adjust A0 to string's text at same time
|
|
_UpperText ; _LwrString with uppercase function <3>
|
|
|
|
move.l (sp)+,d3 ; restore d3 <8/22/87med>
|
|
rts
|
|
endproc
|
|
|
|
;======================================================================
|
|
; routine Compare
|
|
; input a0 source pointer
|
|
; a1 destination pointer
|
|
; d0.w source length (>= 0)
|
|
; d1.w destination length (>=0)
|
|
; output d0.w =0 if match <>0 if not
|
|
; ccr set according to d1
|
|
; matches if source is an initial substring of destination
|
|
;======================================================================
|
|
Compare PROC EXPORT
|
|
|
|
CMP.w D1,D0 ; word length
|
|
BGT.S NotFound ; if source > destination, skip
|
|
|
|
SUBQ.w #1,D0 ; word length
|
|
;; BMI.S NotFound ; destination is never null, so omit this test. <2/23/88med>
|
|
|
|
CompareLoop
|
|
CMPM.B (A0)+,(A1)+
|
|
LoopEnd
|
|
DBNE D0,CompareLoop
|
|
;; BNE.S NotFound
|
|
|
|
CLR.L D0
|
|
BRA.S Exit
|
|
|
|
NotFound
|
|
MOVEQ #-1,D0
|
|
Exit
|
|
RTS
|
|
|
|
ENDPROC
|
|
|
|
;======================================================================
|
|
; FUNCTION MatchString (textPtr : Ptr; textLen: Integer; textMinLen: Integer;
|
|
; strArrPtr : Ptr; strArrMaxLen: Integer;
|
|
; strArrCount: Integer) : Integer; external;
|
|
; function Finds the longest match between the text and an
|
|
; initial portion of a string in the array.
|
|
; return is the number of the match (1 based), -1 if not found
|
|
;======================================================================
|
|
MatchStrFrame record {oldA6},decrement
|
|
result ds.w 1
|
|
textPtr ds.l 1
|
|
textLen ds.w 1
|
|
textMinLen ds.w 1
|
|
strArrPtr ds.l 1
|
|
strArrMaxLen ds.w 1
|
|
strArrCount ds.w 1
|
|
return ds.l 1
|
|
oldA6 ds.l 1
|
|
args equ result-return-4
|
|
endr
|
|
|
|
MatchStrRegs reg a2-a4/d3-d5
|
|
|
|
MatchString proc export
|
|
with MatchStrFrame
|
|
link a6,#Frame ; allocate
|
|
movem.l MatchStrRegs,-(sp) ; save regs
|
|
move.l textPtr(a6),a3 ; get textPtr
|
|
move.w textLen(a6),d3 ; get len
|
|
move.l strArrPtr(a6),a4 ; get string array
|
|
IF NOT FixCacheAndStr2Date THEN ; <10><11>
|
|
; moved the following into loop since we must reset every time
|
|
; around if dealing with variable length pstrings <1-8-91jh>
|
|
move.w strArrMaxLen(a6),d4 ; get max str length
|
|
ENDIF ; <10>
|
|
move.w strArrCount(a6),d5 ; get count
|
|
bra.s @EndLoop ; for dbra
|
|
@MainLoop
|
|
IF FixCacheAndStr2Date THEN ; <10><11>
|
|
; if 0 we have variable length pstrings in the array and handle
|
|
; differently, see below <1-8-91jh>
|
|
move.w strArrMaxLen(a6),d4 ; get max str length
|
|
ENDIF ; <10>
|
|
; call compare with array entry
|
|
|
|
move.l a3,a0 ; pass ptr1
|
|
move.l d3,d0 ; pass len1
|
|
clr.l d1 ; wordize
|
|
move.b (a4)+,d1 ; get length
|
|
IF FixCacheAndStr2Date THEN ; <10><11>
|
|
tst.w d4 ; if d4.w=0 then we need to remember the actual string
|
|
; length for each string and now the strArrMaxLen as
|
|
; above <1-9-91, jh>
|
|
bne.s @UsingStrArrMaxLen ; valid length in d4.2 so we don't need to remember
|
|
; the real length <1-9-91, jh>
|
|
move.b d1,d4 ; remember # of characters so we can move to next string <1-8-91 jh>
|
|
@UsingStrArrMaxLen ; added label to branch to <1-9-91, jh>
|
|
ENDIF ; <10>
|
|
move.l a4,a1 ; pass start of text
|
|
|
|
; move compare to in-line, add min length test <2/23/88med>
|
|
|
|
CMP.w D1,D0 ; word length
|
|
BGT.S @NextString ; if len actual > len template, skip
|
|
beq.s @TryCompare ; lens equal, try anyway
|
|
cmp.w textMinLen(a6),d0 ; len actual < abbrev len?
|
|
blt.s @NextString ; do next
|
|
|
|
@TryCompare
|
|
|
|
SUBQ.w #1,D0 ; word length
|
|
blt.s @NextString ; actual string is null
|
|
@CompareLoop
|
|
CMPM.B (A0)+,(A1)+
|
|
DBNE D0,@CompareLoop
|
|
beq.s @GotString ; exit <2/23/88med>
|
|
|
|
@NextString
|
|
add.w d4,a4 ; get to next string
|
|
@EndLoop
|
|
dbra d5,@MainLoop ; loop til done
|
|
|
|
bra.s @Exit ; bail with d5 = -1.
|
|
|
|
@GotString
|
|
; return number of string, 1 based
|
|
|
|
sub.w strArrCount(a6),d5 ; get difference <2/23/88med>
|
|
neg.w d5 ; now right direction <2/23/88med>
|
|
|
|
@Exit
|
|
move.w d5,result(a6)
|
|
movem.l (sp)+,MatchStrRegs ; restore regs
|
|
|
|
move.w #args, d0 ; for StdUnlink
|
|
bra StdUnlink ; standard exit
|
|
|
|
endWith
|
|
endProc
|
|
|
|
;============================================================================
|
|
InitDateCache FUNC EXPORT
|
|
;
|
|
; function InitDateCache(theCache: CachePtr): OSErr;
|
|
;
|
|
; InitDateCache will initialize the items in the DateCacheRecord pointed to by theCache^
|
|
; and set the initialized item to true
|
|
;
|
|
IF FixCacheAndStr2Date THEN ; <10><11>
|
|
SaveRegs REG A2-A4/D3-d7 ; use d5,d6,d7 in our code to cache separators <1-10-91, jh>
|
|
ELSE ; <10>
|
|
SaveRegs REG A2-A4/D3/D4
|
|
ENDIF ; <10>
|
|
|
|
InitCacheRec RECORD {A6link},decr
|
|
Result DS.W 1 ; offset to function result (integer)
|
|
paramBegin EQU *
|
|
theCache DS.L 1 ; pointer to the cache record
|
|
selector ds.l 1 ; added for resource <8/21/87med>
|
|
paramEnd EQU *
|
|
return DS.L 1
|
|
A6link DS.L 1
|
|
theTokens DS.B 2*TokenRec.tokenRecSize
|
|
Intl0 DS.L 1 ; handle, not pointer
|
|
Intl1 DS.L 1 ; handle, not pointer
|
|
altSpace ds.w 1 ; use top byte
|
|
aLongDate ds LongDateTime ; <1/12/88med>
|
|
IF FixCacheAndStr2Date THEN ; <10><11>
|
|
temp4bytes ds.l 1 ;4 bytes to cache temp string <1-10-91,jh>
|
|
ENDIF ; <10>
|
|
localsize EQU *
|
|
ENDR
|
|
|
|
WITH InitCacheRec,LongDateField
|
|
|
|
parametersize EQU paramBegin - paramEnd ; size of parameter space on stack
|
|
|
|
LINK A6,#localsize ; Establish local frame and variables
|
|
MOVEM.L SaveRegs,-(SP) ; saved used registers
|
|
|
|
CLR.W Result(A6) ; clear function result
|
|
|
|
MOVE.L theCache(A6),A2 ; cache addr
|
|
|
|
move.b #' ',altSpace(a6) ; assume no alt space
|
|
|
|
with SMgrRecord,ScriptRecord
|
|
subq.w #2,sp ; space for IntlScript result
|
|
_IntlScript
|
|
move.w (sp)+,d0 ; we know this script is ok
|
|
lsl.w #2,d0 ; make it a long offset
|
|
GetSMgrCore a0 ; get SMgrRecord pointer
|
|
move.l smgrEntry(a0,d0.w),a0 ; get ScriptRecord pointer
|
|
tst.b scriptRight(a0) ;
|
|
endwith
|
|
|
|
beq.s @NoAltSpace ; no <8/22/87med>
|
|
move.b #' '+$80,altSpace(a6) ; use alt space.
|
|
@NoAltSpace
|
|
|
|
WITH Cache
|
|
|
|
lea aLongDate(a6),a0 ; @temp
|
|
clr.l (a0)+ ; no high
|
|
move.l Time,(a0)+ ; low = current
|
|
pea aLongDate(a6) ; extended
|
|
pea CurrentDate(A2) ; get current date from system globalÉ
|
|
; Étime and convert to date
|
|
_LongSecs2Date
|
|
|
|
lea aLongDate(a6),a0 ; @temp
|
|
clr.l (a0)+ ; no high
|
|
clr.l (a0)+ ; low = current
|
|
pea aLongDate(a6) ; extended
|
|
pea BaseDate(A2) ; get base date and convert to date
|
|
_LongSecs2Date
|
|
|
|
; IUGetIntl(0): Handle
|
|
|
|
CLR.L -(SP)
|
|
CLR.W -(SP)
|
|
_IUGetIntl
|
|
MOVE.L (SP)+,Intl0(A6)
|
|
|
|
move.w ResErr,d0 ; did intl0 load in all right <1/5/88med>
|
|
BEQ.S GotIntl0Ok ; if so, go on
|
|
|
|
MOVE.W d0,Result(A6)
|
|
BRA Exit
|
|
|
|
GotIntl0Ok
|
|
|
|
MOVE.L Intl0(A6),A3
|
|
|
|
; Lock itl0 across Block2String calls (which can now move memory)
|
|
move.l a3,a0
|
|
_HLock
|
|
MOVE.L (A3),A3 ; now a3 is pointer to itl0
|
|
|
|
; Block2String(eveStr,theEveStr,4,true)
|
|
|
|
LEA eveStr(A3),A0 ; get international 0 record for evening string
|
|
LEA theEveStr(A2),A1
|
|
MOVEQ #4,D0
|
|
MOVE.B #1,D1
|
|
move.b altSpace(a6),d2 ; pass alt string <8/22/87med>
|
|
JSR Block2String ; convert packed array of char intoÉ
|
|
; Éstring with no leading spaces
|
|
|
|
; Block2String(mornStr,theMornStr,4,true)
|
|
|
|
LEA mornStr(A3),A0 ; get international 0 record for morning string
|
|
LEA theMornStr(A2),A1
|
|
MOVEQ #4,D0
|
|
MOVE.B #1,D1
|
|
move.b altSpace(a6),d2 ; pass alt string <8/22/87med>
|
|
JSR Block2String ; convert packed array of char intoÉ
|
|
; Éstring with no leading spaces
|
|
|
|
; Block2String(time1Stuff,the24hrStr,1,true)
|
|
IF FixCacheAndStr2Date THEN ; <10><11>
|
|
lea timeSuff(a3),A0 ; AM trailer for 24 hour time
|
|
lea the24hrAMStr(a2),a1 ; position in cache
|
|
moveq #4,d0 ; max four bytes per trailer
|
|
ELSE ; <10>
|
|
LEA timeSuff(A3),A0 ; get international 0 record for 24 hour string
|
|
LEA the24hrStr(A2),A1
|
|
MOVEQ #1,D0
|
|
ENDIF ; <10>
|
|
MOVE.B #1,D1
|
|
move.b altSpace(a6),d2 ; pass alt string <8/22/87med>
|
|
JSR Block2String ; convert packed array of char intoÉ
|
|
; Éstring with no leading spaces
|
|
IF FixCacheAndStr2Date THEN ; <10><11>
|
|
lea timeSuff+4(a3),A0 ; PM trailer for 24 hour time
|
|
lea the24hrPMStr(a2),a1 ; position in cache
|
|
moveq #4,d0 ; max four bytes per trailer
|
|
MOVE.B #1,D1
|
|
move.b altSpace(a6),d2 ; pass alt string <8/22/87med>
|
|
JSR Block2String ; convert packed array of char intoÉ
|
|
ENDIF ; <10>
|
|
|
|
|
|
|
|
MOVE.B timeSep(A3),theTimeSep(A2) ; get time separator from intl 0
|
|
MOVE.B dateOrder(A3),theDateOrder(A2)
|
|
MOVE.B dateSep(A3),(theTimeSep + 1)(A2)
|
|
|
|
; Now unlock itl0
|
|
move.l Intl0(A6),a0
|
|
_HUnlock
|
|
|
|
|
|
; This was moved from above to prevent itl0 and itl1 handles from being purged <7>
|
|
; before we lock them.
|
|
|
|
; IUGetIntl(1): Handle
|
|
|
|
CLR.L -(SP)
|
|
MOVE.W #1,-(SP)
|
|
_IUGetIntl
|
|
MOVE.L (SP)+,Intl1(A6)
|
|
|
|
TST.W ResErr ; did intl1 load in all right
|
|
BEQ.S GotIntl1 ; if so, go on
|
|
|
|
MOVE.W ResErr,Result(A6)
|
|
BRA Exit
|
|
|
|
GotIntl1
|
|
|
|
|
|
MOVE.L Intl1(A6),A3
|
|
|
|
; Lock itl1 across Copy Array calls; it calls Block2String, which can now move memory
|
|
move.l a3,a0
|
|
_HLock
|
|
MOVE.L (A3),A3 ; now a3 is pointer to itl1
|
|
|
|
; Get the long date order and convert <8/24/87med>
|
|
; false => dmy, true => mdy; otherwise fancy stuff
|
|
; see constants defined above: omdy, odmy, etc.
|
|
|
|
move.l #omdy,d1 ; assume false
|
|
clr.w d0 ; wordize
|
|
move.b lngDateFmt(a3),d0 ; get long format
|
|
beq.s @GotLong ; done
|
|
move.l #odmy,d1 ; assume true
|
|
cmp.b #$FF,d0 ; true?
|
|
beq.s @GotLong ; yes, got it
|
|
|
|
; if we are looking at the long date, only the day and year are important,
|
|
; since the dayOfWeek and month are both strings. Walk through the format until
|
|
; we find either one or the other
|
|
|
|
@LongFmtLoop
|
|
move.b d0,d2 ; get bottom half-nybble
|
|
and.b #3,d2 ; got it
|
|
cmp.b #longDay,d2 ; day?
|
|
beq.s @GotLong ; yes, return #odmy
|
|
cmp.b #longYear,d2 ; year?
|
|
beq.s @LongYearFirst ; go for it
|
|
lsr.b #2,d0 ; strip bottom
|
|
bne.s @LongFmtLoop ; repeat until done
|
|
@LongYearFirst
|
|
move.l #oymd,d1 ; year first (also if none found)
|
|
|
|
@GotLong
|
|
move.b d1,longDateOrder(a2) ; set it
|
|
|
|
; continue <8/24/87med>
|
|
|
|
MOVE.B abbrLen(A3),theAbbrLen(A2) ; get abbrLen
|
|
|
|
; changed order for more convenience in the later routine <2/23/88med>
|
|
|
|
lea months(a3),a4 ; source of days <2/23/88med>
|
|
LEA theMonths(A2),a1 ; destination names of the day and months
|
|
MOVE.L #(numMonths - 1),D3 ; load day and months from intl 1 rec into space
|
|
jsr CopyArray ; copy days
|
|
|
|
lea days(a3),a4 ; source of days <2/23/88med>
|
|
LEA theDays(A2),a1 ; destination names of the day and months
|
|
MOVE.L #(numDays - 1),D3 ; load day and months from intl 1 rec into space
|
|
jsr CopyArray ; copy days
|
|
|
|
|
|
IF FixCacheAndStr2Date THEN ; <10><11>
|
|
|
|
; Begin addition where we try to cache any valid st0 through st4 strings <10>
|
|
; and any alternative separators included in the extended itl1
|
|
; note that these separators are not cached as strings but as tokens produced by IntlTokenize
|
|
; jh, 1-8-91
|
|
; Notes on the loop:
|
|
; An itl1 has 5 fields that are declared as PACKED ARRAY[1..4] OF CHAR
|
|
; This field contain valid separators for the long date format
|
|
; This loop walks through those arrays, and converts valid separators into pascal
|
|
; strings; those strings are then converted to tokens and potentially cached in the subroutine TokenizeSepAndCache
|
|
; Register usage in the loop:
|
|
; a0-used to pass address of separator string to TokenizeSepAndCache
|
|
; a1-used briefly in the beginning to copy the date separator obtained previously from the itl0 into the cache
|
|
; a2-just like the rest of this code holds pointer to the cache
|
|
; a3-contains pointer to itl1
|
|
; a4-points at the ST arrays is
|
|
; d0-used to hold characters so they can be compared to null and space
|
|
; d1-used as a scratch register
|
|
; d3 - loop control for inner loop
|
|
; d4 - used to hold count of characters placed in temp4bytes, for that reason used to pass length of string to TokenizeSepAndCache
|
|
; d6 - loop control for outer loop
|
|
; d7 - holds available cache space
|
|
|
|
|
|
move.w #maxExtraSeps,d7 ;hold onto the maximum tokens allowed
|
|
clr.w CountAltSeps(a2) ;clear the count
|
|
|
|
; get the itl resource and stash it in parameter block
|
|
WITH TBlock
|
|
clr.l -(sp) ; return handle
|
|
move.w #4,-(sp) ; get itl4
|
|
_IUGetIntl
|
|
move.l (sp)+,itlResource(a2) ; store itl resource
|
|
ENDWITH
|
|
beq @FatalError ; couldn't get it give up
|
|
|
|
lea st0(a3),a4 ;load start of 4-byte char blocks
|
|
move.l #4,d6 ; 5 ST strings to look at
|
|
|
|
@startSTLoop
|
|
clr.l d4 ; clear our offset into temp4bytes
|
|
move.w #3,d3
|
|
lea temp4bytes(a6),a1 ;get our temp string address
|
|
|
|
@char4loop
|
|
move.b (a4)+,d0
|
|
beq.s @looptotop ; yes its null so just continue
|
|
cmp.b #32,d0 ; space ?
|
|
beq.s @looptotop ; yes don't copy it, but continue
|
|
move.b d0,(a1)+
|
|
addq #1,d4 ;increment our offset
|
|
|
|
@looptotop
|
|
dbra d3,@char4loop ;loop back
|
|
|
|
tst.w d4 ; if d4 > 0 we have some sort of string
|
|
beq.s @looptoTopST ; its 0 so look at the next st[x]
|
|
|
|
;if we got a string we want to turn it into a Token here and then stick the token into
|
|
; our cache
|
|
moveq #1,d5 ; only one token permitted
|
|
|
|
;now we need to tokenize this separator and check to see if it is in the cache
|
|
lea temp4bytes(a6),A0 ; load the address of the source text into A0 which is where the subroutine expects it
|
|
bsr TokenizeSep ; branch to subroutine
|
|
bne.s @looptoTopST ; something went wrong with that one
|
|
bsr CompareAndCache; check the token against the cache
|
|
ble.s @DoneWithItls ; if we have run out of cache, quit this
|
|
@looptoTopST
|
|
dbra d6,@startSTloop
|
|
|
|
;now we've copied the old st0-st4 separators, its time to check and see if we are
|
|
;dealing with an extended itl1 that might have some more separators added
|
|
cmp.w #extformatkey,localRtn(a3) ;is local routine $A89F ($A89F (unimplemented trap)
|
|
; is used here to flag this itl1 as an extended itl1)
|
|
bne.s @DoneWithItls ;nope, so branch around extra sep copying code
|
|
|
|
move.l extraSepsOffset(a3),d1 ;ok move the offset into d1
|
|
beq.s @DoneWithItls ;moved a 0 nothing is actually here so give it up
|
|
|
|
move.l extraSepsLength(a3),d0 ;how long is this array
|
|
ble.s @DoneWithItls ;negative or 0 means nothing is really here so get out
|
|
add.l a3,d1 ;add offset to ptr to itl1
|
|
move.l d1,a4 ;move result to a4
|
|
move.w (a4)+,d3 ;move the count of extra separators to d3,
|
|
subq #1,d3 ;for dbra
|
|
clr.l d4 ;clear d4 for safety
|
|
moveq #1,D5 ;D5 carrys number of token recs allowed into subroutine
|
|
@extraSepLoop
|
|
move.b (a4)+,d4 ;A0 points at the length byte, put that in d4 and increment a0 to point at actual string
|
|
move.l a4,a0 ;TokenizeSep expects source in a0
|
|
bsr TokenizeSep ; branch to subroutine
|
|
bne.s @extraSepLoop ; NE is tokenizer failed
|
|
bsr CompareAndCache ; tokenizer was OK so compare the token and potentially cache it
|
|
ble.s @DoneWithItls ; if we have run out of cache, quit this
|
|
add d4,a4 ; increment to next string
|
|
dbra d3,@extraSepLoop
|
|
|
|
@DoneWithItls
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;end addition
|
|
;jh, 1-8-91 <10>
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;end addition
|
|
ENDIF ; <10>
|
|
|
|
; Now unlock itl1
|
|
move.l Intl1(A6),a0
|
|
_HUnlock
|
|
|
|
IF NOT FixCacheAndStr2Date THEN ; <10><11>
|
|
; load the tokenizer parameter block for later
|
|
|
|
WITH TBlock
|
|
|
|
LEA theTokens(A6),A0 ; spaces for tokens in local frame
|
|
MOVE.L A0,tokenList(A2)
|
|
move.l #2,d0 ; less filling <1/4/88med>
|
|
MOVE.L d0,tokenLength(A2) ; no more than 2 tokens, please
|
|
CLR.L tokenCount(A2)
|
|
CLR.L DoString(A2) ; clear out DoString, DoAppend, DoAlphaNumeric, and DoNest
|
|
|
|
LEA leftDelims(A2),A0
|
|
MOVE.W #(decimalCode-leftDelims)/2,D0 ; load NilToken into leftDelims, rightDelims, leftComment, <1/4/88med>
|
|
@LOOP0
|
|
MOVE.W #NilToken,(A0)+ ; RightComment, EscapeCode & decimal code
|
|
DBRA D0,@LOOP0
|
|
|
|
; get the itl resource and stash it in parameter block <1/4/88med>
|
|
|
|
clr.l -(sp) ; return handle
|
|
move.w #4,-(sp) ; get itl4
|
|
_IUGetIntl
|
|
move.l (sp)+,itlResource(a2) ; store itl resource
|
|
|
|
; get the token corresponding to the time separator
|
|
|
|
LEA theTimeSep(A2),A0
|
|
MOVE.L A0,source(A2) ; inside With TBlock <1/4/88med>
|
|
move.l #2,d0 ; less filling <1/4/88med>
|
|
MOVE.L d0,sourceLength(A2) ; inside With TBlock <1/4/88med>
|
|
|
|
ENDWITH ; TBlock
|
|
|
|
; IntlTokenize(@TBlock): signedByte;
|
|
|
|
CLR.B -(SP)
|
|
PEA TBlock(A2)
|
|
_IntlTokenize ; tokenize text
|
|
TST.B (A7)+ ; check if ok
|
|
BEQ.S GotSeparators ; if so, handle the token
|
|
|
|
ELSE ; new way calls our subroutine <10>
|
|
|
|
|
|
LEA theTimeSep(A2),A0 ;get ready for tokenize sub routine
|
|
moveq #2,d5 ;we allow two tokens
|
|
move.l #2,d4 ; length into d4
|
|
bsr TokenizeSep ;
|
|
beq.s GotSeparators ; OK so back to the old code
|
|
|
|
@FatalError ;added label so I could branch here from new code <10>
|
|
ENDIF
|
|
|
|
MOVE.W #fatalDateTime,Result(A6) ; if not, exit procedure and return fatal error
|
|
BRA.S Exit
|
|
|
|
GotSeparators
|
|
MOVE.W theTokens(A6),theTimeSep(A2)
|
|
MOVE.W (theTokens + TokenRec.tokenRecSize)(A6),theDateSep(A2) ; store date and time sep tokens
|
|
MOVE.L #MaxTokens,TBlock.tokenLength(A2) ; no more than 2 tokens, please
|
|
|
|
Exit
|
|
MOVEM.L (SP)+,SaveRegs ; restore registers to their original value
|
|
|
|
move.w #parametersize, d0 ; for StdUnlink
|
|
bra StdUnlink ; standard exit
|
|
|
|
; little subroutine for code savings
|
|
; a4 is source pointer
|
|
; a1 is dest pointer
|
|
; d3 is byte length
|
|
|
|
CopyArray
|
|
move.l a1,d4 ; dest ptr <2/23/88med>
|
|
|
|
@LOOP MOVE.L A4,A0 ; move string from intl 1 rec <2.5>
|
|
MOVE.L d4,A1 ; into local frame <2/23/88med>
|
|
|
|
moveq #0,d0 ; Block2String wants a long! <2.5>
|
|
MOVE.B (A0)+,D0 ; with length from first byte of string
|
|
MOVEQ #1,D1 ; with no local frame
|
|
move.b altSpace(a6),d2 ; pass alt string <8/22/87med>
|
|
JSR Block2String
|
|
ADD.L #Str15,d4 ; get next string to transfer
|
|
ADD.w #Str15,A4 ; into next string in local frame <2.5>
|
|
DBRA D3,@LOOP
|
|
rts
|
|
|
|
IF FixCacheAndStr2Date THEN ; { <10><11>
|
|
;-----------------------------------------------------------------------------------
|
|
; TokenizeSep
|
|
; This subroutine is called to tokenize any separator we have found and store the
|
|
; resulting token in the datecache
|
|
; registers
|
|
; INPUT
|
|
; A0 - ptr to the source text
|
|
; A2 - which holds a ptr to the cache which contains a token paramblock
|
|
; D5 - number of tokens allowed
|
|
; D4 - length of source text
|
|
; TRASHED
|
|
; A1,D0,D1
|
|
; sets NE if Tokenizer fails
|
|
;-------------------------------------------------------------------------------------
|
|
|
|
TokenizeSep
|
|
; load the tokenizer parameter block for later
|
|
|
|
WITH TBlock
|
|
|
|
LEA theTokens(A6),A1 ; spaces for tokens in local frame
|
|
MOVE.L A1,tokenList(A2)
|
|
MOVE.L d5,tokenLength(A2) ; number of tokens allowed (shouldn't be more than 2)
|
|
CLR.L tokenCount(A2)
|
|
CLR.L DoString(A2) ; clear out DoString, DoAppend, DoAlphaNumeric, and DoNest
|
|
|
|
LEA leftDelims(A2),A1
|
|
MOVE.W #(decimalCode-leftDelims)/2,D0 ; load NilToken into leftDelims, rightDelims, leftComment
|
|
@LOOP0
|
|
MOVE.W #NilToken,(A1)+ ; RightComment, EscapeCode & decimal code
|
|
DBRA D0,@LOOP0
|
|
|
|
|
|
; get the address of the source from a1
|
|
|
|
MOVE.L A0,source(A2) ; inside With TBlock
|
|
MOVE.L d4,sourceLength(A2) ; d4 holds the length
|
|
|
|
ENDWITH ; TBlock
|
|
|
|
; IntlTokenize(@TBlock): signedByte;
|
|
|
|
CLR.B -(SP)
|
|
PEA TBlock(A2)
|
|
_IntlTokenize ; tokenize text
|
|
tst.b (sp)+ ; test the result and set the return bit
|
|
|
|
rts
|
|
|
|
;---------------------------------------------------------------------------------------------------
|
|
; CompareAndCache
|
|
; Once we've sucessfully tokenized one of the separators we use this routine to compare
|
|
; the new token against the stuff already in the cache
|
|
; if the new token is not there it is cached
|
|
;
|
|
; REGISTERS
|
|
; INPUT
|
|
; a2 - Ptr to cache
|
|
; d7.w - token slots available in cache
|
|
; TRASHED
|
|
; d0,d1,a1
|
|
; SETS cc AT EXIT BASED ON UPDATED d7.w
|
|
;-------------------------------------------------------------------------------------------------
|
|
CompareAndCache
|
|
WITH TBlock
|
|
|
|
; so we have a token type in theTokenRec
|
|
lea AltSeps(a2),a1 ; get destination in a1
|
|
move.w countAltSeps(a2),d0 ; number of tokens in d0
|
|
beq.s @storeToken ; none there so store it
|
|
subq #1,d0 ; for dbra
|
|
@tokenCompare ; otherwise compare token with whats in the cache
|
|
move.w (a1)+,d1
|
|
cmp.w theTokens(a6),d1 ;
|
|
beq.s @quitSubroutine ; we've already got this one so lets get on with it
|
|
; addq #2,a1 ; increment the pointer into the cache
|
|
dbra d0,@tokenCompare ; ne so look at the next one
|
|
@storeToken
|
|
move.w theTokens(A6),(a1) ; when loop completes a1 points at first empty slot
|
|
add.w #1,countAltSeps(a2) ; increment our count of separators
|
|
subq #1,d7 ; decrement our number of available token slots in cache
|
|
|
|
ENDWITH
|
|
@quitSubroutine
|
|
tst.w d7 ; set condition codes
|
|
rts
|
|
|
|
ENDIF ; } <10>
|
|
|
|
|
|
ENDWITH ; Cache
|
|
ENDWITH
|
|
ENDFUNC
|
|
;============================================================================
|
|
String2Date FUNC EXPORT
|
|
;
|
|
;function String2Date( textPtr: Ptr;
|
|
; textLen: longint;
|
|
; theCache: DateCachePtr;
|
|
; var lengthUsed: longint;
|
|
; var DateTime: LongDateRec): Integer;
|
|
;
|
|
; String2Date will look for a date in the text given it according to the international
|
|
; resource format. Using the Tokenizer routine it will look for a dayOfWeek (which will
|
|
; be a string), a month (either a string or a number) and a day and year (both numbers).
|
|
; If the month is a number, order is decided by the ShortDate format in INTL 0; otherwise
|
|
; String2Date uses a table. Note if only two numbers are found they are assumed to be day
|
|
; and month. If one number is found it is assumed to be a date. Missing fields are
|
|
; filled in by the current date and time
|
|
;
|
|
; Register Usage
|
|
;
|
|
; A2 - Work register D3 - loop control register
|
|
; A3 - Work register D4 - MonthFound
|
|
; A4 - Cache Addr D5 - ResultNum
|
|
; D6 - AbbrLen
|
|
; D7 - NumDelimsFound
|
|
;
|
|
|
|
SaveRegs REG D3-D7/A2-a4 ; removed a5 <8/22/87med>
|
|
|
|
DateFrame RECORD {A6link},decr
|
|
Result DS.W 1 ; offset to function result (integer)
|
|
paramBegin EQU *
|
|
textPtr DS.L 1 ; offset to Date2Time's paramters
|
|
textLen DS.L 1
|
|
theCache DS.L 1 ; @DateCacheRecord
|
|
RestofText DS.L 1 ; @Longint
|
|
DateTime DS.L 1 ; @LongDateRec
|
|
selector ds.l 1 ; added for resource <8/21/87med>
|
|
paramEnd EQU *
|
|
return DS.L 1
|
|
A6link DS.L 1
|
|
theTokens DS.B MaxTokens*TokenRec.tokenRecSize ; storage for tokens found by tokenizer
|
|
theDate DS LongDateRec ; date time rec
|
|
results DS.W 3 ; three temporary results
|
|
myDateOrder DS.W 1
|
|
DayFound DS.W 1
|
|
lastItemSep DS.W 1
|
|
lastToken DS.W 1
|
|
lastTokenAddr DS.L 1
|
|
lastExToken DS.W 1
|
|
dummyLongDate ds LongDateTime
|
|
stringStorage DS.B NumStrBytes
|
|
localsize EQU *
|
|
ENDR
|
|
|
|
WITH DateFrame
|
|
With Cache,LongDateField
|
|
|
|
parametersize EQU paramBegin - paramEnd ; size of parameter space on stack
|
|
|
|
LINK A6,#localsize ; Establish local frame and variables
|
|
MOVEM.L SaveRegs,-(SP) ; saved used registers
|
|
bsr DateTimeEntry ; initialize & call _IntlTokenize
|
|
|
|
; Note that DateTimeEntry also does the following:
|
|
; 1. moves theCache(a6) into a4
|
|
; 2. moves TheTokens(a6) into a3
|
|
; 3. sets result(a6)
|
|
; 4. clears D7,D6; sets D5.L = -1
|
|
; 5. after IntlTokenize, sets D3= number of tokens - 1
|
|
|
|
tst.w result(a6) ; entry failed?
|
|
bne DTComExit ; bail if so
|
|
|
|
; specific stuff
|
|
|
|
MOVEQ #-1,D4 ; initialize MonthFound to -1
|
|
CLR.W DayFound(A6)
|
|
LEA CurrentDate(A4),A1 ; source
|
|
LEA theDate(A6),A0 ;
|
|
MOVE.L (A1)+,(A0)+ ; era, year
|
|
MOVE.L (A1)+,(A0)+ ; month, day
|
|
MOVE.L (A1)+,(A0)+ ; hour, minute
|
|
move.w (a1)+,(a0)+ ; second
|
|
CLR.W (A0)+ ; clear out dayOfWeek. Will either be set by user orÉ
|
|
; Ébe set in the course of the validity check of the date
|
|
MOVE.B theAbbrLen(A4),D6
|
|
|
|
WITH TokenRec
|
|
|
|
@TokenLoop
|
|
MOVE.W theToken(A3),D1 ; get token code from TokenRec record at (A3)
|
|
CMP.W #NonAlphNumToken,D1 ; is it a separator
|
|
BGE.S @FoundSeparator
|
|
SUB.W #WhiteSpace,D1 ; was it a white space?
|
|
BEQ @TokenLoopEnd ; ignore
|
|
SUBQ.W #(AlphaToken - WhiteSpace),D1 ; is it an alpha token?
|
|
IF FixCacheAndStr2Date THEN ; { <10><11>
|
|
beq @FoundAlpha ; <1-8-91, jh> changed to .w
|
|
SUBQ.W #(NumericToken - AlphaToken),D1 ; is it a number token?
|
|
BEQ @NumberToken ; <1-8-91, jh> changed to .w
|
|
SUBQ.W #(AltNumericToken - NumericToken),D1 ; is it a number token? <9/2/87med>
|
|
BEQ @NumberToken ; <1-8-91, jh> changed to .w <9/2/87med>
|
|
ELSE ; }{ <10>
|
|
beq.s @FoundAlpha
|
|
SUBQ.W #(NumericToken - AlphaToken),D1 ; is it a number token?
|
|
BEQ.S @NumberToken
|
|
SUBQ.W #(AltNumericToken - NumericToken),D1 ; is it a number token? <9/2/87med>
|
|
BEQ.S @NumberToken ; <9/2/87med>
|
|
ENDIF ; } <10>
|
|
BRA @TokenLoopEnd ; ignore any other characters
|
|
|
|
@FoundSeparator
|
|
TST.B D7 ; possible separator. Has a separator already been found?
|
|
BEQ.S @OneDelimFound ; no, so no error yet
|
|
OR.W #TooManySeps,Result(A6) ; yes, so now we have too many separators
|
|
|
|
@OneDelimFound
|
|
IF FixCacheAndStr2Date THEN ; { <10><11>
|
|
;***********************
|
|
;begin <1-8-91 jh> changes <10>
|
|
;here we compare if any of the separators in the itl1 equal this so-called
|
|
;separator we just found
|
|
;*********************
|
|
cmp.w theDateSep(a4),d1 ; start by comparing the DateSep (which is not cached with the other stuff) with the new token
|
|
beq.s @SeparatorFound ; found it
|
|
move.w countAltSeps(a4),d0 ; d0 will be our loop counter
|
|
beq.s @SeparatorFound ; hmm, nothing cached, but didn't match DateSep we could fail completely
|
|
; but I guess will just go with the old method of having everything match
|
|
subq #1,d0 ; set up for dbra
|
|
lea AltSeps(a4),a0 ; address of alternate separators
|
|
@compareSeps
|
|
cmp.w (a0)+,d1 ; compare cached tokens with new token
|
|
beq.s @SeparatorFound ; found it branch out of loop
|
|
dbra d0,@compareSeps ; decrement and branch
|
|
;no separator match. If any of the date is there we set up for an error and kind of continue
|
|
TST.w D5 ; is this after the first number loaded? (.w)
|
|
bmi.s @firstNonAlphaInvalid ; if first non-alphanumeric isn't a valid separator we return dateTimeInvalid
|
|
or.w #SepNotIntlSep+sepNotConsistent+extraneousStrings,Result(a6)
|
|
bra.s @SeparatorFound
|
|
@firstNonAlphaInvalid
|
|
OR.W #dateTimeInvalid,Result(A6) ; date not valid, return error
|
|
BRA DTComExit
|
|
|
|
@SeparatorFound
|
|
;;********************************************
|
|
; end <1-8-91, jh> changes <10>
|
|
;;********************************************
|
|
ENDIF ; } <10>
|
|
ADDQ.B #1,D7 ; record separator found
|
|
TST.w D5 ; is this after the first number loaded? (.w) <1/5/88med>
|
|
BMI @TokenLoopEnd ; if we have not reached a number yet go on
|
|
BNE.S @CheckDateSep ; if we loaded in a number then check consistency
|
|
|
|
MOVE.W D1,lastItemSep(A6) ; otherwise update lastItemSep with just found separator
|
|
BRA @TokenLoopEnd
|
|
|
|
@CheckDateSep
|
|
CMP.W lastItemSep(A6),D1 ; are they consistent
|
|
BEQ @TokenLoopEnd ; if yes, then go on
|
|
|
|
OR.W #SepNotIntlSep+sepNotConsistent,Result(A6) ; record warning
|
|
BRA @TokenLoopEnd
|
|
|
|
@NumberToken
|
|
; check for numbers separated only by white space <9/2/87med>
|
|
tst.w d7 ; got a separator?
|
|
bne.s @1 ; yes
|
|
tst.w d5 ; first number?
|
|
blt.s @1 ; yes, skip
|
|
bne.s @0 ; have 1 number
|
|
move.w #WhiteSpace,lastItemSep(A6) ; set separator
|
|
bra.s @1 ; continue
|
|
@0
|
|
cmp.w #WhiteSpace,lastItemSep(a6) ; same?
|
|
beq.s @1 ; yes, continue
|
|
or.w #SepNotIntlSep+sepNotConsistent,Result(A6) ; record warning
|
|
@1
|
|
; end of white space check <9/2/87med>
|
|
|
|
CLR.L D7 ; clear out past separators
|
|
CMP.W #2,D5 ; make sure that results array is not full
|
|
BGE @ExtrnsToken ; if full, record warning and search for final string (remove .s <2.5>)
|
|
|
|
; ValidLong(position,textLength): longint
|
|
|
|
MOVE.L stringPosition(A3),A0
|
|
JSR ValidLong ; get number in text at TokenRec.position
|
|
IF FixCacheAndStr2Date THEN ; <10><11>
|
|
bpl.s @numberOK ; branch around error if the number is a valid long
|
|
ori.w #dateTimeInvalid,result(a6) ;bad number so or in the dateTimeInvalid error
|
|
bra DTComExit ; and branch to our exit place
|
|
@numberOK
|
|
ELSE ; <10>
|
|
|
|
BMI DTComExit
|
|
|
|
ENDIF
|
|
|
|
bsr FixValue
|
|
bra @TokenRecognized ; get next token (remove .s <2.5>)
|
|
|
|
@FoundAlpha
|
|
CLR.L D7 ; clear out past separators
|
|
;; CMP.L length(A3),D6 ; is alpha token string length less than abbrLen? <2/23/88med>
|
|
;; BGT @ExtrnsToken ; if so, record warning and continue searching <2/23/88med>
|
|
|
|
; UprString(newTextPtr,AbbrLen) ; and make it uppercase for case insensitive search
|
|
|
|
MOVE.L stringPosition(A3),A2
|
|
ADDQ.L #1,A2
|
|
MOVE.L A2,A0
|
|
;; MOVE.L D6,D0
|
|
MOVE.L length(A3),D0 ; use real length
|
|
|
|
_UpperText ; _LwrString with uppercase function <3>
|
|
|
|
TST.W D4 ; d4<0: month not found, otherwise month num
|
|
BPL.S @SearchForDay ; <2.5>
|
|
|
|
; MatchString(newTextPtr,AbbrLen,@months,15,12): integer
|
|
|
|
CLR.W -(SP) ; attempt to find a day/month string which matches alpha token
|
|
MOVE.L A2,-(SP)
|
|
MOVE.W length+2(a3),-(SP) ; push length as integer <2/22/88med>
|
|
MOVE.W D6,-(SP) ; push minlen as integer <2/23/88med>
|
|
PEA theDays(A4)
|
|
MOVE.W #DayMonthLen,-(SP)
|
|
;; MOVE.W #NumMonths,-(SP)
|
|
MOVE.W #NumMonths+NumDays,-(SP) ; check for both at once <2/23/88med>
|
|
JSR MatchString
|
|
MOVE.W (SP)+,D2 ; save in D2
|
|
;; BLE.S @CheckForDay
|
|
BLE.S @ExtrnsToken ; checking both <2/23/88med>
|
|
|
|
; decide between days and months <2/23/88med>
|
|
|
|
sub.w #NumDays,d2 ; months? <2/23/88med>
|
|
ble.s @CheckForDay ; no, do days <2/23/88med>
|
|
|
|
; got a month
|
|
|
|
CMP.W #2,D5 ; is result array already full?
|
|
BGE.S @ExtrnsToken ; if so, then its not a needed token
|
|
|
|
;; CMP.W #NumMonths,D2 ; dump <2/23/88med>
|
|
;; BGT.S @CheckForDay ; got a month but out of range?, check if day <2/23/88med>
|
|
ADDQ.W #1,D5 ; is in range, result is not full and string
|
|
MOVE.W D5,D1 ; did not match as a day
|
|
ADD.W D1,D1 ; double index for integer array
|
|
LEA results(A6),A1 ; ResultNum:= ResultNum + 1
|
|
MOVE.W D2,(A1,D1.W) ; results[ResultNum]:= match result
|
|
MOVE.W D5,D4 ; MonthFound:= resultNum
|
|
BRA.S @TokenRecognized
|
|
|
|
; if day not found yet, we need to see if current string matches a day <2.5>
|
|
@SearchForDay
|
|
TST.B DayFound(a6) ; have we found one yet?
|
|
BNE.S @ExtrnsToken ; day already found, record warning
|
|
|
|
CLR.W -(SP) ; attempt to find a day string which matches alpha token
|
|
MOVE.L A2,-(SP)
|
|
MOVE.W length+2(a3),-(SP) ; push length as integer
|
|
MOVE.W D6,-(SP) ; push minlen as integer
|
|
PEA theDays(A4)
|
|
MOVE.W #DayMonthLen,-(SP)
|
|
MOVE.W #NumDays,-(SP) ; just check days this time
|
|
JSR MatchString
|
|
MOVE.W (SP)+,D2 ; save in D2
|
|
BLE.S @ExtrnsToken ; checking both
|
|
|
|
BRA.S @HaveDay
|
|
|
|
@CheckForDay
|
|
TST.B DayFound(a6) ; off of a6! <8/24/87med>
|
|
BNE.S @ExtrnsToken ; day already found, record warning
|
|
|
|
IF 0 THEN ; <2/23/88med>
|
|
; MatchString(newTextPtr,AbbrLen,@days,15,12): integer
|
|
|
|
CLR.W -(SP) ; also attempt to find a day stringÉ
|
|
; Éwhich matches alpha token
|
|
MOVE.L A2,-(SP)
|
|
;; MOVE.W D6,-(SP) ; push length as integer
|
|
MOVE.W length(a3),-(SP) ; push length as integer <2/22/88med>
|
|
PEA theDays(A4)
|
|
MOVE.W #DayMonthLen,-(SP)
|
|
MOVE.W #NumDays,-(SP)
|
|
JSR MatchString
|
|
MOVE.W (SP)+,D2 ; save DResult in D2
|
|
BLE.S @ExtrnsToken ; neither matched a day or month, record warning
|
|
|
|
CMP.W #NumDays,D2
|
|
BGT.S @ExtrnsToken ; day out of range, record warning
|
|
ENDIF ; <2/23/88med>
|
|
|
|
add.w #NumDays,d2 ; restore days
|
|
@HaveDay
|
|
ST DayFound(A6) ; record that day was found <2.5>
|
|
MOVE.W D2,theDate.dayOfWeek(A6) ; otherwise, load dayOfWeek into date time record
|
|
|
|
TST.W D5 ; is dayOfWeek between two numbers (.w) <1/5/88med>
|
|
BMI.S @NoWarning ; if no number has been found yet, go on
|
|
OR.W #fieldOrderNotIntl,Result(A6) ; record warning
|
|
@NoWarning
|
|
BRA.S @TokenRecognized
|
|
|
|
@ExtrnsToken
|
|
TST.W lastExToken(A6) ; is this the first extraneous token found?
|
|
BPL.S @TokenLoopEnd ; no, go on
|
|
|
|
MOVE.W D3,lastExToken(A6) ; a string which we don't recognize has been found
|
|
BRA.S @TokenLoopEnd ; record warning and go on
|
|
|
|
@TokenRecognized
|
|
MOVE.W D3,lastToken(A6)
|
|
MOVE.L A3,lastTokenAddr(A6) ; save loop and token addr for later use
|
|
|
|
@TokenLoopEnd
|
|
ADD.L #tokenRecSize,A3 ; add size of TokenRec record to A3 to get next token
|
|
CMP.W #2,D5 ; if the result array full (.w) <1/5/88med>
|
|
SGE D0
|
|
AND.B DayFound(A6),D0 ; and dayofWeek string been found
|
|
DBNE D3,@TokenLoop ; then stop loop, otherwise go until all tokens are looked at
|
|
|
|
TST.W D5 ; test if ResultNum is negative
|
|
BPL.S @CheckRestTokens ; if not, go on and check the rest of the tokens
|
|
|
|
OR.W #dateTimeNotFound,Result(A6)
|
|
BRA DTComExit ; if no numbers were found, exit function
|
|
|
|
@CheckRestTokens
|
|
bsr CheckRest
|
|
|
|
;CheckIfSepIntl
|
|
LEA CvtTables,A0 ; load A0 with addr of convert tables
|
|
LEA results(A6),A1 ; load A1 with addr of results
|
|
|
|
move.b longDateOrder(a4),d2 ; assume long date order
|
|
TST.W D4
|
|
BPL.S CheckDateOrder ; if month string found, don't check sep but date order
|
|
move.b theDateOrder(a4),d2 ; is actually short-date
|
|
|
|
TST.W D5 ; first off, check if we needed separator
|
|
BEQ.S MonthNotFound ; if only one number, dont check, go on
|
|
|
|
MOVE.W lastItemSep(A6),D0 ; separators were used
|
|
CMP.W theDateSep(A4),D0 ; was the separator the date separator?
|
|
BEQ.S MonthNotFound ; if yes, go on
|
|
|
|
OR.W #SepNotIntlSep,Result(A6) ; no, return warning
|
|
BRA.S MonthNotFound
|
|
|
|
CheckDateOrder
|
|
OR.W #LongDateFound,Result(A6) ; month string found, long date
|
|
; now clear out warnings irrelevant to long date
|
|
AND.W #-(fieldOrderNotIntl + sepNotConsistent + SepNotIntlSep + 1),Result(A6)
|
|
TST.W D5 ; if Month was found than we must fix order to include it
|
|
BNE.S NotMonthOnly
|
|
MOVEQ #1,D5 ; but if month was all that was found than include date
|
|
MOVE.W #1,2(A1) ; as first day of month (result[1]:= 1). Year will be
|
|
; current year
|
|
NotMonthOnly
|
|
MOVE.W D4,D0 ; theDateOrder= CvtTable.monthReplace[FoundMonth,theDateOrder]
|
|
MULU.W #6,D0 ; fix theDateOrder so that month is where it was found
|
|
ADD.B D2,D0
|
|
MOVE.B monthReplace(A0,D0.W),d2 ; fix order
|
|
; MOVE.B monthReplace(A0,D0.W),theDateOrder(A4)
|
|
|
|
; CMP.B theDateOrder(A4),D0 ; is date order still intl?
|
|
; BEQ.S MonthNotFound ; if so, go on
|
|
; OR.W #fieldOrderNotIntl,Result(A6) ; otherwise record warning
|
|
|
|
WITH LongDateRec
|
|
|
|
MonthNotFound
|
|
CLR.L D1
|
|
LEA theDate(A6),A2 ; load theDate addr in A2
|
|
MOVE.W D5,D0 ; copy ResultNum
|
|
MULU.W #24,D0 ; 24 byte array. multiply index by 24
|
|
; MOVE.B theDateOrder(A4),D2
|
|
ADD.B D2,D2
|
|
ADD.B D2,D2 ; four byte array. multiply index by 4
|
|
ADD.B D2,D0
|
|
MOVE.B (reorder + theYear)(A0,D0.W),D1 ; get CvtTables.reorder[resultNum,theDateOrder].year
|
|
BMI.S YearNotDefined ; if less than zero go to month
|
|
ADD.W D1,D1
|
|
MOVE.W (A1,D1.W),theDate.year(a6) ; theDate.year:= result[year]
|
|
YearNotDefined
|
|
MOVE.B (reorder + theMonth)(A0,D0.W),D1 ; get CvtTables.reorder[resultNum,theDateOrder].month
|
|
BMI.S MonthNotDefined ; if less than zero go to day
|
|
ADD.W D1,D1
|
|
MOVE.W (A1,D1.W),theDate.month(a6) ; theDate.month:= result[month]
|
|
MonthNotDefined
|
|
MOVE.B (reorder + theDay)(A0,D0.W),D1 ; get CvtTables.reorder[resultNum,theDateOrder].day
|
|
ADD.W D1,D1 ; day is always defined, so load it in
|
|
MOVE.W (A1,D1.W),theDate.day(a6) ; theDate.day:= result[day]
|
|
|
|
CMP.W #1,D5 ; were three numbers found?
|
|
BLE.S ValidateDate ; no, so don't bother adjusting year
|
|
|
|
|
|
MOVE.W BaseDate.year(A4),D0
|
|
move.w theDate.year(a6),d1 ; temp values
|
|
CMP.W d1,D0 ; is starting year of Mac calender more than current year
|
|
BLE.S ValidateDate ; if not than year is Ok and see if everthing else is valid
|
|
|
|
; CMP.W #10,d1 ; is year from input less than 10?
|
|
; BGE.S Adjust100 ; if not, adjust century
|
|
; MOVE.W #10,D0 ; yes fill in current decade, century and millenia
|
|
; BRA.S AdjustYear ; do adjustment
|
|
|
|
;Adjust100
|
|
|
|
CMP.W #100, d1 ; is year from input less than 100?
|
|
BGE.S Adjust1000 ; if not adjust millenia
|
|
|
|
lowerYear equ 10
|
|
upperYear equ 100-lowerYear
|
|
|
|
;<9/27/88ldc> Added code to determine how to interpret input years less than 100
|
|
; If currentdate.year >= upperYear and theDate.year <= lowerYear then
|
|
; theDate.year goes to next century
|
|
; else if currentDate.year <= lowerYear and theDate.year >= upperYear then
|
|
; theDate.year goes to previous century
|
|
; else theDate.year belongs in the current century
|
|
|
|
move.w CurrentDate.year(a4), d0 ; currentYear mod 100 <= lowerYear?
|
|
divu.w #100, d0 ; currentYear mod 100 >= upperYear
|
|
mulu.w #100, d0 ;
|
|
move.w d0, d1 ; copy
|
|
move.w CurrentDate.year(a4), d0 ;
|
|
sub.w d1, d0 ; d0 := currentdate.year mod 100
|
|
move.w theDate.year(a6), d1 ;
|
|
cmp.w #upperYear, d0 ; CurrentDate.year mod 100 >= upper year bound?
|
|
bls.s @checkLowerYear ; no, check less than lower
|
|
cmp.w #lowerYear, d1 ; theDate.year <= 10?
|
|
bgt.s Adjust100 ; no, so assume in same century
|
|
add.w #100, theDate.year(a6) ; yes, so put this year in the next century
|
|
bra.s Adjust100
|
|
|
|
@checkLowerYear
|
|
cmp.w #lowerYear, d0 ; current year mod 100 <= lowerYear ?
|
|
bgt.s Adjust100 ; no, no need to adjust
|
|
cmp.w #upperYear, d1 ; input year >= upperYear?
|
|
bls.s Adjust100 ; no, just adjust century
|
|
sub.w #100, theDate.year(a6) ; adjust input date and fall through
|
|
|
|
Adjust100
|
|
|
|
MOVE.W #100,D0 ; yes fill in current century and millenia
|
|
BRA.S AdjustYear
|
|
|
|
Adjust1000
|
|
CMP.W #1000,d1 ; is year from input less than 1000?
|
|
BGE.S ValidateDate ; if not, than there is nothing we can do about it
|
|
MOVE.W #1000,D0 ; put in current millenia
|
|
|
|
AdjustYear
|
|
MOVE.W CurrentDate.year(A4), D1 ; theDate.year:= (CurrentDate.year div D0)*D0 + theDate.year
|
|
DIVU.W D0,D1
|
|
MULU.W D0,D1
|
|
ADD.W D1,theDate.year(a6)
|
|
|
|
ValidateDate
|
|
move.l #yearMask++monthMask++dayMask,d0 ; fields to test <1/11/88med>
|
|
tst.w theDate.dayOfWeek(a6) ; if dayofweek was not gotten from user then <1/11/88med>
|
|
beq.s @0 ; <1/11/88med>
|
|
or.l #dayOfWeekMask,d0 ; add checking this field <1/11/88med>
|
|
@0
|
|
bsr CheckValid ; check the date <1/11/88med>
|
|
blt.s FoundDate ; yes, exit <1/11/88med>
|
|
|
|
ENDWITH ; LongDateRec
|
|
|
|
OR.W #dateTimeInvalid,Result(A6) ; date not valid, return error
|
|
BRA.S DTComExit
|
|
|
|
FoundDate
|
|
MOVE.L DateTime(A6),A1
|
|
LEA theDate(A6),A0
|
|
MOVE.W LongDateRec.dayOfWeek(A0),LongDateRec.dayOfWeek(A1)
|
|
MOVE.L (A0)+,(A1)+ ; era, year
|
|
MOVE.L (A0)+,(A1)+ ; month, day; load date fields into DateTime parameter
|
|
MOVE.L RestofText(A6),A0 ; return last byte of text used
|
|
|
|
;======================================================================
|
|
DTComFinish
|
|
MOVE.L lastTokenAddr(A6),A1
|
|
MOVE.L TokenRec.position(A1),(A0)
|
|
MOVE.L textPtr(A6),D0
|
|
SUB.L TokenRec.length(A1),D0
|
|
SUB.L D0,(A0) ; restofText:= lastToken.position + lastToken.length
|
|
; - textPtr
|
|
DTComExit
|
|
MOVEM.L (SP)+,SaveRegs ; restore registers to their original value
|
|
UNLK A6 ; get rid of local frame and variables
|
|
MOVE.L (SP)+,A0 ; pull return addr
|
|
ADD.L #parametersize,SP ; destroy parameters on stack
|
|
JMP (A0)
|
|
;======================================================================
|
|
CheckRest
|
|
MOVE.L lastTokenAddr(A6),A3
|
|
ADD.L #tokenRecSize,A3 ; get addr of token after last used token
|
|
MOVE.W lastToken(A6),D3 ; restore loop variable
|
|
|
|
TST.W lastExToken(A6) ; any extranous tokens found?
|
|
BMI.S @NoExTokens ; if none anywhere, go on
|
|
CMP.W lastExToken(A6),D3 ; was it after the last token to be recognized
|
|
BGT.S @NoExTokens ; if so, go on
|
|
|
|
OR.W #extraneousStrings,Result(A6) ; no, extraneous token was found
|
|
@NoExTokens
|
|
MOVEQ.L #0,D1 ; force zero flag on
|
|
BRA.S @LoopEnd
|
|
@CheckToken
|
|
MOVE.W theToken(A3),D1 ; get token code from TokenRec record at (A3)
|
|
SUBQ.W #WhiteSpace,D1 ; was it a white space?
|
|
ADD.L #tokenRecSize,A3
|
|
@LoopEnd
|
|
DBNE D3,@CheckToken ; ignore white spaces
|
|
|
|
ENDWITH ; TokenRec
|
|
|
|
TST.B D3
|
|
BMI.S @0 ; if all tokens were checked, branch
|
|
OR.W #LeftOverChars,Result(A6) ; otherwise report left overs
|
|
@0
|
|
rts
|
|
;======================================================================
|
|
FixValue
|
|
ADDQ.W #1,D5 ; resultNum:= resultNum + 1;
|
|
MOVE.W D5,D1
|
|
ADD.W D1,D1 ; integer array, so double index
|
|
LEA results(A6),A1
|
|
MOVE.W D0,(A1,D1.W) ; results[resultNum]:= ValidLong(position,length)
|
|
rts
|
|
|
|
;======================================================================
|
|
DateTimeEntry
|
|
;
|
|
; Side effects (comment added <1.9>)
|
|
; Note that if textLen(a6) ² 0 then nothing is set up except result(a6)
|
|
;
|
|
; 1. moves theCache(a6) into a4
|
|
; 2. moves TheTokens(a6) into a3
|
|
; 3. sets result(a6)
|
|
; 4. clears D7,D6; sets D5.L = -1
|
|
; 5. after IntlTokenize, sets d3= number of tokens - 1
|
|
|
|
; first check degenerate case (len = 0) <8/24/87med>
|
|
|
|
move.w #dateTimeNotFound,result(a6) ; assume bad
|
|
tst.l textLen(A6) ; bad case?
|
|
ble.s DateEntryExit ; yes, take off
|
|
|
|
; continue with initialization <8/24/87med>
|
|
|
|
CLR.W Result(A6) ; clear function result
|
|
MOVE.L theCache(A6),A4
|
|
|
|
CLR.L D7 ; clear out any delims
|
|
CLR.L D6
|
|
MOVEQ #-1,D5 ; initialize ResultNum to -1
|
|
CLR.W lastItemSep(A6) ; clear out separator found in input
|
|
CLR.W lastToken(A6)
|
|
MOVE.W #-1,lastExToken(A6) ; put -1 in lastExToken
|
|
MOVE.L RestOfText(A6),A0
|
|
CLR.L (A0) ; default RestOfText:= 0;
|
|
|
|
LEA results(A6),A0
|
|
CLR.L (A0)+
|
|
CLR.W (A0)+ ; Clear out result array
|
|
|
|
WITH TBLock
|
|
|
|
LEA theTokens(A6),A0 ; spaces for tokens in local frame
|
|
MOVE.L A0,tokenList(A4)
|
|
ST DoString(A4)
|
|
LEA stringStorage(A6),A0
|
|
MOVE.L A0,stringList(A4)
|
|
MOVE.L #NumStrBytes,stringLength(A4)
|
|
MOVE.L textPtr(A6),source(A4) ; tokenize starting at text given routine
|
|
MOVE.L textLen(A6),sourceLength(A4) ; for length given texT
|
|
LEA TheTokens(A6),A3 ; put address of the tokens in A3
|
|
|
|
ENDWITH ; TBlock
|
|
|
|
; IntlTokenize(@Cache^.TBlock): signedByte;
|
|
|
|
CLR.B -(SP)
|
|
PEA TBlock(A4)
|
|
_IntlTokenize ; tokenize text
|
|
TST.B (A7)+ ; check if ok
|
|
BEQ.S @HandleTokens ; if so, handle the tokens
|
|
|
|
OR.W #fatalDateTime,Result(A6) ; if not, exit procedure and return fatal error
|
|
bra.s DateEntryExit
|
|
|
|
@HandleTokens
|
|
MOVE.L TBlock.tokenCount(A4),D3 ; get number of tokens
|
|
SUBQ #1,D3
|
|
clr.w result(a6) ; show ok
|
|
DateEntryExit
|
|
rts
|
|
|
|
;======================================================================
|
|
CheckValid
|
|
move.w #0,-(sp) ; allocate return
|
|
pea theDate(a6) ; pass the date
|
|
move.l d0,-(sp) ; fields to test
|
|
pea dummyLongDate(a6) ; toss result
|
|
_ValidDate ; check it
|
|
tst.w (sp)+ ; ok? (lt?)
|
|
rts
|
|
;======================================================================
|
|
WITH DateOrders
|
|
|
|
CvtTables
|
|
; first array is a 0..2 x 0..6 array, for recasting type when month is inserted
|
|
|
|
; mdy dmy ymd myd dym ydm
|
|
DC.B mdy, mdy, myd, myd, mdy, myd ; month is 0
|
|
DC.B dmy, dmy, ymd, ymd, dmy, ymd ; month is 1
|
|
DC.B dym, dym, ydm, ydm, dym, ydm ; month is 2
|
|
|
|
; second array is a triple array, first by number of elements
|
|
; each item is y,m,d; with -1 for no setting
|
|
; extra 0 is because pascal pads subarrays to even boundary
|
|
|
|
; mdy dmy ymd myd dym ydm
|
|
DC.B -1,-1,0,0, -1,-1,0,0, -1,-1,0,0, -1,-1,0,0, -1,-1,0,0, -1,-1,0,0 ; 1 element
|
|
DC.B -1, 0,1,0, -1, 1,0,0, -1, 0,1,0, -1, 0,1,0, -1, 1,0,0, -1, 1,0,0 ; 2 elements
|
|
DC.B 2, 0,1,0, 2, 1,0,0, 0, 1,2,0, 1, 0,2,0, 1, 2,0,0, 0, 2,1,0 ; 3 elements
|
|
|
|
;============================================================================
|
|
export String2Time
|
|
String2Time
|
|
;
|
|
;function String2Time( textPtr: Ptr;
|
|
; textLen: longint;
|
|
; theCache: CachePtr;
|
|
; var lengthUsed: longint;
|
|
; var DateTime: LongDateRec): integer;
|
|
;
|
|
; String2Time will look for a time in the text given it according to the international resource format. It will
|
|
; look for 1 to 3 numbers in the text using the IntlTokenize routine and assign them to the hour minute and second
|
|
; respectively. If it finds the evestr (in the INTL 0 resource) in the text 12 will be added to the hour.
|
|
;
|
|
; Register Usage
|
|
;
|
|
; A2 - Work register D3 - loop control register
|
|
; A3 - Work register D4 - PMFound
|
|
; A4 - CacheAddr D5 - ResultNum
|
|
; D6 - TimeSep
|
|
; D7 - NumDelimsFound
|
|
;
|
|
|
|
LINK A6,#localsize ; Establish local frame and variables
|
|
MOVEM.L SaveRegs,-(SP) ; saved used registers
|
|
|
|
bsr DateTimeEntry
|
|
tst.w result(a6) ; entry failed?
|
|
bne DTComExit ; bail if so
|
|
|
|
; specific stuff
|
|
|
|
CLR.W D4 ; assume PM not found
|
|
LEA theDate(A6),A0
|
|
LEA BaseDate(A4),A1
|
|
MOVE.w LongDateRec.dayOfWeek(A1),LongDateRec.dayOfWeek(A0)
|
|
MOVE.L (A1)+,(A0)+ ; era, year
|
|
MOVE.L (A1)+,(A0)+ ; hour, minute
|
|
|
|
WITH TokenRec
|
|
@TokenLoop
|
|
MOVE.W theToken(A3),D1 ; get token code from TokenRec record at (A3)
|
|
CMP.W #NonAlphNumToken,D1 ; is it a separator
|
|
BGE.S @FoundSeparator
|
|
sub.w #WhiteSpace,D1 ; was it a white space?
|
|
beq @TokenLoopEnd ; ignore
|
|
SUBQ.W #(AlphaToken - WhiteSpace),D1 ; is it an alpha token?
|
|
BEQ @FoundAlpha
|
|
SUBQ.W #(NumericToken - AlphaToken),D1 ; is it a number token?
|
|
BEQ.S @NumberToken
|
|
SUBQ.W #(AltNumericToken - NumericToken),D1 ; is it a number token? <9/2/87med>
|
|
BEQ.S @NumberToken ; <9/2/87med>
|
|
BRA @TokenLoopEnd ; ignore any other characters
|
|
|
|
@FoundSeparator
|
|
TST.B D7 ; possible separator. Has a separator already been found?
|
|
BEQ.S @OneDelimFound ; no, so no error yet
|
|
OR.W #TooManySeps,Result(A6) ; yes, so now we have too many separators
|
|
|
|
@OneDelimFound
|
|
ADDQ.B #1,D7 ; record separator found
|
|
TST.w D5 ; is this after the first number loaded?
|
|
BEQ.S @GetTimeSep ; one number has been loaded in, so get separator
|
|
BPL.S @CheckTimeSep ; if we loaded in a number then check consistentcy
|
|
|
|
OR.W #extraneousStrings,Result(A6) ; shouldn't be anything before time, record warning
|
|
BRA @TokenLoopEnd
|
|
|
|
@GetTimeSep
|
|
MOVE.W D1,lastItemSep(A6) ; otherwise update lastItemSep with just found separator
|
|
BRA @TokenLoopEnd
|
|
|
|
@CheckTimeSep
|
|
CMP.W lastItemSep(A6),D1 ; are they consistent
|
|
BEQ @TokenLoopEnd ; if yes, than go on
|
|
|
|
OR.W #SepNotIntlSep+sepNotConsistent,Result(A6) ; record warning
|
|
BRA @TokenLoopEnd
|
|
|
|
@NumberToken
|
|
; check for numbers separated only by white space <9/2/87med>
|
|
tst.w d7 ; got a separator?
|
|
bne.s @1 ; yes
|
|
tst.w d5 ; first number?
|
|
blt.s @1 ; yes, skip
|
|
bne.s @0 ; have 1 number
|
|
move.w #WhiteSpace,lastItemSep(A6) ; set separator
|
|
bra.s @1 ; continue
|
|
@0
|
|
cmp.w #WhiteSpace,lastItemSep(a6) ; same?
|
|
beq.s @1 ; yes, continue
|
|
or.w #SepNotIntlSep+sepNotConsistent,Result(A6) ; record warning
|
|
@1
|
|
; end of white space check <9/2/87med>
|
|
|
|
CLR.L D7 ; clear out past separators
|
|
CMP.w #2,D5 ; make sure that results array is not full
|
|
BGE.s @ExtrnsToken ; if full, record warning and search for final string
|
|
|
|
; ValidLong(position,textLength): longint
|
|
|
|
MOVE.L stringPosition(A3),A0
|
|
JSR ValidLong ; get number in text at TokenRec.position
|
|
BMI DTComExit
|
|
|
|
TST.B D6 ; have we found a number after finding AM, PM or 24 hr str?
|
|
BEQ.S @RightFieldOrder
|
|
OR.W #fieldOrderNotIntl,Result(A6) ; if so, record a warning but go on
|
|
|
|
@RightFieldOrder
|
|
bsr FixValue
|
|
BRA.s @TokenRecognized ; get next token
|
|
|
|
@FoundAlpha
|
|
TST.B D6
|
|
BNE.S @ExtrnsToken ; if time strings have been found record warning
|
|
|
|
; UprString(newTextPtr,AbbrLen) ; and make it uppercase for case insensitive search
|
|
|
|
MOVE.L stringPosition(A3),A2
|
|
ADDQ.L #1,A2
|
|
MOVE.L A2,A0
|
|
MOVE.L length(A3),D0
|
|
_UpperText ; _LwrString with uppercase function <3>
|
|
|
|
; change to use MatchString <2/22/88med>
|
|
; MatchString(newTextPtr,AbbrLen,@months,15,12): integer
|
|
|
|
CLR.W -(SP) ; attempt to find a time string which matches alpha token
|
|
MOVE.L A2,-(SP)
|
|
MOVE.W length+2(a3),-(SP) ; push length as integer
|
|
MOVE.W #2,-(SP) ; push minlen as integer <2/23/88med>
|
|
PEA theTimeStrings(a4) ; array
|
|
|
|
MOVE.W #TimeLen,-(SP)
|
|
MOVE.W #NumTimeStrings,-(SP)
|
|
JSR MatchString
|
|
MOVE.W (SP)+,D2 ; save in D2
|
|
BLE.S @DiscardAlpha ; not found, exit gracefully
|
|
cmp.w #2,d2 ; morning?
|
|
bgt.s @GotRightString ; 24hour, exit
|
|
st D4 ; save comparison of alpha token and evening string (-1 if =)
|
|
blt.s @GotRightString ; done if eve
|
|
neg.b d4 ; +1 for AM
|
|
|
|
@GotRightString
|
|
st D6 ; record whether or not time string has been found
|
|
TST.B D7 ; were any separators found. Should be none before time str
|
|
BEQ.S @DiscardAlpha ; if so, go on
|
|
OR.W #TooManySeps,Result(A6) ; otherwise record error
|
|
|
|
@DiscardAlpha
|
|
CLR.L D7 ; clear out any previous separators found
|
|
TST.B D6 ; was a string actually found that we recognize
|
|
BNE.S @TokenRecognized ; if so, record token
|
|
|
|
@ExtrnsToken
|
|
TST.W lastExToken(A6) ; is this the first extraneous token found?
|
|
BPL.S @TokenLoopEnd ; no, go on
|
|
|
|
MOVE.W D3,lastExToken(A6) ; a string which we don't recognize has been found
|
|
BRA.S @TokenLoopEnd ; record warning and go on
|
|
|
|
@TokenRecognized
|
|
MOVE.W D3,lastToken(A6)
|
|
MOVE.L A3,lastTokenAddr(A6) ; put in here for later use
|
|
|
|
@TokenLoopEnd
|
|
ADD.L #tokenRecSize,A3 ; add size of TokenRec record to A3 to get next token
|
|
; CMP.B #2,D5 ; if the result array full
|
|
; SGE D0
|
|
; OR.B D6,D0 ; and time string been found <8/24/87med>
|
|
tst.b d6 ; time string been found <8/25/87med>
|
|
DBNE D3,@TokenLoop ; then stop loop, otherwise go until all tokens are looked at
|
|
|
|
TST.w D5 ; test if ResultNum is negative
|
|
BPL.s @CheckRestTokens ; if not, go on and check the resot of the tokens
|
|
|
|
OR.W #dateTimeNotFound,Result(A6)
|
|
BRA DTComExit ; if no numbers were found, exit function
|
|
|
|
@CheckRestTokens
|
|
bsr CheckRest
|
|
|
|
;CheckIfSepIntl
|
|
TST.w D5 ; first off, check if we needed separator
|
|
BEQ.S CheckPMString ; if only one number, dont check, go on
|
|
MOVE.W lastItemSep(A6),D0 ; separators were used
|
|
CMP.W theTimeSep(A4),D0 ; was the separator the time separator?
|
|
BEQ.S CheckPMString ; if yes, go on
|
|
OR.W #SepNotIntlSep,Result(A6) ; no, return warning
|
|
|
|
CheckPMString
|
|
move.l #NoonHr,d0 ; for testing <8/25/87med>
|
|
TST.B D4 ; was PM/AM string found?
|
|
BEQ.S SaveTime ; no
|
|
blt.s @FixPM
|
|
@FixAM
|
|
sub.w results(a6),d0 ; hour >= 12? <8/22/87med>
|
|
bgt.s SaveTime ; yes, skip add <8/22/87med>
|
|
neg d0 ; 12 => 0, 13 => 1...
|
|
move.w d0,results(a6) ; set result
|
|
bra.s SaveTime ; continue
|
|
@FixPM
|
|
cmp.w results(a6),d0 ; d0 >=? <8/22/87med>
|
|
ble.s SaveTime ; yes, skip add <8/22/87med>
|
|
ADD.W d0,results(A6) ; 11- => x+12
|
|
|
|
SaveTime
|
|
cmp.w #24,results(A6) ; catch degenerate case
|
|
bne.s @1 ; no, skip
|
|
clr.w results(a6) ; set 24:xx:xx to 00:xx:xx
|
|
@1
|
|
LEA results(A6),A2
|
|
LEA theDate.hour(A6),A3
|
|
MOVE.L (A2)+,(A3)+ ; load hour and minute into theDate
|
|
MOVE.W (A2)+,(A3)+ ; load secs into theDate. Note any numbers not found are 0
|
|
|
|
move.l #hourMask++minuteMask++secondMask,d0
|
|
bsr CheckValid ; valid?
|
|
blt.s FoundTime ; yes, exit
|
|
|
|
OR.W #dateTimeInvalid,Result(A6) ; date not valid, return error
|
|
BRA DTComExit
|
|
|
|
FoundTime
|
|
MOVE.L DateTime(A6),A1
|
|
ADDQ.L #LongDateRec.hour,A1
|
|
LEA theDate.hour(A6),A0
|
|
MOVE.L (A0)+,(A1)+
|
|
MOVE.W (A0)+,(A1)+
|
|
MOVE.L RestofText(A6),A0
|
|
bra DTComFinish
|
|
|
|
ENDWITH ;DateOrders
|
|
ENDWITH
|
|
ENDFUNC
|
|
END
|