home *** CD-ROM | disk | FTP | other *** search
/ 17 Bit Software 1: Collection A / 17Bit_Collection_A.iso / files / 1024.dms / 1024.adf / TextPlus / SrcE.lzh / SrcE / fs2.asm < prev    next >
Assembly Source File  |  1990-08-06  |  85KB  |  3,356 lines

  1. * ------------------------------------------------------------------------- *
  2. * FS2.ASM -- Assembly support routines for PathMaster(tm) File Selector
  3. * Copyright © 1987-1989 by Justin V. McCormick.  All Rights Reserved.
  4. * ------------------------------------------------------------------------- *
  5.  
  6. ;BENCHMARK    EQU    1
  7.  
  8.     include "exec/types.i"
  9.     include "exec/nodes.i"
  10.     include "exec/lists.i"
  11.  
  12. SYS    MACRO    *
  13.     IFGT    NARG-2
  14.     FAIL    !!!
  15.     ENDC
  16.     IFEQ    NARG-2
  17.     MOVE.L    \2,a6
  18.     ENDC
  19.     JSR    _LVO\1(a6)
  20.     ENDM
  21.  
  22. XLVO    MACRO    *
  23.     XREF    _LVO\1
  24.     ENDM
  25.  
  26.  
  27. * These three equate control the size of the path, file, and pattern string limits
  28. PATHSTRSIZE    EQU    300
  29. FILESTRSIZE    EQU    32
  30. MATCHSTRSIZE    EQU    32
  31.  
  32. AUTOKNOB    EQU    $1
  33. FREEVERT    EQU    $4
  34. PROPBORDERLESS    EQU    $8
  35. MEMF_CLEAR     EQU    $10000
  36. WINDOWSIZING    EQU    $1
  37. WINDOWDRAG    EQU    $2
  38. WINDOWDEPTH    EQU    $4
  39. WINDOWCLOSE    EQU    $8
  40. WINDOWTGADS    EQU    WINDOWDRAG!WINDOWDEPTH!WINDOWCLOSE
  41. FPEN        EQU    1
  42. DPEN        EQU    3
  43.  
  44. fib_DirEntryType EQU    $4
  45. fib_FileName    EQU    $8
  46. fib_Size    EQU    $7C
  47. fib_DateStamp    EQU    $84
  48. fib_SIZEOF    EQU    $104
  49.  
  50. gg_Flags    EQU    $C
  51. id_SIZEOF    EQU    $24
  52. it_FrontPen    EQU    $0
  53. it_IText    EQU    $C
  54. rp_AreaPtrn    EQU    $8
  55. rp_AreaPtSz    EQU    $1D
  56. wd_Flags    EQU    $18
  57. wd_RPort    EQU    $32
  58.  
  59.     STRUCTURE FSRequest,0
  60.     STRUCT    fs_dirname,PATHSTRSIZE
  61.     STRUCT    fs_filename,FILESTRSIZE
  62.     STRUCT    fs_matchpattern,MATCHSTRSIZE
  63.     WORD    fs_leftedge
  64.     WORD    fs_topedge
  65.     WORD    fs_sorttype
  66.     UWORD    fs_flags
  67.     ULONG    fs_windowflags
  68.     APTR    fs_fullname
  69.     APTR    fs_ignorepattern
  70.     APTR    fs_pathgadstr
  71.     APTR    fs_filegadstr
  72.     APTR    fs_titlestr
  73.     APTR    fs_readingstr
  74.     APTR    fs_sortingstr
  75.     APTR    fs_emptydirstr
  76.     APTR    fs_nomatchstr
  77.     APTR    fs_selectfilestr
  78.     APTR    fs_selectstr
  79.     APTR    fs_cancelstr
  80.     APTR    fs_specgadstr
  81.     APTR    fs_userscreen
  82.     APTR    fs_userport
  83.     APTR    fs_specgadfunc
  84.     APTR    fs_dirfunc
  85.     APTR    fs_filefunc
  86.     APTR    fs_userfunc
  87.     APTR    fs_initfunc
  88.     APTR    fs_matchfunc
  89.     LABEL    fs_SIZEOF
  90.  
  91.     STRUCTURE node_data,0
  92.     STRUCT    nd_alphadata,58
  93.     WORD    nd_filetype
  94.     WORD    nd_showit
  95.     WORD    nd_textcolor
  96.     WORD    nd_namelength
  97.     ULONG    nd_filesize
  98.     ULONG    nd_days
  99.     ULONG    nd_minutes
  100.     ULONG    nd_ticks
  101.     LABEL    nd_SIZEOF
  102.  
  103.     STRUCTURE file_node,0
  104.     STRUCT    fn_Node,MLN_SIZE
  105.     APTR    fn_info
  106.     WORD    fn_idnum
  107.     LABEL    fn_SIZEOF
  108.  
  109.     STRUCTURE dev_node,0
  110.     STRUCT    dn_Node,MLN_SIZE
  111.     STRUCT    dn_name,32
  112.     LABEL    dn_SIZEOF
  113.  
  114.     XREF    _AlphaGad
  115.     XREF    _ColonStr
  116.     XREF    _CurDevNames
  117.     XREF    _DevGads
  118.     XREF    _devList
  119.     XREF    _DevTxts
  120.     XREF    _DOSBase
  121.     XREF    _EmptyPattern
  122.     XREF    _FileUndoBuffer
  123.     XREF    _FileUndoName
  124.     XREF    _fnList
  125.     XREF    _fsbaddatestr
  126.     XREF    _FSCountDown
  127.     XREF    _fscurmicros
  128.     XREF    _fscursecs
  129.     XREF    _fsdatefmtstr
  130.     XREF    _fsdayspermonth
  131.     XREF    _FSDirFmtStr
  132.     XREF    _fsdirlocked
  133.     XREF    _FSDone
  134.     XREF    _FSDownGad
  135.     XREF    _fserrmsgs
  136.     XREF    _FSFib
  137.     XREF    _FSFileGad
  138.     XREF    _FSFileInfo
  139.     XREF    _FSFileNodes
  140.     XREF    _fsflags
  141.     XREF    _FSIgnorePat
  142.     XREF    _FSInfo
  143.     XREF    _FSLock
  144.     XREF    _fsneedshow
  145.     XREF    _FSNextDevs
  146.     XREF    _fsnumentries
  147.     XREF    _fsoldmicros
  148.     XREF    _fsoldsecs
  149.     XREF    _FSPathBuf
  150.     XREF    _FSPathGad
  151.     XREF    _FSPathInfo
  152.     XREF    _FSPatternGad
  153.     XREF    _FSPatternInfo
  154.     XREF    _FSPatternUndoBuffer
  155.     XREF    _FSPrevDevs
  156.     XREF    _fsprevgadid
  157.     XREF    _FSReq
  158.     XREF    _FSRPort
  159.     XREF    _FSSizeFmtStr
  160.     XREF    _FSSlideGad
  161.     XREF    _FSSlideProp
  162.     XREF    _fsstartedstr
  163.     XREF    _fstempdate
  164.     XREF    _fstitlelength
  165.     XREF    _fstitstatus
  166.     XREF    _FSUndoGad
  167.     XREF    _FSUpGad
  168.     XREF    _FSUserGad
  169.     XREF    _fsvheight
  170.     XREF    _fsvirgindir
  171.     XREF    _fsvposition
  172.     XREF    _FSWin
  173.     XREF    _FSWinTitleStr
  174.     XREF    _FSwstr
  175.     XREF    _GfxBase
  176.     XREF    _IntuitionBase
  177.     XREF    _lastdev
  178.     XREF    _NIL2Gad
  179.     XREF    _OldFSPathBuf
  180.     XREF    _RamDirNameStr
  181.     XREF    _SizeGad
  182.     XREF    _SlashStr
  183.     XREF    _TimeGad
  184.     XREF    _topfin
  185.  
  186.     XREF    _sprintf
  187.     XREF    _FSVBDelay
  188.  
  189.     IFD    BENCHMARK
  190.     XREF    _StartTime
  191.     XREF    _StopTime
  192.     XREF    _timermsg1
  193.     ENDC
  194.     
  195.     XLVO    ActivateGadget
  196.     XLVO    AddHead
  197.     XLVO    AddTail
  198.     XLVO    AllocMem
  199.     XLVO    ClipBlit
  200.     XLVO    DisplayBeep
  201.     XLVO    DoubleClick
  202.     XLVO    Examine
  203.     XLVO    ExNext
  204.     XLVO    FreeMem
  205.     XLVO    GetMsg
  206.     XLVO    Insert
  207.     XLVO    IoErr
  208.     XLVO    Move
  209.     XLVO    NewModifyProp
  210.     XLVO    ParentDir
  211.     XLVO    RectFill
  212.     XLVO    RefreshGList
  213.     XLVO    RemHead
  214.     XLVO    ReplyMsg
  215.     XLVO    SetAPen
  216.     XLVO    SetDrMd
  217.     XLVO    SetWindowTitles
  218.     XLVO    Text
  219.     XLVO    UnLock
  220.  
  221.     SECTION    CODE
  222. * ------------------------------------------------------------------------
  223. ; LONG MyActivateGad(gadget, window)
  224. ;   struct Gadget *gadget;
  225. ;   struct Window *window;
  226. ;   
  227. ; Activate a gadget, wait till it is ready.  Try up to 3 times.  Returns
  228. ; TRUE (1) if it succeeded, FALSE (0) if it failed to activate.
  229. * ------------------------------------------------------------------------
  230.     XDEF    _MyActivateGad
  231. _MyActivateGad:
  232.     movem.l    d2/a2/a6,-(sp)
  233.     moveq    #2,d2            ;Try 3 times to activate gadget
  234.  
  235. 1$    movem.l    16(sp),a0/a1        ;Grab gadget pointer, window pointer
  236.     suba.l    a2,a2            ;No requester pointer
  237.     movea.l    _IntuitionBase,a6
  238.     jsr    _LVOActivateGadget(a6)    ;Activate!
  239.     tst.l    d0            ;Did it catch?
  240.      bne.s    2$            ;Yep, move on
  241.  
  242.     pea    5
  243.     jsr    _FSVBDelay
  244.     addq.w    #4,sp
  245.     dbf    d2,1$
  246. 2$
  247.     movem.l    (sp)+,d2/a2/a6
  248.     rts
  249.  
  250. * --------------------------------------------------------------------- *
  251. * LONG FSCheckFlagChange(VOID);
  252. * --------------------------------------------------------------------- *
  253.     XDEF    _FSCheckFlagChange
  254. _FSCheckFlagChange:
  255.  
  256.     movea.l    _FSReq,a0
  257.     move.w    fs_flags(a0),d0
  258.     move.w    _fsflags,d1
  259.     andi.w    #%00011000,d0
  260.     andi.w    #%00011000,d1
  261.     cmp.w    d0,d1            ;FS_SHOW_FILES_FIRST or FS_SHOW_DIRS_FIRST changed?
  262.      beq.s    1$            ;Nope
  263.     move.w    #1,_fsvirgindir    ;Else we need to re-read the directory
  264. 1$
  265.     move.w    fs_flags(a0),d0
  266.     move.w    _fsflags,d1
  267.     andi.w    #%01100000,d0
  268.     andi.w    #%01100000,d1
  269.     cmp.w    d0,d1            ;FS_SHOW_FILES_ONLY or FS_SHOW_DIRS_ONLY changed?
  270.      beq.s    2$            ;Nope
  271.     moveq    #1,d0            ;Else flag that we need to FSMatchPattern()
  272.     bra.s    3$
  273. 2$
  274.     moveq    #0,d0
  275. 3$
  276.     move.w    fs_flags(a0),_fsflags ;Reset flags to match FSReq now
  277.     rts
  278.  
  279. * ------------------------------------------------------------------------
  280. ; Assign device name texts to intuitexts in the 4 Device Gadgets
  281. * ------------------------------------------------------------------------
  282.     XDEF    _SetDevGads
  283. _SetDevGads:
  284.     movem.l    d3-d4/a2-a3/a5,-(sp)
  285.  
  286. ;for (i = 0, tnode = lastdev; i < 4;)
  287.     moveq    #0,d4            ;d4 = i = 0
  288.     movea.l    _lastdev,a2        ;a2 = tnode = lastdev
  289.     move.l    a2,d3            ;Copy for comparison
  290.     lea    _CurDevNames,a3    ;a3 = &CurDevNames[0]
  291.     lea    _DevTxts,a5        ;a5 = &DevTxts[0]
  292.  
  293. 1$
  294.     lea    dn_name(a2),a1
  295.     move.l    a1,0(a3,d4.w)        ;CurDevNames[i] = tnode->name
  296.  
  297.     moveq    #4,d0
  298.     move.l    0(a5,d4.w),a0
  299.     movea.l    it_IText(a0),a0
  300.     jsr    astrncpy        ;astrncpy (DevTxts[i]->IText, tnode->name, 4)
  301.  
  302.     addq.w    #4,d4            ;i++
  303.  
  304.     movea.l    dn_Node+MLN_SUCC(a2),a2    ;tnode = tnode->dn_Node.mln_Succ
  305.     tst.l    dn_Node+MLN_SUCC(a2)    ;if (tnode->dn_Node.mln_Succ == 0)
  306.      bne.s    2$            ;Nope
  307.     movea.l    _devList,a2
  308.     movea.l    MLH_HEAD(a2),a2        ;Else start the listing over at the start
  309. 2$
  310.     cmpa.l    d3,a2            ;Have we already shown this node?
  311.      beq.s    3$            ;Yep, disable the rest
  312.  
  313.     cmpi.w    #16,d4            ;Set all 4 Device gadgets yet?
  314.      bcs    1$            ;Nope, do next
  315.  
  316. 3$
  317. * Disable any leftover gadgets
  318. ;for (; i < 4; i++)
  319.     lea    _DevGads,a0
  320.     bra.s    5$
  321.  
  322. 4$    movea.l    0(a0,d4.w),a1
  323.     bset.b    #0,gg_Flags(a1)        ;DevGads[i]->Flags |= GADGDISABLED
  324.     addq.w    #4,d4
  325.  
  326. 5$    cmpi.w    #16,d4
  327.      bcs    4$
  328.  
  329.     movem.l    (sp)+,d3-d4/a2-a3/a5
  330.     rts
  331.  
  332. * ------------------------------------------------------------------------
  333. ; FSScrollDevGads(direction)
  334. ;   WORD direction;
  335. * ------------------------------------------------------------------------
  336.     XDEF    _FSScrollDevGads
  337. _FSScrollDevGads:
  338.     movem.l    a2/a6,-(sp)
  339.  
  340.     movea.l    _lastdev,a0
  341.     tst.w    12+2(sp)        ;Grab scroll direction
  342.      beq.s    1$            ;If zero, scroll to next
  343.  
  344. * Bump list pointer one direction or the other
  345.     move.l    dn_Node+MLN_SUCC(a0),a0    ;Get successor
  346.     tst.l    dn_Node+MLN_SUCC(a0)    ;EndoList?
  347.      bne.s    2$            ;Nope
  348.     movea.l _devList,a0
  349.     movea.l    MLH_HEAD(a0),a0        ;Else lastdev = devList->lh_Head
  350.     bra.s    2$
  351. 1$
  352.     movea.l    dn_Node+MLN_PRED(a0),a0 ;Else, lastdev = lastdev->next
  353.     tst.l    dn_Node+MLN_PRED(a0)    ;Endolist?
  354.      bne.s    2$
  355.     movea.l _devList,a0
  356.     movea.l    MLH_TAILPRED(a0),a0    ;Else lastdev = devList->lh_TailPred
  357. 2$
  358.     move.l    a0,_lastdev
  359.     jsr    _SetDevGads        ;Set the gadget text fields
  360.  
  361. * Refresh gadget texts
  362. ;RefreshGList(&NIL2Gad, FSWin, 0L, 4L);
  363.     moveq    #4,d0
  364.     suba.l    a2,a2
  365.     movea.l    _FSWin,a1
  366.     lea    _NIL2Gad,a0
  367.     SYS    RefreshGList,_IntuitionBase
  368.  
  369.     movem.l    (sp)+,a2/a6
  370.     rts
  371.  
  372. * ------------------------------------------------------------------------
  373. ; CheckFSArrows()
  374. ;  See if the Up or Down arrow gadgets are currently activated, scroll
  375. ; the file display area or device gadget list if so.
  376. * ------------------------------------------------------------------------
  377.     XDEF    _CheckFSArrows
  378. _CheckFSArrows:
  379.     subq.w    #1,_FSCountDown
  380.      bge.s    12$
  381.  
  382.     btst.b    #7,_FSUpGad+gg_Flags+1    ;FSUpGad.Flags & SELECTED?
  383.      beq.s    2$            ;Nope, maybe FSDownGad
  384.     pea    1            ;Otherwise scroll filegadgets up
  385.     bra.s    3$
  386.  
  387. 2$    btst.b    #7,_FSDownGad+gg_Flags+1     ;FSDownGad.Flags & SELECTED?
  388.      beq.s    4$            ;Nope, maybe slide gadget is selected
  389.     pea    0            ;Otherwise scroll filegadgets down
  390.  
  391. 3$    jsr    _FSScrollFileGads
  392.     addq.w    #4,sp
  393.     move.w    #0,_FSCountDown    ;Set timer to wake up in .02 secs.
  394.     bra.s    12$
  395.  
  396. 4$    btst.b    #7,_FSSlideGad+gg_Flags+1    ;FSSlideGad.Flags & SELECTED?
  397.      beq.s    5$            ;Nope, maybe UpDev
  398.     jsr    _FSDoSlideGadget    ;Process slide gadget motion
  399.     move.w    #0,_FSCountDown    ;Set timer to wake up in .02 secs.
  400.     bra.s    12$
  401.  
  402. 5$    btst.b    #7,_FSPrevDevs+gg_Flags+1    ;FSPrevDevs.Flags & SELECTED?
  403.      beq.s    7$            ;Nope, maybe DownDev
  404.     pea    1            ;Otherwise FSScrollDevGads(1);
  405. 6$    jsr    _FSScrollDevGads
  406.     addq.w    #4,sp
  407.     move.w    #1,_FSCountDown    ;Set timer to wake up in .16 secs.
  408.     bra.s    12$
  409.  
  410. 7$    btst.b    #7,_FSNextDevs+gg_Flags+1    ;FSNextDevs.Flags & SELECTED?
  411.      beq.s    10$            ;Nope, nothing of interest, slow down
  412.     pea    0            ;Else FSScrollDevGads(0);
  413.     bra    6$
  414.  
  415. 10$
  416.     move.w    #4,_FSCountDown
  417. 12$
  418.     rts
  419.  
  420. * ------------------------------------------------------------------------
  421. ; BYTE *FibFileDate(fib_date)
  422. ;   struct DateStamp *fib_date;
  423. ;
  424. ;   Calculate date based on DateStamp structure and return a pointer
  425. ; to the formatted date text.
  426. * ------------------------------------------------------------------------
  427.     XDEF    _FibFileDate
  428. _FibFileDate:
  429.     link    a5,#0
  430.     movem.l    d3-d7,-(sp)
  431.  
  432.     movea.l    8(a5),a1        ;Grab datestamp pointer
  433.     moveq    #78,d7            ;Initial year = 1978
  434.     
  435.     move.l    (a1),d5            ;days = fib_date->ds_Days
  436.      blt    ffdbaddate        ;Hey! you can't be negative! Invalid date...
  437.  
  438. * Determine what year it is
  439.     divu    #1461,d5
  440.     move.l    d5,d0            ;Stash it
  441.     ext.l    d5
  442.     lsl.l    #2,d5
  443.     add.l    d5,d7            ;year += (days / 1461) * 4
  444.  
  445. * Count how many months into that year
  446. ffdgetmo:
  447.     swap    d0
  448.     moveq    #0,d5
  449.     move.w    d0,d5            ;days %= 1461
  450.  
  451. 1$    tst.w    d5            ;Out of days yet?
  452.      beq.s    3$            ;Yep, done here
  453.  
  454.     move.w    #365,d6            ;Else month_days = 365
  455.     move.w    d7,d0            ;Grab year
  456.     andi.w    #3,d0            ;if (year & 3) == 0 Leap year?
  457.      bne.s    2$            ;Nope
  458.     addq.w    #1,d6            ;Otherwise bump month_days
  459.  
  460. 2$    cmp.w    d6,d5            ;is day < month_days?
  461.      bcs.s    3$            ;yep, done here
  462.     sub.w    d6,d5            ;otherwise day -= month_days
  463.  
  464.     addq.l    #1,d7            ; year++
  465.     bra    1$
  466. 3$
  467.  
  468. * Count how many days into that month of that year
  469. ffdgetday:
  470. ;for (i = 0, day++; i < 12; i++)
  471.     moveq    #0,d4            ;current month = 0
  472.     moveq    #0,d6            ;Zap hinybs
  473.     addq.w    #1,d5
  474.     lea    _fsdayspermonth,a0
  475.  
  476. 1$    move.b    0(a0,d4.w),d6        ;month_days = _fsdayspermonth[i]
  477.  
  478.     cmpi.w    #1,d4            ;if (i == 1 && (year & 3) == 0)
  479.      bne.s    2$
  480.     move.w    d7,d0
  481.     andi.w    #3,d0
  482.      bne.s    2$
  483.     addq.w    #1,d6            ;month_days++
  484.  
  485. 2$    cmp.w    d6,d5            ;if (day <= month_days)
  486.      ble.s    4$            ;Break out, found the right month
  487.  
  488.     sub.w    d6,d5            ;Else, day -= month_days
  489.  
  490.     addq.w    #1,d4            ;i++
  491. 3$    cmpi.w    #12,d4            ;Done all months yet?
  492.      bcs    1$            ;Nope
  493.  
  494. 4$
  495. ffdprint:
  496. 1$    cmpi.l    #99,d7            ;while (year >= 100)
  497.      ble.s    2$
  498.     subi.l    #100,d7            ;year -= 100
  499.     bra    1$
  500. 2$
  501. ;sprintf(_fstempdate, "%02ld-%02ld-%02ld %02ld:%02ld:%02ld", year, i + 1, day, hour, min, sec)
  502.     move.l    8(a1),d0        ;sec = fib_date->ds_Tick / 50;
  503.     divu.w    #50,d0
  504.     ext.l    d0
  505.     move.l    d0,-(sp)        ;Push secs
  506.  
  507.     moveq    #0,d0            ;Zap reg
  508.     move.w    6(a1),d0        ;min = fib_date->ds_Minute
  509.     move.w    d0,d1            ;Clone it
  510.     divu    #60,d0
  511.     move.w    d0,d3            ;hour = min / 60
  512.     ext.l    d3
  513.     mulu    #60,d0
  514.     sub.w    d0,d1            ;min -= hour * 60
  515.     ext.l    d1
  516.     move.l    d1,-(sp)        ;Push mins
  517.  
  518.     move.l    d3,-(sp)        ;Push hours
  519.     move.l    d5,-(sp)        ;Push day of month
  520.     addq.w    #1,d4            ;Push month (offset by 1!)
  521.     move.l    d4,-(sp)
  522.     move.l    d7,-(sp)        ;Push year
  523.     pea    _fsdatefmtstr    ;Push the format pattern
  524.     pea    _fstempdate        ;Push destination buffer
  525.     jsr    _sprintf    
  526.     lea    32(sp),sp
  527.     lea    _fstempdate,a0
  528.     move.l    a0,d0            ;return((BYTE *)&_fstempdate[0])
  529.  
  530. ffddone:
  531.     movem.l    (sp)+,d3-d7
  532.     unlk    a5
  533.     rts
  534.  
  535. ffdbaddate:
  536.     lea    _fsbaddatestr,a0
  537.     move.l    a0,d0            ;return (" <Invalid Date> ")
  538.     bra    ffddone
  539.  
  540. * --------------------------------------------------------------------- *
  541.     XDEF    _FSSetKnobHeight
  542. _FSSetKnobHeight:
  543. ;vheight = (ULONG)( 655350L / (long)fsnumentries );
  544.     move.w    _fsnumentries,d1
  545.     cmpi.w    #10,d1
  546.      bhi.s    1$
  547.     move.w    #$ffff,_fsvheight
  548.     rts
  549. 1$
  550.     move.l    #655350,d0    
  551.     divu    d1,d0
  552.     move.w    d0,_fsvheight
  553. 3$
  554.     rts
  555.  
  556. * --------------------------------------------------------------------- *
  557.     XDEF    _FSSetKnobPos
  558. _FSSetKnobPos:
  559.     movea.l    _topfin,a0
  560.     moveq    #0,d0
  561.     move.w    fn_idnum(a0),d0
  562.     swap    d0
  563.     move.w    _fsnumentries,d1
  564.     subi.w    #10,d1
  565.      bhi.s    1$
  566.     moveq    #0,d0
  567.     bra.s    2$
  568. 1$
  569.     divu    d1,d0
  570.      bvc.s    2$
  571.     move.w    #$ffff,d0
  572. 2$
  573.     move.w    d0,_fsvposition
  574.     rts
  575.  
  576. * --------------------------------------------------------------------- *
  577.     XDEF    _FSResetKnob
  578. _FSResetKnob:
  579.     jsr    _FSSetKnobHeight
  580.     jsr    _FSSetKnob
  581.     rts
  582.  
  583. * ------------------------------------------------------------------------
  584. ; FSSetKnob()
  585. ;  Call ModifyProp() to actually update slide image in window.
  586. * ------------------------------------------------------------------------
  587.     XDEF    _FSSetKnob
  588. _FSSetKnob:
  589.     movem.l    d2-d5/a2/a6,-(sp)
  590.  
  591. ;NewModifyProp(&FSSlideGad, FSWin, 0L, AUTOKNOB|FREEVERT|PROPB, 0L, vposition, 0xffffL, vheight, 1L)
  592.     lea    _FSSlideGad,a0
  593.     movea.l    _FSWin,a1
  594.     suba.l    a2,a2
  595.     moveq    #AUTOKNOB!FREEVERT!PROPBORDERLESS,d0
  596.     moveq    #0,d1
  597.     moveq    #0,d2
  598.     move.w    _fsvposition,d2
  599.     move.l    #$ffff,d3
  600.     moveq    #0,d4
  601.     move.w    _fsvheight,d4
  602.     moveq    #1,d5
  603.     SYS    NewModifyProp,_IntuitionBase
  604.  
  605.     movem.l    (sp)+,d2-d5/a2/a6
  606.     rts
  607.  
  608. * ------------------------------------------------------------------------
  609. ; FSEnableFGad(gadg_num)
  610. ;  LONG gadg_num;
  611. ;
  612. ; Given a file gadget number, refresh the text for that entry.
  613. * ------------------------------------------------------------------------
  614.     XDEF    _FSEnableFGad
  615. _FSEnableFGad:
  616.     movem.l    a2-a3/a6,-(sp)
  617.  
  618.     movea.l    _FSRPort,a2
  619.  
  620.     move.w  4+4*3+2(sp),d0        ;Grab gadget number
  621.     move.w    d0,d1            ;Copy
  622.     lsl.w    #2,d0            ;Conver to long offset
  623.     lea    _FSFileNodes,a0
  624.     movea.l    0(a0,d0.w),a0        ;tnode = FSFileNodes[gadg_num]
  625.     movea.l    fn_info(a0),a3        ;a3 = tnode->info
  626.  
  627. * Move to the right slot text position
  628.     mulu    #11,d1
  629.     addi.w    #19,d1
  630.     moveq    #9,d0
  631.     movea.l    a2,a1
  632.     SYS    Move,_GfxBase    ;Move(FSRPort, 9, gadnum*11+19)
  633.  
  634. * Set the pen color according to the node
  635.     move.w    nd_textcolor(a3),d0
  636.     movea.l    a2,a1
  637.     SYS    SetAPen            ;SetAPen(FSRPort, tinfo->textcolor)
  638.  
  639. * Blast out the text
  640.     moveq    #56,d0
  641.     lea    nd_alphadata(a3),a0
  642.     movea.l    a2,a1
  643.     SYS    Text            ;Text(FSRPort, tinfo->alphadata, 56)
  644.  
  645.     movem.l    (sp)+,a2-a3/a6
  646.     rts
  647.  
  648. * ------------------------------------------------------------------------
  649. ; FSDisableFGad(gadg_num)
  650. ;  LONG gadg_num;
  651. ;
  652. ; Given a file gadget number, fill that slot with the EmptyPattern
  653. ; and clear the FileNode[] slot for that gadget.
  654. * ------------------------------------------------------------------------
  655.     XDEF    _FSDisableFGad
  656. _FSDisableFGad:
  657.     movem.l    d2-d4/a2/a6,-(sp)
  658.  
  659.     move.w    4*5+4+2(sp),d4        ;Grab gadget number
  660.  
  661.     movea.l    _FSRPort,a2
  662.  
  663.     lea    _EmptyPattern,a0
  664.     move.l    a0,rp_AreaPtrn(a2)    ;rp->AreaPtrn = EmptyPattern
  665.     move.b    #1,rp_AreaPtSz(a2)    ;rp->AreaPtSz = (BYTE)1
  666.  
  667.     movea.l    a2,a1
  668.     moveq    #2,d0
  669.     SYS    SetAPen,_GfxBase     ;SetAPen(rp, 2)
  670.  
  671.     move.w    d4,d1
  672.     mulu    #11,d1
  673.     addi.w    #13,d1            ;miny = 13L + (gadg_num * 11)
  674.  
  675.     move.l    d1,d3
  676.     addq.w    #7,d3            ;maxy = miny + 7L
  677.  
  678.     movea.l    a2,a1            ;FSWin->RPort
  679.     moveq    #9,d0            ;minx
  680.     move.l    #456,d2            ;maxx
  681.     SYS    RectFill        ;RectFill(rp, minx, miny, maxx, maxy)
  682.  
  683.     clr.l    rp_AreaPtrn(a2)        ;rp->AreaPtrn = 0L
  684.     clr.b    rp_AreaPtSz(a2)        ;rp->AreaPtSz = (BYTE)0
  685.  
  686.     move.w    d4,d0
  687.     lsl.w    #2,d0
  688.     lea    _FSFileNodes,a0
  689.     clr.l    0(a0,d0.w)        ;FSFileNodes[gadg_num] = 0L
  690.  
  691.     movem.l    (sp)+,d2-d4/a2/a6
  692.     rts
  693.  
  694. * --------------------------------------------------------------------- *
  695.     XDEF    _FSDisableAllFGads
  696. _FSDisableAllFGads:
  697.     move.l    d2,-(sp)
  698.  
  699.     moveq    #0,d2
  700.     move.w    _fsnumentries,d2
  701.     bra.s    2$
  702. 1$    move.l    d2,-(sp)
  703.     jsr    _FSDisableFGad        ;FSDisableFGad(i)
  704.     addq.w    #4,sp
  705.     addq.w    #1,d2            ;i++
  706. 2$    cmpi.w    #10,d2            ;Hit 10 entries?
  707.      bcs    1$            ;Nope, disable one
  708.     move.l    (sp)+,d2
  709.     rts
  710.  
  711. * ------------------------------------------------------------------------
  712. ;struct file_node *AllocFileNode()
  713. ;
  714. ;  Allocate a file_node structure and it's info block, return pointer
  715. ; to the file_node or NULL if allocation failed.
  716. * ------------------------------------------------------------------------
  717.     XDEF    _AllocFileNode
  718. _AllocFileNode:
  719.     move.l    a6,-(sp)
  720.  
  721.     moveq    #fn_SIZEOF+nd_SIZEOF,d0    ;sizeof(struct file_node)+sizeof(struct node_data)
  722.     move.l    #MEMF_CLEAR,d1        ;MEMF_CLEAR
  723.     SYS    AllocMem,4        ;Allocate file node structure
  724.     move.l    d0,d1
  725.      beq.s    1$
  726.     movea.l    d0,a0
  727.         addi.l    #fn_SIZEOF,d1
  728.     move.l    d1,fn_info(a0)        ;Set pointer to tnode->info area
  729. 1$
  730.     movea.l    (sp)+,a6
  731.     rts
  732.  
  733. * ------------------------------------------------------------------------
  734. ; FreeFileNode(tnode)
  735. ;  struct file_node *tnode;
  736. ;
  737. ;  Given a pointer to a file_node, Free the memory allocated for that node.
  738. * ------------------------------------------------------------------------
  739.     XDEF    _FreeFileNode
  740. _FreeFileNode:
  741.     move.l    a6,-(sp)
  742.  
  743.     move.l    4+4(sp),d0        ;Grab tnode
  744.      beq.s    2$            ;Nope, get outta here
  745.     movea.l    d0,a1
  746.     moveq    #fn_SIZEOF+nd_SIZEOF,d0
  747.     SYS    FreeMem,4        ;FreeMem(tnode, sizeof(struct file_node)+sizeof(struct node_data))
  748.  
  749. 2$    movea.l    (sp)+,a6
  750.     rts
  751.     
  752.  
  753. * ------------------------------------------------------------------------
  754. ; FreeAllFNodes()
  755. ;
  756. ;  Call FreeFileNode for each node in the linked list of file_nodes,
  757. ;then deallocate the head of the list (fnList)
  758. * ------------------------------------------------------------------------
  759.     XDEF    _FreeAllFNodes
  760. _FreeAllFNodes:
  761.     movem.l    a2/a6,-(sp)
  762.  
  763.     move.l    _fnList,d0        ;Is there a list?
  764.      beq.s    2$            ;Nope, get outta here
  765.  
  766.     movea.l    d0,a2            ;Grab head
  767.     movea.l    4,a6            ;Set for ExecBase
  768. 1$
  769.     movea.l    a2,a0
  770.     SYS    RemHead            ;d0 = RemHead(fnList)
  771.     tst.l    d0            ;Hit end?
  772.      beq.s    2$            ;yep
  773.  
  774.     move.l    d0,-(sp)
  775.     jsr    _FreeFileNode        ;Free the node
  776.     addq.w    #4,sp
  777.     bra    1$            ;Remove next node
  778.  
  779. 2$
  780. * Reset other globals
  781.     clr.w    _fsvposition    ;Set slider position to top of area
  782.     move.w    #$ffff,_fsvheight    ;Max height
  783.     clr.w    _fsnumentries    ;Zero entries
  784.  
  785.     movem.l    (sp)+,a2/a6
  786.     rts
  787.  
  788. * ------------------------------------------------------------------------
  789. ;struct dev_node *AllocDevNode()
  790. ;
  791. ;  Allocate a dev_node, return pointer to same
  792. * ------------------------------------------------------------------------
  793.     XDEF    _AllocDevNode
  794. _AllocDevNode:
  795.     move.l    a6,-(sp)
  796.  
  797.     moveq    #dn_SIZEOF,d0
  798.     move.l    #MEMF_CLEAR,d1
  799.     SYS    AllocMem,4        ;AllocMem(sizeof(struct dev_node), MEMF_CLEAR)
  800.     
  801.     movea.l    (sp)+,a6
  802.     rts
  803.  
  804. * ------------------------------------------------------------------------
  805. ;FreeDevNode(tnode)
  806. ;  struct dev_node *tnode;
  807. ;
  808. ;  Given a pointer to a dev_node, free memory allocated for that node.
  809. * ------------------------------------------------------------------------
  810.     XDEF    _FreeDevNode
  811. _FreeDevNode:
  812.     move.l    a6,-(sp)
  813.  
  814.     move.l    4+4(sp),d0        ;Grab dev_node to free
  815.      beq.s    1$            ;Oops, nothing here
  816.  
  817.     movea.l    d0,a1
  818.     moveq    #dn_SIZEOF,d0
  819.     SYS    FreeMem,4        ;FreeMem(tnode, (long)sizeof(struct dev_node))
  820.  
  821. 1$
  822.     movea.l    (sp)+,a6
  823.     rts
  824.  
  825.  
  826. * ------------------------------------------------------------------------
  827. ;FreeAllDNodes()
  828. ;
  829. ;  Call FreeDevNode() for each dev_node in the linked list, then free the
  830. ; head of the list, devList.
  831. * ------------------------------------------------------------------------
  832.     XDEF    _FreeAllDNodes
  833. _FreeAllDNodes:
  834.     movem.l    a2/a6,-(sp)
  835.  
  836.     move.l    _devList,d0        ;Is there a head node?
  837.      beq.s    3$            ;Nope, don't deallocate
  838.  
  839.     movea.l    d0,a2            ;Grab head of device list
  840.     movea.l    4,a6            ;Set for execbase
  841.  
  842. 1$    movea.l    a2,a0
  843.     SYS    RemHead            ;d0 = RemHead(devList)
  844.     tst.l    d0            ;Got one?
  845.      beq.s    2$            ;Nope, list is empty
  846.  
  847.     move.l    d0,-(sp)
  848.     jsr    _FreeDevNode        ;Free this device node
  849.     addq.w    #4,sp
  850.     bra    1$
  851.  
  852. 2$    movea.l    a2,a1
  853.     moveq    #MLH_SIZE,d0
  854.     SYS    FreeMem            ;FreeMem(devList, sizeof(MinList))
  855.     clr.l    _devList
  856.  
  857. 3$    movem.l    (sp)+,a2/a6
  858.     rts
  859.  
  860. * ------------------------------------------------------------------------
  861. ; FreeFileSelect()
  862. ;   Deallocate filenames and fileinfoblocks, unlock any locks
  863. * ------------------------------------------------------------------------
  864.     XDEF    _FreeFileSelect
  865. _FreeFileSelect:
  866.     move.l    a6,-(sp)
  867.     move.w    #1,_fsvirgindir    ;virgindir = 1
  868.     jsr    _FreeAllFNodes        ;Free all allocated filenames
  869.     jsr    _FSClearLock        ;Unlock any locks
  870.  
  871. * Free the head node itself
  872.     move.l    _fnList,d0
  873.      beq.s    1$
  874.     movea.l    d0,a1
  875.     moveq    #MLH_SIZE,d0
  876.     SYS    FreeMem,4        ;FreeMem(fnList, sizeof(MinList))
  877.     clr.l    _fnList        ;And clear the pointer
  878. 1$
  879. * Free the global FileInfoBlock and InfoData struct
  880.     move.l    _FSFib,d0        ;Do we have a FileInfoBlock allocated?
  881.      beq.s    2$            ;Nope
  882.     movea.l    d0,a1
  883.     move.l    #fib_SIZEOF+id_SIZEOF,d0
  884.     SYS    FreeMem,4        ;FreeMem(FSFib, 300L)
  885.     clr.l    _FSFib        ;Set to NULL so we don't re-free it
  886.     clr.l    _FSInfo
  887. 2$
  888.     movea.l    (sp)+,a6
  889.     rts
  890.  
  891. * --------------------------------------------------------------------- *
  892. * Cleanup function for fileselect
  893. * --------------------------------------------------------------------- *
  894.     XDEF    _ReleaseFileSelect
  895. _ReleaseFileSelect:
  896.     jsr    _FreeFileSelect
  897.     jsr    _FreeAllDNodes
  898.     rts
  899.  
  900. * ------------------------------------------------------------------------
  901. ; LONG FSGetNextFib(VOID)
  902. ;
  903. ;  Call ExNext() to fill in next FileInfoBlock, set titlebar to reflect
  904. ; status of the request.
  905. * ------------------------------------------------------------------------
  906.     XDEF    _FSGetNextFib
  907. _FSGetNextFib:
  908.     movem.l    d2/a6,-(sp)
  909.  
  910. * Try to get next fileinfoblock from dos
  911.     move.l    _FSLock,d1
  912.     move.l    _FSFib,d2
  913.     SYS    ExNext,_DOSBase
  914.     tst.l    d0            ;Did we get an entry?
  915.      bne.s    gnfgot1            ;Yep, got it
  916.  
  917. * Didn't get one, find out why
  918. ;if ( (error = IoErr()) != ERROR_NO_MORE_ENTRIES)
  919.     SYS    IoErr            ;Get error number
  920.     cmpi.l    #232,d0            ;No more entries?
  921.      beq.s    gnfnme            ;Yep
  922.  
  923.     move.l    d0,-(sp)
  924.     jsr    _ioerrnum        ;Otherwise set window title to error number
  925.     addq.w    #4,sp
  926.     move.w    d0,_fstitstatus
  927.     moveq    #-1,d2            ;Return bad get status
  928.     bra.s    gnfsetwintit
  929.  
  930. gnfnme:
  931.     moveq    #0,d2            ;Return DONE!
  932.     tst.w    _fsnumentries    ;Got any valid pattern matches?
  933.      bne.s    gnfselect        ;Yep, select a file time
  934.  
  935.     movea.l    _fnList,a6
  936.     movea.l    MLH_HEAD(a6),a6
  937.     tst.l    fn_Node+MLN_SUCC(a6)     ;Do we have any files?
  938.      beq.s    gnfnoentry        ;Nope, no entries
  939.  
  940.     move.w    #24,_fstitstatus    ;Otherwise no match
  941.     bra.s    gnfsetwintit
  942.  
  943. gnfnoentry:
  944.     move.w    #22,_fstitstatus    ;No Entries...
  945.     bra.s    gnfsetwintit
  946.  
  947. gnfselect:
  948.     move.w    #29,_fstitstatus    ;Select a file...
  949.  
  950. gnfsetwintit:
  951.     bra.s    gnfdone
  952.  
  953. gnfgot1:
  954.     moveq    #1,d2
  955.  
  956. gnfdone:
  957.     move.l    d2,d0
  958.     movem.l    (sp)+,d2/a6
  959.     rts
  960.  
  961. * ------------------------------------------------------------------------
  962. ;AllocFSFib()
  963. ;Allocate a fileinfoblock, return status
  964. * ------------------------------------------------------------------------
  965.     XDEF    _AllocFSFib
  966. _AllocFSFib:
  967.     move.l    a6,-(sp)
  968.     tst.l    _FSFib        ;Do we already have a fib?
  969.      bne.s    1$            ;Yep, get out of here
  970.  
  971. ;FSFib = AllocMem(sizeof(*FSFib) + sizeof(*FSInfo), MEMF_CLEAR);
  972.     move.l    #fib_SIZEOF+id_SIZEOF,d0
  973.     move.l    #MEMF_CLEAR,d1
  974.     SYS    AllocMem,4
  975.     move.l    d0,_FSFib
  976.      beq.s    2$            ;Oops, allocation failed, return 0
  977.  
  978.     addi.l    #fib_SIZEOF,d0
  979.     move.l    d0,_FSInfo        ;Set pointer to InfoData struct too
  980.  
  981. 1$    moveq    #1,d0            ;Return good status
  982.  
  983. 2$    movea.l    (sp)+,a6
  984.     rts
  985.  
  986. * ------------------------------------------------------------------------
  987. ;LONG ioerrnum(num)
  988. ;  LONG num;
  989. ;
  990. ; Given an IoErr number, convert to error text table offset, return
  991. ; converted index number.
  992. * ------------------------------------------------------------------------
  993.     XDEF    _ioerrnum
  994. _ioerrnum:
  995.     move.l    4(sp),d0
  996.  
  997.     cmpi.w    #202,d0            ;if (num < 202L || num > 231L)
  998.      bcs.s    ioetl
  999.     cmpi.w    #231,d0
  1000.      bls.s    ioe3l
  1001. ioetl:
  1002.     moveq    #27,d0            ;return(27)
  1003.     rts
  1004. ioe3l:
  1005.     cmpi.w    #209,d0            ;if (num < 209L)
  1006.      bcc.s    ioe4l
  1007.     subi.w    #202,d0            ;num -= 202L
  1008.     rts
  1009. ioe4l:
  1010.     subi.w    #205,d0            ;else num -= 205L
  1011.     rts
  1012.  
  1013. * ------------------------------------------------------------------------
  1014. ; BYTE *ioerrmsg(num)
  1015. ;  long num;
  1016. ;
  1017. ;  Given a IoErr number, return pointer to error message text that
  1018. ; describes that error.
  1019. * ------------------------------------------------------------------------
  1020.     XDEF    _ioerrmsg
  1021. _ioerrmsg:
  1022.     move.l    4(sp),-(sp)        ;Push error number
  1023.     jsr    _ioerrnum
  1024.     addq.w    #4,sp
  1025.     lsl.w    #2,d0            ;Convert return to text table offset
  1026.     lea    _fserrmsgs,a0
  1027.     move.l    0(a0,d0.w),d0        ;Return pointer to fserrmsgs[num]
  1028.     rts
  1029.  
  1030. * ------------------------------------------------------------------------
  1031. ; VOID FSPutPath(VOID)
  1032. ;  Refresh the FSPathGadget imagery.
  1033. * ------------------------------------------------------------------------
  1034.     XDEF    _FSPutPath
  1035. _FSPutPath:
  1036.     movem.l    a2/a6,-(sp)
  1037.  
  1038. ;RefreshGList(&FSPathGad, FSWin, 0L, 1L);
  1039.     lea    _FSPathGad,a0
  1040.     movea.l    _FSWin,a1
  1041.     suba.l    a2,a2
  1042.     moveq    #1,d0
  1043.     SYS    RefreshGList,_IntuitionBase
  1044.  
  1045.     movem.l    (sp)+,a2/a6
  1046.     rts
  1047.  
  1048. * ------------------------------------------------------------------------
  1049. ; VOID FSClearLock(VOID)
  1050. ;
  1051. ;  If we have a Lock on the current directory, unlock it.
  1052. * ------------------------------------------------------------------------
  1053.     XDEF    _FSClearLock
  1054. _FSClearLock:
  1055.     move.l    a6,-(sp)
  1056.     tst.w    _fsdirlocked    ;Is it locked?
  1057.      beq.s    2$            ;Nope, don't dare unlock
  1058.  
  1059.     move.l    _FSLock,d1
  1060.      beq.s    1$
  1061.     SYS    UnLock,_DOSBase    ;UnLock(FSLock)
  1062.     clr.l    _FSLock        ;FSLock = 0L;
  1063. 1$    clr.w    _fsdirlocked    ;dirlocked = 0
  1064.  
  1065. 2$    movea.l    (sp)+,a6
  1066.     rts
  1067.  
  1068. * ------------------------------------------------------------------------
  1069. ; FSWinTitle()
  1070. ;   Refresh current window title using contents of windowtitle[].
  1071. * ------------------------------------------------------------------------
  1072.     XDEF    _FSWinTitle
  1073. _FSWinTitle:
  1074.     movem.l    a2/a6,-(sp)
  1075.  
  1076.     move.w    _fstitlelength,d0
  1077.     lea    _FSWinTitleStr,a0
  1078.     clr.b    0(a0,d0.w)        ;windowtitle[fstitlelength] = '\x0'
  1079.  
  1080.     move.w    _fstitstatus,d1
  1081.     lsl.w    #2,d1
  1082.     lea    _fserrmsgs,a1
  1083.     movea.l    0(a1,d1.w),a1
  1084.     adda.w    d0,a0
  1085.     jsr    astrcpy            ;astrcpy(&windowtitle[fstitlelength], fserrmsgs[fstitstatus])
  1086.  
  1087.     movea.l    _FSWin,a1
  1088.     move.l    wd_Flags(a1),d0        ;d0 = FSWin->Flags
  1089.     andi.l    #WINDOWTGADS,d0     ;Do we have titlebar gadgets?
  1090.      bne.s    3$            ;Yep, refresh is automatic
  1091.  
  1092.     lea    _FSWinTitleStr+79,a1
  1093.     clr.b    (a1)            ;FSWinTitleStr[79] = 0
  1094.     move.b    #' ',d0            ;for (;ptr != &FSWinTitle[79];ptr++)
  1095. 2$    cmpa.l    a0,a1
  1096.      beq.s    4$
  1097.     move.b    d0,(a0)+        ;*ptr = ' '
  1098.     bra    2$
  1099. 3$
  1100.     move.b    #' ',(a0)+        ;Concat a space and a null onto the end
  1101.     clr.b    (a0)
  1102. 4$
  1103. ;SetWindowTitles(FSWin, windowtitle, -1L)
  1104.     movea.l    _FSWin,a0
  1105.     lea    _FSWinTitleStr,a1
  1106.     movea.l    #-1,a2
  1107.     SYS    SetWindowTitles,_IntuitionBase
  1108.  
  1109.     movem.l    (sp)+,a2/a6
  1110.     rts
  1111.  
  1112. * ------------------------------------------------------------------------
  1113. ; VOID FSEndString(VOID)
  1114. ;
  1115. ; If user started a string gadget entry then clicked in another gadget,
  1116. ;ignore any changes to the string and restore the previous string.
  1117. * ------------------------------------------------------------------------
  1118.     XDEF    _FSEndString
  1119. _FSEndString:
  1120.     movem.l    a2/a6,-(sp)
  1121.  
  1122.     move.w    _fsstartedstr,d0    ;Grab starttext flag
  1123.     cmpi.w    #1,d0            ;Did user start at file entry?
  1124.      bne.s    fstnotfile        ;Nope
  1125.  
  1126.     movea.l    _FSFileInfo,a0    ;Grab filename buffer
  1127.     lea    _FileUndoName,a1
  1128.     lea    _FSFileGad,a2    ;Grab filetext gadget
  1129.     bra.s    fstrefresh        ;Refresh it
  1130.  
  1131. fstnotfile:
  1132.     cmpi.w    #2,d0            ;Did user start a path entry?
  1133.      bne.s    fstnotpath        ;Nope, maybe pattern
  1134.  
  1135.     movea.l    _FSPathInfo,a0    ;Grab pathtext buffer
  1136.     lea    _FileUndoBuffer,a1
  1137.     lea    _FSPathGad,a2    ;Pointer to path gadget
  1138.     bra.s    fstrefresh        ;Refresh text
  1139.  
  1140. fstnotpath:
  1141.     cmpi.w    #3,d0            ;Started a pattern entry?
  1142.      bne.s    fstdone            ;Nope, don't have to do anything
  1143.  
  1144.     movea.l    _FSPatternInfo,a0    ;Else grab the pattern buffer
  1145.     lea    _FSPatternUndoBuffer,a1
  1146.     lea    _FSPatternGad,a2    ;Pointer to pattern gadget
  1147.  
  1148. fstrefresh:
  1149.     jsr    astrcpy            ;astrcpy(tstr, FSwstr)
  1150.  
  1151.     movea.l    a2,a0
  1152.     movea.l    _FSWin,a1
  1153.     suba.l    a2,a2
  1154.     moveq    #1,d0
  1155.     SYS    RefreshGList,_IntuitionBase ;RefreshGList(tgad, FSWin, 0L, 1L)
  1156.  
  1157.     clr.w    _fsstartedstr    ;fsstartedstr = 0
  1158.  
  1159. fstdone:
  1160.     movem.l    (sp)+,a2/a6
  1161.     rts
  1162.  
  1163.  
  1164. * ------------------------------------------------------------------------
  1165. ; FSDoGadget(gadgid)
  1166. ;  ULONG gadgid;
  1167. ;
  1168. ; Given a gadget id number, perform action associated with that gadget.
  1169. * ------------------------------------------------------------------------
  1170.     XDEF    _FSDoGadget
  1171. _FSDoGadget:
  1172.     movem.l    d4/a2,-(sp)
  1173.  
  1174.     move.w    14(sp),d4        ;Grab gadget id number
  1175.      bne.s    dgnotusergad        ;Not zero, not Undo gadget
  1176.  
  1177. * FSUserGad
  1178.     jsr    _ConcatPathString     ;Concat final output text, return
  1179.     clr.w    _FSDone
  1180.  
  1181.     movea.l    _FSReq,a1
  1182.     movea.l    fs_specgadfunc(a1),a0
  1183.     pea    _FSUserGad
  1184.     move.l    _FSWin,-(sp)
  1185.     move.l    a1,-(sp)
  1186.     jsr    (a0)
  1187.     lea    12(sp),sp
  1188.     tst.l    d0
  1189.      bne    dgnewdir
  1190.     bra    dogaddone
  1191.  
  1192. dgnotusergad:
  1193. * FSSelectGad
  1194.     cmpi.w    #1,d4            ;Is the the FSSelect gadget?
  1195.      bne.s    dgnotselect        ;Nope
  1196.     jsr    _ConcatPathString     ;Concat final output text, return
  1197.     bra    dogaddone
  1198.  
  1199. dgnotselect:
  1200. * FSCancelGad
  1201.     cmpi.w    #2,d4            ;Is it the FSCancel Gadget?
  1202.      bne.s    dgnotcancel        ;Nope
  1203.     move.w    #1,_FSDone        ;Global signal that we're done
  1204.     movea.l    _FSReq,a0        ;a0 = fsreq
  1205.     movea.l    fs_fullname(a0),a0    ;a0 = fsreq->fullname
  1206.     clr.b    (a0)            ;Return filename == ""
  1207.     bra    dogaddone
  1208.  
  1209. dgnotcancel:
  1210. * UndoGad
  1211.     cmpi.w    #3,d4            ;Undo?
  1212.      bne.s    dgnotundo
  1213.     movea.l    _FSPathInfo,a0    ;Copy OldFSPathBuf to FSPathInfo.Buffer
  1214.     movea.l    _OldFSPathBuf,a1
  1215.     jsr    astrcpy            ;astrcpy(FSPathInfo.Buffer, OldFSPathBuf)
  1216.     bra    dgnewdir        ;Process new directory
  1217.  
  1218. dgnotundo:
  1219. * Dev1Gad
  1220.     cmpi.w    #20,d4            ;Is it the first Device Gadget?
  1221.      bne.s    dgnotram        ;Nope
  1222.     movea.l    _CurDevNames+12,a1    ;Push the name text
  1223. dgdevs:
  1224.     movea.l    _FSPathInfo,a0    ;Destination text
  1225.     jsr    astrcpy            ;Copy new path
  1226.     bra    dgnewdir        ;Now set new directory
  1227.  
  1228. dgnotram:
  1229.     cmpi.w    #21,d4            ;Is it the second Device Gadget?
  1230.      bne.s    dgnotdf0        ;Nope
  1231.     movea.l    _CurDevNames+8,a1    ;Push the name text
  1232.     bra    dgdevs            ;Change path
  1233.  
  1234. dgnotdf0:
  1235.     cmpi.w    #22,d4            ;Is it the third Device Gadget?
  1236.      bne.s    dgnotnil1        ;Nope
  1237.     movea.l    _CurDevNames+4,a1    ;Push the name text
  1238.     bra    dgdevs            ;Set the path
  1239.  
  1240. dgnotnil1:
  1241.     cmpi.w    #23,d4            ;Is it the fourth Device Gadget?
  1242.      bne.s    dgnotnil2        ;Nope
  1243.     movea.l    _CurDevNames,a1    ;Push the name text
  1244.     bra    dgdevs            ;And set the new path
  1245.  
  1246. dgnotnil2:
  1247. * RootGad
  1248.     cmpi.w    #24,d4            ;Is it the ROOT gadget?
  1249.      bne.s    dgnotroot        ;Nope
  1250.     jsr    _SetRootDir        ;Set root directory!
  1251.     bra    dogaddone        ;Done
  1252.  
  1253. dgnotroot:
  1254. * ParentGad
  1255.     cmpi.w    #25,d4            ;Is it the Parent gadget?
  1256.      bne.s    dgnotpar        ;Nope
  1257.     jsr    _SetParentDir        ;Change to parent directory
  1258.     bra    dogaddone        ;Done!
  1259.  
  1260. dgnotpar:
  1261. * FSPatternGad
  1262.     cmpi.w    #30,d4            ;Maybe its the pattern text gadget?
  1263.      bne.s    dgnotpattern
  1264.     jsr    _FSMatchPattern        ;Otherwise attempt to match new pattern
  1265.     bra    dogaddone        ;We're done!
  1266.  
  1267. dgnotpattern:
  1268. * FSFileGad
  1269.     cmpi.w    #31,d4            ;Is it the file text gadget?
  1270.      bne.s    dgnotfileg        ;Nope
  1271.     jsr    _FSFileFunc
  1272.     jsr    _ConcatPathString    ;Form final path text
  1273.     btst.b    #1,_fsflags+1    ;FS_NO_STRING_EXIT?
  1274.      beq    dogaddone
  1275.     clr.w    _FSDone
  1276.     bra    dogaddone
  1277. 1$
  1278.     movea.l    _FSFileInfo,a0
  1279.     tst.b    (a0)            ;Really a filename here?
  1280.      bne.s    2$            ;yep
  1281.     btst.b    #2,_fsflags+1    ;FS_NO_STRING_OKAY?
  1282.      beq.s  2$            ;Nope
  1283.      bra    dogaddone        ;let user exit with no filename
  1284. 2$
  1285.     clr.w    _FSDone        ;Else we ain't done yet!
  1286.     bra    dogaddone
  1287.  
  1288. dgnotfileg:
  1289. * FSPathGad
  1290.     cmpi.w    #32,d4            ;Is it the path text gadget?
  1291.      bne.s    dgnotpath        ;Nope
  1292.     movea.l    _FSPathInfo,a2    ;Grab pointer to path text
  1293.     movea.l    a2,a0
  1294.     jsr    astrlen            ;Determine length
  1295.     subq.w    #1,d0            ;Move back to last BYTE
  1296.      blt.s    dgnotdamnsla        ;Oops, null text!
  1297.  
  1298.     cmpi.b    #'/',0(a2,d0.w)        ;Is the last char a slash?
  1299.      bne.s    dgnotdamnsla        ;Nope, don't have to tromp it
  1300.  
  1301. 1$      cmpi.b    #'/',0(a2,d0.w)        ;Check for a trailing slash
  1302.          bne.s    2$            ;Didn't find another
  1303.     clr.b    0(a2,d0.w)        ;Clobber this slash
  1304.     subq.w    #1,d0            ;Dec character pointer
  1305.      bne.s    1$            ;till we run out of slashes or chars
  1306.  
  1307. 2$    jsr    _FSPutPath        ;Refresh path text
  1308. dgnotdamnsla:
  1309.     jsr    _FSDirFunc        ;Do fsreq->dirfunc, if there is one
  1310.     tst.w    d0            ;Ignore new dir?
  1311.      beq.s    1$            ;Nope
  1312.     jsr    _SetParentDir        ;Else chop off the new path
  1313.     jsr    _FSPutPath        ;Update string gad
  1314.     clr.w    _fsvirgindir    ;Virgin again
  1315.     bra.s    dogaddone        ;All done
  1316. 1$
  1317.     move.l    _FSWin,-(sp)
  1318.     pea    _FSFileGad
  1319.     jsr    _MyActivateGad        ;Activate file text gadget
  1320.     addq.w    #8,sp
  1321.     bra.s    dgnewdir        ;Set new path, read new dir
  1322.  
  1323. dgnotpath:
  1324. * Slide Gadget
  1325.     cmpi.w    #33,d4            ;Is it the SlideGadget?
  1326.      bne.s    dgnotslide        ;nope
  1327.     jsr    _FSDoSlideGadget    ;Else it's been released, update position
  1328.     bra.s    dgresetarrows        ;Done here, reset timer
  1329.  
  1330. dgnotslide:
  1331. * Arrow gadgets
  1332.     cmpi.w    #40,d4            ;Is it one of the four arrows gadgets?
  1333.      blt.s    dogaddone
  1334.     cmpi.w    #43,d4
  1335.      bgt.s    dogaddone
  1336. dgresetarrows:
  1337.     clr.w    _FSCountDown    ;Kill any timer requests in progress
  1338.     bra.s    dogaddone
  1339.  
  1340. dgnewdir:
  1341.     move.w    #1,_fsvirgindir    ;Set flag to read new directory!
  1342.  
  1343. dogaddone:
  1344.     movem.l    (sp)+,d4/a2
  1345.     rts
  1346.  
  1347. * --------------------------------------------------------------------- *
  1348. * VOID FillFileNode(tnode)
  1349. *   struct file_node *tnode;
  1350. * --------------------------------------------------------------------- *
  1351. ffnnode    EQU    4+4*4
  1352.  
  1353.     XDEF    _FillFileNode
  1354. _FillFileNode:
  1355.     movem.l    d2/a2-a3/a6,-(sp)
  1356.  
  1357.     movea.l    ffnnode(sp),a0        ;a0 = tnode passed
  1358.     movea.l    fn_info(a0),a2        ;a2 = tinfo = tnode->info
  1359.     movea.l    _FSFib,a3        ;a3 = FSFib
  1360.  
  1361.     move.l    fib_Size(a3),nd_filesize(a2) ;tinfo->filesize = FSFib->fib_Size
  1362.     move.l    fib_DateStamp+0(a3),nd_days(a2) ;tinfo->day = FSFib->fib_DateStamp.ds_Days
  1363.     move.l    fib_DateStamp+4(a3),nd_minutes(a2)
  1364.     move.l    fib_DateStamp+8(a3),nd_ticks(a2)
  1365.  
  1366.     pea    fib_DateStamp(a3)
  1367.     jsr    _FibFileDate
  1368.     addq.w    #4,sp
  1369.  
  1370.     movea.l    d0,a1
  1371.     lea    nd_alphadata(a2),a0    ;a0 = tinfo->alphadata
  1372.     jsr    astrcpy            ;a0 = astrcpy(&tinfo->alphadata[0], FibFileDate(&FSFib->DateStamp))
  1373.  
  1374.     tst.l    fib_DirEntryType(a3)    ;If < 0 it is a file
  1375.      bge.s    ffnisdir        ;>= 0, it is a dir
  1376.  
  1377. ffnisfile:
  1378.     move.w    #1,nd_filetype(a2)    ;tinfo->filetype = 1
  1379.     move.w    #FPEN,nd_textcolor(a2)    ;tinfo->textcolor = FPEN
  1380.  
  1381.     move.l    a0,-(sp)
  1382.     move.l    fib_Size(a3),-(sp)
  1383.     pea    _FSSizeFmtStr
  1384.     move.l    a0,-(sp)
  1385.     jsr    _sprintf        ;sprintf(a0, "%8ld ", FSFib->fib_Size)
  1386.     lea    12(sp),sp
  1387.     movea.l    (sp)+,a0
  1388.     adda.w    #9,a0            ;Skip filesize part of message
  1389.     bra.s    ffnsetname
  1390.  
  1391. ffnisdir:
  1392.     move.w    #2,nd_filetype(a2)    ;tinfo->filetype = 2
  1393.     move.w    #DPEN,nd_textcolor(a2)    ;tinfo->textcolor = DPEN
  1394.  
  1395.     lea    _FSDirFmtStr,a1
  1396.     jsr    astrcpy            ;astrcpy(dest, FSDirFmtStr)
  1397.  
  1398. ffnsetname:
  1399.     moveq    #0,d0
  1400.     lea    fib_FileName(a3),a1    ;a1 = FSFib->fib_FileName
  1401. 1$    move.b    (a1)+,d1
  1402.      beq.s    2$            ;Hit null, see if we need to pad
  1403.     move.b    d1,(a0)+        ;copy a char, till null
  1404.     addq.w    #1,d0            ;i++
  1405.     cmpi.w    #30,d0            ;Max chars yet?
  1406.      bcs    1$
  1407.  
  1408. 2$    move.w    d0,nd_namelength(a2)    ;tinfo->namelength = i
  1409.     move.b    #' ',d1
  1410.     bra.s    4$            ;Append spaces till 30 chars
  1411. 3$    move.b    d1,(a0)+
  1412.     addq.w    #1,d0
  1413. 4$    cmpi.w    #30,d0
  1414.      bcs    3$
  1415.  
  1416.     clr.b    (a0)            ;Null terminate at 31st char
  1417.  
  1418. ffnsetshow:
  1419.     movea.l    ffnnode(sp),a2
  1420.     moveq    #1,d0
  1421.     movea.l    a2,a0            ;a0 = tnode
  1422.     jsr    _FSValidateEntry    ;FSValidateEntry(tnode, 1)
  1423.  
  1424. * Now insert the node into list according to sort type
  1425. ffninsert:
  1426.     movea.l    _fnList,a3
  1427.     movea.l    MLH_HEAD(a3),a3        ;a3 = fnList->lh_Head
  1428.  
  1429.     movea.l    _FSReq,a0
  1430.     move.w    fs_sorttype(a0),d2    ;d0 = FSReq->sorttype
  1431.  
  1432. 1$
  1433.     tst.l    fn_Node+MLN_SUCC(a3)    ;Is this the end of the list?
  1434.      beq.s    2$            ;Nope, insert it here
  1435.  
  1436.     move.l    fn_info(a3),a1        ;Push existing node->info
  1437.     move.l    fn_info(a2),a0        ;Push tnode->info
  1438.     move.w    d2,d0            ;Push sort type
  1439.     jsr    _CompareNodes        ;Compare info's according to sort type
  1440.     tst.w    d0            ;Is a0 > a1?
  1441.      beq.s    2$            ;nope, found insertion point
  1442.     movea.l    fn_Node+MLN_SUCC(a3),a3    ;oldnode = oldnode->next
  1443.     bra    1$            ;Nope, keep looking
  1444.  
  1445. 2$
  1446.     movea.l    _fnList,a0
  1447.     movea.l    a2,a1
  1448.     move.l    fn_Node+MLN_PRED(a3),a2
  1449.     SYS    Insert,4
  1450.  
  1451. ffndone:
  1452.     movem.l    (sp)+,d2/a2-a3/a6
  1453.     rts
  1454.  
  1455. * --------------------------------------------------------------------- *
  1456. * VOID FSValidateEntry(tnode, mode)
  1457. *                       a0     d0
  1458. * --------------------------------------------------------------------- *
  1459.     XDEF    _FSValidateEntry
  1460. _FSValidateEntry:
  1461.     movem.l    d2-d3/a2,-(sp)
  1462.  
  1463. * See if the Acceptor likes this node name
  1464.     move.l    d0,d3            ;d3 = mode
  1465.     movea.l    a0,a2            ;a2 = tnode
  1466.     move.l    a2,-(sp)
  1467.     jsr    _FSAcceptEntry        ;if (FSAcceptEntry(tnode) == 0)
  1468.     addq.w    #4,sp
  1469.     tst.w    d0
  1470.      bne.s    1$
  1471.  
  1472. * Don't display this node
  1473.     movea.l    fn_info(a2),a0
  1474.     clr.w    nd_showit(a0)        ;tnode->info->showit = 0;
  1475.     move.w    #-1,fn_idnum(a2)    ;tnode->idnum = -1
  1476.     bra.s    4$            ;And return
  1477.  
  1478. * Accept this node for display
  1479. 1$    movea.l    fn_info(a2),a0
  1480.     move.w    #1,nd_showit(a0)    ;else tnode->info->showit = 1;
  1481.  
  1482.     moveq    #0,d2
  1483.     move.w    _fsnumentries,d2    ;Grab entry number for this node
  1484.      bne.s    2$            ;Not first entry
  1485.     move.l    a2,_topfin        ;topnode = tnode, first visible node
  1486. 2$
  1487.     move.w    d2,fn_idnum(a2)        ;tnode->idnum = fsnumentries
  1488.     addq.w    #1,_fsnumentries    ;fsnumentries++, one more visible entry
  1489.     clr.w    _fsneedshow     ;fsneedshow = 0, needs sorting
  1490.  
  1491. * If we haven't filled display area, show this entry
  1492.     cmpi.w    #10,d2            ;> 10 entries already?
  1493.      bcc.s    3$            ;Yep, just set the knob
  1494.  
  1495.     lea    _FSFileNodes,a0
  1496.     move.w    d2,d0            ;Grab entry number
  1497.     lsl.w    #2,d0            ;Convert to long table offset
  1498.     move.l    a2,0(a0,d0.w)        ;FSFileNodes[fsnumentries] = tnode
  1499.  
  1500.     move.l    d2,-(sp)
  1501.     jsr    _FSEnableFGad        ;FSEnableFGad(fsnumentries)
  1502.     addq.w    #4,sp
  1503.     bra.s    4$            ;Skip setting knob, it is still full size
  1504.  
  1505. 3$
  1506.     tst.w    d3            ;Want slide update?
  1507.      beq.s    4$            ;Nope
  1508.  
  1509. ;    btst.b    #7,_FSSlideGad+gg_Flags+1 ;User has slide gadget in use?
  1510. ;     bne.s    4$            ;Yes, don't refresh it while in use
  1511.  
  1512. * Calc new knob size and refresh
  1513.     btst.l    #0,d2            ;(idnum % 2) == 0?
  1514.      beq.s    4$            ;Yep, don't reset on even values
  1515.     jsr    _FSResetKnob
  1516.  
  1517. 4$
  1518.     movem.l    (sp)+,d2-d3/a2
  1519.     rts
  1520.  
  1521. * --------------------------------------------------------------------- *
  1522. * Update FileTexts list, redisplay
  1523. * Renumber list, find new topfin
  1524. * --------------------------------------------------------------------- *
  1525.     XDEF    _FSUpdateSort
  1526. _FSUpdateSort:
  1527.     move.w    _fsneedshow,d0
  1528.      blt.s    3$
  1529.     move.w    _fsnumentries,d1
  1530.      beq.s    2$
  1531.     subi.w    #10,d1            ;Less max number of visible files
  1532.     move.w    _FSSlideProp+4,d0    ;Grab current vpot
  1533.     mulu    d1,d0            ;Times position percentage
  1534.     addi.l    #32768,d0
  1535.     clr.w    d0
  1536.     swap    d0
  1537.     jsr    _FSResetNumEntries
  1538.     jsr    _FSSetFileGads
  1539. 2$
  1540.     move.w    #-1,_fsneedshow
  1541.     moveq    #0,d0
  1542.  
  1543. 3$    tst.w    d0
  1544.     rts
  1545.  
  1546. * --------------------------------------------------------------------- *
  1547. * VOID FSResetNumEntrys(idnum)
  1548. *                       d0:16
  1549. * --------------------------------------------------------------------- *
  1550.     XDEF    _FSResetNumEntries
  1551. _FSResetNumEntries:
  1552.     move.l    a2,-(sp)
  1553.  
  1554.     movea.l    _fnList,a2        ;Grab List
  1555.     movea.l    MLH_HEAD(a2),a2        ;Head of list
  1556.  
  1557.  
  1558.     moveq    #0,d1            ;i = 0
  1559.  
  1560. 1$    tst.l    fn_Node+MLN_SUCC(a2)    ;End of list?
  1561.      beq.s    5$
  1562.     movea.l    fn_info(a2),a0        ;a0 = tnode->info
  1563.     tst.w    nd_showit(a0)        ;Visible?
  1564.      bne.s    2$            ;Yep
  1565.     move.w    #-1,fn_idnum(a2)    ;Else tnode->idnum = -1
  1566.     bra.s    4$            ;Next node
  1567. 2$    move.w    d1,fn_idnum(a2)        ;tnode->idnum = i
  1568.     cmp.w    d1,d0            ;if (idnum == oldidnum)
  1569.      bne.s    3$    
  1570.     move.l    a2,_topfin        ; topfin = tnode;
  1571. 3$
  1572.     addq.w    #1,d1            ;i++
  1573. 4$
  1574.     movea.l    fn_Node+MLN_SUCC(a2),a2    ;tnode = tnode->fn_Node.mln_Succ
  1575.     bra    1$            ; Check next node
  1576.  
  1577. 5$
  1578.     move.w    d1,_fsnumentries    ;Update number of entries
  1579.     
  1580.     movea.l    (sp)+,a2
  1581.     rts
  1582.  
  1583. * --------------------------------------------------------------------- *
  1584. * LONG FSAcceptEntry(struct file_node *tnode);
  1585. * Decide whether given tnode is displayable.
  1586. * Return 0L for ignore this node, 1L for valid node.
  1587. * --------------------------------------------------------------------- *
  1588. aftnode    EQU    8
  1589. aftname    EQU    -48
  1590.  
  1591.     XDEF    _FSAcceptEntry
  1592. _FSAcceptEntry:
  1593.     link    a5,#aftname
  1594.     movem.l    a2-a3,-(sp)
  1595.  
  1596.     movea.l    aftnode(a5),a2        ;Grab tnode
  1597.     movea.l    fn_info(a2),a3        ;Grab tnode->info
  1598.  
  1599. * Copy tnode->info->alphadata name section to stack, null terminate
  1600.     move.w    nd_namelength(a3),d0    ;Push tinfo->namelength
  1601.     lea    nd_alphadata+26(a3),a1    ;Push tinfo->alphadata + 26
  1602.     lea    aftname(a5),a0        ;Push destination
  1603.     jsr    astrncpy        ;Copy and null terminate
  1604.  
  1605. * If there is a special match function defined, use that...
  1606.     movea.l    _FSReq,a0
  1607.     tst.l    fs_matchfunc(a0)    ;If FSReq->matchfunc != 0
  1608.      beq.s    1$
  1609.     move.l    aftnode(a5),-(sp)
  1610.     pea    aftname(a5)
  1611.     move.l    _FSReq,-(sp)
  1612.     move.l    fs_matchfunc(a0),a0
  1613.     jsr    (a0)            ;return((FSReq->matchfunc)(FSReq, name, tnode)
  1614.     lea    12(sp),sp
  1615.     bra.s    aftdone
  1616.  
  1617. * Otherwise use built-in acceptor routine
  1618. 1$    cmpi.w    #2,nd_filetype(a3)    ;Is tinfo->filetype == 2? (a directory)
  1619.      beq.s    aftisdir        ;Yep, we need it in list
  1620.  
  1621. * Check file name against patterns
  1622.     btst.b    #6,_fsflags+1    ;Want dirs only?
  1623.      bne.s  aftwrongpat        ;Yep, ignore all files
  1624.  
  1625.     pea    _FSIgnorePat    ;See if it matches the ignore text
  1626.     pea    aftname(a5)
  1627.     jsr    _wildmatch
  1628.     addq.w    #8,sp
  1629.     tst.w    d0            ;Did it match the ignore text?
  1630.      bne.s    aftwrongpat        ;Yep, ignore this file
  1631.  
  1632.     move.l    _FSPatternInfo,-(sp) ;See if it matches desired pattern
  1633.     pea    aftname(a5)
  1634.     jsr    _wildmatch
  1635.     addq.w    #8,sp
  1636.     tst.w    d0            ;Did it match?
  1637.      beq.s    aftwrongpat        ;Nope, skip it
  1638.     bra.s    aftgoodpat        ;Else accept this file
  1639.  
  1640. aftisdir:
  1641.     btst.b    #5,_fsflags+1    ;This is a dir, want files only?
  1642.      bne.s    aftwrongpat        ;Yep, ignore this dir
  1643.  
  1644. aftgoodpat:
  1645.     moveq    #1,d0            ;Accept this entry
  1646.     bra.s    aftdone
  1647.  
  1648. aftwrongpat:
  1649.     moveq    #0,d0            ;Ignore this entry
  1650.  
  1651. aftdone:
  1652.     movem.l    (sp)+,a2-a3
  1653.     unlk    a5
  1654.     rts
  1655.  
  1656. * --------------------------------------------------------------------- *
  1657. * VOID FSMatchPattern(VOID);
  1658. * Called when path or pattern has changed - rematch all entries
  1659. * against the new pattern, display entries that match.
  1660. * --------------------------------------------------------------------- *
  1661.     XDEF    _FSMatchPattern
  1662. _FSMatchPattern:
  1663.     movem.l    d4/a2-a3/a6,-(sp)
  1664.  
  1665. * Pattern match list against new pattern, flag unwanted names 
  1666.     movea.l    _FSPatternInfo,a0     ;Grab pattern
  1667.     tst.b    (a0)            ;Null pattern text?
  1668.      bne.s    mnpnotnop        ;Nope, process it
  1669.  
  1670.     move.b    #'*',(a0)+        ;Otherwise put back wildstar
  1671.     clr.b    (a0)            ;Null terminate
  1672.     lea    _FSPatternInfo,a0    ;Grab stringinfo
  1673.     move.w    #1,8(a0)        ;FSPatternInfo.BufferPos = 1;
  1674.  
  1675.     lea    _FSPatternGad,a0
  1676.     movea.l    _FSWin,a1
  1677.     suba.l    a2,a2
  1678.     moveq    #1,d0
  1679.     SYS    RefreshGList,_IntuitionBase ;Refresh pattern text gadget
  1680.  
  1681.     move.l    _FSWin,-(sp)
  1682.     pea    _FSPatternGad
  1683.     jsr    _MyActivateGad        ;MyActivateGad(&FSPatternGad, FSWin)
  1684.     addq.w    #8,sp
  1685.     bra.s    mnpdone            ;Make the user type something else in
  1686.  
  1687. mnpnotnop:
  1688.     movea.l    _fnList,a0
  1689.     move.l    MLH_HEAD(a0),a0
  1690.     tst.l    fn_Node+MLN_SUCC(a0)    ;Do we have any files to match?
  1691.      beq.s    mnpdone            ;Nope, nothing to do
  1692.  
  1693. * Reset knob to full height, zero position
  1694.     clr.w    _fsnumentries    ;Clear fsnumentries count
  1695.     clr.w    _fsvposition
  1696.     move.w    #$ffff,_fsvheight
  1697.     jsr    _FSSetKnob        ;Show new knob
  1698.  
  1699. * Disable all file "gadgets"
  1700.     jsr    _FSDisableAllFGads
  1701.  
  1702. * Scan list, enable/flag entries that match new pattern
  1703.     movea.l    _fnList,a2        ;tnode = fnList
  1704.     movea.l    MLH_HEAD(a2),a2        ;tnode = head node
  1705.     clr.l    _topfin        ;Clear out top/bot display pointers
  1706. 1$
  1707.     tst.l    fn_Node+MLN_SUCC(a2)    ;End of list?
  1708.      beq.s    2$
  1709.  
  1710.     moveq    #0,d0
  1711.     movea.l    a2,a0
  1712.     jsr    _FSValidateEntry    ;FSValidateEntry(tnode, 0)
  1713.     movea.l    fn_Node+MLN_SUCC(a2),a2    ;tnode = tnode->fn_Node.mln_Succ
  1714.     bra    1$            ;Nope, process this one too
  1715. 2$
  1716.     move.w    #-1,_fsneedshow    ;Clear reshow/sort flag, list valid
  1717.     cmpi.w    #10,_fsnumentries    ;Found some entries?
  1718.      bls.s    mnpsettitle        ;Yep, skip setting knob again
  1719.     jsr    _FSResetKnob        ;Show new knob size
  1720.  
  1721. mnpsettitle:
  1722.     tst.w    _fsnumentries    ;Got any matches to pattern?
  1723.      bne.s    mnpmatchedsome        ;Yep
  1724.  
  1725.     move.w    #24,_fstitstatus    ;"Nothing matched PATTERN"
  1726.     bra.s    mnpnewtit
  1727.  
  1728. mnpmatchedsome:
  1729.     move.w    #29,_fstitstatus    ;"Select a file..."
  1730.  
  1731. mnpnewtit:
  1732.     jsr    _FSWinTitle        ;Show final title status
  1733.  
  1734. mnpdone:
  1735.     movem.l    (sp)+,d4/a2-a3/a6
  1736.     rts
  1737.  
  1738. * ----------------------------------------------------------------------
  1739. ; VOID ConcatPathString(VOID)
  1740. ;
  1741. ;  If the file text is non-NULL, concat path text and file text,
  1742. ; set global exit flag to show user selected a filename.
  1743. * ----------------------------------------------------------------------
  1744.     XDEF    _ConcatPathString
  1745. _ConcatPathString:
  1746. * Try to add path prefix
  1747.     move.l    _FSFileInfo,-(sp)
  1748.     move.l    _FSPathInfo,-(sp)
  1749.     movea.l    _FSReq,a0        ;Grab final pathtext
  1750.     movea.l    fs_fullname(a0),a0
  1751.     move.l    a0,-(sp)
  1752.     jsr    _ConcatDirFile        ;ConcatDirFile(FSReq->fullname, FSPathInfo->Buffer, FSFileInfo->Buffer)
  1753.     lea    12(sp),sp
  1754.  
  1755. * Did the user select a filename yet?
  1756.     movea.l    _FSFileInfo,a0
  1757.     tst.b    (a0)            ;First byte of name null?
  1758.      bne.s    1$            ;Nope, must be okay
  1759.     btst.b    #2,_fsflags+1    ;(FSFlags & FS_NO_STRING_OKAY) == 0?
  1760.      beq.s    2$            ;Yep, user can't exit till something is entered
  1761. 1$
  1762. * Flag main loop to exit
  1763.     move.w    #1,_FSDone
  1764. 2$
  1765.     rts
  1766.  
  1767. * --------------------------------------------------------------------- *
  1768. * VOID __stdargs ConcatDirFile(BYTE *, BYTE *, BYTE *)
  1769. * --------------------------------------------------------------------- *
  1770.     XDEF    _ConcatDirFile
  1771. _ConcatDirFile:
  1772.     movem.l    4(sp),a0-a1        ;grab dest, dirname
  1773.     tst.b    (a1)            ;Is there a dirname here?
  1774.      beq.s    1$            ;Nope
  1775.     jsr    astrcpy            ;astrcpy(dest, dirname)
  1776.         movea.l    12(sp),a1        ;grab filename
  1777.     tst.b    (a1)            ;Is there a filename?
  1778.      beq.s    2$            ;Nope, don't concat a slash
  1779.     move.b    -1(a0),d0        ;d0 = dest[strlen(dest - 1)]
  1780.     cmpi.b    #':',d0            ;Already has a colon?
  1781.      beq.s    1$            ;Yep
  1782.     cmpi.b    #'/',d0            ;Already has a slash?
  1783.      beq.s    1$            ;Yep
  1784.     move.b    #'/',(a0)+        ;Append a slash
  1785.     clr.b    (a0)            ;Terminate
  1786. 1$
  1787.     movea.l    12(sp),a1
  1788.     jsr    astrcpy            ;astrcpy(dest, name)
  1789. 2$
  1790.     rts
  1791.  
  1792. * ------------------------------------------------------------------------
  1793. * VOID FSDoSlideGadget(VOID)
  1794. *
  1795. *  Process the current slide gadget position, scroll file entries
  1796. * to match current position.
  1797. * ------------------------------------------------------------------------
  1798.     XDEF    _FSDoSlideGadget
  1799. _FSDoSlideGadget:
  1800.     movem.l    d4-d5,-(sp)
  1801.  
  1802.     jsr    _FSUpdateSort
  1803.      beq    dsgdone
  1804.  
  1805.     cmpi.w    #10,_fsnumentries    ;Do we have less than 10 entries?
  1806.      blt    dsgdone            ;Yep, can't move anyhow
  1807.  
  1808.     moveq    #0,d0
  1809.     move.w    _FSSlideProp+4,d0    ;Grab new vpot
  1810.     cmp.w    _fsvposition,d0     ;Has it moved?
  1811.      beq    dsgdone            ;Nope
  1812.  
  1813.     move.w d0,_fsvposition     ;Otherwise update position
  1814.  
  1815.     move.w    _fsnumentries,d4    ;Grab number of entries
  1816.     subi.w    #10,d4            ;Less max number of visible files
  1817.     mulu    d0,d4            ;Times position percentage
  1818.     addi.l    #32768,d4
  1819.     clr.w    d4
  1820.     swap    d4
  1821.  
  1822.     movea.l    _topfin,a0        ;Grab top node
  1823.     cmp.w    fn_idnum(a0),d4        ;Is node->idnum the same as newpos?
  1824.      beq.s    dsgdone            ;Yep, don't have to move it
  1825.      bcc.s    dsgscrup        ;newpos is lower, scroll up
  1826.  
  1827. **************
  1828. * Scroll Down
  1829. **************
  1830.     move.w    fn_idnum(a0),d0        ;Grab topfin->idnum
  1831.     sub.w    d4,d0            ;i = idnum - newpos
  1832.     cmpi.w    #8,d0            ;Need to scroll more than 8?
  1833.      ble.s    dsgssdwn        ;Nope, use slow scroll
  1834.  
  1835. dsgdwn1:
  1836.     cmp.w    fn_idnum(a0),d4        ;Is topfin->idnum == newpos yet?
  1837.      beq.s    dsgredo            ;Yep, we are done
  1838.  
  1839. dsgpretop:
  1840.     movea.l    fn_Node+MLN_PRED(a0),a0    ;topfin = topfin->fn_Node.mln_Pred
  1841.     tst.w    fn_idnum(a0)        ;Is this idnum >= 0?
  1842.      blt.s    dsgpretop        ;Nope, keep looking
  1843.     bra.s    dsgdwn1            ;Check this new position
  1844.  
  1845. dsgssdwn:
  1846.     move.l    d0,-(sp)
  1847.     jsr    _FSScrollDownGads    ;Scroll entries down d5 times
  1848.     addq.w    #4,sp
  1849.     bra.s    dsgdone
  1850.  
  1851. ************
  1852. * Scroll Up
  1853. ************
  1854. dsgscrup:
  1855.     move.w    d4,d5            ;Grab newpos
  1856.     sub.w    fn_idnum(a0),d5        ;i = newpos - node->idnum
  1857.     cmpi.w    #8,d5            ;i > 8?
  1858.      ble.s    dsgssup            ;Nope, use slow scroll
  1859.  
  1860. dsgmvup1:
  1861.     cmp.w    fn_idnum(a0),d4        ;Is topfin->idnum == newpos yet?
  1862.      beq.s    dsgredo            ;Yep, we are done
  1863.  
  1864. dsgnxttop:
  1865.     movea.l    fn_Node+MLN_SUCC(a0),a0    ;topfin = topfin->fn_Node.mln_Succ
  1866.     tst.w    fn_idnum(a0)        ;Is this a valid entry?
  1867.      blt.s    dsgnxttop        ;Nope, move on
  1868.     bra.s    dsgmvup1
  1869.  
  1870. dsgredo:
  1871.     move.l    a0,_topfin        ;Set new top and bottom
  1872.     jsr    _FSSetFileGads        ;Redraw all the file entries
  1873.     bra.s    dsgdone            ;We're done
  1874.  
  1875. dsgssup:
  1876.     move.l    d5,-(sp)
  1877.     jsr    _FSScrollUpGads        ;Scroll the entries up d5 times
  1878.     addq.w    #4,sp
  1879.  
  1880. dsgdone:
  1881.     movem.l    (sp)+,d4-d5
  1882.     rts
  1883.  
  1884. * --------------------------------------------------------------------
  1885. * VOID FSStartScrollGad(gadcode)
  1886. *   ULONG gadcode;
  1887. * Given Gadget ID code, respond to first user click on a arrow gadget.
  1888. * Reset the timer.device so that .25 seconds delay occurs before
  1889. * the autorepeat kicks in.
  1890. * --------------------------------------------------------------------
  1891.     XDEF    _FSStartScrollGad
  1892. _FSStartScrollGad:
  1893.     move.w    6(sp),d0    ;Grab gadget code
  1894.     subi.w    #33,d0        ;Slide gad
  1895.      bne.s    1$
  1896.     jsr    _FSDoSlideGadget
  1897.     clr.w    _FSCountDown
  1898.     rts
  1899.  
  1900. 1$
  1901.     subi.w    #7,d0        ;33+7=40, UpGad
  1902.      bne.s    2$
  1903.     pea    1
  1904. 11$    jsr    _FSScrollFileGads
  1905.     addq.w    #4,sp
  1906.     bra.s    ssgdone
  1907. 2$
  1908.     subq.w    #1,d0        ;33+7+1=41, DownGad
  1909.      bne.s    3$
  1910.     pea    0
  1911.     bra    11$
  1912. 3$
  1913.     subq.w    #1,d0        ;33+7+2=42, UpDev
  1914.      bne.s    4$
  1915.     pea    1
  1916. 33$    jsr    _FSScrollDevGads
  1917.     addq.w    #4,sp
  1918.     bra.s    ssgdone
  1919. 4$
  1920.     subq.w    #1,d0        ;33+7+3=43, DownDev
  1921.      bne.s    ssgrts
  1922.     pea    0
  1923.     bra    33$
  1924.  
  1925. ssgdone:
  1926.     move.w    #4,_FSCountDown
  1927. ssgrts:
  1928.     rts
  1929.  
  1930. * -----------------------------------------------------------------------
  1931. * FSScrollFileGads(direction)
  1932. *   BOOL direction;
  1933. *
  1934. * Scroll the file entries up or down by 1
  1935. * if (direction == 0)
  1936. *   scrollup;
  1937. * else
  1938. *   scrolldown;
  1939. * -----------------------------------------------------------------------
  1940.     XDEF    _FSScrollFileGads
  1941. _FSScrollFileGads:
  1942.  
  1943. ;if (fsnumentries > 10)
  1944.     cmpi.w    #10,_fsnumentries    ;Less than 10 entries?
  1945.      ble.s    sfgdone            ;Yep, can't scroll anyhow
  1946.  
  1947. ;if (direction)
  1948. ;  FSScrollDownGads(1);
  1949.     tst.w    6(sp)            ;ScrollDown?
  1950.      beq.s    sfgup            ;Nope, scroll up
  1951.     pea    1
  1952.     jsr    _FSScrollDownGads
  1953.     addq.w    #4,sp
  1954.     bra.s    sfgpos
  1955.  
  1956. sfgup:
  1957. ;FSScrollUpGads(1)
  1958.     pea    1
  1959.     jsr    _FSScrollUpGads
  1960.     addq.w    #4,sp
  1961.  
  1962. sfgpos:
  1963. * Reset the slide knob position the display movement
  1964.     jsr    _FSSetKnobPos
  1965.     jsr    _FSSetKnob        ;Set new knob position
  1966.  
  1967. sfgdone:
  1968.     rts
  1969.  
  1970. * -------------------------------------------------------------------------
  1971. ; FSScrollUpGads(count)
  1972. ;  LONG count;
  1973. ;
  1974. ;  Single-step scroll the file entries up count times.
  1975. * -------------------------------------------------------------------------
  1976.     XDEF    _FSScrollUpGads
  1977. _FSScrollUpGads:
  1978.     link    a5,#0
  1979.     movem.l    d2-d7/a2/a6,-(sp)
  1980.  
  1981.     jsr    _FSUpdateSort
  1982.      beq.s    sugdone
  1983.  
  1984.     movea.l    _FSRPort,a2
  1985.  
  1986. ;for (i = 0; i < count; i++)
  1987.     moveq    #0,d7
  1988.     bra.s    sugchk1
  1989.  
  1990. sugloop1:
  1991. * If the bottom entry is not the last entry, scroll it up
  1992.     movea.l    _topfin,a0        ;Grab top visible node
  1993.     move.w    fn_idnum(a0),d0        ;Grab id number
  1994.     addi.w    #11,d0            ;Plus 11
  1995.     cmp.w    _fsnumentries,d0    ;Compare to last known entry
  1996.      bgt.s    sugdone            ;Yep, can't scroll up any more
  1997.  
  1998. * Bump the top pointer down the list to the next visible entry
  1999.     movea.l    _topfin,a0
  2000. 1$    move.l    fn_Node+MLN_SUCC(a0),a0    ;topfin = topfin->fn_Node.mln_Succ
  2001.     tst.w    fn_idnum(a0)        ;while (topfin->idnum < 0)
  2002.      blt    1$            ;Not a valid entry
  2003.     move.l    a0,_topfin        ;Here's our new top entry node
  2004.  
  2005. * Now reassign the visible file gadget array to the new node list
  2006.     jsr    _FSAssignNodes
  2007.  
  2008. * Display new file entries and redraw borders
  2009. ;ClipBlit(rp, 9L, 24L, rp, 9L, 13L, 447L, 96L, 0xc0L);
  2010.     movea.l    a2,a0
  2011.     moveq    #9,d0
  2012.     moveq    #24,d1
  2013.     movea.l    a2,a1
  2014.     moveq    #9,d2
  2015.     moveq    #13,d3
  2016.     move.l    #447,d4
  2017.     moveq    #96,d5
  2018.     move.l    #$0c0,d6
  2019.     SYS    ClipBlit,_GfxBase
  2020.  
  2021. ;FSEnableFGad(9);
  2022.     move.l    #9,-(sp)
  2023.     jsr    _FSEnableFGad        ;Now draw the new gadget at bottom
  2024.     addq.w    #4,sp
  2025.  
  2026.     addq.w    #1,d7            ;Bump scroll count
  2027.  
  2028. sugchk1:
  2029.     cmp.w    10(a5),d7        ;Have we scrolled enough?
  2030.      blt    sugloop1        ;Nope, do again
  2031.  
  2032. sugdone:
  2033.     movem.l    (sp)+,d2-d7/a2/a6
  2034.     unlk    a5
  2035.     rts
  2036.  
  2037. * -------------------------------------------------------------------------
  2038. ; FSScrollDownGads(count)
  2039. ;   LONG count;
  2040. ;
  2041. ;  Single-step scroll the file entries down count times.
  2042. * -------------------------------------------------------------------------
  2043.     XDEF    _FSScrollDownGads
  2044. _FSScrollDownGads:
  2045.     link    a5,#0
  2046.     movem.l    d2-d7/a2/a6,-(sp)
  2047.  
  2048.     jsr    _FSUpdateSort
  2049.      beq.s    sdgdone
  2050.  
  2051.     movea.l    _FSRPort,a2
  2052.  
  2053. ;for (i = 0; i < count; i++)
  2054.     moveq    #0,d7
  2055.     bra.s    sdgchk1
  2056.  
  2057. sdgloop1:
  2058. ;If the top entry is not the first entry, scroll it down
  2059.     movea.l    _topfin,a0        ;Grab top node
  2060.     tst.w    fn_idnum(a0)        ;idnum == 0?
  2061.      beq.s    sdgdone            ;Yep, can't scroll down any more
  2062.  
  2063. * Bump the top and bottom entry pointers down the list
  2064. 1$    movea.l    fn_Node+MLN_PRED(a0),a0    ;topfin = topfin->fn_Node.mln_Pred
  2065.     tst.w    fn_idnum(a0)        ;while (topfin->idnum < 0)
  2066.      blt    1$
  2067.     move.l    a0,_topfin        ;New topfin
  2068.  
  2069. * Now reassign the visible file gadget array to the new node list
  2070.     jsr    _FSAssignNodes
  2071.  
  2072. * Display new file entries and redraw borders
  2073. ;ClipBlit(rp, 9L, 13L, rp, 9L, 24L, 447L, 96L, 0xc0L)
  2074.     movea.l    a2,a0
  2075.     moveq    #9,d0
  2076.     moveq    #13,d1
  2077.     movea.l    a2,a1
  2078.     moveq    #9,d2
  2079.     moveq    #24,d3
  2080.     move.l    #447,d4
  2081.     moveq    #96,d5
  2082.     move.l    #$0c0,d6
  2083.     SYS    ClipBlit,_GfxBase
  2084.  
  2085. ;FSEnableFGad(0);
  2086.     pea    0
  2087.     jsr    _FSEnableFGad        ;Display the only new "gadget"
  2088.     addq.w    #4,sp
  2089.  
  2090.     addq.w    #1,d7            ;Bump scroll count
  2091.  
  2092. sdgchk1:
  2093.     cmp.w    10(a5),d7        ;Have we scrolled enough?
  2094.      blt    sdgloop1        ;Nope, do again
  2095.  
  2096. sdgdone:
  2097.     movem.l    (sp)+,d2-d7/a2/a6
  2098.     unlk    a5
  2099.     rts
  2100.  
  2101. * -------------------------------------------------------------------
  2102. * VOID FSAssignNodes(VOID)
  2103. * -------------------------------------------------------------------
  2104.     XDEF    _FSAssignNodes
  2105. _FSAssignNodes:
  2106.     movem.l    a2-a3,-(sp)
  2107.  
  2108. ;for (tnode = topfin, i = 0; ;tnode = tnode->next)
  2109.     lea    _FSFileNodes,a3    ;Grab base address of array of filegadgets
  2110.     movea.l    _topfin,a2        ;Grab our top visible filenode
  2111.     moveq    #10,d0            ;Fill 10 gadgets max
  2112. ran1:
  2113.     tst.l    fn_Node+MLN_SUCC(a2)    ;Succ == 0?
  2114.      beq.s    ragdone            ;Ran out of list entries
  2115.  
  2116. ;if (tnode->idnum >= 0)
  2117.     tst.w    fn_idnum(a2)        ;Is this name "visible"?
  2118.      blt.s    ragchkbot        ;Nope, skip it
  2119.     move.l    a2,(a3)+        ;FSFileNodes[i] = tnode
  2120.     subq.w    #1,d0            ;One less slot available
  2121.      beq.s    ragdone            ;Filled all the slots, exit loop
  2122.  
  2123. ragchkbot:
  2124.     movea.l    fn_Node+MLN_SUCC(a2),a2
  2125.     bra    ran1            ;check next node
  2126.  
  2127. ragdone:
  2128.     movem.l    (sp)+,a2-a3
  2129.     rts
  2130.  
  2131. * -----------------------------------------------------------------------
  2132. ; VOID __stdargs FSDoFileGad(Ypos)
  2133. ;   LONG Ypos;
  2134. ;
  2135. ;  Based on the mouse's Ypos passed, select file entry that user clicked.
  2136. * -----------------------------------------------------------------------
  2137.     XDEF    _FSDoFileGad
  2138. _FSDoFileGad:
  2139.     link    a5,#0
  2140.     movem.l    d2-d4/a2-a3/a6,-(sp)
  2141.  
  2142.     moveq    #0,d4
  2143.     move.w    10(a5),d4        ;Grab gadget y position
  2144.     subi.w    #12,d4            ;Less 12 (top edge of first entry)
  2145.     divu    #11,d4            ; divided by 11 (height of each entry)
  2146.     ext.l    d4            ;Blow remainder, this is our entry number
  2147.  
  2148.     move.w    d4,d0
  2149.     lsl.w    #2,d0            ;Convert to long offset
  2150.     lea    _FSFileNodes,a2    ;Grab base address of visible node_datas
  2151.     movea.l    0(a2,d0.w),a3        ;Grab FSFileNodes[gadg_num]
  2152.     cmpa.l    #0,a3
  2153.      beq    dfgdone            ;If zero, not a active "gadget" slot
  2154.  
  2155. ;strncpy(FSwstr, tinfo->alphadata + 26L, tinfo->namelength)
  2156.     movea.l    fn_info(a3),a3        ;tinfo = tnode->info
  2157.     lea    _FSwstr,a2        ;Grab address of worktext
  2158.     move.w    nd_namelength(a3),d0    ;Push tinfo->namelength
  2159.     lea    nd_alphadata+26(a3),a1    ;Push tinfo->alphadata + 26
  2160.     movea.l    a2,a0            ;Push dest text
  2161.     jsr    astrncpy        ;strncpy(FSwstr, filename, namelength)
  2162.  
  2163. ;if (tinfo->filetype == 1)
  2164.     cmpi.w    #1,nd_filetype(a3)    ;Did user click on a filename?
  2165.      bne.s    dfgnotfile        ;Nope, must be a dir
  2166.  
  2167. ;if ( strcmp(FSFileInfo.Buffer, FSwstr) )
  2168.     movea.l    a2,a1            ;Push FSwstr
  2169.     movea.l    _FSFileInfo,a0    ;Push address of filebuffer
  2170.     jsr    astrcmp
  2171.     tst.w    d0            ;Is this the same as what we already have?
  2172.      beq.s    dfgnsname        ;Yep, see if it was double-clicked
  2173.  
  2174. ;strcpy(FSFileInfo.Buffer, FSwstr)
  2175.     movea.l    a2,a1
  2176.     movea.l    _FSFileInfo,a0
  2177.     jsr    astrcpy            ;Otherwise copy new filename to filebuffer
  2178.  
  2179.     lea    _FSFileGad,a0     ;And refresh filename text gadget
  2180.     movea.l    _FSWin,a1
  2181.     suba.l    a2,a2
  2182.     moveq    #1,d0
  2183.     SYS    RefreshGList,_IntuitionBase
  2184.     bra    dfgfiledone
  2185.  
  2186. dfgnsname:
  2187. ;if ( DoubleClick(fsoldsecs, fsoldmicros, fscursecs, fscurmicros &&
  2188. ; (gadg_num == fsprevgadid) )
  2189. ;  ConcatPathString();
  2190.     btst.b    #0,_fsflags+1    ;FS_NO_DCLICK_EXIT?
  2191.      bne    dfgfiledone        ;Yep, programmer doesn't allow that
  2192.  
  2193.     cmp.w    _fsprevgadid,d4     ;Is it the same gadget?
  2194.      bne    dfgfiledone        ;Nope, can't be a double click
  2195.  
  2196.     move.l    _fsoldsecs,d0
  2197.     move.l    _fsoldmicros,d1
  2198.     move.l    _fscursecs,d2
  2199.     move.l    _fscurmicros,d3
  2200.     SYS    DoubleClick,_IntuitionBase
  2201.     tst.w    d0            ;Is it within click speed parameters?
  2202.      beq.s    dfgfiledone        ;Nope
  2203.  
  2204.     jsr    _ConcatPathString     ;Construct full path text
  2205.     bra.s    dfgdone
  2206.  
  2207. ;Clicked on a DIR
  2208. dfgnotfile:
  2209.     cmpi.w    #1,_fsvirgindir    ;if (virgindir != 1)
  2210.      beq.s    dfgdone         ;Don't concat if we haven't locked dir yet
  2211.  
  2212. ;i = strlen(FSPathInfo.Buffer);
  2213.     move.l    _FSPathInfo,a0
  2214.     jsr    astrlen
  2215.     move.w    d0,d2            ;Length of stuff already in path text
  2216.  
  2217. ;if ( (strlen(FSwstr) + i) < PATHSTRSIZE)
  2218.     movea.l    a2,a0
  2219.     jsr    astrlen
  2220.     add.w    d2,d0
  2221.     cmpi.w    #PATHSTRSIZE-1,d0
  2222.      bge.s    dfgtoodeep         ;Don't append path if no room!
  2223.  
  2224.     move.l    a2,-(sp)
  2225.     move.l    _FSPathInfo,-(sp)
  2226.     move.l    _FSPathInfo,-(sp)
  2227.     jsr    _ConcatDirFile        ;ConcatDirFile(FSPathInfo->Buffer, FSPathInfo->Buffer, FSwstr)
  2228.     lea    12(sp),sp
  2229.  
  2230.     jsr    _FSDirFunc        ;Do FSReq->dirfunc, if there is one
  2231.     tst.w    d0            ;Avoid reading this dir?
  2232.      beq.s    1$            ;Nope, process it
  2233.     move.l    _FSPathInfo,a0
  2234.     clr.b    0(a0,d2.w)        ;Else FSPathInfo->Buffer[oldstrlen] = 0
  2235.     bra.s    dfgdone
  2236. 1$
  2237.     move.w    #1,_fsvirgindir    ;virgindir = 1, read the new directory
  2238.     bra.s    dfgdone
  2239.  
  2240. dfgtoodeep:
  2241.     move.w    #12,_fstitstatus    ;fstitstatus = 12
  2242.     jsr    _FSWinTitle
  2243.     suba.l    a0,a0
  2244.     SYS    DisplayBeep,_IntuitionBase
  2245.     bra.s    dfgdone
  2246.  
  2247. dfgfiledone:
  2248.     jsr    _FSFileFunc        ;Call FSReq->filefunc, if there is one
  2249.  
  2250. dfgdone:
  2251.     move.w    d4,_fsprevgadid     ;fsprevgadid = gadg_num
  2252.     movem.l    (sp)+,d2-d4/a2-a3/a6
  2253.     unlk    a5
  2254.     rts
  2255.  
  2256. * --------------------------------------------------------------------- *
  2257. * LONG FSDirFunc(VOID);
  2258. *  If there is a fsrequest->dirfunc, this routine handles the interface.
  2259. * --------------------------------------------------------------------- *
  2260.     XDEF    _FSDirFunc
  2261. _FSDirFunc:
  2262.     move.l    d2,-(sp)
  2263.  
  2264.     moveq    #0,d0
  2265.     movea.l    _FSReq,a0        ;Grab our FSRequest struct
  2266.     move.l    fs_dirfunc(a0),d2    ;Is there a user dir function to call?
  2267.      beq.s    1$            ;Nope, that's all we have to do this click!
  2268.  
  2269.     jsr    _ConcatPathString     ;Combine dir/file as fullname for return
  2270.     clr.w    _FSDone        ;Not done though, undo return status
  2271.  
  2272.     move.l    _FSWin,-(sp)
  2273.     move.l    _FSReq,-(sp)
  2274.     movea.l    d2,a0
  2275.     jsr    (a0)            ;d0 = (FSReq->dirfunc)(FSReq, FSWin)
  2276.     addq.w    #8,sp
  2277. 1$
  2278.     move.l    (sp)+,d2
  2279.     rts
  2280.  
  2281. * --------------------------------------------------------------------- *
  2282. * VOID FSFileFunc(VOID);
  2283. *  If there is a fsrequest->filefunc, this routine handles the interface.
  2284. * --------------------------------------------------------------------- *
  2285.     XDEF    _FSFileFunc
  2286. _FSFileFunc:
  2287.     move.l    d2,-(sp)
  2288.  
  2289.     movea.l    _FSReq,a0        ;Grab our FSRequest struct
  2290.     move.l    fs_filefunc(a0),d2    ;Is there a user file function to call?
  2291.      beq.s    1$            ;Nope, that's all we have to do this click!
  2292.  
  2293.     jsr    _ConcatPathString     ;Combine dir/file as fullname for return
  2294.     clr.w    _FSDone        ;Not done though, undo return status
  2295.  
  2296.     move.l    _FSWin,-(sp)
  2297.     move.l    _FSReq,-(sp)
  2298.     movea.l    d2,a0
  2299.     jsr    (a0)            ;d0 = (FSReq->filefunc)(FSReq, FSWin)
  2300.     addq.w    #8,sp
  2301.     tst.l    d0            ;Return 0?
  2302.      beq.s    1$            ;Yep
  2303.     move.w    #1,_fsvirgindir    ;Else re-read directory
  2304. 1$
  2305.     move.l    (sp)+,d2
  2306.     rts
  2307.  
  2308. * -----------------------------------------------------------------------
  2309. * VOID FSSetFileGads(VOID)
  2310. *   Assign and render currently active file texts, disable remainder
  2311. * -----------------------------------------------------------------------
  2312.     XDEF    _FSSetFileGads
  2313. _FSSetFileGads:
  2314.     movem.l    d4-d5,-(sp)
  2315.  
  2316.     move.w    _fsnumentries,d5    ;Grab number of entries
  2317.      beq.s    3$            ;No entries, nothing to set!
  2318.  
  2319. * Update visible list based on topfin point in linked list
  2320.     jsr    _FSAssignNodes
  2321.  
  2322. * Show all used gadgets
  2323.     moveq    #0,d4            ;i = 0
  2324.     bra.s    2$
  2325. 1$
  2326.     move.l    d4,-(sp)
  2327.     jsr    _FSEnableFGad
  2328.     addq.w    #4,sp
  2329.     addq.w    #1,d4            ;Bump gadget count
  2330. 2$
  2331.     cmpi.w    #10,d4            ;Hit highest gadget?
  2332.      bcc.s    3$            ;Yep, done
  2333.     cmp.w    d5,d4            ;Else, Hit last gadget?
  2334.      bcs    1$            ;Nope enable another
  2335. 3$
  2336.     movem.l    (sp)+,d4-d5
  2337.     rts
  2338.  
  2339. * ------------------------------------------------------------------------
  2340. * SetRootDir()
  2341. * Chop off all subdirectory names contained in FSPathInfo, moving up to
  2342. * root name if possible.  Flag to read new directory in any case.
  2343. * ------------------------------------------------------------------------
  2344.     XDEF    _SetRootDir
  2345. _SetRootDir:
  2346. ;if ( (tstr = strchr(FSPathInfo.Buffer, ':')) != 0L)
  2347.     moveq    #':',d0
  2348.     movea.l    _FSPathInfo,a0
  2349.     jsr    aindex
  2350.     tst.l    d0
  2351.      beq.s    1$            ;Nope
  2352.  
  2353.     clr.b    1(a0)            ;Otherwise clobber the char after ':'
  2354.     move.w    #1,_fsvirgindir    ;virgindir = 1, read directory
  2355.  
  2356. 1$    rts
  2357.  
  2358. * ------------------------------------------------------------------------
  2359. ; SetParentDir()
  2360. ;  Chop off last directory name contained in FSPathInfo, moving up one level
  2361. ; if possible.
  2362. * ------------------------------------------------------------------------
  2363.     XDEF    _SetParentDir
  2364. _SetParentDir:
  2365.     movem.l    a2-a3,-(sp)
  2366.  
  2367. ;if (FSPathInfo.Buffer[0])
  2368.     movea.l    _FSPathInfo,a3    ;Grab pointer to path text
  2369.     tst.b    (a3)            ;Is it of zero length?
  2370.      beq.s    spddone            ;Yep, at root already
  2371.  
  2372. ;tstr = rindex(FSPathInfo.Buffer, '/')
  2373.     moveq    #'/',d0
  2374.     movea.l    a3,a0
  2375.     jsr    arindex
  2376.     tst.l    d0            ;Grab index to last occurance of slash
  2377.      bne.s    spdnotsub        ;If we got one that is
  2378.  
  2379. ; if ( tstr = rindex(FSPathInfo.Buffer, ':') )
  2380. ;        tstr++;
  2381.     moveq    #':',d0
  2382.     movea.l    a3,a0
  2383.     jsr    arindex            ;Grab index to last occurance of colon
  2384.     tst.l    d0
  2385.      beq.s    spdnotroot        ;Oops, no colon either, at top of path?
  2386.     addq.w    #1,a0            ;Move past the ':'
  2387.     bra.s    spdnotsub        ;Terminate the text
  2388. ;else
  2389. spdnotroot:
  2390.     movea.l    a3,a0            ;tstr = (BYTE *)FSPathInfo.Buffer
  2391.  
  2392. spdnotsub:
  2393.     clr.b    (a0)            ;*tstr = '\x0'
  2394.     move.w    #1,_fsvirgindir    ;virgindir = 1, read the new directory
  2395.  
  2396. spddone:
  2397.     movem.l    (sp)+,a2-a3
  2398.     rts
  2399.  
  2400. * -----------------------------------------------------------------
  2401. ;HCompGad(rp, g2)
  2402. ;  struct RastPort *rp;
  2403. ;  struct Gadget *g2;
  2404. ;
  2405. ;  Given a rastport and a gadget pointer, highlight or de-highlight
  2406. ; a gadget using RectFill in COMPLEMENT mode.
  2407. * -----------------------------------------------------------------
  2408. hrp    EQU    16
  2409. hgad    EQU    20
  2410.     XDEF    _HCompGad
  2411. _HCompGad:
  2412.     movem.l    d2-d3/a6,-(sp)
  2413.  
  2414.     movea.l    hrp(sp),a1
  2415.     moveq    #2,d0
  2416.     SYS    SetDrMd,_GfxBase     ;SetDrMd(rp, COMPLEMENT)
  2417.  
  2418.     movea.l    hgad(sp),a0        ;Grab gadget pointer
  2419.     moveq    #0,d0
  2420.     move.w    4(a0),d0        ;x0 = (ULONG)g2->LeftEdge
  2421.  
  2422.     move.l    d0,d2
  2423.     add.w    8(a0),d2
  2424.     subq.w    #1,d2            ;x1 = x0 + g2->Width - 1L
  2425.  
  2426.     moveq    #0,d1
  2427.     move.w    6(a0),d1        ;y0 = (ULONG)g2->TopEdge
  2428.  
  2429.     move.l    d1,d3
  2430.     add.w    10(a0),d3
  2431.     subq.w    #1,d3            ;y1 = y0 + g2->Height - 1L
  2432.  
  2433.     movea.l    hrp(sp),a1
  2434.     SYS    RectFill        ;RectFill(rp, x0, y0, x1, y1)
  2435.  
  2436.     movea.l    hrp(sp),a1
  2437.     moveq    #1,d0
  2438.     SYS    SetDrMd            ;SetDrMd(rp, JAM2)
  2439.  
  2440.     movem.l    (sp)+,d2-d3/a6
  2441.     rts
  2442.  
  2443. * -----------------------------------------------------------------
  2444. ;HCompEntry(num)
  2445. ;  LONG num;
  2446. ;
  2447. ;   Highlight or de-highlight a slot in the filename area, given its
  2448. ; entry number
  2449. * -----------------------------------------------------------------
  2450.     XDEF    _HCompEntry
  2451. _HCompEntry:
  2452.     movem.l    d2-d3/a2/a6,-(sp)
  2453.  
  2454.     movea.l    _FSRPort,a2        ;Grab window
  2455.  
  2456.     movea.l    a2,a1
  2457.     moveq    #2,d0
  2458.     SYS    SetDrMd,_GfxBase     ;SetDrMd(rp, COMPLEMENT)
  2459.  
  2460.     moveq    #5,d0            ;x0 = (ULONG)g2->LeftEdge
  2461.     move.l    #460,d2            ;x1 = x0 + g2->Width - 1L
  2462.  
  2463.     move.w    16+4+2(sp),d1
  2464.     mulu    #11,d1
  2465.     add.w    #12,d1            ;y0 = (ULONG)g2->TopEdge
  2466.  
  2467.     move.l    d1,d3
  2468.     add.w    #9,d3            ;y1 = y0 + g2->Height - 1L
  2469.  
  2470.     movea.l    a2,a1
  2471.     SYS    RectFill        ;RectFill(rp, x0, y0, x1, y1)
  2472.  
  2473.     movea.l    a2,a1
  2474.     moveq    #1,d0
  2475.     SYS    SetDrMd            ;SetDrMd(rp, JAM2)
  2476.  
  2477.     movem.l    (sp)+,d2-d3/a2/a6
  2478.     rts
  2479.  
  2480. * --------------------------------------------------------------------- *
  2481. * VOID FSDoSortGadget(type)
  2482. *   LONG type;
  2483. * --------------------------------------------------------------------- *
  2484. dosgtype    EQU    4+4*3
  2485.  
  2486.     XDEF    _FSDoSortGadget
  2487. _FSDoSortGadget:
  2488.     movem.l    d2/a2/a6,-(sp)
  2489.  
  2490.     movea.l    _FSReq,a0
  2491.     moveq    #0,d0
  2492.     move.w    fs_sorttype(a0),d0
  2493.     cmp.w    dosgtype+2(sp),d0
  2494.      beq    dosgsame
  2495.  
  2496. * Unhighlight previous setting
  2497.     tst.w    d0            ;Alphabetize?
  2498.      bne.s    1$
  2499.     lea    _AlphaGad,a0
  2500.     bra.s    3$
  2501. 1$
  2502.     subq.w    #1,d0            ;FileSize?
  2503.      bne.s    2$
  2504.     lea    _SizeGad,a0
  2505.     bra.s    3$
  2506. 2$
  2507.     subq.w    #1,d0            ;Time?
  2508.      bne.s    4$            ;Nope, nosort previously
  2509.     lea    _TimeGad,a0
  2510. 3$
  2511.     bclr.b    #7,gg_Flags+1(a0)    ;gad->Flags &= ~SELECTED
  2512.  
  2513.     movea.l    _FSWin,a1
  2514.     suba.l    a2,a2
  2515.     moveq    #1,d0
  2516.     SYS    RefreshGList,_IntuitionBase ;RefreshGList(gad, FSWin, 0L, 1)
  2517. 4$
  2518. * Set new sort type
  2519.     movea.l    _FSReq,a0
  2520.     move.l    dosgtype(sp),d1
  2521.     move.w    d1,fs_sorttype(a0)
  2522.  
  2523.     movea.l    _fnList,a0
  2524.     movea.l    MLH_HEAD(a0),a0
  2525.     tst.l    fn_Node+MLN_SUCC(a0)
  2526.      beq.s    dosgdone        ;No list, don't bother sorting
  2527.     tst.l    _topfin        ;Grab current topfin
  2528.      beq.s    5$            ;No currently visible files
  2529.     clr.w    _fsneedshow     ;fsneedshow = 0, needs sorting
  2530.     bra.s    6$
  2531. 5$
  2532.     move.w    #-1,_fsneedshow    ;No topfin, fsneedshow = -1
  2533. 6$
  2534. dossort:
  2535. * Sort the list using the new sort type
  2536.     move.l    d1,-(sp)
  2537.     jsr    _SortNodes        ;SortNodes(type)
  2538.     addq.w    #4,sp
  2539.  
  2540.     jsr    _FSUpdateSort
  2541.  
  2542.     jsr    _FSWinTitle        ;Reset title to previous
  2543.     bra.s    dosgdone
  2544.  
  2545. dosgsame:
  2546.     move.w    #-1,fs_sorttype(a0)
  2547.  
  2548. dosgdone:
  2549.     movem.l    (sp)+,d2/a2/a6
  2550.     rts
  2551.  
  2552. * -----------------------------------------------------------------------
  2553. ; SortNodes(key)
  2554. ;   LONG key;
  2555. ; Selection sort list of filenames using one of three key types
  2556. * -----------------------------------------------------------------------
  2557.     XDEF    _SortNodes
  2558. _SortNodes:
  2559.     movem.l    d4/a2-a3/a6,-(sp)
  2560.  
  2561.     IFD    BENCHMARK
  2562.     jsr    _StartTime
  2563.     ENDC
  2564.  
  2565.     move.l    4+4*4(sp),d4        ;Grab our key type
  2566.      blt    snsortdone        ;No sort wanted
  2567.     cmpi.w    #1,_fsnumentries    ;More than one entry?
  2568.      ble    snsortdone        ;Nope, don't bother sorting
  2569.  
  2570.     move.w    _fstitstatus,-(sp)    ;Save old titstatus
  2571.     move.w    #28,_fstitstatus
  2572.     jsr    _FSWinTitle        ;FSWinTitle("Sorting...")
  2573.     move.w    (sp)+,_fstitstatus    ;Restore previous titlemsg
  2574.  
  2575. * Convert Exec list to a simple head->next->NULL type
  2576.     movea.l    _fnList,a3        ;Grab old list
  2577.     movea.l    MLH_TAILPRED(a3),a1    ;a0 = last entry in list
  2578.     movea.l    MLH_HEAD(a3),a0
  2579.     clr.l    fn_Node+MLN_SUCC(a1)    ;Zap last nodes next field
  2580.  
  2581.     NEWLIST    a3            ;New the old list
  2582.  
  2583.     move.l    d4,d0            ;d0 = sorttype, a0 = headnode
  2584.     jsr    _FSListSort        ;list_sort(headnode, key) (a0/d0)
  2585.     movea.l    d0,a1            ;Grab new head of sorted list
  2586.  
  2587. * Now add the new nodes back into the list
  2588.     movea.l    4,a6            ;Execbase calls
  2589.  
  2590. 1$    cmpa.l    #0,a1            ;Grab next node in new list
  2591.      beq.s    2$            ;End of list
  2592.     movea.l    fn_Node+MLN_SUCC(a1),a2    ;node = node->fn_Node.mln_Succ
  2593.  
  2594.     movea.l    a3,a0
  2595.     SYS    AddTail            ;AddTail(fnList, newnode)
  2596.  
  2597.     movea.l    a2,a1            ;a2 = next node
  2598.     bra    1$            ;Add the next node
  2599. 2$
  2600. snsortdone:
  2601.     IFD    BENCHMARK
  2602.     pea    _timermsg1
  2603.     jsr    _StopTime
  2604.     addq.w    #4,sp
  2605.     ENDC
  2606.  
  2607.     movem.l    (sp)+,d4/a2-a3/a6
  2608.     rts
  2609.  
  2610. * --------------------------------------------------------------------
  2611. * struct file_node *FSListSort (list, type)
  2612. *   struct file_node *list;
  2613. *   long type;
  2614. *
  2615. *   Assumes a list of structures, with a pointer to "next" as the first
  2616. *   field.  It reorders the list into ascending order, and returns the
  2617. *   new first node's address.  It is order N log(N).
  2618. *
  2619. *   The compare routine should return 0 if the items are in order, and 1
  2620. *   if they are not.  If the compare routine returns 0 in case of
  2621. *   equality, the sort will be stable.
  2622. *
  2623. *   This routine depends upon compiler-dependant struct layout, but this
  2624. *   assumption is likely to be fairly commonly valid.
  2625. *
  2626. *   The basic notion of this sort is to make sorted sublists longer and
  2627. *   longer by merging.  On the Nth pass through the list, sorted
  2628. *   sublists of length 2^(N-1) are produced.  Eventually, the entire
  2629. *   list is sorted, in log2(N)+1 passes through the list.  There is
  2630. *   extra bookkeeping overhead, but minimal extra storage space needed.
  2631. *   Counts and clever pointer management substitute for extra "glue"
  2632. *   nodes.
  2633. *
  2634. *   while more than one list
  2635. *      while not at end of composite lists
  2636. *            for each merge_length(m) block
  2637. *                  merge first items in lists onto current output list
  2638. *            toggle current output list
  2639. *
  2640. * Register parameters:
  2641. * struct file_node *FSListSort __ARGS((struct file_node *, LONG));
  2642. *          d0                                a0             d0
  2643. * --------------------------------------------------------------------- *
  2644. flsold1    equ    -4
  2645. flsold0    equ    -8
  2646. flsnew1    equ    -12
  2647. flsnew0    equ    -16
  2648. flscnt1    equ    -20
  2649. flscnt0    equ    -24
  2650. flsffn1    equ    flscnt0-16
  2651. flsffn0    equ    flsffn1-16
  2652. flssend    equ    flsffn0-4
  2653.  
  2654. * --------------------------------------------------------------------- *
  2655.     XDEF    _FSListSort
  2656. _FSListSort:
  2657.     link    a5,#flssend
  2658.     movem.l    d2-d7/a2-a3,-(sp)
  2659.  
  2660.     move.l    d0,d3            ;d3 = sorttype
  2661.     clr.l    flsffn0+LN_SUCC(a5)    ;front[0].next = 0
  2662.     move.l    a0,flsffn1+LN_SUCC(a5)    ;front[0].next = list
  2663.  
  2664.     moveq    #1,d7            ;m = 1
  2665.     moveq    #0,d6            ;hm = 0
  2666.  
  2667. flsLoop1:
  2668.     tst.l    flsffn1+LN_SUCC(a5)    ;while (front[1].next)
  2669.      beq    flsdone
  2670.  
  2671.     lea    flsffn0(a5),a0
  2672.     move.l    a0,flsnew0(a5)        ;new[0] = &front[0]
  2673.     lea    flsffn1(a5),a0
  2674.     move.l    a0,flsnew1(a5)        ;new[1] = &front[1]
  2675.     move.l    flsffn0+LN_SUCC(a5),flsold0(a5)    ;old[0] = front[0].next
  2676.     move.l    flsffn1+LN_SUCC(a5),flsold1(a5)    ;old[1] = front[1].next
  2677.     clr.l    flscnt0(a5)        ;count[0] = 0
  2678.     clr.l    flscnt1(a5)        ;count[1] = 0
  2679.     moveq    #0,d4            ;n = 0
  2680.  
  2681.     moveq    #0,d5            ;items_merged = 0
  2682. flsLoop2:
  2683.     tst.l    flsold0(a5)        ;old[0]?
  2684.      bne.s    1$            ;Yep, get an item from this list
  2685.     tst.l    flsold1(a5)        ;old[1]?
  2686.      beq    flsNext2        ;Nope, both lists exhausted
  2687.  
  2688. 1$    cmp.l    d7,d5            ;if (items_merged >= m)
  2689.      bcs.s    2$            ;Nope, m > items_merged
  2690.     moveq    #0,d5            ;items_merged = 0
  2691.     bchg.l    #0,d4            ;n = 1 - n
  2692.     clr.l    flscnt0(a5)        ;count[0] = 0
  2693.     clr.l    flscnt1(a5)        ;count[1] = 0
  2694.  
  2695. 2$    tst.l    flsold0(a5)        ;old[0]?
  2696.      beq.s    3$
  2697.     tst.l    flsold1(a5)        ;old[1]?
  2698.      beq.s    3$
  2699.     cmp.l    flscnt0(a5),d6        ;count[0] < hm?
  2700.      bls.s    3$            ;Nope, hm >= count[0]
  2701.     cmp.l    flscnt1(a5),d6        ;count[1] < hm?
  2702.      bls.s    3$            ;Nope
  2703.  
  2704.     movea.l    flsold1(a5),a1
  2705.     movea.l    fn_info(a1),a1
  2706.     movea.l    flsold0(a5),a0
  2707.     movea.l    fn_info(a0),a0
  2708.     move.l    d3,d0
  2709.     jsr    _CompareNodes        ;CompareNodes(type, old[0]->info, old[1]->info)
  2710.     lsl.w    #2,d0            ;d0 = result of compare (0 or 1)
  2711.  
  2712.     move.w    d4,d1
  2713.     lsl.w    #2,d1            ;d1 = n<<2
  2714.     movea.l    flsnew0(a5,d1.w),a1    ;a1 = new[n]
  2715.     movea.l    flsold0(a5,d0.w),a0    ;a0 = old[o]
  2716.     move.l    a0,LN_SUCC(a1)        ;new[n]->next = old[o]
  2717.     move.l    LN_SUCC(a0),flsold0(a5,d0.w)  ;old[o] = old[o]->next
  2718.     addq.l    #1,flscnt0(a5,d0.w)    ;count[o]++
  2719.     bra.s    flsNext1
  2720. 3$
  2721. flselse1:
  2722.     tst.l    flsold0(a5)        ;old[0]?
  2723.      beq.s    2$            ;Nope, use old[1]
  2724.     cmp.l    flscnt0(a5),d6        ;count[0] < hm?
  2725.      bls.s    2$            ;Nope, count[0] >= hm, use old[1]
  2726. 1$    lea    flsold0(a5),a0        ;else a0 = &old[0]
  2727.     bra.s    3$
  2728. 2$    lea    flsold1(a5),a0        ;a0 = &old[1]
  2729. 3$
  2730.     move.w    d4,d1
  2731.     lsl.w    #2,d1
  2732.     movea.l    flsnew0(a5,d1.w),a1    ;a1 = new[n]
  2733.     move.l    (a0),LN_SUCC(a1)    ;new[n]->next = old[o]
  2734.     movea.l    (a0),a1
  2735.     move.l    LN_SUCC(a1),(a0)    ;old[o] = old[o]->next
  2736.  
  2737. flsNext1:
  2738.     move.w    d4,d0
  2739.     lsl.w    #2,d0
  2740.     movea.l    flsnew0(a5,d0.w),a0    ;a0 = new[n]
  2741.     move.l    LN_SUCC(a0),flsnew0(a5,d0.w) ;new[n] = new[n]->next
  2742.     addq.l    #1,d5            ;items_merged++
  2743.     bra    flsLoop2
  2744.  
  2745. flsNext2:
  2746.     movea.l    flsnew0(a5),a0
  2747.     clr.l    LN_SUCC(a0)        ;new[0]->next = 0
  2748.     movea.l    flsnew1(a5),a0
  2749.     clr.l    LN_SUCC(a0)        ;new[1]->next = 0
  2750.     move.l    d7,d6            ;hm = m
  2751.     lsl.l    #1,d7            ;m *= 2
  2752.     bra    flsLoop1
  2753.     
  2754. flsdone:
  2755.     move.l    flsffn0+LN_SUCC(a5),d0    ;return(front[0].next)
  2756.  
  2757.     movem.l    (sp)+,d2-d7/a2-a3
  2758.     unlk    a5
  2759.     rts
  2760.  
  2761. * -------------------------------------------------------------------------
  2762. ; d0 = WORD CompareNodes(d0, a0, a1)
  2763. ;   WORD key = d0;
  2764. ;   struct node_data *a = a0, *b = a1;
  2765. ;   
  2766. ; Compare data in two nodes, based upon key type.  Return boolean result
  2767. ; of the comparison in d0. Note that this is a register based function.
  2768. * -------------------------------------------------------------------------
  2769.     XDEF    _CompareNodes
  2770. _CompareNodes:
  2771.     move.w    nd_filetype(a0),d1
  2772.     cmp.w    nd_filetype(a1),d1    ;Comparing same type of entries?
  2773.      beq.s    3$            ;Yep, use sort for compare
  2774.  
  2775.     btst.b    #3,_fsflags+1    ;Want files first?
  2776.      bne.s    2$            ;Yep
  2777.     btst.b    #4,_fsflags+1    ;Want dirs first?
  2778.      beq.s    3$            ;Don't care, see if there is a sort
  2779.  
  2780.     cmp.w    nd_filetype(a1),d1    ;Recompare
  2781.      bcs.s    cnmatch            ;a0->filetype = 2, a1->filetype = 1
  2782.     bra.s    cnnomatch        ;a0->filetype = 1, a1->filetype = 2
  2783. 2$
  2784.     cmp.w    nd_filetype(a1),d1    ;Recompare
  2785.      bhi.s    cnmatch            ;a0->filetype = 2, a1->filetype = 1
  2786.     bra.s    cnnomatch        ;a0->filetype = 1, a1->filetype = 2
  2787. 3$
  2788.     tst.w    d0
  2789.      blt.s    cnmatch            ;No sort, append to end
  2790.      bne.s    cnnotalpha        ;Not zero, not alphabetize
  2791.  
  2792. cnnalpha:
  2793.     pea    nd_alphadata+26(a1)
  2794.     pea    nd_alphadata+26(a0)
  2795.     jsr    _lstrcmp        ;return(lstrcmp(a->alphadata + 26L, b->alphadata + 26L) > 0)
  2796.     addq.w    #8,sp
  2797.     tst.w    d0
  2798.      ble.s    cnnomatch
  2799.     bra.s    cnmatch
  2800.     
  2801. cnnotalpha:
  2802.     cmpi.w    #1,d0            ;Sort by size?
  2803.      bne.s    cnnotsize        ;Nope, must be by date
  2804.  
  2805.     move.l    nd_filesize(a0),d0
  2806.     cmp.l    nd_filesize(a1),d0    ;return(a->filesize > b->filesize)
  2807.      beq    cnnalpha        ;Same size, sort alpha
  2808.      bcs.s    cnnomatch        ;a1 > a0
  2809.     bra.s    cnmatch
  2810.  
  2811. cnnotsize:
  2812.     move.l    nd_days(a0),d0
  2813.     cmp.l    nd_days(a1),d0        ;if (a->days > b->days)
  2814.      beq.s    cntstmins        ;Nope, a->days == b->days, check minutes
  2815.      bls.s    cnnomatch        ;Nope, a->days < b->days
  2816.     bra.s    cnmatch
  2817.  
  2818. cntstmins:
  2819. ;t1 = (a->minutes - b->minutes) * 3000L + (a->ticks - b->ticks)
  2820.     move.l    nd_minutes(a0),d0
  2821.     sub.l    nd_minutes(a1),d0
  2822.     muls    #3000,d0
  2823.  
  2824.     move.l    nd_ticks(a0),d1
  2825.     sub.l    nd_ticks(a1),d1
  2826.     add.l    d1,d0
  2827.  
  2828.     tst.l    d0            ;return(t1 > 0L);
  2829.      beq    cnnalpha        ;Same date, sort alpha
  2830.      bgt.s    cnmatch
  2831.  
  2832. cnnomatch:
  2833.     moveq    #0,d0
  2834.     bra.s    cndone
  2835.  
  2836. cnmatch:
  2837.     moveq    #1,d0
  2838. cndone:
  2839.     rts
  2840.  
  2841. * ---------------------------- lstrcmp -------------------------------
  2842. * LONG lstrcmp(astr, bstr)
  2843. *   BYTE *astr, *bstr;    
  2844. *
  2845. * Compare two texts for lexigraphic order, ignoring case differences
  2846. *---------------------------------------------------------------------
  2847.     XDEF    _lstrcmp
  2848. _lstrcmp:
  2849.     movem.l    4(sp),a0/a1        ;Grab astr, bstr
  2850.  
  2851. ;for(;*a && tolower(*a) == tolower(*b); a++, b++)
  2852. lccstart:
  2853.     move.b    (a0)+,d0        ;Grab a char from astr
  2854.     cmpi.b    #$40,d0            ;less than @ character?
  2855.      bls.s    1$            ;Yep
  2856.     cmpi.b    #$5a,d0            ;Greater than Z?
  2857.      bhi.s    1$            ;Yep
  2858.     addi.b    #$20,d0
  2859. 1$
  2860.     move.b    (a1)+,d1        ;Grab a char from bstr
  2861.     cmpi.b    #$40,d1            ;less than @ character?
  2862.      bls.s    2$            ;Yep
  2863.     cmpi.b    #$5a,d1            ;Greater than Z?
  2864.      bhi.s    2$            ;Yep
  2865.     addi.b    #$20,d1
  2866. 2$
  2867.     tst.b    d0            ;End of astr?
  2868.      beq.s    3$
  2869.     cmp.b    d1,d0            ;Are they the same character?
  2870.      beq    lccstart        ;Yep, compare next pair of chars
  2871. 3$
  2872.     sub.b    d1,d0            ;return(tolower(*astr) - tolower(*bstr))
  2873.     ext.w    d0
  2874.     ext.l    d0
  2875.     rts
  2876.  
  2877. *----------------------------------------------------------------------
  2878. * Search a text for wild characters, return 1 if found
  2879. *----------------------------------------------------------------------
  2880.     XDEF    _iswild
  2881. _iswild:
  2882.     movea.l    4(sp),a0        ;Grab text pointer
  2883.     moveq    #0,d0            ;Clear out our character register
  2884. ischk1:
  2885.     move.b    (a0)+,d0        ;Grab a char
  2886.      beq.s    iswdone            ;Might be end of text?
  2887.     cmpi.b    #'*',d0            ;Is it *?
  2888.      beq.s    iswdone            ;yep, is wild
  2889.     cmpi.b    #'?',d0            ;Is it a qmark
  2890.      bne    ischk1            ;Nope, check next character
  2891.     rts                ;Otherwise it is wild
  2892.  
  2893. iswdone:
  2894.     rts
  2895.  
  2896.  
  2897. * ------------------------------------------------------------------------
  2898. ; Compare a wild card name with a normal name
  2899. ; WORD wildmatch (name, wild)
  2900. ;   BYTE *name, *wild;
  2901. * ------------------------------------------------------------------------
  2902.     XDEF    _wildmatch
  2903. _wildmatch:
  2904.     link    a5,#-64
  2905.     movem.l    d3/a2-a3,-(sp)
  2906.  
  2907.     movem.l    8(a5),a2-a3        ;Grab name/pattern
  2908.     lea    -64(a5),a0        ;back[0][0]
  2909.     lea    -60(a5),a1        ;back[0][1]
  2910.  
  2911.     moveq    #0,d3            ;bi = 0
  2912.  
  2913. wmloop1:
  2914.     tst.b    (a2)            ;End of name?
  2915.      bne.s    wmnoteon
  2916.     tst.b    (a3)            ;End of pattern?
  2917.      beq    wmmatched        ;Yep, we matched
  2918.  
  2919. wmnoteon:
  2920.     cmpi.b    #'*',(a3)        ;Is it a splat?
  2921.      bne.s    wmnotstar        ;Nope, maybe '?'
  2922.  
  2923.     cmpi.w    #64,d3            ;Have we hit max expression depth?
  2924.      beq    wmnomatch        ;Yep, ran out of room in recursion table
  2925.  
  2926. ;back[bi][0] = w
  2927.     move.l    a3,0(a0,d3.w)        ;Stash pointer to this '*' in table
  2928.  
  2929. ;back[bi][1] = n
  2930.     move.l    a2,0(a1,d3.w)
  2931.  
  2932.     addq.w    #8,d3            ;++bi
  2933.     addq.w    #1,a3            ;++w
  2934.     bra    wmloop1            ;Check next
  2935.  
  2936. wmgoback:
  2937.     subq.w    #8,d3            ;--bi
  2938.     move.l    a0,d0
  2939. wmback1:
  2940.     tst.w    d3            ;while (bi >= 0 && *back[bi][1] == '\x0')
  2941.      blt.s    wmbacked
  2942.     movea.l    0(a1,d3.l),a0
  2943.     tst.b    (a0)
  2944.      bne.s    wmbacked
  2945.  
  2946.     subq.w    #8,d3            ;--bi
  2947.     bra    wmback1
  2948.  
  2949. wmbacked:
  2950.     tst.w    d3            ;if (bi < 0)
  2951.      blt.s    wmnomatch        ;return (0)
  2952.  
  2953.     movea.l    d0,a0
  2954.     movea.l    0(a0,d3.w),a3        ;w = back[bi][0] + 1
  2955.     addq.w    #1,a3    
  2956.  
  2957.     addq.l    #1,0(a1,d3.w)
  2958.     movea.l    0(a1,d3.l),a2        ;n = ++back[bi][1]
  2959.  
  2960.     addq.w    #8,d3            ;++bi
  2961.     bra    wmloop1
  2962.  
  2963. wmnotstar:
  2964.     cmpi.b    #'?',(a3)        ;Is it '?'
  2965.      bne.s    wmnotqmark
  2966.  
  2967.     tst.b    (a2)            ;Reached end of text?
  2968.      bne.s    wmincpoint        ;Nope, move on to next char
  2969.  
  2970.     tst.w    d3            ;Are we at top level of expression?
  2971.      beq.s    wmnomatch        ;Yep, expression didn't match
  2972.     bra    wmgoback        ;Otherwise pop a level and try to match
  2973.  
  2974. wmnotqmark:
  2975.     move.b    (a2),d0            ;Grab a char from bstr
  2976.     cmpi.b    #$40,d0            ;less than @ character?
  2977.      bls.s    1$            ;Yep
  2978.     cmpi.b    #$5a,d0            ;Greater than Z?
  2979.      bhi.s    1$            ;Yep
  2980.     addi.b    #$20,d0
  2981. 1$
  2982.     move.b    (a3),d1            ;Grab a char from bstr
  2983.     cmpi.b    #$40,d1            ;less than @ character?
  2984.      bls.s    2$            ;Yep
  2985.     cmpi.b    #$5a,d1            ;Greater than Z?
  2986.      bhi.s    2$            ;Yep
  2987.     addi.b    #$20,d1
  2988. 2$
  2989.     cmp.b    d0,d1            ;*n = *w?
  2990.      beq.s    wmincpoint        ;Yep, move on past
  2991.  
  2992.     tst.w    d3            ;Are we at top expression level?
  2993.      beq.s    wmnomatch        ;Yep, they didn't match
  2994.     bra    wmgoback        ;Nope, process next part
  2995.  
  2996. wmincpoint:
  2997.     tst.b    (a2)            ;Done with name?
  2998.      beq.s    wmnamend        ;Yep
  2999.     addq.w    #1,a2            ;Otherwise increment name pointer
  3000.  
  3001. wmnamend:
  3002.     tst.b    (a3)            ;End of pattern?
  3003.      beq.s    wmmatched        ;Yep, we matched
  3004.     addq.w    #1,a3            ;Otherwise inc wild pointer, match next char
  3005.     bra    wmloop1
  3006.  
  3007. wmmatched:
  3008.     moveq    #1,d0
  3009.     bra.s    wmdone
  3010.  
  3011. wmnomatch:
  3012.     moveq    #0,d0
  3013.  
  3014. wmdone:
  3015.     movem.l    (sp)+,d3/a2-a3
  3016.     unlk    a5
  3017.     rts
  3018.  
  3019.  
  3020. * --------------------------------------------------------------------- *
  3021. * LONG MakePathString(lock, dest)
  3022. *                      a0     a1
  3023. *   struct FileLock *lock;
  3024. *   BYTE *dest;
  3025. *
  3026. * DESCRIPTION:
  3027. *   Given text and a filelock, construct entire pathname and
  3028. * return in dest.
  3029. * --------------------------------------------------------------------- *
  3030.     XDEF    _MakePathString
  3031. _MakePathString:
  3032.     link    a5,#0
  3033.     movem.l    d2-d5/d7/a2-a3/a6,-(sp)
  3034.  
  3035. * Grab pointer to lock and dest text to fill
  3036.     move.l    8(a5),d3        ;d3 = lock
  3037.     movea.l    12(a5),a2        ;a2 = dest
  3038.     clr.b    (a2)            ;NULL terminate dest
  3039.     moveq    #0,d5            ;LockFlag = 0
  3040.  
  3041. * Allocate a FileInfoBlock for local use
  3042.     moveq    #0,d1
  3043.     move.l    #fib_SIZEOF,d0
  3044.     SYS    AllocMem,4        ;AllocMem(sizeof(fib), 0L)
  3045.     move.l    d0,d7            ;d7 = *fib
  3046.      beq    mpsfailed        ;Whoops no mem? return!
  3047.  
  3048.     movea.l    _DOSBase(a4),a6        ;DOSBase calls from here on
  3049.  
  3050. * while (lock != 0)
  3051. 1$
  3052.     tst.l    d3            ;Got a lock?
  3053.      beq.s    mpsokay            ;Nope, must be at root
  3054.  
  3055. * Examine the current lock
  3056.     move.l    d3,d1
  3057.     move.l    d7,d2
  3058.     SYS    Examine            ;Examine(lock, fib)
  3059.     tst.l    d0            ;Okay?
  3060.      beq.s    mpsfailed        ;Nope, some sort of dos failure?
  3061.  
  3062.     movea.l    d7,a1
  3063.     cmpi.b    #' ',fib_FileName(a1)    ;if (fib->fib_FileName[0] >= ' ')
  3064.      bcs.s    3$            ;Nope, don't bother inserting?
  3065.  
  3066.     tst.b    (a2)            ;if (dest[0] != 0)
  3067.      beq.s    2$
  3068.     lea    _SlashStr(a4),a1
  3069.     movea.l    a2,a0
  3070.     jsr    _InsertPathString    ;InsertPathString(dest, "/");
  3071. 2$
  3072.     movea.l    d7,a1
  3073.     lea    fib_FileName(a1),a1
  3074.     movea.l    a2,a0
  3075.     jsr    _InsertPathString    ;InsertPathString(dest, fib->fib_FileName)
  3076. 3$
  3077. * Okay, move up one directory
  3078.     move.l    d3,d4            ;oldlock = lock
  3079.  
  3080.     move.l    d3,d1
  3081.     SYS    ParentDir
  3082.     move.l    d0,d3            ;lock = ParentDir(lock)
  3083.  
  3084.     tst.w    d5            ;LockFlag set?
  3085.      bne.s    4$            ;Yep, unlock
  3086.     moveq    #1,d5            ;Else LockFlag = 1, unlock next time
  3087.      bra    1$            ;Next directory up
  3088. 4$
  3089.     move.l    d4,d1
  3090.     SYS    UnLock            ;UnLock(oldlock)
  3091.     bra    1$            ;Examine
  3092.  
  3093. mpsokay:
  3094. * See if root was RAM:, special case
  3095.     movea.l    d7,a1            ;a1 = fib
  3096.     cmpi.b    #' ',fib_FileName(a1)    ;if (fib->fib_FileName[0] >= ' ')
  3097.      bcc.s    1$            ;Yep, not 1.1/1.2 RAM:
  3098.     lea    _RamDirNameStr(a4),a1    ;Else...
  3099.     movea.l    a2,a0
  3100.     jsr    _InsertPathString    ;InsertPathString(dest, "RAM:")
  3101.     bra.s    mpsdone
  3102. 1$
  3103. * Find last slash we tacked on, change to a colon, or, add a colon
  3104.     moveq    #'/',d0
  3105.     movea.l    a2,a0
  3106.     jsr    aindex            ;d0 = strchr(dest, '/')
  3107.     tst.l    d0            ;Do we have a slash?
  3108.      beq.s    2$            ;Nope, at root....
  3109.     movea.l    d0,a0
  3110.     move.b    #':',(a0)        ;Else change first '/' to a ':'
  3111.     bra.s    mpsdone
  3112.  
  3113. * No slash, must be locked at the root.  Append a colon to the dest.
  3114. 2$
  3115.     lea    _ColonStr(a4),a1    
  3116.     movea.l    a2,a0
  3117.     jsr    astrcat            ;strcat (dest, ":")
  3118.     bra.s    mpsdone
  3119.  
  3120. * Come here if an error occured, return empty text to caller
  3121. mpsfailed:
  3122.     clr.b    (a2)            ;dest[0] = (BYTE)0
  3123.     moveq    #0,d3            ;return (0L)
  3124.     bra.s    mpsdeall
  3125.  
  3126. * Come here if everything is okay, deallocate FileInfoBlock
  3127. mpsdone:
  3128.     moveq    #1,d3            ;return (1L)
  3129.  
  3130. mpsdeall:
  3131.     tst.l    d7            ;Did we allocate a fib?
  3132.      beq.s    mpsfinis        ;nope
  3133.     movea.l    d7,a1            ;Else free the memory
  3134.     move.l    #fib_SIZEOF,d0
  3135.     SYS    FreeMem            ;FreeMem(fib, sizeof(fib))
  3136.  
  3137. mpsfinis:
  3138.     move.l    d3,d0            ;Put return value in d0
  3139.     movem.l    (sp)+,d2-d5/d7/a2-a3/a6
  3140.     unlk    a5
  3141.     rts
  3142.  
  3143. * --------------------------------------------------------------------- *
  3144. * VOID InsertPathString(dest, source)
  3145. *                        a0     a1
  3146. *   BYTE *dest, *source;
  3147. *
  3148. * DESCRIPTION:
  3149. *   Insert source text into dest text.
  3150. * Special case for source length == 0, source must be RAM.
  3151. * --------------------------------------------------------------------- *
  3152.     XDEF    _InsertPathString
  3153. _InsertPathString:
  3154.     movem.l    d7/a2-a3,-(sp)
  3155.  
  3156.     movea.l    a1,a3            ;a3 = source
  3157.     move.l    a0,a2            ;a2 = dest
  3158.  
  3159.     movea.l    a3,a0
  3160.     jsr    astrlen
  3161.     move.l    d0,d7            ;d7 = strlen(source)
  3162.  
  3163. 1$    movea.l    a2,a0
  3164.     jsr    astrlen            ;d0 = strlen(dest)
  3165.  
  3166.     addq.w    #1,d0            ;Bump the length to include zero byte at end
  3167.     movea.l    a2,a1
  3168.     adda.w    d7,a1            ;Push dest + slen
  3169.     movea.l    a2,a0            ;Push dest
  3170.     jsr    amovmem            ;amovmem(dest, dest + slen, strlen(dest) + 1)
  3171.  
  3172.     move.w    d7,d0
  3173.     movea.l    a2,a1
  3174.     movea.l    a3,a0
  3175.     jsr    amovmem            ;amovmem(source, dest, slen)
  3176.  
  3177.     movem.l    (sp)+,d7/a2-a3
  3178.     rts
  3179.  
  3180. * --------------------------------------------------------------------- *
  3181. * BYTE *myrindex(text, searchchar)
  3182. *   BYTE *text;
  3183. *   LONG searchchar;
  3184. *
  3185. * C stack version of arindex.
  3186. * --------------------------------------------------------------------- *
  3187.     XDEF    _myrindex
  3188. _myrindex:
  3189.     movea.l    4(sp),a0
  3190.     move.l    8(sp),d0
  3191.  
  3192. * --------------------------------------------------------------------- *
  3193. * BYTE *aindex(BYTE *, BYTE);
  3194. * --------------------------------------------------------------------- *
  3195.     XDEF    aindex
  3196. aindex:
  3197. 1$    cmp.b    (a0),d0
  3198.      beq.s    aifound
  3199.     tst.b    (a0)+
  3200.      beq.s    ainomatch
  3201.     bra    1$
  3202.  
  3203. ainomatch:
  3204.     moveq    #0,d0
  3205.     rts
  3206.  
  3207. aifound:
  3208.     move.l    a0,d0
  3209.     rts
  3210.  
  3211. * --------------------------------------------------------------------- *
  3212. * BYTE *arindex(BYTE *, BYTE);
  3213. * --------------------------------------------------------------------- *
  3214.     XDEF    arindex
  3215. arindex:
  3216.     move.l    a0,d1            ;Copy start of string for compares
  3217.  
  3218. 1$    tst.b    (a0)+            ;Find end of text
  3219.      bne    1$
  3220.  
  3221. 2$    cmp.b    -(a0),d0        ;Now work backward comparing along the way
  3222.      beq.s    rifound            ;..Until we find a match
  3223.     cmpa.l    d1,a0            ;...or hit the beginning of the text
  3224.      bgt    2$
  3225.  
  3226. rinomatch:
  3227.     moveq    #0,d0
  3228.     rts
  3229.  
  3230. rifound:
  3231.     move.l    a0,d0
  3232.     rts    
  3233.  
  3234. * ------------------------------------------------------------------------- *
  3235. *  d0            a0
  3236. * LONG astrlen(text)
  3237. *   BYTE *text;
  3238. *
  3239. * Synopsis: Calculate length of null-byte terminated text.
  3240. * a0 returns pointing to null char at end of text
  3241. * d0 returns number of bytes in the text
  3242. * ------------------------------------------------------------------------- *
  3243.     XDEF    astrlen
  3244. astrlen:
  3245.     move.l    a0,d0            ;Save initial address
  3246. 1$    tst.b    (a0)+            ;Test a byte for zero-ness
  3247.      bne    1$
  3248.  
  3249.     suba.l    d0,a0            ;Minus initial address
  3250.     subq.w    #1,a0            ;Less one for overshoot
  3251.     exg    d0,a0            ;swap em
  3252.     rts
  3253.  
  3254. * ------------------------------------------------------------------------- *
  3255. * astrcat()
  3256. * Takes text in a0, appends text in a1
  3257. * a0 returns pointing to null at end of final text
  3258. * ------------------------------------------------------------------------- *
  3259.     XDEF    astrcat
  3260. astrcat:
  3261. * Find end of first text
  3262. 1$    tst.b    (a0)+
  3263.      bne    1$
  3264.     subq.w    #1,a0            ;Back up to null char
  3265.  
  3266. * Append second text
  3267. 2$    move.b    (a1)+,(a0)+
  3268.      bne    2$
  3269.     subq.w    #1,a0            ;a0 = the null at end of final text
  3270.     rts
  3271.  
  3272. * ------------------------------------------------------------------------- *
  3273. * astrcpy()
  3274. * Takes text in a0, copies text in a1
  3275. * a0 returns pointing to null at end of final text
  3276. * ------------------------------------------------------------------------- *
  3277.     XDEF    astrcpy
  3278. astrcpy:
  3279. * Copy second text
  3280. 1$    move.b    (a1)+,(a0)+
  3281.      bne    1$
  3282.     subq.w    #1,a0            ;Back up to null
  3283.     rts
  3284.  
  3285. * ------------------------------------------------------------------------- *
  3286. * astrcmp()
  3287. * Takes text in a0, compares to text in a1
  3288. * a0 returns pointing to first difference, d0 contains the difference
  3289. * or zero if the two texts are identical
  3290. * ------------------------------------------------------------------------- *
  3291.     XDEF    astrcmp
  3292. astrcmp:
  3293. 1$    move.b    (a0)+,d0        ;Grab a char from A
  3294.     move.b    (a1)+,d1        ;Grab a char from B
  3295.     tst.b    d0            ;Hit end of A?
  3296.      beq.s    2$            ;Yep, diff em
  3297.     cmp.b    d1,d0            ;Else the same char?
  3298.      beq    1$            ;Compare next pair
  3299. 2$    sub.b    d1,d0            ;A - B
  3300.     ext.w    d0
  3301.     ext.l    d0
  3302.     rts
  3303.  
  3304. * -----------------------------------------------------------------------
  3305. * safestrcpy(dest, source, length)
  3306. *   Copies at most length chars of source to dest, if source < length
  3307. * don't pad with nulls like strncpy.  Always null terminates dest.
  3308. * -----------------------------------------------------------------------
  3309.     XDEF    _safestrcpy
  3310. _safestrcpy:
  3311.     movem.l    4(sp),a0/a1        ;Grab dest and source pointers
  3312.     move.w    14(sp),d0        ;Grab count
  3313.  
  3314. * ------------------------------------------------------------------------- *
  3315. * astrncpy()
  3316. * Takes text in a1, copies d0 bytes to text in a0.
  3317. * a0 returns pointing to null at end of final text.
  3318. * Dest text is always null terminated.
  3319. * ------------------------------------------------------------------------- *
  3320.     XDEF    astrncpy
  3321. astrncpy:
  3322. 1$    move.b    (a1)+,(a0)+
  3323. 2$    dbeq    d0,1$
  3324.     subq.w    #1,a0
  3325.     clr.b    (a0)            ;Null terminate dest
  3326.     move.l    a0,d0
  3327.     rts
  3328.  
  3329. * ------------------------------------------------------------------------- *
  3330. * amovmem()
  3331. * Takes text in a0, copies d0 bytes to text in a1. Correctly handles
  3332. * overlapping memory.
  3333. * ------------------------------------------------------------------------- *
  3334.     XDEF    amovmem
  3335. amovmem:
  3336.     cmpa.l    a0,a1            ;Low to high or high to low?
  3337.      bcs.s    2$            ;High to low, copy forward
  3338.     adda.w    d0,a0            ;Else start at end, copy backward
  3339.     adda.w    d0,a1
  3340.  
  3341. 1$    move.b    -(a0),-(a1)
  3342.     subq.w    #1,d0
  3343.      bgt    1$
  3344.     bra.s    amdone
  3345.  
  3346. 2$    move.b    (a0)+,(a1)+
  3347.     subq.w    #1,d0
  3348.      bgt    2$
  3349. amdone:
  3350.     rts
  3351.  
  3352. * --------------------------------------------------------------------- *
  3353. *             END OF SOURCE
  3354. * --------------------------------------------------------------------- *
  3355.     END
  3356.