* ------------------------------------------------------------------------- * * FS2.ASM -- Assembly support routines for PathMaster(tm) File Selector * Copyright © 1987-1989 by Justin V. McCormick. All Rights Reserved. * ------------------------------------------------------------------------- * ;BENCHMARK EQU 1 include "exec/types.i" include "exec/nodes.i" include "exec/lists.i" SYS MACRO * IFGT NARG-2 FAIL !!! ENDC IFEQ NARG-2 MOVE.L \2,a6 ENDC JSR _LVO\1(a6) ENDM XLVO MACRO * XREF _LVO\1 ENDM * These three equate control the size of the path, file, and pattern string limits PATHSTRSIZE EQU 300 FILESTRSIZE EQU 32 MATCHSTRSIZE EQU 32 AUTOKNOB EQU $1 FREEVERT EQU $4 PROPBORDERLESS EQU $8 MEMF_CLEAR EQU $10000 WINDOWSIZING EQU $1 WINDOWDRAG EQU $2 WINDOWDEPTH EQU $4 WINDOWCLOSE EQU $8 WINDOWTGADS EQU WINDOWDRAG!WINDOWDEPTH!WINDOWCLOSE FPEN EQU 1 DPEN EQU 3 fib_DirEntryType EQU $4 fib_FileName EQU $8 fib_Size EQU $7C fib_DateStamp EQU $84 fib_SIZEOF EQU $104 gg_Flags EQU $C id_SIZEOF EQU $24 it_FrontPen EQU $0 it_IText EQU $C rp_AreaPtrn EQU $8 rp_AreaPtSz EQU $1D wd_Flags EQU $18 wd_RPort EQU $32 STRUCTURE FSRequest,0 STRUCT fs_dirname,PATHSTRSIZE STRUCT fs_filename,FILESTRSIZE STRUCT fs_matchpattern,MATCHSTRSIZE WORD fs_leftedge WORD fs_topedge WORD fs_sorttype UWORD fs_flags ULONG fs_windowflags APTR fs_fullname APTR fs_ignorepattern APTR fs_pathgadstr APTR fs_filegadstr APTR fs_titlestr APTR fs_readingstr APTR fs_sortingstr APTR fs_emptydirstr APTR fs_nomatchstr APTR fs_selectfilestr APTR fs_selectstr APTR fs_cancelstr APTR fs_specgadstr APTR fs_userscreen APTR fs_userport APTR fs_specgadfunc APTR fs_dirfunc APTR fs_filefunc APTR fs_userfunc APTR fs_initfunc APTR fs_matchfunc LABEL fs_SIZEOF STRUCTURE node_data,0 STRUCT nd_alphadata,58 WORD nd_filetype WORD nd_showit WORD nd_textcolor WORD nd_namelength ULONG nd_filesize ULONG nd_days ULONG nd_minutes ULONG nd_ticks LABEL nd_SIZEOF STRUCTURE file_node,0 STRUCT fn_Node,MLN_SIZE APTR fn_info WORD fn_idnum LABEL fn_SIZEOF STRUCTURE dev_node,0 STRUCT dn_Node,MLN_SIZE STRUCT dn_name,32 LABEL dn_SIZEOF XREF _AlphaGad XREF _ColonStr XREF _CurDevNames XREF _DevGads XREF _devList XREF _DevTxts XREF _DOSBase XREF _EmptyPattern XREF _FileUndoBuffer XREF _FileUndoName XREF _fnList XREF _fsbaddatestr XREF _FSCountDown XREF _fscurmicros XREF _fscursecs XREF _fsdatefmtstr XREF _fsdayspermonth XREF _FSDirFmtStr XREF _fsdirlocked XREF _FSDone XREF _FSDownGad XREF _fserrmsgs XREF _FSFib XREF _FSFileGad XREF _FSFileInfo XREF _FSFileNodes XREF _fsflags XREF _FSIgnorePat XREF _FSInfo XREF _FSLock XREF _fsneedshow XREF _FSNextDevs XREF _fsnumentries XREF _fsoldmicros XREF _fsoldsecs XREF _FSPathBuf XREF _FSPathGad XREF _FSPathInfo XREF _FSPatternGad XREF _FSPatternInfo XREF _FSPatternUndoBuffer XREF _FSPrevDevs XREF _fsprevgadid XREF _FSReq XREF _FSRPort XREF _FSSizeFmtStr XREF _FSSlideGad XREF _FSSlideProp XREF _fsstartedstr XREF _fstempdate XREF _fstitlelength XREF _fstitstatus XREF _FSUndoGad XREF _FSUpGad XREF _FSUserGad XREF _fsvheight XREF _fsvirgindir XREF _fsvposition XREF _FSWin XREF _FSWinTitleStr XREF _FSwstr XREF _GfxBase XREF _IntuitionBase XREF _lastdev XREF _NIL2Gad XREF _OldFSPathBuf XREF _RamDirNameStr XREF _SizeGad XREF _SlashStr XREF _TimeGad XREF _topfin XREF _sprintf XREF _FSVBDelay IFD BENCHMARK XREF _StartTime XREF _StopTime XREF _timermsg1 ENDC XLVO ActivateGadget XLVO AddHead XLVO AddTail XLVO AllocMem XLVO ClipBlit XLVO DisplayBeep XLVO DoubleClick XLVO Examine XLVO ExNext XLVO FreeMem XLVO GetMsg XLVO Insert XLVO IoErr XLVO Move XLVO NewModifyProp XLVO ParentDir XLVO RectFill XLVO RefreshGList XLVO RemHead XLVO ReplyMsg XLVO SetAPen XLVO SetDrMd XLVO SetWindowTitles XLVO Text XLVO UnLock SECTION CODE * ------------------------------------------------------------------------ ; LONG MyActivateGad(gadget, window) ; struct Gadget *gadget; ; struct Window *window; ; ; Activate a gadget, wait till it is ready. Try up to 3 times. Returns ; TRUE (1) if it succeeded, FALSE (0) if it failed to activate. * ------------------------------------------------------------------------ XDEF _MyActivateGad _MyActivateGad: movem.l d2/a2/a6,-(sp) moveq #2,d2 ;Try 3 times to activate gadget 1$ movem.l 16(sp),a0/a1 ;Grab gadget pointer, window pointer suba.l a2,a2 ;No requester pointer movea.l _IntuitionBase,a6 jsr _LVOActivateGadget(a6) ;Activate! tst.l d0 ;Did it catch? bne.s 2$ ;Yep, move on pea 5 jsr _FSVBDelay addq.w #4,sp dbf d2,1$ 2$ movem.l (sp)+,d2/a2/a6 rts * --------------------------------------------------------------------- * * LONG FSCheckFlagChange(VOID); * --------------------------------------------------------------------- * XDEF _FSCheckFlagChange _FSCheckFlagChange: movea.l _FSReq,a0 move.w fs_flags(a0),d0 move.w _fsflags,d1 andi.w #%00011000,d0 andi.w #%00011000,d1 cmp.w d0,d1 ;FS_SHOW_FILES_FIRST or FS_SHOW_DIRS_FIRST changed? beq.s 1$ ;Nope move.w #1,_fsvirgindir ;Else we need to re-read the directory 1$ move.w fs_flags(a0),d0 move.w _fsflags,d1 andi.w #%01100000,d0 andi.w #%01100000,d1 cmp.w d0,d1 ;FS_SHOW_FILES_ONLY or FS_SHOW_DIRS_ONLY changed? beq.s 2$ ;Nope moveq #1,d0 ;Else flag that we need to FSMatchPattern() bra.s 3$ 2$ moveq #0,d0 3$ move.w fs_flags(a0),_fsflags ;Reset flags to match FSReq now rts * ------------------------------------------------------------------------ ; Assign device name texts to intuitexts in the 4 Device Gadgets * ------------------------------------------------------------------------ XDEF _SetDevGads _SetDevGads: movem.l d3-d4/a2-a3/a5,-(sp) ;for (i = 0, tnode = lastdev; i < 4;) moveq #0,d4 ;d4 = i = 0 movea.l _lastdev,a2 ;a2 = tnode = lastdev move.l a2,d3 ;Copy for comparison lea _CurDevNames,a3 ;a3 = &CurDevNames[0] lea _DevTxts,a5 ;a5 = &DevTxts[0] 1$ lea dn_name(a2),a1 move.l a1,0(a3,d4.w) ;CurDevNames[i] = tnode->name moveq #4,d0 move.l 0(a5,d4.w),a0 movea.l it_IText(a0),a0 jsr astrncpy ;astrncpy (DevTxts[i]->IText, tnode->name, 4) addq.w #4,d4 ;i++ movea.l dn_Node+MLN_SUCC(a2),a2 ;tnode = tnode->dn_Node.mln_Succ tst.l dn_Node+MLN_SUCC(a2) ;if (tnode->dn_Node.mln_Succ == 0) bne.s 2$ ;Nope movea.l _devList,a2 movea.l MLH_HEAD(a2),a2 ;Else start the listing over at the start 2$ cmpa.l d3,a2 ;Have we already shown this node? beq.s 3$ ;Yep, disable the rest cmpi.w #16,d4 ;Set all 4 Device gadgets yet? bcs 1$ ;Nope, do next 3$ * Disable any leftover gadgets ;for (; i < 4; i++) lea _DevGads,a0 bra.s 5$ 4$ movea.l 0(a0,d4.w),a1 bset.b #0,gg_Flags(a1) ;DevGads[i]->Flags |= GADGDISABLED addq.w #4,d4 5$ cmpi.w #16,d4 bcs 4$ movem.l (sp)+,d3-d4/a2-a3/a5 rts * ------------------------------------------------------------------------ ; FSScrollDevGads(direction) ; WORD direction; * ------------------------------------------------------------------------ XDEF _FSScrollDevGads _FSScrollDevGads: movem.l a2/a6,-(sp) movea.l _lastdev,a0 tst.w 12+2(sp) ;Grab scroll direction beq.s 1$ ;If zero, scroll to next * Bump list pointer one direction or the other move.l dn_Node+MLN_SUCC(a0),a0 ;Get successor tst.l dn_Node+MLN_SUCC(a0) ;EndoList? bne.s 2$ ;Nope movea.l _devList,a0 movea.l MLH_HEAD(a0),a0 ;Else lastdev = devList->lh_Head bra.s 2$ 1$ movea.l dn_Node+MLN_PRED(a0),a0 ;Else, lastdev = lastdev->next tst.l dn_Node+MLN_PRED(a0) ;Endolist? bne.s 2$ movea.l _devList,a0 movea.l MLH_TAILPRED(a0),a0 ;Else lastdev = devList->lh_TailPred 2$ move.l a0,_lastdev jsr _SetDevGads ;Set the gadget text fields * Refresh gadget texts ;RefreshGList(&NIL2Gad, FSWin, 0L, 4L); moveq #4,d0 suba.l a2,a2 movea.l _FSWin,a1 lea _NIL2Gad,a0 SYS RefreshGList,_IntuitionBase movem.l (sp)+,a2/a6 rts * ------------------------------------------------------------------------ ; CheckFSArrows() ; See if the Up or Down arrow gadgets are currently activated, scroll ; the file display area or device gadget list if so. * ------------------------------------------------------------------------ XDEF _CheckFSArrows _CheckFSArrows: subq.w #1,_FSCountDown bge.s 12$ btst.b #7,_FSUpGad+gg_Flags+1 ;FSUpGad.Flags & SELECTED? beq.s 2$ ;Nope, maybe FSDownGad pea 1 ;Otherwise scroll filegadgets up bra.s 3$ 2$ btst.b #7,_FSDownGad+gg_Flags+1 ;FSDownGad.Flags & SELECTED? beq.s 4$ ;Nope, maybe slide gadget is selected pea 0 ;Otherwise scroll filegadgets down 3$ jsr _FSScrollFileGads addq.w #4,sp move.w #0,_FSCountDown ;Set timer to wake up in .02 secs. bra.s 12$ 4$ btst.b #7,_FSSlideGad+gg_Flags+1 ;FSSlideGad.Flags & SELECTED? beq.s 5$ ;Nope, maybe UpDev jsr _FSDoSlideGadget ;Process slide gadget motion move.w #0,_FSCountDown ;Set timer to wake up in .02 secs. bra.s 12$ 5$ btst.b #7,_FSPrevDevs+gg_Flags+1 ;FSPrevDevs.Flags & SELECTED? beq.s 7$ ;Nope, maybe DownDev pea 1 ;Otherwise FSScrollDevGads(1); 6$ jsr _FSScrollDevGads addq.w #4,sp move.w #1,_FSCountDown ;Set timer to wake up in .16 secs. bra.s 12$ 7$ btst.b #7,_FSNextDevs+gg_Flags+1 ;FSNextDevs.Flags & SELECTED? beq.s 10$ ;Nope, nothing of interest, slow down pea 0 ;Else FSScrollDevGads(0); bra 6$ 10$ move.w #4,_FSCountDown 12$ rts * ------------------------------------------------------------------------ ; BYTE *FibFileDate(fib_date) ; struct DateStamp *fib_date; ; ; Calculate date based on DateStamp structure and return a pointer ; to the formatted date text. * ------------------------------------------------------------------------ XDEF _FibFileDate _FibFileDate: link a5,#0 movem.l d3-d7,-(sp) movea.l 8(a5),a1 ;Grab datestamp pointer moveq #78,d7 ;Initial year = 1978 move.l (a1),d5 ;days = fib_date->ds_Days blt ffdbaddate ;Hey! you can't be negative! Invalid date... * Determine what year it is divu #1461,d5 move.l d5,d0 ;Stash it ext.l d5 lsl.l #2,d5 add.l d5,d7 ;year += (days / 1461) * 4 * Count how many months into that year ffdgetmo: swap d0 moveq #0,d5 move.w d0,d5 ;days %= 1461 1$ tst.w d5 ;Out of days yet? beq.s 3$ ;Yep, done here move.w #365,d6 ;Else month_days = 365 move.w d7,d0 ;Grab year andi.w #3,d0 ;if (year & 3) == 0 Leap year? bne.s 2$ ;Nope addq.w #1,d6 ;Otherwise bump month_days 2$ cmp.w d6,d5 ;is day < month_days? bcs.s 3$ ;yep, done here sub.w d6,d5 ;otherwise day -= month_days addq.l #1,d7 ; year++ bra 1$ 3$ * Count how many days into that month of that year ffdgetday: ;for (i = 0, day++; i < 12; i++) moveq #0,d4 ;current month = 0 moveq #0,d6 ;Zap hinybs addq.w #1,d5 lea _fsdayspermonth,a0 1$ move.b 0(a0,d4.w),d6 ;month_days = _fsdayspermonth[i] cmpi.w #1,d4 ;if (i == 1 && (year & 3) == 0) bne.s 2$ move.w d7,d0 andi.w #3,d0 bne.s 2$ addq.w #1,d6 ;month_days++ 2$ cmp.w d6,d5 ;if (day <= month_days) ble.s 4$ ;Break out, found the right month sub.w d6,d5 ;Else, day -= month_days addq.w #1,d4 ;i++ 3$ cmpi.w #12,d4 ;Done all months yet? bcs 1$ ;Nope 4$ ffdprint: 1$ cmpi.l #99,d7 ;while (year >= 100) ble.s 2$ subi.l #100,d7 ;year -= 100 bra 1$ 2$ ;sprintf(_fstempdate, "%02ld-%02ld-%02ld %02ld:%02ld:%02ld", year, i + 1, day, hour, min, sec) move.l 8(a1),d0 ;sec = fib_date->ds_Tick / 50; divu.w #50,d0 ext.l d0 move.l d0,-(sp) ;Push secs moveq #0,d0 ;Zap reg move.w 6(a1),d0 ;min = fib_date->ds_Minute move.w d0,d1 ;Clone it divu #60,d0 move.w d0,d3 ;hour = min / 60 ext.l d3 mulu #60,d0 sub.w d0,d1 ;min -= hour * 60 ext.l d1 move.l d1,-(sp) ;Push mins move.l d3,-(sp) ;Push hours move.l d5,-(sp) ;Push day of month addq.w #1,d4 ;Push month (offset by 1!) move.l d4,-(sp) move.l d7,-(sp) ;Push year pea _fsdatefmtstr ;Push the format pattern pea _fstempdate ;Push destination buffer jsr _sprintf lea 32(sp),sp lea _fstempdate,a0 move.l a0,d0 ;return((BYTE *)&_fstempdate[0]) ffddone: movem.l (sp)+,d3-d7 unlk a5 rts ffdbaddate: lea _fsbaddatestr,a0 move.l a0,d0 ;return (" ") bra ffddone * --------------------------------------------------------------------- * XDEF _FSSetKnobHeight _FSSetKnobHeight: ;vheight = (ULONG)( 655350L / (long)fsnumentries ); move.w _fsnumentries,d1 cmpi.w #10,d1 bhi.s 1$ move.w #$ffff,_fsvheight rts 1$ move.l #655350,d0 divu d1,d0 move.w d0,_fsvheight 3$ rts * --------------------------------------------------------------------- * XDEF _FSSetKnobPos _FSSetKnobPos: movea.l _topfin,a0 moveq #0,d0 move.w fn_idnum(a0),d0 swap d0 move.w _fsnumentries,d1 subi.w #10,d1 bhi.s 1$ moveq #0,d0 bra.s 2$ 1$ divu d1,d0 bvc.s 2$ move.w #$ffff,d0 2$ move.w d0,_fsvposition rts * --------------------------------------------------------------------- * XDEF _FSResetKnob _FSResetKnob: jsr _FSSetKnobHeight jsr _FSSetKnob rts * ------------------------------------------------------------------------ ; FSSetKnob() ; Call ModifyProp() to actually update slide image in window. * ------------------------------------------------------------------------ XDEF _FSSetKnob _FSSetKnob: movem.l d2-d5/a2/a6,-(sp) ;NewModifyProp(&FSSlideGad, FSWin, 0L, AUTOKNOB|FREEVERT|PROPB, 0L, vposition, 0xffffL, vheight, 1L) lea _FSSlideGad,a0 movea.l _FSWin,a1 suba.l a2,a2 moveq #AUTOKNOB!FREEVERT!PROPBORDERLESS,d0 moveq #0,d1 moveq #0,d2 move.w _fsvposition,d2 move.l #$ffff,d3 moveq #0,d4 move.w _fsvheight,d4 moveq #1,d5 SYS NewModifyProp,_IntuitionBase movem.l (sp)+,d2-d5/a2/a6 rts * ------------------------------------------------------------------------ ; FSEnableFGad(gadg_num) ; LONG gadg_num; ; ; Given a file gadget number, refresh the text for that entry. * ------------------------------------------------------------------------ XDEF _FSEnableFGad _FSEnableFGad: movem.l a2-a3/a6,-(sp) movea.l _FSRPort,a2 move.w 4+4*3+2(sp),d0 ;Grab gadget number move.w d0,d1 ;Copy lsl.w #2,d0 ;Conver to long offset lea _FSFileNodes,a0 movea.l 0(a0,d0.w),a0 ;tnode = FSFileNodes[gadg_num] movea.l fn_info(a0),a3 ;a3 = tnode->info * Move to the right slot text position mulu #11,d1 addi.w #19,d1 moveq #9,d0 movea.l a2,a1 SYS Move,_GfxBase ;Move(FSRPort, 9, gadnum*11+19) * Set the pen color according to the node move.w nd_textcolor(a3),d0 movea.l a2,a1 SYS SetAPen ;SetAPen(FSRPort, tinfo->textcolor) * Blast out the text moveq #56,d0 lea nd_alphadata(a3),a0 movea.l a2,a1 SYS Text ;Text(FSRPort, tinfo->alphadata, 56) movem.l (sp)+,a2-a3/a6 rts * ------------------------------------------------------------------------ ; FSDisableFGad(gadg_num) ; LONG gadg_num; ; ; Given a file gadget number, fill that slot with the EmptyPattern ; and clear the FileNode[] slot for that gadget. * ------------------------------------------------------------------------ XDEF _FSDisableFGad _FSDisableFGad: movem.l d2-d4/a2/a6,-(sp) move.w 4*5+4+2(sp),d4 ;Grab gadget number movea.l _FSRPort,a2 lea _EmptyPattern,a0 move.l a0,rp_AreaPtrn(a2) ;rp->AreaPtrn = EmptyPattern move.b #1,rp_AreaPtSz(a2) ;rp->AreaPtSz = (BYTE)1 movea.l a2,a1 moveq #2,d0 SYS SetAPen,_GfxBase ;SetAPen(rp, 2) move.w d4,d1 mulu #11,d1 addi.w #13,d1 ;miny = 13L + (gadg_num * 11) move.l d1,d3 addq.w #7,d3 ;maxy = miny + 7L movea.l a2,a1 ;FSWin->RPort moveq #9,d0 ;minx move.l #456,d2 ;maxx SYS RectFill ;RectFill(rp, minx, miny, maxx, maxy) clr.l rp_AreaPtrn(a2) ;rp->AreaPtrn = 0L clr.b rp_AreaPtSz(a2) ;rp->AreaPtSz = (BYTE)0 move.w d4,d0 lsl.w #2,d0 lea _FSFileNodes,a0 clr.l 0(a0,d0.w) ;FSFileNodes[gadg_num] = 0L movem.l (sp)+,d2-d4/a2/a6 rts * --------------------------------------------------------------------- * XDEF _FSDisableAllFGads _FSDisableAllFGads: move.l d2,-(sp) moveq #0,d2 move.w _fsnumentries,d2 bra.s 2$ 1$ move.l d2,-(sp) jsr _FSDisableFGad ;FSDisableFGad(i) addq.w #4,sp addq.w #1,d2 ;i++ 2$ cmpi.w #10,d2 ;Hit 10 entries? bcs 1$ ;Nope, disable one move.l (sp)+,d2 rts * ------------------------------------------------------------------------ ;struct file_node *AllocFileNode() ; ; Allocate a file_node structure and it's info block, return pointer ; to the file_node or NULL if allocation failed. * ------------------------------------------------------------------------ XDEF _AllocFileNode _AllocFileNode: move.l a6,-(sp) moveq #fn_SIZEOF+nd_SIZEOF,d0 ;sizeof(struct file_node)+sizeof(struct node_data) move.l #MEMF_CLEAR,d1 ;MEMF_CLEAR SYS AllocMem,4 ;Allocate file node structure move.l d0,d1 beq.s 1$ movea.l d0,a0 addi.l #fn_SIZEOF,d1 move.l d1,fn_info(a0) ;Set pointer to tnode->info area 1$ movea.l (sp)+,a6 rts * ------------------------------------------------------------------------ ; FreeFileNode(tnode) ; struct file_node *tnode; ; ; Given a pointer to a file_node, Free the memory allocated for that node. * ------------------------------------------------------------------------ XDEF _FreeFileNode _FreeFileNode: move.l a6,-(sp) move.l 4+4(sp),d0 ;Grab tnode beq.s 2$ ;Nope, get outta here movea.l d0,a1 moveq #fn_SIZEOF+nd_SIZEOF,d0 SYS FreeMem,4 ;FreeMem(tnode, sizeof(struct file_node)+sizeof(struct node_data)) 2$ movea.l (sp)+,a6 rts * ------------------------------------------------------------------------ ; FreeAllFNodes() ; ; Call FreeFileNode for each node in the linked list of file_nodes, ;then deallocate the head of the list (fnList) * ------------------------------------------------------------------------ XDEF _FreeAllFNodes _FreeAllFNodes: movem.l a2/a6,-(sp) move.l _fnList,d0 ;Is there a list? beq.s 2$ ;Nope, get outta here movea.l d0,a2 ;Grab head movea.l 4,a6 ;Set for ExecBase 1$ movea.l a2,a0 SYS RemHead ;d0 = RemHead(fnList) tst.l d0 ;Hit end? beq.s 2$ ;yep move.l d0,-(sp) jsr _FreeFileNode ;Free the node addq.w #4,sp bra 1$ ;Remove next node 2$ * Reset other globals clr.w _fsvposition ;Set slider position to top of area move.w #$ffff,_fsvheight ;Max height clr.w _fsnumentries ;Zero entries movem.l (sp)+,a2/a6 rts * ------------------------------------------------------------------------ ;struct dev_node *AllocDevNode() ; ; Allocate a dev_node, return pointer to same * ------------------------------------------------------------------------ XDEF _AllocDevNode _AllocDevNode: move.l a6,-(sp) moveq #dn_SIZEOF,d0 move.l #MEMF_CLEAR,d1 SYS AllocMem,4 ;AllocMem(sizeof(struct dev_node), MEMF_CLEAR) movea.l (sp)+,a6 rts * ------------------------------------------------------------------------ ;FreeDevNode(tnode) ; struct dev_node *tnode; ; ; Given a pointer to a dev_node, free memory allocated for that node. * ------------------------------------------------------------------------ XDEF _FreeDevNode _FreeDevNode: move.l a6,-(sp) move.l 4+4(sp),d0 ;Grab dev_node to free beq.s 1$ ;Oops, nothing here movea.l d0,a1 moveq #dn_SIZEOF,d0 SYS FreeMem,4 ;FreeMem(tnode, (long)sizeof(struct dev_node)) 1$ movea.l (sp)+,a6 rts * ------------------------------------------------------------------------ ;FreeAllDNodes() ; ; Call FreeDevNode() for each dev_node in the linked list, then free the ; head of the list, devList. * ------------------------------------------------------------------------ XDEF _FreeAllDNodes _FreeAllDNodes: movem.l a2/a6,-(sp) move.l _devList,d0 ;Is there a head node? beq.s 3$ ;Nope, don't deallocate movea.l d0,a2 ;Grab head of device list movea.l 4,a6 ;Set for execbase 1$ movea.l a2,a0 SYS RemHead ;d0 = RemHead(devList) tst.l d0 ;Got one? beq.s 2$ ;Nope, list is empty move.l d0,-(sp) jsr _FreeDevNode ;Free this device node addq.w #4,sp bra 1$ 2$ movea.l a2,a1 moveq #MLH_SIZE,d0 SYS FreeMem ;FreeMem(devList, sizeof(MinList)) clr.l _devList 3$ movem.l (sp)+,a2/a6 rts * ------------------------------------------------------------------------ ; FreeFileSelect() ; Deallocate filenames and fileinfoblocks, unlock any locks * ------------------------------------------------------------------------ XDEF _FreeFileSelect _FreeFileSelect: move.l a6,-(sp) move.w #1,_fsvirgindir ;virgindir = 1 jsr _FreeAllFNodes ;Free all allocated filenames jsr _FSClearLock ;Unlock any locks * Free the head node itself move.l _fnList,d0 beq.s 1$ movea.l d0,a1 moveq #MLH_SIZE,d0 SYS FreeMem,4 ;FreeMem(fnList, sizeof(MinList)) clr.l _fnList ;And clear the pointer 1$ * Free the global FileInfoBlock and InfoData struct move.l _FSFib,d0 ;Do we have a FileInfoBlock allocated? beq.s 2$ ;Nope movea.l d0,a1 move.l #fib_SIZEOF+id_SIZEOF,d0 SYS FreeMem,4 ;FreeMem(FSFib, 300L) clr.l _FSFib ;Set to NULL so we don't re-free it clr.l _FSInfo 2$ movea.l (sp)+,a6 rts * --------------------------------------------------------------------- * * Cleanup function for fileselect * --------------------------------------------------------------------- * XDEF _ReleaseFileSelect _ReleaseFileSelect: jsr _FreeFileSelect jsr _FreeAllDNodes rts * ------------------------------------------------------------------------ ; LONG FSGetNextFib(VOID) ; ; Call ExNext() to fill in next FileInfoBlock, set titlebar to reflect ; status of the request. * ------------------------------------------------------------------------ XDEF _FSGetNextFib _FSGetNextFib: movem.l d2/a6,-(sp) * Try to get next fileinfoblock from dos move.l _FSLock,d1 move.l _FSFib,d2 SYS ExNext,_DOSBase tst.l d0 ;Did we get an entry? bne.s gnfgot1 ;Yep, got it * Didn't get one, find out why ;if ( (error = IoErr()) != ERROR_NO_MORE_ENTRIES) SYS IoErr ;Get error number cmpi.l #232,d0 ;No more entries? beq.s gnfnme ;Yep move.l d0,-(sp) jsr _ioerrnum ;Otherwise set window title to error number addq.w #4,sp move.w d0,_fstitstatus moveq #-1,d2 ;Return bad get status bra.s gnfsetwintit gnfnme: moveq #0,d2 ;Return DONE! tst.w _fsnumentries ;Got any valid pattern matches? bne.s gnfselect ;Yep, select a file time movea.l _fnList,a6 movea.l MLH_HEAD(a6),a6 tst.l fn_Node+MLN_SUCC(a6) ;Do we have any files? beq.s gnfnoentry ;Nope, no entries move.w #24,_fstitstatus ;Otherwise no match bra.s gnfsetwintit gnfnoentry: move.w #22,_fstitstatus ;No Entries... bra.s gnfsetwintit gnfselect: move.w #29,_fstitstatus ;Select a file... gnfsetwintit: bra.s gnfdone gnfgot1: moveq #1,d2 gnfdone: move.l d2,d0 movem.l (sp)+,d2/a6 rts * ------------------------------------------------------------------------ ;AllocFSFib() ;Allocate a fileinfoblock, return status * ------------------------------------------------------------------------ XDEF _AllocFSFib _AllocFSFib: move.l a6,-(sp) tst.l _FSFib ;Do we already have a fib? bne.s 1$ ;Yep, get out of here ;FSFib = AllocMem(sizeof(*FSFib) + sizeof(*FSInfo), MEMF_CLEAR); move.l #fib_SIZEOF+id_SIZEOF,d0 move.l #MEMF_CLEAR,d1 SYS AllocMem,4 move.l d0,_FSFib beq.s 2$ ;Oops, allocation failed, return 0 addi.l #fib_SIZEOF,d0 move.l d0,_FSInfo ;Set pointer to InfoData struct too 1$ moveq #1,d0 ;Return good status 2$ movea.l (sp)+,a6 rts * ------------------------------------------------------------------------ ;LONG ioerrnum(num) ; LONG num; ; ; Given an IoErr number, convert to error text table offset, return ; converted index number. * ------------------------------------------------------------------------ XDEF _ioerrnum _ioerrnum: move.l 4(sp),d0 cmpi.w #202,d0 ;if (num < 202L || num > 231L) bcs.s ioetl cmpi.w #231,d0 bls.s ioe3l ioetl: moveq #27,d0 ;return(27) rts ioe3l: cmpi.w #209,d0 ;if (num < 209L) bcc.s ioe4l subi.w #202,d0 ;num -= 202L rts ioe4l: subi.w #205,d0 ;else num -= 205L rts * ------------------------------------------------------------------------ ; BYTE *ioerrmsg(num) ; long num; ; ; Given a IoErr number, return pointer to error message text that ; describes that error. * ------------------------------------------------------------------------ XDEF _ioerrmsg _ioerrmsg: move.l 4(sp),-(sp) ;Push error number jsr _ioerrnum addq.w #4,sp lsl.w #2,d0 ;Convert return to text table offset lea _fserrmsgs,a0 move.l 0(a0,d0.w),d0 ;Return pointer to fserrmsgs[num] rts * ------------------------------------------------------------------------ ; VOID FSPutPath(VOID) ; Refresh the FSPathGadget imagery. * ------------------------------------------------------------------------ XDEF _FSPutPath _FSPutPath: movem.l a2/a6,-(sp) ;RefreshGList(&FSPathGad, FSWin, 0L, 1L); lea _FSPathGad,a0 movea.l _FSWin,a1 suba.l a2,a2 moveq #1,d0 SYS RefreshGList,_IntuitionBase movem.l (sp)+,a2/a6 rts * ------------------------------------------------------------------------ ; VOID FSClearLock(VOID) ; ; If we have a Lock on the current directory, unlock it. * ------------------------------------------------------------------------ XDEF _FSClearLock _FSClearLock: move.l a6,-(sp) tst.w _fsdirlocked ;Is it locked? beq.s 2$ ;Nope, don't dare unlock move.l _FSLock,d1 beq.s 1$ SYS UnLock,_DOSBase ;UnLock(FSLock) clr.l _FSLock ;FSLock = 0L; 1$ clr.w _fsdirlocked ;dirlocked = 0 2$ movea.l (sp)+,a6 rts * ------------------------------------------------------------------------ ; FSWinTitle() ; Refresh current window title using contents of windowtitle[]. * ------------------------------------------------------------------------ XDEF _FSWinTitle _FSWinTitle: movem.l a2/a6,-(sp) move.w _fstitlelength,d0 lea _FSWinTitleStr,a0 clr.b 0(a0,d0.w) ;windowtitle[fstitlelength] = '\x0' move.w _fstitstatus,d1 lsl.w #2,d1 lea _fserrmsgs,a1 movea.l 0(a1,d1.w),a1 adda.w d0,a0 jsr astrcpy ;astrcpy(&windowtitle[fstitlelength], fserrmsgs[fstitstatus]) movea.l _FSWin,a1 move.l wd_Flags(a1),d0 ;d0 = FSWin->Flags andi.l #WINDOWTGADS,d0 ;Do we have titlebar gadgets? bne.s 3$ ;Yep, refresh is automatic lea _FSWinTitleStr+79,a1 clr.b (a1) ;FSWinTitleStr[79] = 0 move.b #' ',d0 ;for (;ptr != &FSWinTitle[79];ptr++) 2$ cmpa.l a0,a1 beq.s 4$ move.b d0,(a0)+ ;*ptr = ' ' bra 2$ 3$ move.b #' ',(a0)+ ;Concat a space and a null onto the end clr.b (a0) 4$ ;SetWindowTitles(FSWin, windowtitle, -1L) movea.l _FSWin,a0 lea _FSWinTitleStr,a1 movea.l #-1,a2 SYS SetWindowTitles,_IntuitionBase movem.l (sp)+,a2/a6 rts * ------------------------------------------------------------------------ ; VOID FSEndString(VOID) ; ; If user started a string gadget entry then clicked in another gadget, ;ignore any changes to the string and restore the previous string. * ------------------------------------------------------------------------ XDEF _FSEndString _FSEndString: movem.l a2/a6,-(sp) move.w _fsstartedstr,d0 ;Grab starttext flag cmpi.w #1,d0 ;Did user start at file entry? bne.s fstnotfile ;Nope movea.l _FSFileInfo,a0 ;Grab filename buffer lea _FileUndoName,a1 lea _FSFileGad,a2 ;Grab filetext gadget bra.s fstrefresh ;Refresh it fstnotfile: cmpi.w #2,d0 ;Did user start a path entry? bne.s fstnotpath ;Nope, maybe pattern movea.l _FSPathInfo,a0 ;Grab pathtext buffer lea _FileUndoBuffer,a1 lea _FSPathGad,a2 ;Pointer to path gadget bra.s fstrefresh ;Refresh text fstnotpath: cmpi.w #3,d0 ;Started a pattern entry? bne.s fstdone ;Nope, don't have to do anything movea.l _FSPatternInfo,a0 ;Else grab the pattern buffer lea _FSPatternUndoBuffer,a1 lea _FSPatternGad,a2 ;Pointer to pattern gadget fstrefresh: jsr astrcpy ;astrcpy(tstr, FSwstr) movea.l a2,a0 movea.l _FSWin,a1 suba.l a2,a2 moveq #1,d0 SYS RefreshGList,_IntuitionBase ;RefreshGList(tgad, FSWin, 0L, 1L) clr.w _fsstartedstr ;fsstartedstr = 0 fstdone: movem.l (sp)+,a2/a6 rts * ------------------------------------------------------------------------ ; FSDoGadget(gadgid) ; ULONG gadgid; ; ; Given a gadget id number, perform action associated with that gadget. * ------------------------------------------------------------------------ XDEF _FSDoGadget _FSDoGadget: movem.l d4/a2,-(sp) move.w 14(sp),d4 ;Grab gadget id number bne.s dgnotusergad ;Not zero, not Undo gadget * FSUserGad jsr _ConcatPathString ;Concat final output text, return clr.w _FSDone movea.l _FSReq,a1 movea.l fs_specgadfunc(a1),a0 pea _FSUserGad move.l _FSWin,-(sp) move.l a1,-(sp) jsr (a0) lea 12(sp),sp tst.l d0 bne dgnewdir bra dogaddone dgnotusergad: * FSSelectGad cmpi.w #1,d4 ;Is the the FSSelect gadget? bne.s dgnotselect ;Nope jsr _ConcatPathString ;Concat final output text, return bra dogaddone dgnotselect: * FSCancelGad cmpi.w #2,d4 ;Is it the FSCancel Gadget? bne.s dgnotcancel ;Nope move.w #1,_FSDone ;Global signal that we're done movea.l _FSReq,a0 ;a0 = fsreq movea.l fs_fullname(a0),a0 ;a0 = fsreq->fullname clr.b (a0) ;Return filename == "" bra dogaddone dgnotcancel: * UndoGad cmpi.w #3,d4 ;Undo? bne.s dgnotundo movea.l _FSPathInfo,a0 ;Copy OldFSPathBuf to FSPathInfo.Buffer movea.l _OldFSPathBuf,a1 jsr astrcpy ;astrcpy(FSPathInfo.Buffer, OldFSPathBuf) bra dgnewdir ;Process new directory dgnotundo: * Dev1Gad cmpi.w #20,d4 ;Is it the first Device Gadget? bne.s dgnotram ;Nope movea.l _CurDevNames+12,a1 ;Push the name text dgdevs: movea.l _FSPathInfo,a0 ;Destination text jsr astrcpy ;Copy new path bra dgnewdir ;Now set new directory dgnotram: cmpi.w #21,d4 ;Is it the second Device Gadget? bne.s dgnotdf0 ;Nope movea.l _CurDevNames+8,a1 ;Push the name text bra dgdevs ;Change path dgnotdf0: cmpi.w #22,d4 ;Is it the third Device Gadget? bne.s dgnotnil1 ;Nope movea.l _CurDevNames+4,a1 ;Push the name text bra dgdevs ;Set the path dgnotnil1: cmpi.w #23,d4 ;Is it the fourth Device Gadget? bne.s dgnotnil2 ;Nope movea.l _CurDevNames,a1 ;Push the name text bra dgdevs ;And set the new path dgnotnil2: * RootGad cmpi.w #24,d4 ;Is it the ROOT gadget? bne.s dgnotroot ;Nope jsr _SetRootDir ;Set root directory! bra dogaddone ;Done dgnotroot: * ParentGad cmpi.w #25,d4 ;Is it the Parent gadget? bne.s dgnotpar ;Nope jsr _SetParentDir ;Change to parent directory bra dogaddone ;Done! dgnotpar: * FSPatternGad cmpi.w #30,d4 ;Maybe its the pattern text gadget? bne.s dgnotpattern jsr _FSMatchPattern ;Otherwise attempt to match new pattern bra dogaddone ;We're done! dgnotpattern: * FSFileGad cmpi.w #31,d4 ;Is it the file text gadget? bne.s dgnotfileg ;Nope jsr _FSFileFunc jsr _ConcatPathString ;Form final path text btst.b #1,_fsflags+1 ;FS_NO_STRING_EXIT? beq dogaddone clr.w _FSDone bra dogaddone 1$ movea.l _FSFileInfo,a0 tst.b (a0) ;Really a filename here? bne.s 2$ ;yep btst.b #2,_fsflags+1 ;FS_NO_STRING_OKAY? beq.s 2$ ;Nope bra dogaddone ;let user exit with no filename 2$ clr.w _FSDone ;Else we ain't done yet! bra dogaddone dgnotfileg: * FSPathGad cmpi.w #32,d4 ;Is it the path text gadget? bne.s dgnotpath ;Nope movea.l _FSPathInfo,a2 ;Grab pointer to path text movea.l a2,a0 jsr astrlen ;Determine length subq.w #1,d0 ;Move back to last BYTE blt.s dgnotdamnsla ;Oops, null text! cmpi.b #'/',0(a2,d0.w) ;Is the last char a slash? bne.s dgnotdamnsla ;Nope, don't have to tromp it 1$ cmpi.b #'/',0(a2,d0.w) ;Check for a trailing slash bne.s 2$ ;Didn't find another clr.b 0(a2,d0.w) ;Clobber this slash subq.w #1,d0 ;Dec character pointer bne.s 1$ ;till we run out of slashes or chars 2$ jsr _FSPutPath ;Refresh path text dgnotdamnsla: jsr _FSDirFunc ;Do fsreq->dirfunc, if there is one tst.w d0 ;Ignore new dir? beq.s 1$ ;Nope jsr _SetParentDir ;Else chop off the new path jsr _FSPutPath ;Update string gad clr.w _fsvirgindir ;Virgin again bra.s dogaddone ;All done 1$ move.l _FSWin,-(sp) pea _FSFileGad jsr _MyActivateGad ;Activate file text gadget addq.w #8,sp bra.s dgnewdir ;Set new path, read new dir dgnotpath: * Slide Gadget cmpi.w #33,d4 ;Is it the SlideGadget? bne.s dgnotslide ;nope jsr _FSDoSlideGadget ;Else it's been released, update position bra.s dgresetarrows ;Done here, reset timer dgnotslide: * Arrow gadgets cmpi.w #40,d4 ;Is it one of the four arrows gadgets? blt.s dogaddone cmpi.w #43,d4 bgt.s dogaddone dgresetarrows: clr.w _FSCountDown ;Kill any timer requests in progress bra.s dogaddone dgnewdir: move.w #1,_fsvirgindir ;Set flag to read new directory! dogaddone: movem.l (sp)+,d4/a2 rts * --------------------------------------------------------------------- * * VOID FillFileNode(tnode) * struct file_node *tnode; * --------------------------------------------------------------------- * ffnnode EQU 4+4*4 XDEF _FillFileNode _FillFileNode: movem.l d2/a2-a3/a6,-(sp) movea.l ffnnode(sp),a0 ;a0 = tnode passed movea.l fn_info(a0),a2 ;a2 = tinfo = tnode->info movea.l _FSFib,a3 ;a3 = FSFib move.l fib_Size(a3),nd_filesize(a2) ;tinfo->filesize = FSFib->fib_Size move.l fib_DateStamp+0(a3),nd_days(a2) ;tinfo->day = FSFib->fib_DateStamp.ds_Days move.l fib_DateStamp+4(a3),nd_minutes(a2) move.l fib_DateStamp+8(a3),nd_ticks(a2) pea fib_DateStamp(a3) jsr _FibFileDate addq.w #4,sp movea.l d0,a1 lea nd_alphadata(a2),a0 ;a0 = tinfo->alphadata jsr astrcpy ;a0 = astrcpy(&tinfo->alphadata[0], FibFileDate(&FSFib->DateStamp)) tst.l fib_DirEntryType(a3) ;If < 0 it is a file bge.s ffnisdir ;>= 0, it is a dir ffnisfile: move.w #1,nd_filetype(a2) ;tinfo->filetype = 1 move.w #FPEN,nd_textcolor(a2) ;tinfo->textcolor = FPEN move.l a0,-(sp) move.l fib_Size(a3),-(sp) pea _FSSizeFmtStr move.l a0,-(sp) jsr _sprintf ;sprintf(a0, "%8ld ", FSFib->fib_Size) lea 12(sp),sp movea.l (sp)+,a0 adda.w #9,a0 ;Skip filesize part of message bra.s ffnsetname ffnisdir: move.w #2,nd_filetype(a2) ;tinfo->filetype = 2 move.w #DPEN,nd_textcolor(a2) ;tinfo->textcolor = DPEN lea _FSDirFmtStr,a1 jsr astrcpy ;astrcpy(dest, FSDirFmtStr) ffnsetname: moveq #0,d0 lea fib_FileName(a3),a1 ;a1 = FSFib->fib_FileName 1$ move.b (a1)+,d1 beq.s 2$ ;Hit null, see if we need to pad move.b d1,(a0)+ ;copy a char, till null addq.w #1,d0 ;i++ cmpi.w #30,d0 ;Max chars yet? bcs 1$ 2$ move.w d0,nd_namelength(a2) ;tinfo->namelength = i move.b #' ',d1 bra.s 4$ ;Append spaces till 30 chars 3$ move.b d1,(a0)+ addq.w #1,d0 4$ cmpi.w #30,d0 bcs 3$ clr.b (a0) ;Null terminate at 31st char ffnsetshow: movea.l ffnnode(sp),a2 moveq #1,d0 movea.l a2,a0 ;a0 = tnode jsr _FSValidateEntry ;FSValidateEntry(tnode, 1) * Now insert the node into list according to sort type ffninsert: movea.l _fnList,a3 movea.l MLH_HEAD(a3),a3 ;a3 = fnList->lh_Head movea.l _FSReq,a0 move.w fs_sorttype(a0),d2 ;d0 = FSReq->sorttype 1$ tst.l fn_Node+MLN_SUCC(a3) ;Is this the end of the list? beq.s 2$ ;Nope, insert it here move.l fn_info(a3),a1 ;Push existing node->info move.l fn_info(a2),a0 ;Push tnode->info move.w d2,d0 ;Push sort type jsr _CompareNodes ;Compare info's according to sort type tst.w d0 ;Is a0 > a1? beq.s 2$ ;nope, found insertion point movea.l fn_Node+MLN_SUCC(a3),a3 ;oldnode = oldnode->next bra 1$ ;Nope, keep looking 2$ movea.l _fnList,a0 movea.l a2,a1 move.l fn_Node+MLN_PRED(a3),a2 SYS Insert,4 ffndone: movem.l (sp)+,d2/a2-a3/a6 rts * --------------------------------------------------------------------- * * VOID FSValidateEntry(tnode, mode) * a0 d0 * --------------------------------------------------------------------- * XDEF _FSValidateEntry _FSValidateEntry: movem.l d2-d3/a2,-(sp) * See if the Acceptor likes this node name move.l d0,d3 ;d3 = mode movea.l a0,a2 ;a2 = tnode move.l a2,-(sp) jsr _FSAcceptEntry ;if (FSAcceptEntry(tnode) == 0) addq.w #4,sp tst.w d0 bne.s 1$ * Don't display this node movea.l fn_info(a2),a0 clr.w nd_showit(a0) ;tnode->info->showit = 0; move.w #-1,fn_idnum(a2) ;tnode->idnum = -1 bra.s 4$ ;And return * Accept this node for display 1$ movea.l fn_info(a2),a0 move.w #1,nd_showit(a0) ;else tnode->info->showit = 1; moveq #0,d2 move.w _fsnumentries,d2 ;Grab entry number for this node bne.s 2$ ;Not first entry move.l a2,_topfin ;topnode = tnode, first visible node 2$ move.w d2,fn_idnum(a2) ;tnode->idnum = fsnumentries addq.w #1,_fsnumentries ;fsnumentries++, one more visible entry clr.w _fsneedshow ;fsneedshow = 0, needs sorting * If we haven't filled display area, show this entry cmpi.w #10,d2 ;> 10 entries already? bcc.s 3$ ;Yep, just set the knob lea _FSFileNodes,a0 move.w d2,d0 ;Grab entry number lsl.w #2,d0 ;Convert to long table offset move.l a2,0(a0,d0.w) ;FSFileNodes[fsnumentries] = tnode move.l d2,-(sp) jsr _FSEnableFGad ;FSEnableFGad(fsnumentries) addq.w #4,sp bra.s 4$ ;Skip setting knob, it is still full size 3$ tst.w d3 ;Want slide update? beq.s 4$ ;Nope ; btst.b #7,_FSSlideGad+gg_Flags+1 ;User has slide gadget in use? ; bne.s 4$ ;Yes, don't refresh it while in use * Calc new knob size and refresh btst.l #0,d2 ;(idnum % 2) == 0? beq.s 4$ ;Yep, don't reset on even values jsr _FSResetKnob 4$ movem.l (sp)+,d2-d3/a2 rts * --------------------------------------------------------------------- * * Update FileTexts list, redisplay * Renumber list, find new topfin * --------------------------------------------------------------------- * XDEF _FSUpdateSort _FSUpdateSort: move.w _fsneedshow,d0 blt.s 3$ move.w _fsnumentries,d1 beq.s 2$ subi.w #10,d1 ;Less max number of visible files move.w _FSSlideProp+4,d0 ;Grab current vpot mulu d1,d0 ;Times position percentage addi.l #32768,d0 clr.w d0 swap d0 jsr _FSResetNumEntries jsr _FSSetFileGads 2$ move.w #-1,_fsneedshow moveq #0,d0 3$ tst.w d0 rts * --------------------------------------------------------------------- * * VOID FSResetNumEntrys(idnum) * d0:16 * --------------------------------------------------------------------- * XDEF _FSResetNumEntries _FSResetNumEntries: move.l a2,-(sp) movea.l _fnList,a2 ;Grab List movea.l MLH_HEAD(a2),a2 ;Head of list moveq #0,d1 ;i = 0 1$ tst.l fn_Node+MLN_SUCC(a2) ;End of list? beq.s 5$ movea.l fn_info(a2),a0 ;a0 = tnode->info tst.w nd_showit(a0) ;Visible? bne.s 2$ ;Yep move.w #-1,fn_idnum(a2) ;Else tnode->idnum = -1 bra.s 4$ ;Next node 2$ move.w d1,fn_idnum(a2) ;tnode->idnum = i cmp.w d1,d0 ;if (idnum == oldidnum) bne.s 3$ move.l a2,_topfin ; topfin = tnode; 3$ addq.w #1,d1 ;i++ 4$ movea.l fn_Node+MLN_SUCC(a2),a2 ;tnode = tnode->fn_Node.mln_Succ bra 1$ ; Check next node 5$ move.w d1,_fsnumentries ;Update number of entries movea.l (sp)+,a2 rts * --------------------------------------------------------------------- * * LONG FSAcceptEntry(struct file_node *tnode); * Decide whether given tnode is displayable. * Return 0L for ignore this node, 1L for valid node. * --------------------------------------------------------------------- * aftnode EQU 8 aftname EQU -48 XDEF _FSAcceptEntry _FSAcceptEntry: link a5,#aftname movem.l a2-a3,-(sp) movea.l aftnode(a5),a2 ;Grab tnode movea.l fn_info(a2),a3 ;Grab tnode->info * Copy tnode->info->alphadata name section to stack, null terminate move.w nd_namelength(a3),d0 ;Push tinfo->namelength lea nd_alphadata+26(a3),a1 ;Push tinfo->alphadata + 26 lea aftname(a5),a0 ;Push destination jsr astrncpy ;Copy and null terminate * If there is a special match function defined, use that... movea.l _FSReq,a0 tst.l fs_matchfunc(a0) ;If FSReq->matchfunc != 0 beq.s 1$ move.l aftnode(a5),-(sp) pea aftname(a5) move.l _FSReq,-(sp) move.l fs_matchfunc(a0),a0 jsr (a0) ;return((FSReq->matchfunc)(FSReq, name, tnode) lea 12(sp),sp bra.s aftdone * Otherwise use built-in acceptor routine 1$ cmpi.w #2,nd_filetype(a3) ;Is tinfo->filetype == 2? (a directory) beq.s aftisdir ;Yep, we need it in list * Check file name against patterns btst.b #6,_fsflags+1 ;Want dirs only? bne.s aftwrongpat ;Yep, ignore all files pea _FSIgnorePat ;See if it matches the ignore text pea aftname(a5) jsr _wildmatch addq.w #8,sp tst.w d0 ;Did it match the ignore text? bne.s aftwrongpat ;Yep, ignore this file move.l _FSPatternInfo,-(sp) ;See if it matches desired pattern pea aftname(a5) jsr _wildmatch addq.w #8,sp tst.w d0 ;Did it match? beq.s aftwrongpat ;Nope, skip it bra.s aftgoodpat ;Else accept this file aftisdir: btst.b #5,_fsflags+1 ;This is a dir, want files only? bne.s aftwrongpat ;Yep, ignore this dir aftgoodpat: moveq #1,d0 ;Accept this entry bra.s aftdone aftwrongpat: moveq #0,d0 ;Ignore this entry aftdone: movem.l (sp)+,a2-a3 unlk a5 rts * --------------------------------------------------------------------- * * VOID FSMatchPattern(VOID); * Called when path or pattern has changed - rematch all entries * against the new pattern, display entries that match. * --------------------------------------------------------------------- * XDEF _FSMatchPattern _FSMatchPattern: movem.l d4/a2-a3/a6,-(sp) * Pattern match list against new pattern, flag unwanted names movea.l _FSPatternInfo,a0 ;Grab pattern tst.b (a0) ;Null pattern text? bne.s mnpnotnop ;Nope, process it move.b #'*',(a0)+ ;Otherwise put back wildstar clr.b (a0) ;Null terminate lea _FSPatternInfo,a0 ;Grab stringinfo move.w #1,8(a0) ;FSPatternInfo.BufferPos = 1; lea _FSPatternGad,a0 movea.l _FSWin,a1 suba.l a2,a2 moveq #1,d0 SYS RefreshGList,_IntuitionBase ;Refresh pattern text gadget move.l _FSWin,-(sp) pea _FSPatternGad jsr _MyActivateGad ;MyActivateGad(&FSPatternGad, FSWin) addq.w #8,sp bra.s mnpdone ;Make the user type something else in mnpnotnop: movea.l _fnList,a0 move.l MLH_HEAD(a0),a0 tst.l fn_Node+MLN_SUCC(a0) ;Do we have any files to match? beq.s mnpdone ;Nope, nothing to do * Reset knob to full height, zero position clr.w _fsnumentries ;Clear fsnumentries count clr.w _fsvposition move.w #$ffff,_fsvheight jsr _FSSetKnob ;Show new knob * Disable all file "gadgets" jsr _FSDisableAllFGads * Scan list, enable/flag entries that match new pattern movea.l _fnList,a2 ;tnode = fnList movea.l MLH_HEAD(a2),a2 ;tnode = head node clr.l _topfin ;Clear out top/bot display pointers 1$ tst.l fn_Node+MLN_SUCC(a2) ;End of list? beq.s 2$ moveq #0,d0 movea.l a2,a0 jsr _FSValidateEntry ;FSValidateEntry(tnode, 0) movea.l fn_Node+MLN_SUCC(a2),a2 ;tnode = tnode->fn_Node.mln_Succ bra 1$ ;Nope, process this one too 2$ move.w #-1,_fsneedshow ;Clear reshow/sort flag, list valid cmpi.w #10,_fsnumentries ;Found some entries? bls.s mnpsettitle ;Yep, skip setting knob again jsr _FSResetKnob ;Show new knob size mnpsettitle: tst.w _fsnumentries ;Got any matches to pattern? bne.s mnpmatchedsome ;Yep move.w #24,_fstitstatus ;"Nothing matched PATTERN" bra.s mnpnewtit mnpmatchedsome: move.w #29,_fstitstatus ;"Select a file..." mnpnewtit: jsr _FSWinTitle ;Show final title status mnpdone: movem.l (sp)+,d4/a2-a3/a6 rts * ---------------------------------------------------------------------- ; VOID ConcatPathString(VOID) ; ; If the file text is non-NULL, concat path text and file text, ; set global exit flag to show user selected a filename. * ---------------------------------------------------------------------- XDEF _ConcatPathString _ConcatPathString: * Try to add path prefix move.l _FSFileInfo,-(sp) move.l _FSPathInfo,-(sp) movea.l _FSReq,a0 ;Grab final pathtext movea.l fs_fullname(a0),a0 move.l a0,-(sp) jsr _ConcatDirFile ;ConcatDirFile(FSReq->fullname, FSPathInfo->Buffer, FSFileInfo->Buffer) lea 12(sp),sp * Did the user select a filename yet? movea.l _FSFileInfo,a0 tst.b (a0) ;First byte of name null? bne.s 1$ ;Nope, must be okay btst.b #2,_fsflags+1 ;(FSFlags & FS_NO_STRING_OKAY) == 0? beq.s 2$ ;Yep, user can't exit till something is entered 1$ * Flag main loop to exit move.w #1,_FSDone 2$ rts * --------------------------------------------------------------------- * * VOID __stdargs ConcatDirFile(BYTE *, BYTE *, BYTE *) * --------------------------------------------------------------------- * XDEF _ConcatDirFile _ConcatDirFile: movem.l 4(sp),a0-a1 ;grab dest, dirname tst.b (a1) ;Is there a dirname here? beq.s 1$ ;Nope jsr astrcpy ;astrcpy(dest, dirname) movea.l 12(sp),a1 ;grab filename tst.b (a1) ;Is there a filename? beq.s 2$ ;Nope, don't concat a slash move.b -1(a0),d0 ;d0 = dest[strlen(dest - 1)] cmpi.b #':',d0 ;Already has a colon? beq.s 1$ ;Yep cmpi.b #'/',d0 ;Already has a slash? beq.s 1$ ;Yep move.b #'/',(a0)+ ;Append a slash clr.b (a0) ;Terminate 1$ movea.l 12(sp),a1 jsr astrcpy ;astrcpy(dest, name) 2$ rts * ------------------------------------------------------------------------ * VOID FSDoSlideGadget(VOID) * * Process the current slide gadget position, scroll file entries * to match current position. * ------------------------------------------------------------------------ XDEF _FSDoSlideGadget _FSDoSlideGadget: movem.l d4-d5,-(sp) jsr _FSUpdateSort beq dsgdone cmpi.w #10,_fsnumentries ;Do we have less than 10 entries? blt dsgdone ;Yep, can't move anyhow moveq #0,d0 move.w _FSSlideProp+4,d0 ;Grab new vpot cmp.w _fsvposition,d0 ;Has it moved? beq dsgdone ;Nope move.w d0,_fsvposition ;Otherwise update position move.w _fsnumentries,d4 ;Grab number of entries subi.w #10,d4 ;Less max number of visible files mulu d0,d4 ;Times position percentage addi.l #32768,d4 clr.w d4 swap d4 movea.l _topfin,a0 ;Grab top node cmp.w fn_idnum(a0),d4 ;Is node->idnum the same as newpos? beq.s dsgdone ;Yep, don't have to move it bcc.s dsgscrup ;newpos is lower, scroll up ************** * Scroll Down ************** move.w fn_idnum(a0),d0 ;Grab topfin->idnum sub.w d4,d0 ;i = idnum - newpos cmpi.w #8,d0 ;Need to scroll more than 8? ble.s dsgssdwn ;Nope, use slow scroll dsgdwn1: cmp.w fn_idnum(a0),d4 ;Is topfin->idnum == newpos yet? beq.s dsgredo ;Yep, we are done dsgpretop: movea.l fn_Node+MLN_PRED(a0),a0 ;topfin = topfin->fn_Node.mln_Pred tst.w fn_idnum(a0) ;Is this idnum >= 0? blt.s dsgpretop ;Nope, keep looking bra.s dsgdwn1 ;Check this new position dsgssdwn: move.l d0,-(sp) jsr _FSScrollDownGads ;Scroll entries down d5 times addq.w #4,sp bra.s dsgdone ************ * Scroll Up ************ dsgscrup: move.w d4,d5 ;Grab newpos sub.w fn_idnum(a0),d5 ;i = newpos - node->idnum cmpi.w #8,d5 ;i > 8? ble.s dsgssup ;Nope, use slow scroll dsgmvup1: cmp.w fn_idnum(a0),d4 ;Is topfin->idnum == newpos yet? beq.s dsgredo ;Yep, we are done dsgnxttop: movea.l fn_Node+MLN_SUCC(a0),a0 ;topfin = topfin->fn_Node.mln_Succ tst.w fn_idnum(a0) ;Is this a valid entry? blt.s dsgnxttop ;Nope, move on bra.s dsgmvup1 dsgredo: move.l a0,_topfin ;Set new top and bottom jsr _FSSetFileGads ;Redraw all the file entries bra.s dsgdone ;We're done dsgssup: move.l d5,-(sp) jsr _FSScrollUpGads ;Scroll the entries up d5 times addq.w #4,sp dsgdone: movem.l (sp)+,d4-d5 rts * -------------------------------------------------------------------- * VOID FSStartScrollGad(gadcode) * ULONG gadcode; * Given Gadget ID code, respond to first user click on a arrow gadget. * Reset the timer.device so that .25 seconds delay occurs before * the autorepeat kicks in. * -------------------------------------------------------------------- XDEF _FSStartScrollGad _FSStartScrollGad: move.w 6(sp),d0 ;Grab gadget code subi.w #33,d0 ;Slide gad bne.s 1$ jsr _FSDoSlideGadget clr.w _FSCountDown rts 1$ subi.w #7,d0 ;33+7=40, UpGad bne.s 2$ pea 1 11$ jsr _FSScrollFileGads addq.w #4,sp bra.s ssgdone 2$ subq.w #1,d0 ;33+7+1=41, DownGad bne.s 3$ pea 0 bra 11$ 3$ subq.w #1,d0 ;33+7+2=42, UpDev bne.s 4$ pea 1 33$ jsr _FSScrollDevGads addq.w #4,sp bra.s ssgdone 4$ subq.w #1,d0 ;33+7+3=43, DownDev bne.s ssgrts pea 0 bra 33$ ssgdone: move.w #4,_FSCountDown ssgrts: rts * ----------------------------------------------------------------------- * FSScrollFileGads(direction) * BOOL direction; * * Scroll the file entries up or down by 1 * if (direction == 0) * scrollup; * else * scrolldown; * ----------------------------------------------------------------------- XDEF _FSScrollFileGads _FSScrollFileGads: ;if (fsnumentries > 10) cmpi.w #10,_fsnumentries ;Less than 10 entries? ble.s sfgdone ;Yep, can't scroll anyhow ;if (direction) ; FSScrollDownGads(1); tst.w 6(sp) ;ScrollDown? beq.s sfgup ;Nope, scroll up pea 1 jsr _FSScrollDownGads addq.w #4,sp bra.s sfgpos sfgup: ;FSScrollUpGads(1) pea 1 jsr _FSScrollUpGads addq.w #4,sp sfgpos: * Reset the slide knob position the display movement jsr _FSSetKnobPos jsr _FSSetKnob ;Set new knob position sfgdone: rts * ------------------------------------------------------------------------- ; FSScrollUpGads(count) ; LONG count; ; ; Single-step scroll the file entries up count times. * ------------------------------------------------------------------------- XDEF _FSScrollUpGads _FSScrollUpGads: link a5,#0 movem.l d2-d7/a2/a6,-(sp) jsr _FSUpdateSort beq.s sugdone movea.l _FSRPort,a2 ;for (i = 0; i < count; i++) moveq #0,d7 bra.s sugchk1 sugloop1: * If the bottom entry is not the last entry, scroll it up movea.l _topfin,a0 ;Grab top visible node move.w fn_idnum(a0),d0 ;Grab id number addi.w #11,d0 ;Plus 11 cmp.w _fsnumentries,d0 ;Compare to last known entry bgt.s sugdone ;Yep, can't scroll up any more * Bump the top pointer down the list to the next visible entry movea.l _topfin,a0 1$ move.l fn_Node+MLN_SUCC(a0),a0 ;topfin = topfin->fn_Node.mln_Succ tst.w fn_idnum(a0) ;while (topfin->idnum < 0) blt 1$ ;Not a valid entry move.l a0,_topfin ;Here's our new top entry node * Now reassign the visible file gadget array to the new node list jsr _FSAssignNodes * Display new file entries and redraw borders ;ClipBlit(rp, 9L, 24L, rp, 9L, 13L, 447L, 96L, 0xc0L); movea.l a2,a0 moveq #9,d0 moveq #24,d1 movea.l a2,a1 moveq #9,d2 moveq #13,d3 move.l #447,d4 moveq #96,d5 move.l #$0c0,d6 SYS ClipBlit,_GfxBase ;FSEnableFGad(9); move.l #9,-(sp) jsr _FSEnableFGad ;Now draw the new gadget at bottom addq.w #4,sp addq.w #1,d7 ;Bump scroll count sugchk1: cmp.w 10(a5),d7 ;Have we scrolled enough? blt sugloop1 ;Nope, do again sugdone: movem.l (sp)+,d2-d7/a2/a6 unlk a5 rts * ------------------------------------------------------------------------- ; FSScrollDownGads(count) ; LONG count; ; ; Single-step scroll the file entries down count times. * ------------------------------------------------------------------------- XDEF _FSScrollDownGads _FSScrollDownGads: link a5,#0 movem.l d2-d7/a2/a6,-(sp) jsr _FSUpdateSort beq.s sdgdone movea.l _FSRPort,a2 ;for (i = 0; i < count; i++) moveq #0,d7 bra.s sdgchk1 sdgloop1: ;If the top entry is not the first entry, scroll it down movea.l _topfin,a0 ;Grab top node tst.w fn_idnum(a0) ;idnum == 0? beq.s sdgdone ;Yep, can't scroll down any more * Bump the top and bottom entry pointers down the list 1$ movea.l fn_Node+MLN_PRED(a0),a0 ;topfin = topfin->fn_Node.mln_Pred tst.w fn_idnum(a0) ;while (topfin->idnum < 0) blt 1$ move.l a0,_topfin ;New topfin * Now reassign the visible file gadget array to the new node list jsr _FSAssignNodes * Display new file entries and redraw borders ;ClipBlit(rp, 9L, 13L, rp, 9L, 24L, 447L, 96L, 0xc0L) movea.l a2,a0 moveq #9,d0 moveq #13,d1 movea.l a2,a1 moveq #9,d2 moveq #24,d3 move.l #447,d4 moveq #96,d5 move.l #$0c0,d6 SYS ClipBlit,_GfxBase ;FSEnableFGad(0); pea 0 jsr _FSEnableFGad ;Display the only new "gadget" addq.w #4,sp addq.w #1,d7 ;Bump scroll count sdgchk1: cmp.w 10(a5),d7 ;Have we scrolled enough? blt sdgloop1 ;Nope, do again sdgdone: movem.l (sp)+,d2-d7/a2/a6 unlk a5 rts * ------------------------------------------------------------------- * VOID FSAssignNodes(VOID) * ------------------------------------------------------------------- XDEF _FSAssignNodes _FSAssignNodes: movem.l a2-a3,-(sp) ;for (tnode = topfin, i = 0; ;tnode = tnode->next) lea _FSFileNodes,a3 ;Grab base address of array of filegadgets movea.l _topfin,a2 ;Grab our top visible filenode moveq #10,d0 ;Fill 10 gadgets max ran1: tst.l fn_Node+MLN_SUCC(a2) ;Succ == 0? beq.s ragdone ;Ran out of list entries ;if (tnode->idnum >= 0) tst.w fn_idnum(a2) ;Is this name "visible"? blt.s ragchkbot ;Nope, skip it move.l a2,(a3)+ ;FSFileNodes[i] = tnode subq.w #1,d0 ;One less slot available beq.s ragdone ;Filled all the slots, exit loop ragchkbot: movea.l fn_Node+MLN_SUCC(a2),a2 bra ran1 ;check next node ragdone: movem.l (sp)+,a2-a3 rts * ----------------------------------------------------------------------- ; VOID __stdargs FSDoFileGad(Ypos) ; LONG Ypos; ; ; Based on the mouse's Ypos passed, select file entry that user clicked. * ----------------------------------------------------------------------- XDEF _FSDoFileGad _FSDoFileGad: link a5,#0 movem.l d2-d4/a2-a3/a6,-(sp) moveq #0,d4 move.w 10(a5),d4 ;Grab gadget y position subi.w #12,d4 ;Less 12 (top edge of first entry) divu #11,d4 ; divided by 11 (height of each entry) ext.l d4 ;Blow remainder, this is our entry number move.w d4,d0 lsl.w #2,d0 ;Convert to long offset lea _FSFileNodes,a2 ;Grab base address of visible node_datas movea.l 0(a2,d0.w),a3 ;Grab FSFileNodes[gadg_num] cmpa.l #0,a3 beq dfgdone ;If zero, not a active "gadget" slot ;strncpy(FSwstr, tinfo->alphadata + 26L, tinfo->namelength) movea.l fn_info(a3),a3 ;tinfo = tnode->info lea _FSwstr,a2 ;Grab address of worktext move.w nd_namelength(a3),d0 ;Push tinfo->namelength lea nd_alphadata+26(a3),a1 ;Push tinfo->alphadata + 26 movea.l a2,a0 ;Push dest text jsr astrncpy ;strncpy(FSwstr, filename, namelength) ;if (tinfo->filetype == 1) cmpi.w #1,nd_filetype(a3) ;Did user click on a filename? bne.s dfgnotfile ;Nope, must be a dir ;if ( strcmp(FSFileInfo.Buffer, FSwstr) ) movea.l a2,a1 ;Push FSwstr movea.l _FSFileInfo,a0 ;Push address of filebuffer jsr astrcmp tst.w d0 ;Is this the same as what we already have? beq.s dfgnsname ;Yep, see if it was double-clicked ;strcpy(FSFileInfo.Buffer, FSwstr) movea.l a2,a1 movea.l _FSFileInfo,a0 jsr astrcpy ;Otherwise copy new filename to filebuffer lea _FSFileGad,a0 ;And refresh filename text gadget movea.l _FSWin,a1 suba.l a2,a2 moveq #1,d0 SYS RefreshGList,_IntuitionBase bra dfgfiledone dfgnsname: ;if ( DoubleClick(fsoldsecs, fsoldmicros, fscursecs, fscurmicros && ; (gadg_num == fsprevgadid) ) ; ConcatPathString(); btst.b #0,_fsflags+1 ;FS_NO_DCLICK_EXIT? bne dfgfiledone ;Yep, programmer doesn't allow that cmp.w _fsprevgadid,d4 ;Is it the same gadget? bne dfgfiledone ;Nope, can't be a double click move.l _fsoldsecs,d0 move.l _fsoldmicros,d1 move.l _fscursecs,d2 move.l _fscurmicros,d3 SYS DoubleClick,_IntuitionBase tst.w d0 ;Is it within click speed parameters? beq.s dfgfiledone ;Nope jsr _ConcatPathString ;Construct full path text bra.s dfgdone ;Clicked on a DIR dfgnotfile: cmpi.w #1,_fsvirgindir ;if (virgindir != 1) beq.s dfgdone ;Don't concat if we haven't locked dir yet ;i = strlen(FSPathInfo.Buffer); move.l _FSPathInfo,a0 jsr astrlen move.w d0,d2 ;Length of stuff already in path text ;if ( (strlen(FSwstr) + i) < PATHSTRSIZE) movea.l a2,a0 jsr astrlen add.w d2,d0 cmpi.w #PATHSTRSIZE-1,d0 bge.s dfgtoodeep ;Don't append path if no room! move.l a2,-(sp) move.l _FSPathInfo,-(sp) move.l _FSPathInfo,-(sp) jsr _ConcatDirFile ;ConcatDirFile(FSPathInfo->Buffer, FSPathInfo->Buffer, FSwstr) lea 12(sp),sp jsr _FSDirFunc ;Do FSReq->dirfunc, if there is one tst.w d0 ;Avoid reading this dir? beq.s 1$ ;Nope, process it move.l _FSPathInfo,a0 clr.b 0(a0,d2.w) ;Else FSPathInfo->Buffer[oldstrlen] = 0 bra.s dfgdone 1$ move.w #1,_fsvirgindir ;virgindir = 1, read the new directory bra.s dfgdone dfgtoodeep: move.w #12,_fstitstatus ;fstitstatus = 12 jsr _FSWinTitle suba.l a0,a0 SYS DisplayBeep,_IntuitionBase bra.s dfgdone dfgfiledone: jsr _FSFileFunc ;Call FSReq->filefunc, if there is one dfgdone: move.w d4,_fsprevgadid ;fsprevgadid = gadg_num movem.l (sp)+,d2-d4/a2-a3/a6 unlk a5 rts * --------------------------------------------------------------------- * * LONG FSDirFunc(VOID); * If there is a fsrequest->dirfunc, this routine handles the interface. * --------------------------------------------------------------------- * XDEF _FSDirFunc _FSDirFunc: move.l d2,-(sp) moveq #0,d0 movea.l _FSReq,a0 ;Grab our FSRequest struct move.l fs_dirfunc(a0),d2 ;Is there a user dir function to call? beq.s 1$ ;Nope, that's all we have to do this click! jsr _ConcatPathString ;Combine dir/file as fullname for return clr.w _FSDone ;Not done though, undo return status move.l _FSWin,-(sp) move.l _FSReq,-(sp) movea.l d2,a0 jsr (a0) ;d0 = (FSReq->dirfunc)(FSReq, FSWin) addq.w #8,sp 1$ move.l (sp)+,d2 rts * --------------------------------------------------------------------- * * VOID FSFileFunc(VOID); * If there is a fsrequest->filefunc, this routine handles the interface. * --------------------------------------------------------------------- * XDEF _FSFileFunc _FSFileFunc: move.l d2,-(sp) movea.l _FSReq,a0 ;Grab our FSRequest struct move.l fs_filefunc(a0),d2 ;Is there a user file function to call? beq.s 1$ ;Nope, that's all we have to do this click! jsr _ConcatPathString ;Combine dir/file as fullname for return clr.w _FSDone ;Not done though, undo return status move.l _FSWin,-(sp) move.l _FSReq,-(sp) movea.l d2,a0 jsr (a0) ;d0 = (FSReq->filefunc)(FSReq, FSWin) addq.w #8,sp tst.l d0 ;Return 0? beq.s 1$ ;Yep move.w #1,_fsvirgindir ;Else re-read directory 1$ move.l (sp)+,d2 rts * ----------------------------------------------------------------------- * VOID FSSetFileGads(VOID) * Assign and render currently active file texts, disable remainder * ----------------------------------------------------------------------- XDEF _FSSetFileGads _FSSetFileGads: movem.l d4-d5,-(sp) move.w _fsnumentries,d5 ;Grab number of entries beq.s 3$ ;No entries, nothing to set! * Update visible list based on topfin point in linked list jsr _FSAssignNodes * Show all used gadgets moveq #0,d4 ;i = 0 bra.s 2$ 1$ move.l d4,-(sp) jsr _FSEnableFGad addq.w #4,sp addq.w #1,d4 ;Bump gadget count 2$ cmpi.w #10,d4 ;Hit highest gadget? bcc.s 3$ ;Yep, done cmp.w d5,d4 ;Else, Hit last gadget? bcs 1$ ;Nope enable another 3$ movem.l (sp)+,d4-d5 rts * ------------------------------------------------------------------------ * SetRootDir() * Chop off all subdirectory names contained in FSPathInfo, moving up to * root name if possible. Flag to read new directory in any case. * ------------------------------------------------------------------------ XDEF _SetRootDir _SetRootDir: ;if ( (tstr = strchr(FSPathInfo.Buffer, ':')) != 0L) moveq #':',d0 movea.l _FSPathInfo,a0 jsr aindex tst.l d0 beq.s 1$ ;Nope clr.b 1(a0) ;Otherwise clobber the char after ':' move.w #1,_fsvirgindir ;virgindir = 1, read directory 1$ rts * ------------------------------------------------------------------------ ; SetParentDir() ; Chop off last directory name contained in FSPathInfo, moving up one level ; if possible. * ------------------------------------------------------------------------ XDEF _SetParentDir _SetParentDir: movem.l a2-a3,-(sp) ;if (FSPathInfo.Buffer[0]) movea.l _FSPathInfo,a3 ;Grab pointer to path text tst.b (a3) ;Is it of zero length? beq.s spddone ;Yep, at root already ;tstr = rindex(FSPathInfo.Buffer, '/') moveq #'/',d0 movea.l a3,a0 jsr arindex tst.l d0 ;Grab index to last occurance of slash bne.s spdnotsub ;If we got one that is ; if ( tstr = rindex(FSPathInfo.Buffer, ':') ) ; tstr++; moveq #':',d0 movea.l a3,a0 jsr arindex ;Grab index to last occurance of colon tst.l d0 beq.s spdnotroot ;Oops, no colon either, at top of path? addq.w #1,a0 ;Move past the ':' bra.s spdnotsub ;Terminate the text ;else spdnotroot: movea.l a3,a0 ;tstr = (BYTE *)FSPathInfo.Buffer spdnotsub: clr.b (a0) ;*tstr = '\x0' move.w #1,_fsvirgindir ;virgindir = 1, read the new directory spddone: movem.l (sp)+,a2-a3 rts * ----------------------------------------------------------------- ;HCompGad(rp, g2) ; struct RastPort *rp; ; struct Gadget *g2; ; ; Given a rastport and a gadget pointer, highlight or de-highlight ; a gadget using RectFill in COMPLEMENT mode. * ----------------------------------------------------------------- hrp EQU 16 hgad EQU 20 XDEF _HCompGad _HCompGad: movem.l d2-d3/a6,-(sp) movea.l hrp(sp),a1 moveq #2,d0 SYS SetDrMd,_GfxBase ;SetDrMd(rp, COMPLEMENT) movea.l hgad(sp),a0 ;Grab gadget pointer moveq #0,d0 move.w 4(a0),d0 ;x0 = (ULONG)g2->LeftEdge move.l d0,d2 add.w 8(a0),d2 subq.w #1,d2 ;x1 = x0 + g2->Width - 1L moveq #0,d1 move.w 6(a0),d1 ;y0 = (ULONG)g2->TopEdge move.l d1,d3 add.w 10(a0),d3 subq.w #1,d3 ;y1 = y0 + g2->Height - 1L movea.l hrp(sp),a1 SYS RectFill ;RectFill(rp, x0, y0, x1, y1) movea.l hrp(sp),a1 moveq #1,d0 SYS SetDrMd ;SetDrMd(rp, JAM2) movem.l (sp)+,d2-d3/a6 rts * ----------------------------------------------------------------- ;HCompEntry(num) ; LONG num; ; ; Highlight or de-highlight a slot in the filename area, given its ; entry number * ----------------------------------------------------------------- XDEF _HCompEntry _HCompEntry: movem.l d2-d3/a2/a6,-(sp) movea.l _FSRPort,a2 ;Grab window movea.l a2,a1 moveq #2,d0 SYS SetDrMd,_GfxBase ;SetDrMd(rp, COMPLEMENT) moveq #5,d0 ;x0 = (ULONG)g2->LeftEdge move.l #460,d2 ;x1 = x0 + g2->Width - 1L move.w 16+4+2(sp),d1 mulu #11,d1 add.w #12,d1 ;y0 = (ULONG)g2->TopEdge move.l d1,d3 add.w #9,d3 ;y1 = y0 + g2->Height - 1L movea.l a2,a1 SYS RectFill ;RectFill(rp, x0, y0, x1, y1) movea.l a2,a1 moveq #1,d0 SYS SetDrMd ;SetDrMd(rp, JAM2) movem.l (sp)+,d2-d3/a2/a6 rts * --------------------------------------------------------------------- * * VOID FSDoSortGadget(type) * LONG type; * --------------------------------------------------------------------- * dosgtype EQU 4+4*3 XDEF _FSDoSortGadget _FSDoSortGadget: movem.l d2/a2/a6,-(sp) movea.l _FSReq,a0 moveq #0,d0 move.w fs_sorttype(a0),d0 cmp.w dosgtype+2(sp),d0 beq dosgsame * Unhighlight previous setting tst.w d0 ;Alphabetize? bne.s 1$ lea _AlphaGad,a0 bra.s 3$ 1$ subq.w #1,d0 ;FileSize? bne.s 2$ lea _SizeGad,a0 bra.s 3$ 2$ subq.w #1,d0 ;Time? bne.s 4$ ;Nope, nosort previously lea _TimeGad,a0 3$ bclr.b #7,gg_Flags+1(a0) ;gad->Flags &= ~SELECTED movea.l _FSWin,a1 suba.l a2,a2 moveq #1,d0 SYS RefreshGList,_IntuitionBase ;RefreshGList(gad, FSWin, 0L, 1) 4$ * Set new sort type movea.l _FSReq,a0 move.l dosgtype(sp),d1 move.w d1,fs_sorttype(a0) movea.l _fnList,a0 movea.l MLH_HEAD(a0),a0 tst.l fn_Node+MLN_SUCC(a0) beq.s dosgdone ;No list, don't bother sorting tst.l _topfin ;Grab current topfin beq.s 5$ ;No currently visible files clr.w _fsneedshow ;fsneedshow = 0, needs sorting bra.s 6$ 5$ move.w #-1,_fsneedshow ;No topfin, fsneedshow = -1 6$ dossort: * Sort the list using the new sort type move.l d1,-(sp) jsr _SortNodes ;SortNodes(type) addq.w #4,sp jsr _FSUpdateSort jsr _FSWinTitle ;Reset title to previous bra.s dosgdone dosgsame: move.w #-1,fs_sorttype(a0) dosgdone: movem.l (sp)+,d2/a2/a6 rts * ----------------------------------------------------------------------- ; SortNodes(key) ; LONG key; ; Selection sort list of filenames using one of three key types * ----------------------------------------------------------------------- XDEF _SortNodes _SortNodes: movem.l d4/a2-a3/a6,-(sp) IFD BENCHMARK jsr _StartTime ENDC move.l 4+4*4(sp),d4 ;Grab our key type blt snsortdone ;No sort wanted cmpi.w #1,_fsnumentries ;More than one entry? ble snsortdone ;Nope, don't bother sorting move.w _fstitstatus,-(sp) ;Save old titstatus move.w #28,_fstitstatus jsr _FSWinTitle ;FSWinTitle("Sorting...") move.w (sp)+,_fstitstatus ;Restore previous titlemsg * Convert Exec list to a simple head->next->NULL type movea.l _fnList,a3 ;Grab old list movea.l MLH_TAILPRED(a3),a1 ;a0 = last entry in list movea.l MLH_HEAD(a3),a0 clr.l fn_Node+MLN_SUCC(a1) ;Zap last nodes next field NEWLIST a3 ;New the old list move.l d4,d0 ;d0 = sorttype, a0 = headnode jsr _FSListSort ;list_sort(headnode, key) (a0/d0) movea.l d0,a1 ;Grab new head of sorted list * Now add the new nodes back into the list movea.l 4,a6 ;Execbase calls 1$ cmpa.l #0,a1 ;Grab next node in new list beq.s 2$ ;End of list movea.l fn_Node+MLN_SUCC(a1),a2 ;node = node->fn_Node.mln_Succ movea.l a3,a0 SYS AddTail ;AddTail(fnList, newnode) movea.l a2,a1 ;a2 = next node bra 1$ ;Add the next node 2$ snsortdone: IFD BENCHMARK pea _timermsg1 jsr _StopTime addq.w #4,sp ENDC movem.l (sp)+,d4/a2-a3/a6 rts * -------------------------------------------------------------------- * struct file_node *FSListSort (list, type) * struct file_node *list; * long type; * * Assumes a list of structures, with a pointer to "next" as the first * field. It reorders the list into ascending order, and returns the * new first node's address. It is order N log(N). * * The compare routine should return 0 if the items are in order, and 1 * if they are not. If the compare routine returns 0 in case of * equality, the sort will be stable. * * This routine depends upon compiler-dependant struct layout, but this * assumption is likely to be fairly commonly valid. * * The basic notion of this sort is to make sorted sublists longer and * longer by merging. On the Nth pass through the list, sorted * sublists of length 2^(N-1) are produced. Eventually, the entire * list is sorted, in log2(N)+1 passes through the list. There is * extra bookkeeping overhead, but minimal extra storage space needed. * Counts and clever pointer management substitute for extra "glue" * nodes. * * while more than one list * while not at end of composite lists * for each merge_length(m) block * merge first items in lists onto current output list * toggle current output list * * Register parameters: * struct file_node *FSListSort __ARGS((struct file_node *, LONG)); * d0 a0 d0 * --------------------------------------------------------------------- * flsold1 equ -4 flsold0 equ -8 flsnew1 equ -12 flsnew0 equ -16 flscnt1 equ -20 flscnt0 equ -24 flsffn1 equ flscnt0-16 flsffn0 equ flsffn1-16 flssend equ flsffn0-4 * --------------------------------------------------------------------- * XDEF _FSListSort _FSListSort: link a5,#flssend movem.l d2-d7/a2-a3,-(sp) move.l d0,d3 ;d3 = sorttype clr.l flsffn0+LN_SUCC(a5) ;front[0].next = 0 move.l a0,flsffn1+LN_SUCC(a5) ;front[0].next = list moveq #1,d7 ;m = 1 moveq #0,d6 ;hm = 0 flsLoop1: tst.l flsffn1+LN_SUCC(a5) ;while (front[1].next) beq flsdone lea flsffn0(a5),a0 move.l a0,flsnew0(a5) ;new[0] = &front[0] lea flsffn1(a5),a0 move.l a0,flsnew1(a5) ;new[1] = &front[1] move.l flsffn0+LN_SUCC(a5),flsold0(a5) ;old[0] = front[0].next move.l flsffn1+LN_SUCC(a5),flsold1(a5) ;old[1] = front[1].next clr.l flscnt0(a5) ;count[0] = 0 clr.l flscnt1(a5) ;count[1] = 0 moveq #0,d4 ;n = 0 moveq #0,d5 ;items_merged = 0 flsLoop2: tst.l flsold0(a5) ;old[0]? bne.s 1$ ;Yep, get an item from this list tst.l flsold1(a5) ;old[1]? beq flsNext2 ;Nope, both lists exhausted 1$ cmp.l d7,d5 ;if (items_merged >= m) bcs.s 2$ ;Nope, m > items_merged moveq #0,d5 ;items_merged = 0 bchg.l #0,d4 ;n = 1 - n clr.l flscnt0(a5) ;count[0] = 0 clr.l flscnt1(a5) ;count[1] = 0 2$ tst.l flsold0(a5) ;old[0]? beq.s 3$ tst.l flsold1(a5) ;old[1]? beq.s 3$ cmp.l flscnt0(a5),d6 ;count[0] < hm? bls.s 3$ ;Nope, hm >= count[0] cmp.l flscnt1(a5),d6 ;count[1] < hm? bls.s 3$ ;Nope movea.l flsold1(a5),a1 movea.l fn_info(a1),a1 movea.l flsold0(a5),a0 movea.l fn_info(a0),a0 move.l d3,d0 jsr _CompareNodes ;CompareNodes(type, old[0]->info, old[1]->info) lsl.w #2,d0 ;d0 = result of compare (0 or 1) move.w d4,d1 lsl.w #2,d1 ;d1 = n<<2 movea.l flsnew0(a5,d1.w),a1 ;a1 = new[n] movea.l flsold0(a5,d0.w),a0 ;a0 = old[o] move.l a0,LN_SUCC(a1) ;new[n]->next = old[o] move.l LN_SUCC(a0),flsold0(a5,d0.w) ;old[o] = old[o]->next addq.l #1,flscnt0(a5,d0.w) ;count[o]++ bra.s flsNext1 3$ flselse1: tst.l flsold0(a5) ;old[0]? beq.s 2$ ;Nope, use old[1] cmp.l flscnt0(a5),d6 ;count[0] < hm? bls.s 2$ ;Nope, count[0] >= hm, use old[1] 1$ lea flsold0(a5),a0 ;else a0 = &old[0] bra.s 3$ 2$ lea flsold1(a5),a0 ;a0 = &old[1] 3$ move.w d4,d1 lsl.w #2,d1 movea.l flsnew0(a5,d1.w),a1 ;a1 = new[n] move.l (a0),LN_SUCC(a1) ;new[n]->next = old[o] movea.l (a0),a1 move.l LN_SUCC(a1),(a0) ;old[o] = old[o]->next flsNext1: move.w d4,d0 lsl.w #2,d0 movea.l flsnew0(a5,d0.w),a0 ;a0 = new[n] move.l LN_SUCC(a0),flsnew0(a5,d0.w) ;new[n] = new[n]->next addq.l #1,d5 ;items_merged++ bra flsLoop2 flsNext2: movea.l flsnew0(a5),a0 clr.l LN_SUCC(a0) ;new[0]->next = 0 movea.l flsnew1(a5),a0 clr.l LN_SUCC(a0) ;new[1]->next = 0 move.l d7,d6 ;hm = m lsl.l #1,d7 ;m *= 2 bra flsLoop1 flsdone: move.l flsffn0+LN_SUCC(a5),d0 ;return(front[0].next) movem.l (sp)+,d2-d7/a2-a3 unlk a5 rts * ------------------------------------------------------------------------- ; d0 = WORD CompareNodes(d0, a0, a1) ; WORD key = d0; ; struct node_data *a = a0, *b = a1; ; ; Compare data in two nodes, based upon key type. Return boolean result ; of the comparison in d0. Note that this is a register based function. * ------------------------------------------------------------------------- XDEF _CompareNodes _CompareNodes: move.w nd_filetype(a0),d1 cmp.w nd_filetype(a1),d1 ;Comparing same type of entries? beq.s 3$ ;Yep, use sort for compare btst.b #3,_fsflags+1 ;Want files first? bne.s 2$ ;Yep btst.b #4,_fsflags+1 ;Want dirs first? beq.s 3$ ;Don't care, see if there is a sort cmp.w nd_filetype(a1),d1 ;Recompare bcs.s cnmatch ;a0->filetype = 2, a1->filetype = 1 bra.s cnnomatch ;a0->filetype = 1, a1->filetype = 2 2$ cmp.w nd_filetype(a1),d1 ;Recompare bhi.s cnmatch ;a0->filetype = 2, a1->filetype = 1 bra.s cnnomatch ;a0->filetype = 1, a1->filetype = 2 3$ tst.w d0 blt.s cnmatch ;No sort, append to end bne.s cnnotalpha ;Not zero, not alphabetize cnnalpha: pea nd_alphadata+26(a1) pea nd_alphadata+26(a0) jsr _lstrcmp ;return(lstrcmp(a->alphadata + 26L, b->alphadata + 26L) > 0) addq.w #8,sp tst.w d0 ble.s cnnomatch bra.s cnmatch cnnotalpha: cmpi.w #1,d0 ;Sort by size? bne.s cnnotsize ;Nope, must be by date move.l nd_filesize(a0),d0 cmp.l nd_filesize(a1),d0 ;return(a->filesize > b->filesize) beq cnnalpha ;Same size, sort alpha bcs.s cnnomatch ;a1 > a0 bra.s cnmatch cnnotsize: move.l nd_days(a0),d0 cmp.l nd_days(a1),d0 ;if (a->days > b->days) beq.s cntstmins ;Nope, a->days == b->days, check minutes bls.s cnnomatch ;Nope, a->days < b->days bra.s cnmatch cntstmins: ;t1 = (a->minutes - b->minutes) * 3000L + (a->ticks - b->ticks) move.l nd_minutes(a0),d0 sub.l nd_minutes(a1),d0 muls #3000,d0 move.l nd_ticks(a0),d1 sub.l nd_ticks(a1),d1 add.l d1,d0 tst.l d0 ;return(t1 > 0L); beq cnnalpha ;Same date, sort alpha bgt.s cnmatch cnnomatch: moveq #0,d0 bra.s cndone cnmatch: moveq #1,d0 cndone: rts * ---------------------------- lstrcmp ------------------------------- * LONG lstrcmp(astr, bstr) * BYTE *astr, *bstr; * * Compare two texts for lexigraphic order, ignoring case differences *--------------------------------------------------------------------- XDEF _lstrcmp _lstrcmp: movem.l 4(sp),a0/a1 ;Grab astr, bstr ;for(;*a && tolower(*a) == tolower(*b); a++, b++) lccstart: move.b (a0)+,d0 ;Grab a char from astr cmpi.b #$40,d0 ;less than @ character? bls.s 1$ ;Yep cmpi.b #$5a,d0 ;Greater than Z? bhi.s 1$ ;Yep addi.b #$20,d0 1$ move.b (a1)+,d1 ;Grab a char from bstr cmpi.b #$40,d1 ;less than @ character? bls.s 2$ ;Yep cmpi.b #$5a,d1 ;Greater than Z? bhi.s 2$ ;Yep addi.b #$20,d1 2$ tst.b d0 ;End of astr? beq.s 3$ cmp.b d1,d0 ;Are they the same character? beq lccstart ;Yep, compare next pair of chars 3$ sub.b d1,d0 ;return(tolower(*astr) - tolower(*bstr)) ext.w d0 ext.l d0 rts *---------------------------------------------------------------------- * Search a text for wild characters, return 1 if found *---------------------------------------------------------------------- XDEF _iswild _iswild: movea.l 4(sp),a0 ;Grab text pointer moveq #0,d0 ;Clear out our character register ischk1: move.b (a0)+,d0 ;Grab a char beq.s iswdone ;Might be end of text? cmpi.b #'*',d0 ;Is it *? beq.s iswdone ;yep, is wild cmpi.b #'?',d0 ;Is it a qmark bne ischk1 ;Nope, check next character rts ;Otherwise it is wild iswdone: rts * ------------------------------------------------------------------------ ; Compare a wild card name with a normal name ; WORD wildmatch (name, wild) ; BYTE *name, *wild; * ------------------------------------------------------------------------ XDEF _wildmatch _wildmatch: link a5,#-64 movem.l d3/a2-a3,-(sp) movem.l 8(a5),a2-a3 ;Grab name/pattern lea -64(a5),a0 ;back[0][0] lea -60(a5),a1 ;back[0][1] moveq #0,d3 ;bi = 0 wmloop1: tst.b (a2) ;End of name? bne.s wmnoteon tst.b (a3) ;End of pattern? beq wmmatched ;Yep, we matched wmnoteon: cmpi.b #'*',(a3) ;Is it a splat? bne.s wmnotstar ;Nope, maybe '?' cmpi.w #64,d3 ;Have we hit max expression depth? beq wmnomatch ;Yep, ran out of room in recursion table ;back[bi][0] = w move.l a3,0(a0,d3.w) ;Stash pointer to this '*' in table ;back[bi][1] = n move.l a2,0(a1,d3.w) addq.w #8,d3 ;++bi addq.w #1,a3 ;++w bra wmloop1 ;Check next wmgoback: subq.w #8,d3 ;--bi move.l a0,d0 wmback1: tst.w d3 ;while (bi >= 0 && *back[bi][1] == '\x0') blt.s wmbacked movea.l 0(a1,d3.l),a0 tst.b (a0) bne.s wmbacked subq.w #8,d3 ;--bi bra wmback1 wmbacked: tst.w d3 ;if (bi < 0) blt.s wmnomatch ;return (0) movea.l d0,a0 movea.l 0(a0,d3.w),a3 ;w = back[bi][0] + 1 addq.w #1,a3 addq.l #1,0(a1,d3.w) movea.l 0(a1,d3.l),a2 ;n = ++back[bi][1] addq.w #8,d3 ;++bi bra wmloop1 wmnotstar: cmpi.b #'?',(a3) ;Is it '?' bne.s wmnotqmark tst.b (a2) ;Reached end of text? bne.s wmincpoint ;Nope, move on to next char tst.w d3 ;Are we at top level of expression? beq.s wmnomatch ;Yep, expression didn't match bra wmgoback ;Otherwise pop a level and try to match wmnotqmark: move.b (a2),d0 ;Grab a char from bstr cmpi.b #$40,d0 ;less than @ character? bls.s 1$ ;Yep cmpi.b #$5a,d0 ;Greater than Z? bhi.s 1$ ;Yep addi.b #$20,d0 1$ move.b (a3),d1 ;Grab a char from bstr cmpi.b #$40,d1 ;less than @ character? bls.s 2$ ;Yep cmpi.b #$5a,d1 ;Greater than Z? bhi.s 2$ ;Yep addi.b #$20,d1 2$ cmp.b d0,d1 ;*n = *w? beq.s wmincpoint ;Yep, move on past tst.w d3 ;Are we at top expression level? beq.s wmnomatch ;Yep, they didn't match bra wmgoback ;Nope, process next part wmincpoint: tst.b (a2) ;Done with name? beq.s wmnamend ;Yep addq.w #1,a2 ;Otherwise increment name pointer wmnamend: tst.b (a3) ;End of pattern? beq.s wmmatched ;Yep, we matched addq.w #1,a3 ;Otherwise inc wild pointer, match next char bra wmloop1 wmmatched: moveq #1,d0 bra.s wmdone wmnomatch: moveq #0,d0 wmdone: movem.l (sp)+,d3/a2-a3 unlk a5 rts * --------------------------------------------------------------------- * * LONG MakePathString(lock, dest) * a0 a1 * struct FileLock *lock; * BYTE *dest; * * DESCRIPTION: * Given text and a filelock, construct entire pathname and * return in dest. * --------------------------------------------------------------------- * XDEF _MakePathString _MakePathString: link a5,#0 movem.l d2-d5/d7/a2-a3/a6,-(sp) * Grab pointer to lock and dest text to fill move.l 8(a5),d3 ;d3 = lock movea.l 12(a5),a2 ;a2 = dest clr.b (a2) ;NULL terminate dest moveq #0,d5 ;LockFlag = 0 * Allocate a FileInfoBlock for local use moveq #0,d1 move.l #fib_SIZEOF,d0 SYS AllocMem,4 ;AllocMem(sizeof(fib), 0L) move.l d0,d7 ;d7 = *fib beq mpsfailed ;Whoops no mem? return! movea.l _DOSBase(a4),a6 ;DOSBase calls from here on * while (lock != 0) 1$ tst.l d3 ;Got a lock? beq.s mpsokay ;Nope, must be at root * Examine the current lock move.l d3,d1 move.l d7,d2 SYS Examine ;Examine(lock, fib) tst.l d0 ;Okay? beq.s mpsfailed ;Nope, some sort of dos failure? movea.l d7,a1 cmpi.b #' ',fib_FileName(a1) ;if (fib->fib_FileName[0] >= ' ') bcs.s 3$ ;Nope, don't bother inserting? tst.b (a2) ;if (dest[0] != 0) beq.s 2$ lea _SlashStr(a4),a1 movea.l a2,a0 jsr _InsertPathString ;InsertPathString(dest, "/"); 2$ movea.l d7,a1 lea fib_FileName(a1),a1 movea.l a2,a0 jsr _InsertPathString ;InsertPathString(dest, fib->fib_FileName) 3$ * Okay, move up one directory move.l d3,d4 ;oldlock = lock move.l d3,d1 SYS ParentDir move.l d0,d3 ;lock = ParentDir(lock) tst.w d5 ;LockFlag set? bne.s 4$ ;Yep, unlock moveq #1,d5 ;Else LockFlag = 1, unlock next time bra 1$ ;Next directory up 4$ move.l d4,d1 SYS UnLock ;UnLock(oldlock) bra 1$ ;Examine mpsokay: * See if root was RAM:, special case movea.l d7,a1 ;a1 = fib cmpi.b #' ',fib_FileName(a1) ;if (fib->fib_FileName[0] >= ' ') bcc.s 1$ ;Yep, not 1.1/1.2 RAM: lea _RamDirNameStr(a4),a1 ;Else... movea.l a2,a0 jsr _InsertPathString ;InsertPathString(dest, "RAM:") bra.s mpsdone 1$ * Find last slash we tacked on, change to a colon, or, add a colon moveq #'/',d0 movea.l a2,a0 jsr aindex ;d0 = strchr(dest, '/') tst.l d0 ;Do we have a slash? beq.s 2$ ;Nope, at root.... movea.l d0,a0 move.b #':',(a0) ;Else change first '/' to a ':' bra.s mpsdone * No slash, must be locked at the root. Append a colon to the dest. 2$ lea _ColonStr(a4),a1 movea.l a2,a0 jsr astrcat ;strcat (dest, ":") bra.s mpsdone * Come here if an error occured, return empty text to caller mpsfailed: clr.b (a2) ;dest[0] = (BYTE)0 moveq #0,d3 ;return (0L) bra.s mpsdeall * Come here if everything is okay, deallocate FileInfoBlock mpsdone: moveq #1,d3 ;return (1L) mpsdeall: tst.l d7 ;Did we allocate a fib? beq.s mpsfinis ;nope movea.l d7,a1 ;Else free the memory move.l #fib_SIZEOF,d0 SYS FreeMem ;FreeMem(fib, sizeof(fib)) mpsfinis: move.l d3,d0 ;Put return value in d0 movem.l (sp)+,d2-d5/d7/a2-a3/a6 unlk a5 rts * --------------------------------------------------------------------- * * VOID InsertPathString(dest, source) * a0 a1 * BYTE *dest, *source; * * DESCRIPTION: * Insert source text into dest text. * Special case for source length == 0, source must be RAM. * --------------------------------------------------------------------- * XDEF _InsertPathString _InsertPathString: movem.l d7/a2-a3,-(sp) movea.l a1,a3 ;a3 = source move.l a0,a2 ;a2 = dest movea.l a3,a0 jsr astrlen move.l d0,d7 ;d7 = strlen(source) 1$ movea.l a2,a0 jsr astrlen ;d0 = strlen(dest) addq.w #1,d0 ;Bump the length to include zero byte at end movea.l a2,a1 adda.w d7,a1 ;Push dest + slen movea.l a2,a0 ;Push dest jsr amovmem ;amovmem(dest, dest + slen, strlen(dest) + 1) move.w d7,d0 movea.l a2,a1 movea.l a3,a0 jsr amovmem ;amovmem(source, dest, slen) movem.l (sp)+,d7/a2-a3 rts * --------------------------------------------------------------------- * * BYTE *myrindex(text, searchchar) * BYTE *text; * LONG searchchar; * * C stack version of arindex. * --------------------------------------------------------------------- * XDEF _myrindex _myrindex: movea.l 4(sp),a0 move.l 8(sp),d0 * --------------------------------------------------------------------- * * BYTE *aindex(BYTE *, BYTE); * --------------------------------------------------------------------- * XDEF aindex aindex: 1$ cmp.b (a0),d0 beq.s aifound tst.b (a0)+ beq.s ainomatch bra 1$ ainomatch: moveq #0,d0 rts aifound: move.l a0,d0 rts * --------------------------------------------------------------------- * * BYTE *arindex(BYTE *, BYTE); * --------------------------------------------------------------------- * XDEF arindex arindex: move.l a0,d1 ;Copy start of string for compares 1$ tst.b (a0)+ ;Find end of text bne 1$ 2$ cmp.b -(a0),d0 ;Now work backward comparing along the way beq.s rifound ;..Until we find a match cmpa.l d1,a0 ;...or hit the beginning of the text bgt 2$ rinomatch: moveq #0,d0 rts rifound: move.l a0,d0 rts * ------------------------------------------------------------------------- * * d0 a0 * LONG astrlen(text) * BYTE *text; * * Synopsis: Calculate length of null-byte terminated text. * a0 returns pointing to null char at end of text * d0 returns number of bytes in the text * ------------------------------------------------------------------------- * XDEF astrlen astrlen: move.l a0,d0 ;Save initial address 1$ tst.b (a0)+ ;Test a byte for zero-ness bne 1$ suba.l d0,a0 ;Minus initial address subq.w #1,a0 ;Less one for overshoot exg d0,a0 ;swap em rts * ------------------------------------------------------------------------- * * astrcat() * Takes text in a0, appends text in a1 * a0 returns pointing to null at end of final text * ------------------------------------------------------------------------- * XDEF astrcat astrcat: * Find end of first text 1$ tst.b (a0)+ bne 1$ subq.w #1,a0 ;Back up to null char * Append second text 2$ move.b (a1)+,(a0)+ bne 2$ subq.w #1,a0 ;a0 = the null at end of final text rts * ------------------------------------------------------------------------- * * astrcpy() * Takes text in a0, copies text in a1 * a0 returns pointing to null at end of final text * ------------------------------------------------------------------------- * XDEF astrcpy astrcpy: * Copy second text 1$ move.b (a1)+,(a0)+ bne 1$ subq.w #1,a0 ;Back up to null rts * ------------------------------------------------------------------------- * * astrcmp() * Takes text in a0, compares to text in a1 * a0 returns pointing to first difference, d0 contains the difference * or zero if the two texts are identical * ------------------------------------------------------------------------- * XDEF astrcmp astrcmp: 1$ move.b (a0)+,d0 ;Grab a char from A move.b (a1)+,d1 ;Grab a char from B tst.b d0 ;Hit end of A? beq.s 2$ ;Yep, diff em cmp.b d1,d0 ;Else the same char? beq 1$ ;Compare next pair 2$ sub.b d1,d0 ;A - B ext.w d0 ext.l d0 rts * ----------------------------------------------------------------------- * safestrcpy(dest, source, length) * Copies at most length chars of source to dest, if source < length * don't pad with nulls like strncpy. Always null terminates dest. * ----------------------------------------------------------------------- XDEF _safestrcpy _safestrcpy: movem.l 4(sp),a0/a1 ;Grab dest and source pointers move.w 14(sp),d0 ;Grab count * ------------------------------------------------------------------------- * * astrncpy() * Takes text in a1, copies d0 bytes to text in a0. * a0 returns pointing to null at end of final text. * Dest text is always null terminated. * ------------------------------------------------------------------------- * XDEF astrncpy astrncpy: 1$ move.b (a1)+,(a0)+ 2$ dbeq d0,1$ subq.w #1,a0 clr.b (a0) ;Null terminate dest move.l a0,d0 rts * ------------------------------------------------------------------------- * * amovmem() * Takes text in a0, copies d0 bytes to text in a1. Correctly handles * overlapping memory. * ------------------------------------------------------------------------- * XDEF amovmem amovmem: cmpa.l a0,a1 ;Low to high or high to low? bcs.s 2$ ;High to low, copy forward adda.w d0,a0 ;Else start at end, copy backward adda.w d0,a1 1$ move.b -(a0),-(a1) subq.w #1,d0 bgt 1$ bra.s amdone 2$ move.b (a0)+,(a1)+ subq.w #1,d0 bgt 2$ amdone: rts * --------------------------------------------------------------------- * * END OF SOURCE * --------------------------------------------------------------------- * END