mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-29 20:49:19 +00:00
3378 lines
110 KiB
Plaintext
3378 lines
110 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
|