; tll_stuff.i     Version 1.00    10th February, 2002

*>>************************************************************************
*
*  Subroutines to get catalogs
*  ~~~~~~~~~~~~~~~~~~~~~~~~~~~
*  TLLstart  - load strings from catalogs
*  TLLwrap   - re-wrap the TLL strings
*  TLLinfo   - show some TLL strings on a scroller window
*  TLLfinish - release the memory created by TLLstart
*
***************************************************************************


 IFND 'TLL_Stuff'


 TLL_Stuff: SET -1


*>> load strings from a catalog

; D0 = shared lock for '.../Catalogs' (see below)
; D1 = name of file with strings
; D2 = number of strings required to be in file
; A6 = dos.library base


; This subroutine takes as input a lock for a directory which contains
; sub-riectories for each language. Its path will presumably end with
; '/Catalogs'. The directory should have sub-directories for each language,
; and a filename (presumably with suffix '.catalog') with a pre-determined
; number of strings. In each laguage file will be a file with the same
; name and number of strings, and each string will have the same semantics
; as the corresponding stirng in other directories.

; this routine tries to get the Locale structure, and scans through all the
; loc_PrefLanguages until it finds a file with the required name and number
; of strings. If it succeeds, it returns a pointer to a pointer to a
; memory buffer which contains all the strings. The strings in file can
; be delimited by $0A or $00, but in memory they will be delimited by
; $00. They must be in HTML format.

; If TLLstart is successful, the caller must eventually call TLLfinish to
; free the memory TLLstart creates.


TLLstart:
 movem.l d0-d7/a0-a6,-(a7) ;save all except result in d0

 move.l a6,a5              ;a5 = dos.library base
 move.l d0,d4              ;d4 = lock
 move.l d1,a2              ;a2 = fname

 clr.l (a7)                ;stack d0 = 0 pro-tem

 move.l _AbsExecBase,a6    ;open locale.library, base to d7
 lea .lnam,a1
 moveq #37,d0
 jsr _LVOOpenLibrary(a6)
 move.l d0,d7
 beq .quit                 ;bad if can't

 move.l d7,a6              ;set d6 = default locale
 sub.l a0,a0
 jsr _LVOOpenLocale(a6)
 move.l d0,d6
 beq .clos                 ;bad if can't

 move.l d6,a3              ;a3 scans pref languages
 add.w #loc_PrefLanguages,a3
 moveq #9,d5               ;d5 counts items in list

 move.l a5,a6              ;a6 = dos.library base
 sub.w #140,a7             ;build filepath in stack

.try:                      ;try next preference language
 move.l (a3),d0
 beq .pop                  ;quit bad if no mor in list

 move.l d4,d1              ;get path to .../Catalogs from lock
 move.l a7,d2
 move.l #140,d3
 jsr _LVONameFromLock(a6)
 tst.l d0
 beq .pop                  ;bad if can't (can't happen?)

 move.l a7,d1              ;add the language to the path
 move.l (a3),d2
 jsr _LVOAddPart(a6)
 tst.l d0
 beq .ntry                 ;to next if can't (can't happen?)

 move.l a7,d1              ;add fname to path
 move.l a2,d2
 jsr _LVOAddPart(a6)
 tst.l d0
 beq .ntry                 ;to next if can't (can't happen?)

 move.l a7,d1              ;attempt to open the file
 move.l #MODE_OLDFILE,d2
 jsr _LVOOpen(a6)
 move.l d0,d1
 beq .ntry                 ;to next if can't

 moveq #0,d2               ;get file size
 moveq #OFFSET_END,d3
 move.l d1,-(a7)
 jsr _LVOSeek(a6)
 move.l (a7),d1
 moveq #OFFSET_BEGINNING,d3
 jsr _LVOSeek(a6)
 move.l d0,d3              ;d3 = file size
 move.l (a7)+,d1
 addq.l #3,d0
 and.l #$FFFFFFFC,d0       ;round up to nearest longword
 bne.s .mem
 jsr _LVOClose(a6)         ;close file & to next if null
 bra .ntry

.mem:                      ;create memory to load file
 move.l d1,d2
 moveq #MEMF_PUBLIC,d1
 move.l _AbsExecBase,a6
 jsr _LVOAllocVec(a6)
 move.l a5,a6
 tst.l d0
 bne.s .load
 move.l d2,d1              ;if can't, close file & to next
 jsr _LVOClose(a6)
 bra .ntry

.load:
 move.l d2,d1              ;d1 = file handle
 move.l d0,d2              ;d2 = memory   d3 already = file size
 move.l d1,-(a7)
 jsr _LVORead(a6)          ;read the file
 move.l (a7)+,d1
 move.l d0,-(a7)
 jsr _LVOClose(a6)         ;close the file
 move.l (a7)+,d0
 cmp.l d0,d3
 bne.s .kill               ;go release the memory & to next if bad load

; validate file contents...

 move.l d2,a0              ;a0 gets
 move.l d2,a1              ;a1 puts
 move.l d2,a6              ;a6 = end of input file
 add.l d3,a6
 move.w 140+8+2(a7),d0     ;d0 = input d2 = number of strings required
.strg:
 move.b (a0)+,d1           ;get next byte
 beq.s .eol
 cmp.b #$0A,d1             ;go if eol
 beq.s .eol
 cmp.l a6,a0               ;bad if eof reached
 bcc.s .kill

 cmp.b #'#',d1             ;slough line if '##' at start
 bne.s .put
 subq.l #1,a0
 cmp.l a0,d2
 addq.l #1,a0
 beq.s .com
 tst.b -2(a0)
 beq.s .com
 cmp.b #$0A,-2(a0)
 bne.s .put
.com:
 cmp.b #'#',(a0)
 bne.s .put
.slof:                     ;slough comment...
 move.b (a0)+,d1
 cmp.l a6,a0               ;bad if eof reached
 bcc.s .kill
 tst.b d1
 beq .strg
 cmp.b #$0A,d1
 beq .strg
 bra .slof

.put:
 move.b d1,(a1)+           ;put byte to output
 cmp.b #'~',d1
 bne .strg
 subq.l #1,a1              ;if chr was '~' at start of output line, remove
 cmp.l a1,d2               ;   it from the output & replace the eol with a
 addq.l #1,a1              ;   space
 beq .strg
 tst.b -2(a1)
 bne .strg
 subq.l #1,a1
 move.b #' ',-1(a1)
 addq.w #1,d0
 bra .strg

.eol:
 clr.b (a1)+               ;eol found - $00 to output
 subq.w #1,d0
 bne .strg                 ;until enough strings found

 add.w #140,a7             ;release stack workspace
 move.l d2,(a7)            ;put memory address to stack d0
 bra.s .cloc               ;go wrap up

.kill:                     ;here to free the memory (due to bad file)
 move.l _AbsExecBase,a6
 move.l d2,a1
 jsr _LVOFreeVec(a6)
 move.l a5,a6

.ntry:                     ;to next in pref list
 addq.l #4,a3
 dbra d5,.try              ;until all tried

.pop:
 add.w #140,a7             ;here to release stack workspace

.cloc:
 move.l d7,a6              ;release the Locale structure
 move.l d6,a0
 jsr _LVOCloseLocale(a6)

.clos:
 move.l _AbsExecBase,a6    ;close locale.library
 move.l d7,a1
 jsr _LVOCloseLibrary(a6)

.quit:
 movem.l (a7)+,d0-d7/a0-a6 ;EQ, D0=0 if bad
 tst.l d0
 rts

.lnam: dc.b 'locale.library',0
 dc.w 0


*>> re-wrap a set of strings created by TLLstart

; D0 = number of first string
; D1 = number of last string
; D2 = max line width
; D3 = max number of lines after wrapping
; D7 = cspace
; A0 = where strings are (as loaded by TLLstart)
; A1 = D3+1 longwords to hold line start addresses
; A2 = ucode_path
; A3 = ucode.library base

; returns D0 = number of line addresses (followed by end of last)

; TLLwrap does not change the contents of (A0). What it does, is to make
; a set of pointers in (A1). You can then call TLUstring to print string D0
; with A2 = pointer D0, and A3 = pointer D1. If after wrapping there are
; more than D3 lines, then only the first D3 will be in (A1).


TLLwrap:

; returns D0 = number of line addrs put in (A1)+ (followed by delim of last)

 movem.l d0-d7/a0-a6,-(a7) ;save all except result in D0

 move.l a1,a5              ;a5 puts addresses

 sub.w d0,d1
 move.l a0,a2              ;point a2 to first line
 bra.s .frsg
.frst:
 tst.b (a2)+
 bne .frst
.frsg:
 dbra d0,.frst
 move.l a2,a3              ;point a3 past last line
.last:
 tst.b (a3)+
 bne .last
 subq.w #1,d1
 bpl .last

 move.l a2,(a5)+           ;put first line

 moveq #0,d6               ;d6 counts lines (not mroe than d3)

 moveq #0,d4               ;d4 = flags
 bset #31,d4               ;     ASCII
 bset #30,d4               ;     &...;
 bset #27,d4               ;     A3 operative
 move.l 32+8(a7),a0        ;a0 = ucode_path
 move.l 32+12(a7),a6       ;a6 = ucode.library base
.lins:
 move.l d2,d0              ;d0 = maxwidth, d7 alreay = cspace
 jsr _LVOTLUbreak(a6)
 move.l d0,a2
 move.l a2,(a5)+           ;put end of each line
 addq.w #1,d6
 cmp.w d3,d6
 bcc.s .max
 cmp.l a3,a2
 bcs .lins

.max:
 move.l d6,(a7)

 movem.l (a7)+,d0-d7/a0-a6
 rts


*>> show some TLL strings on a scroller window

; D0 = first string
; D1 = last string
; D2 = flags
;      bit 31 set if use d3 (else, ignore d3, keep wbox = entire wint)
;          30 (and also bit 31 set) qit if wbox entirely invisible
;          29 quit if LMB inside wint
;          28 quit if resize
; D3 = wbox (ignored if D2 bit 31 unset)
; D4 = bits 0-7   fgpen
;           8-15  bgpen
;           16-23 lspace
;           24-31 cspace
; D5 = max number of lines after wrapping (as per TLLwrap)
; D6 = ucode_path
; D7 = address to copy messages (im_SIZEOF bytes)
; A0 = window with scrollers
; A1 = window's xxp_scro
; A2 = where strings are (as loaded by TLLstart)
; A3 = D3+1 longwords to hold line start addresses (as per TLLwrap)
; A5 = gadtools.library base
; A6 = ucode.library base

; n.b. calls  TLDShow (hence TLScroll, TLSarea, TLDArea), TLDWindow
; processes scroller movements, and scrolls in response to arrow keys
; ignores activewindow and sizeverify messages
; ignore idcmpupdate messages other than scroller movements
; returns on all other messages
; returns if D2=+1 and wbox moves entirely off window


TLLinfo:

; stack offsets

.wint: EQU 0               ;8 wint
.wbox: EQU 8               ;8 wbox
.lins: EQU 16              ;2 strings after TLLwrap
.visi: EQU 18              ;2 lines that will fit on window
.ytop: EQU 20              ;2 top line that fits on window
.dsiz: EQU 24              ;position of regs

 movem.l d0-d7/a0-a6,-(a7) ;save all
 sub.w #.dsiz,a7
 move.l d3,a0
 move.l (a0),.wbox(a7)     ;fill .wbox with (d3)
 move.l 4(a0),.wbox+4(a7)

; here to redraw window if resized

.rsiz:

; set wint

 move.l .dsiz+32(a7),a0    ;a0 = window
 move.l a7,a1              ;a1 = wint
 bsr TLDWindow             ;update wint

; go unless using input d3

 tst.b .dsiz+8(a7)         ;bit 31 = 1 = use d3
 bpl.s .nod3

; set wbox to input wbox

 move.l .dsiz+12(a7),a2
 move.l (a2),.wbox(a7)
 move.l 4(a2),.wbox+4(a7)
 bra .wrap

; here if ignoring input d3

.nod3:

; go if stopping if wbox invisible

 btst #6,.dsiz+8(a7)       ;bit 30 = 1 = quit if wbox invisible
 bne.s .invi

; set wbox = all wint & clear, then shrink 2/1 pixels

 clr.l .wbox(a7)
 move.l .wint+4(a7),.wbox+4(a7)
 moveq #0,d0
 moveq #0,d1
 move.w .wbox+4(a7),d2
 move.w .wbox+6(a7),d3
 move.b .dsiz+16+2(a7),d4
 move.l .dsiz+32(a7),a1
 move.l wd_RPort(a1),a0
 move.l .dsiz+24(a7),a1
 move.l xxp_gfxp(a1),a6
 move.l a7,a1
 move.l a7,a2
 addq.l #8,a2
 bsr TLDArea

 addq.w #2,.wbox(a7)       ;horz margins 2
 subq.w #4,.wbox+4(a7)
 bgt.s .mar1
 clr.w .wbox(a7)
 addq.w #4,.wbox+4(a7)
.mar1:
 addq.w #1,.wbox+2(a7)     ;vert margins 1
 subq.w #2,.wbox+6(a7)
 bgt.s .mar2
 clr.w .wbox+2(a7)
 addq.w #2,.wbox+6(a7)
.mar2:

 bra.s .wrap

; if d2 was +1, quit if wbox invisible

.invi:
 move.l a7,a0              ;a0 = wint
 move.l .dsiz+12(a7),a1    ;a1 = wint
 move.w 6(a1),d3
 move.w 2(a1),d2
 bpl.s .cry1
 add.w d2,d3
 ble .quit
 moveq #0,d2
.cry1:
 add.w d2,d3
 cmp.w 6(a0),d3
 ble.s .cry2
 move.w 6(a0),d3
.cry2
 sub.w d2,d3
 ble .quit
 move.w 4(a1),d3
 move.w (a1),d2
 bpl.s .cry3
 add.w d2,d3
 ble .quit
 moveq #0,d2
.cry3:
 add.w d2,d3
 cmp.w 4(a0),d3
 ble.s .cry4
 move.w 4(a0),d3
.cry4:
 sub.w d2,d3
 ble .quit

; wrap strings to wbox size

.wrap:
 move.w .dsiz+0+2(a7),d0   ;d0 = first string
 move.w .dsiz+4+2(a7),d1   ;d1 = last string
 move.w .wbox+4(a7),d2     ;d2 = width of wbox
 move.w .dsiz+20+2(a7),d3  ;d3 = max number of strings
 move.b .dsiz+16+0(a7),d7  ;d7 = cspace
 move.l .dsiz+32+8(a7),a0  ;a0 = strings
 move.l .dsiz+32+12(a7),a1 ;a1 = d3+1 pointers
 move.l .dsiz+24(a7),a2    ;a2 = ucode_path
 move.l .dsiz+32+24(a7),a3 ;a3 = ucode.library base
 bsr TLLwrap
 move.w d0,.lins(a7)       ;.lins = number of strings as wrapped

; draw lines after wrapping

.draw:
 move.w .lins(a7),d0       ;d0 = number of lines
 moveq #0,d1
 move.b .dsiz+16+1(a7),d1  ;d1 = lspace
 move.l a7,d2              ;d2 = wint
 move.l a7,d3
 addq.l #8,d3              ;d3 = wbox
 move.l .dsiz+16(a7),d4    ;d4 = cspace - bgpen fgpen
 move.l .dsiz+28(a7),d5    ;d5 = addr to copy messages
 move.l .dsiz+24(a7),a0    ;     ucode_path
 move.l xxp_intp(a0),d6    ;d6 = intuition.library base
 move.l .dsiz+32+20(a7),d7 ;d7 = gadtools.library base
 move.l xxp_gfxp(a0),a6    ;a6 = graphics.library base
 move.l .dsiz+32(a7),a0    ;a0 = window
 move.l .dsiz+32+4(a7),a1  ;a1 = xxp_scro
 move.l #.linp,a2          ;a2 = address to call for line d0
 move.l a7,a3              ;a3 = data for .linp
 sub.l a5,a5               ;a5 = pop up data = none
 bsr TLDShow

 move.l d5,a0              ;a2 = address of message
 move.l im_Class(a0),d0    ;d0 = message class

; stop if LMB in wint, if required

 btst #5,.dsiz+8(a7)       ;bit 29 = 1 = quit if LMB in wint
 beq.s .misc

 move.l a7,a1              ;set NE if LMB in wint
 bsr TLDMouse
 bne.s .quit               ;when quit

; process miscellaneous message from TLDShow

.misc:
 cmp.l #IDCMP_NEWSIZE,d0      ;go unless window resized
 bne .msc2
 btst #4,.dsiz+8(a7)          ;quit if bit 28 = 1 = quit if resized
 bne.s .quit
 beq .rsiz                    ;else go redraw

.msc2:
 cmp.l #IDCMP_CLOSEWINDOW,d0  ;quit if close window
 beq.s .quit

 cmp.l #IDCMP_VANILLAKEY,d0   ;quit if <Esc>
 bne .draw
 cmp.w #$001B,im_Code(a0)
 bne .draw                    ;else Re-call TLDShow

.quit:                     ;quit from TLLinfo
 add.w #.dsiz,a7
 movem.l (a7)+,d0-d7/a0-a6
 rts


; ** print line d0 - called via TLDShow

; d0 = line num
; d1 = ypos
; d2 = wint
; d3 = wbox
; d4 = fgpen
; d5 = bgpen
; d6 = cspace
; a1 = rastport
; a3 = data = a7 when called

.linp:
 move.l a3,a5              ;a5 = a7 when TLDShow called

 move.l .dsiz+32+12(a5),a0 ;a0 = pointers to wrapped lines
 lsl.w #2,d0
 move.l 0(a0,d0.w),a2      ;a2 = start of line
 move.l 4(a0,d0.w),a3      ;a3 = end of line

 move.l .dsiz+24(a5),a0    ;a0 = ucode_path, a1 already = rastport
 moveq #0,d0               ;d0 = xpos, d1 already = ypos
 exg d2,d3                 ;d2 = wbox, d3 = wint
 move.b d6,d7              ;d7 = cspace
 move.b d5,d6              ;d6 = bgpen
 move.b d4,d5              ;d5 = fgpen
 moveq #0,d4               ;d4 = flags
 bset #31,d4               ;     ascii
 bset #30,d4               ;     &...;
 bset #27,d4               ;     use A3
 move.l .dsiz+32+24(a5),a6 ;a6 = ucode.library base
 jsr _LVOTLUstring(a6)
 rts


*>> release memory created by TLLstart

; D0 = address retuned by a successful call to TLLstart


TLLfinish:
 movem.l d0-d1/a0-a1/a6,-(a7) ;save all
 move.l _AbsExecBase,a6
 move.l d0,a1
 jsr _LVOFreeVec(a6)
 movem.l (a7)+,d0-d1/a0-a1/a6
 rts


 ENDC                       ;end of TLL_Stuff
