                opt     l+,o+,ow-
*
*   string.s version 7.6 - © Copyright 1990 Jaba Development
*
*   Author    : Jan van den Baard
*   Assembler : Devpac version 2.14
*

                incdir  'sys:devpac_inc/'
                include 'mymacros.i'
                include 'exec/memory.i'
                include 'exec/exec_lib.i'
                include 'libraries/dos.i'
                include 'libraries/dos_lib.i'
                include 'tool.i'

                xref    DoFmt
                xref    DoBuf
                xref    CharRight
                xref    CharLeft
                xref    StrCpy
                xref    ToUpper
                xref    ToLower
                xref    StrLen
                xref    StrCmp
                xref    StriCmp

                xref    _DOSBase

                xdef    Format
                xdef    WriteFormat
                xdef    MatchPattern
                xdef    Isolate
                xdef    BstrToCstr
                xdef    GetDate

Format:         movem.l a2-a3/a6,-(sp)
                move.l  a0,a3               ; buffer to a3
                move.l  a1,a0               ; format string to a0
                move.l  a2,a1               ; arguments (pointer!) to a1
                move.l  #DoBuf,a2           ; specal routine (support.s)
                move.l  (_SysBase).w,a6
                libcall RawDoFmt            ; format the output
                movem.l (sp)+,a2-a3/a6
                rts

WriteFormat:    movem.l d2-d3/a2-a3/a6,-(sp)
                movem.l a0-a2,-(sp)         ; stack arguments
                move.l  #512,d0             ; MAXIMUM OUTPUT SIZE!!!!
                moveq   #MEMF_PUBLIC,d1
                move.l  (_SysBase).w,a6
                libcall AllocMem            ; allocate buffer
                move.l  d0,-(sp)            ; stack buffer
                bne.s   MemOK
                lea.l   16(sp),sp           ; reset stack
                moveq   #-1,d0              ; -1 for error
                bra.s   FmtDone
MemOK:          move.l  (sp),a3             ; buffer to a3
                move.l  8(sp),a0            ; format string to a0
                move.l  12(sp),a1           ; arguments (pointer!) to a1
                move.l  #DoBuf,a2           ; special routine (support.s)
                libcall RawDoFmt            ; format the output
                move.l  (sp),a0             ; buffer to a0
                bsr     StrLen              ; get the length
                move.l  d0,d3               ; put it in d3
                move.l  4(sp),d1            ; handle to d1
                move.l  (sp),d2             ; buffer to d2
                move.l  _DOSBase,a6
                libcall Write               ; write it to the handle
                move.l  (sp)+,a1            ; buffer to a1
                move.l  d0,-(sp)            ; stack Write return code
                move.l  #512,d0
                move.l  (_SysBase).w,a6
                libcall FreeMem             ; free the buffer
                move.l  (sp)+,d0            ; pull Write return code
                lea.l   12(sp),sp           ; reset the stack
FmtDone:        movem.l (sp)+,d2-d3/a2-a3/a6
                rts


MatchPattern:   move.l  d0,-(sp)
                movem.l a0-a1,-(sp)         ; push arguments
                bsr     Match               ; call Match
                lea.l   12(sp),sp           ; restore stack
                rts
*
* this is the actual pattern matching routine. It expects the parrameters
* on the stack. It call's tiself several times. recursive, needs some stack!
*
Match:          movem.l a2-a3/a5/d2,-(sp)
                move.l  20(sp),a2               ; str = a2
                move.l  24(sp),a3               ; pat = a3
                move.l  28(sp),d2               ; case flag
                move.l  a3,a0                   ; a0 = pat
                bsr     StrLen                  ; strlen(a0)
                tst.l   d0                      ; len == 0 ?
                bne.s   FOREVER                 ; no, there is a pattern
                moveq   #1,d0                   ; always return TRUE when no
                bra.s   TheEnd                  ; pattern is found.
FOREVER:        move.b  (a2),d0                 ; d0 = *str
;                tst.l   d2                      ; case check true ?
;                bne.s   NotLow                  ; no
                bsr     ToLower                 ; tolower(d0)
NotLow:         move.b  d0,d1                   ; d1 = d0
                move.b  (a3),d0                 ; d0 = *pat
;                tst.l   d2                      ; case check true ?
;                bne.s   NotLow1                 ; no
                bsr     ToLower                 ; tolower(d0)
NotLow1:        cmp.b   d0,d1                   ; d0 == d1 ?
                bne.s   NotSameChar             ; no.. check for WildCards
                tst.b   (a2)+                   ; *str++ == 0 ?
                bne.s   AddPat                  ; no..
                moveq   #1,d0                   ; TRUE
TheEnd:         movem.l (sp)+,a2-a3/a5/d2
                rts                             ; return
AddPat:         inc.w   a3                      ; pat++
                bra.s   FOREVER                 ; loop
NotSameChar:    cmp.b   #'?',(a3)               ; *pat == '?' ?
                bne.s   Artis                   ; no..
                tst.b   (a2)                    ; *str == 0   ?
                beq.s   Artis                   ; yes..
                inc.w   a3                      ; pat++
                inc.w   a2                      ; str++
                bra.s   FOREVER
Artis:          cmp.b   #'*',(a3)               ; *pat == '*' ?
                beq.s   IsArt                   ; yes..
                cldat   d0                      ; FALSE
                bra.s   TheEnd                  ; return
IsArt:          cmp.b   #'*',(a3)               ; *pat == '*' ?
                bne.s   DoAgain                 ; no..
                inc.w   a3
                tst.b   (a3)                    ; *++pat == 0 ?
                bne.s   IsArt                   ; no.. loop
                moveq   #1,d0                   ; TRUE
                bra.s   TheEnd                  ; return
DoAgain:        move.l  a2,a0                   ; a0 = str
                bsr     StrLen                  ; strlen(a0)
                move.l  d0,a5                   ; a5 = len
                add.l   a2,a5                   ; a5 += str
                dec.w   a5                      ; a5--
                bra.s   CheckEnd1               ; check if all are done
LoopIt:         move.b  (a5),d0                 ; d0 = *a5
                tst.l   d2                      ; check case flag
                bne.s   DoCase                  ; yes.. check the case
                bsr     ToLower                 ; make lower case
DoCase:         move.b  d0,d1                   ; put char in d1
                move.b  (a3),d0                 ; d0 == *pat
                tst.l   d2                      ; check case flag
                bne.s   DoCase2                 ; yes.. check the case
                bsr     ToLower                 ; make lower case
DoCase2:        cmp.b   d0,d1                   ; compare to chars
                bne.s   CheckEnd                ; check if all are done
                move.l  d2,-(sp)                ; push case flag
                move.l  a3,-(sp)                ; push pat
                move.l  a5,-(sp)                ; push a5
                bsr     Match                   ; Match(a5,a3,d2)
                lea     12(sp),sp               ; reset the stack
                tst.l   d0                      ; d0 == 0 ?
                beq.s   CheckEnd                ; yes.. check if all are done
                moveq   #1,d0                   ; TRUE
                bra     TheEnd                  ; return
CheckEnd:       dec.w   a5                      ; a5--
CheckEnd1:      cmp.l   a2,a5                   ; a5 >= str
                bcc.s   LoopIt                  ; yes loop
                cldat   d0                      ; FALSE
                bra     TheEnd                  ; return


Isolate:        movem.l a2-a3/a6,-(sp)
                move.l  a0,a2                   ; fp = a2
                move.l  a1,a3                   ; b  = a3
                move.b  #'/',d0
                move.l  a2,a0
                bsr     CharRight               ; charright(fp,'/')
                tst.l   d0                      ; found ?
                bne.s   FoundChar               ; yes..
                move.b  #':',d0
                move.l  a2,a0
                bsr     CharLeft                ; charleft(fp,':')
                tst.l   d0                      ; found ?
                bne.s   FoundChar               ; yes..
                move.b  #'*',d0
                move.l  a2,a0
                bsr     CharRight               ; charright(fp,'*')
                tst.l   d0                      ; found ?
                bne.s   DoCopy                  ; yes..
                move.b  #'?',d0
                move.l  a2,a0
                bsr     CharRight               ; charright(fp,'?')
                tst.l   d0                      ; found ?
                beq.s   NoCopy                  ; no..
DoCopy:         move.l  a3,a0                   ; dest = b
                move.l  a2,a1                   ; source = fp
                bsr     StrCpy                  ; StrCpy(b,fp)
                clr.b   (a2)                    ; fp[0] = 0
                moveq   #1,d0                   ; TRUE
                bra.s   EndIso                  ; return
NoCopy:         clr.b   (a3)                    ; b[0] = 0
                cldat   d0                      ; FALSE
                bra.s   EndIso                  ; return
FoundChar:      move.l  d0,a6                   ; adr to a6
                move.b  #'*',d0
                move.l  a6,a0
                bsr     CharLeft                ; charleft(adr,'*')
                tst.l   d0                      ; found ?
                bne.s   GotWild                 ; yes..
                move.b  #'?',d0
                move.l  a2,a0
                bsr     CharRight               ; charright(fp,'?')
                tst.l   d0                      ; found ?
                beq.s   NoWild                  ; no..
GotWild:        inc.w   a6                      ; adr++
                move.l  a3,a0                   ; dest = b
                move.l  a6,a1                   ; source = adr
                bsr     StrCpy                  ; StrCpy(dest,source)
                clr.b   (a6)                    ; adr[1] = 0
                moveq   #1,d0                   ; TRUE
                bra.s   EndIso                  ; return
NoWild:         clr.b   (a3)                    ; b[0] = 0
                cldat   d0                      ; FALSE
EndIso:         movem.l (sp)+,a2-a3/a6
                rts                             ; return


BstrToCstr:     add.l   a0,a0
                add.l   a0,a0                   ; BADDR(bstr)
                cldat   d0
                move.b  (a0)+,d0                ; size = bstr[0]
                bra.s   Begin                   ; begin loop
Copy:           move.b  (a0)+,(a1)+             ; buf[i-1] = bstr[i]
Begin:          dbra    d0,Copy                 ; loop until size bytes copied
                clr.b   (a1)                    ; buf[size] = 0
                rts                             ; return


GetDate:        movem.l d2-d7/a2-a3/a5-a6,-(sp)
                move.l  d0,-(sp)
                movem.l a0-a1,-(sp)
                moveq   #ds_SIZEOF,d0           ; sizeof(struct DateStamp)
                moveq   #MEMF_PUBLIC,d1         ; MEMF_PUBLIC
                move.l  (_SysBase).w,a6
                libcall AllocMem                ; AllocMem(ds_SIZEOF,MEMF_PUBLIC)
                move.l  d0,a2                   ; pointer to a2
                bne.s   AllocOK                 ; if NULL allocation failed
                moveq   #0,d0                   ; FALSE
                bra     AllocFailed             ; return
AllocOK:        move.l  4(sp),a3                ; buffer pointer to a3
                tst.l   (sp)                    ; passed a DateStamp ?
                beq.s   StampIt                 ; no.. system time
                move.l  (sp),a0                 ; your stamp as source
                moveq   #2,d0
Doit:           move.l  (a0)+,(a2)+
                dbra    d0,Doit
                sub.l   #12,a2
                bra.s   Copied
StampIt:        move.l  a2,d1                   ; buffer to d1
                move.l  _DOSBase,a6
                libcall DateStamp               ; DateStamp(buffer)
Copied:         move.l  ds_Days(a2),d4          ; days to d4
                move.l  ds_Minute(a2),d0        ; minutes to d0
                divu    #60,d0                  ; devide by 60
                move.w  d0,d5                   ; low 16 bits is hours
                ext.l   d5                      ; long extension
                swap    d0                      ; high 16 bits is remainder (minutes)
                move.w  d0,d6                   ; to d6
                ext.l   d6                      ; long extension
                move.l  ds_Tick(a2),d0          ; ticks to d0
                divu    #TICKS_PER_SECOND,d0    ; devide by TICKS_PER_SECOND
                move.w  d0,d7                   ; low 16 bits is seconds
                ext.l   d7                      ; long extension
                tst.l   d4                      ; days < 0
                blt.s   ScrewedUp               ; if so, error
                tst.l   d6                      ; mins < 0
                blt.s   ScrewedUp               ; if so, error
                tst.l   d7                      ; secs < 0
                bge.s   DateOK                  ; if not,  OK
ScrewedUp:      pea     su                      ; copy error string
                move.l  a3,-(sp)                ; into your buffer
                jsr     DoFmt
                addq.w  #8,sp                   ; reset stack
                moveq   #0,d0                   ; FALSE
                bra     EndGD                   ; return
DateOK:         inc.l   d4                      ; days++
                move.l  #1978,d2                ; start at 1978
YearLoop:       move.l  d2,d0                   ; year to d0
                divu    #4,d0                   ; devide by 4
                swap    d0                      ; swap for remainder
                tst.w   d0                      ; is there a remainder ?
                bne.s   NotLeap                 ; yes.. it's no leap year
                move.l  #366,d1                 ; 366 days in a leap year
                bra.s   CheckDays
NotLeap:        move.l  #365,d1                 ; 365 days in a normal year
CheckDays:      cmp.l   d1,d4                   ; days <= dayes_per_year
                ble.s   EndYear                 ; yes.. break
                sub.l   d1,d4                   ; days -= dayes_per_year
                inc.l   d2                      ; year++
                bra.s   YearLoop                ; loop
EndYear:        cldat   d3                      ; mon = 0
MonLoop:        cmp.l   #12,d3                  ; mon <= 12
                bgt.s   EndMon                  ; no.. break
                lea.l   dim,a0                  ; dayes_in_month table to a0
                move.l  d3,d0                   ; mon to d0
                add.l   d0,d0                   ; d0 * 2 for correct table offset
                move.w  (a0,d0.l),d1            ; dpm = dayes_per_month[mon]
                ext.l   d1                      ; long extension
                cmp.l   #1,d3                   ; is mon 1 ?
                bne.s   NotFeb                  ; no not february
                move.l  d2,d0                   ; year to d0
                divu    #4,d0                   ; devide by four
                swap    d0                      ; swap for remainder
                tst.w   d0                      ; is there a remainder ?
                bne.s   NotFeb                  ; yes.. it's not a leap year
                inc.l   d1                      ; else february has 29 days
NotFeb:         cmp.l   d1,d4                   ; days <= dpm
                ble.s   EndMon                  ; yes.. break
                sub.l   d1,d4                   ; days -= dpm
                inc.l   d3                      ; mon++
                bra.s   MonLoop                 ; loop
EndMon:         move.l  ds_Days(a2),d0          ; days to d0
                divu    #7,d0                   ; devide by 7
                swap    d0                      ; swap for remaider
                ext.l   d0                      ; long extension
                asl.l   #2,d0                   ; d0 * 4 for correct table offset
                lea     dys,a0                  ; days table to a0
                move.l  (a0,d0.l),a6            ; a6 = dayes[d0]
                lea.l   mnt,a0                  ; month table to a0
                asl.l   #2,d3                   ; d3 * 4 for correct table offset
                move.l  (a0,d3.l),a5            ; a5 = month[d3]
                cmp.l   #ONLY_DAY,8(sp)         ; do you want only the day ?
                bne.s   Date                    ; no.. branch
                move.l  a6,-(sp)                ; push day
                pea     j1                      ; push format string
                move.l  a3,-(sp)                ; push buffer
                bsr     DoFmt                   ; format the output
                lea.l   12(sp),sp               ; reset stack
                bra.s   Done                    ; return
Date:           cmp.l   #ONLY_DATE,8(sp)        ; do you want only the date ?
                bne.s   Time                    ; no.. branch
                move.l  d2,-(sp)                ; push year
                move.l  a5,-(sp)                ; push month
                move.l  d4,-(sp)                ; push day
                pea     j2                      ; push format string
                move.l  a3,-(sp)                ; push buffer
                bsr     DoFmt                   ; format the output
                lea.l   20(sp),sp               ; reset stack
                bra.s   Done                    ; return
Time:           cmp.l   #ONLY_TIME,8(sp)        ; do you want only the time ?
                bne.s   All                     ; no branch
                move.l  d7,-(sp)                ; push second
                move.l  d6,-(sp)                ; push minute
                move.l  d5,-(sp)                ; push hours
                pea     j3                      ; push format string
                move.l  a3,-(sp)                ; push buffer
                bsr     DoFmt                   ; format the output
                lea.l   20(sp),sp               ; reset stack
                bra.s   Done                    ; return
All:            move.l  d7,-(sp)                ; push second
                move.l  d6,-(sp)                ; push minute
                move.l  d5,-(sp)                ; push hour
                move.l  d2,-(sp)                ; push year
                move.l  a5,-(sp)                ; push month
                move.l  d4,-(sp)                ; push day
                move.l  a6,-(sp)                ; push ascii day
                pea     j4                      ; push format string
                move.l  a3,-(sp)                ; push buffer
                bsr     DoFmt                   ; format the output
                lea.l   36(sp),sp               ; reset the stack
Done:           moveq   #1,d0                   ; TRUE
EndGD:          move.l  d0,-(sp)                ; push return code
                move.l  a2,a1                   ; date buffer to a1
                moveq   #ds_SIZEOF,d0           ; sizeof(struct DateStamp)
                move.l  (_SysBase).w,a6
                libcall FreeMem                 ; FreeMem(dbuf,ds_SIZEOF)
                move.l  (sp)+,d0                ; pull return code
AllocFailed:    lea.l   12(sp),sp
                movem.l (sp)+,d2-d7/a2/a3/a5/a6
                rts                             ; return

                even
dim:            dc.w    31,28,31,30,31,30,31,31,30,31,30,31
mnt:            dc.l    s+0,s+4,s+8,s+12,s+16,s+20,s+24,s+28,s+32,s+36,s+40,s+44
dys:            dc.l    s+48,s+55,s+62,s+70,s+80,s+89,s+96
                even
s:              dc.b    'Jan',0,'Feb',0,'Mar',0,'Apr',0,'May',0,'Jun',0
                dc.b    'Jul',0,'Aug',0,'Sep',0,'Oct',0,'Nov',0,'Dec',0
                dc.b    'Sunday',0,'Monday',0,'Tuesday',0,'Wednesday',0
                dc.b    'Thursday',0,'Friday',0,'Saterday',0
su:             dc.b    'Date screwed up !',0
                even
j1:             dc.b    '%-9ls',0
j2:             dc.b    '%02.2ld-%3ls-%04.4ld',0
j3:             dc.b    '%02.2ld:%02.2ld:%02.2ld',0
j4:             dc.b    '%-9ls %02.2ld-%3ls-%04.4ld %02.2ld:%02.2ld:%02.2ld',0
                even
