home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / newc_dev / ls40.lzh / src / lssup.a < prev    next >
Text File  |  1990-05-10  |  35KB  |  1,313 lines

  1. * --------------------------------------------------------------------- *
  2. * lssup.a - Assembly support routines for ls.c
  3. * Written by Justin V. McCormick 89-07-24
  4. * Modified for use in v4.0k by Kim E. DeVaughn - 05/11/90
  5. * --------------------------------------------------------------------- *
  6.     IFD    CAPE
  7.     CSYMFMT
  8.     BASEREG B
  9.     SMALLOBJ
  10.     ADDSYM
  11.     OPTIMON
  12.     IDNT    "lssup.a"
  13.     ENDC
  14.  
  15.  
  16. SYS    MACRO    *
  17.     IFGT    NARG-2
  18.     FAIL    !!!
  19.     ENDC
  20.     IFEQ    NARG-2
  21.     MOVE.L    \2,a6
  22.     ENDC
  23.     JSR    LVO\1(a6)
  24.     ENDM
  25.  
  26. XLVO    MACRO    *
  27.     XREF    LVO\1
  28.     ENDM
  29.  
  30. ; Equates
  31. fib_DiskKey        EQU    $0
  32. fib_DirEntryType    EQU    $4
  33. fib_FileName        EQU     $8
  34. fib_Size        EQU     $7C
  35. fib_NumBlocks        EQU     $80
  36. fib_DateStamp        EQU     $84
  37. fib_SIZEOF        EQU     $104
  38.  
  39. ds_Days         EQU     $0
  40. ds_Minute        EQU     $4
  41. ds_Tick         EQU     $8
  42.  
  43. LH_HEAD         EQU     $0
  44. LN_PRED         EQU     $4
  45. LN_SUCC         EQU     $0
  46.  
  47. fe_Node         EQU     $0
  48. fe_Fib            EQU     $8
  49.  
  50. pr_ConsoleTask        EQU     $A4
  51.  
  52. MEMF_CLEAR        EQU     $10000
  53. sp_Msg            EQU     $0
  54. sp_Pkt            EQU     $14
  55. sp_SIZEOF        EQU     $44
  56. dp_Link         EQU     $0
  57. dp_Port         EQU     $4
  58. dp_Arg1         EQU     $14
  59. dp_Type         EQU     $8
  60. ACTION_SCREEN_MODE  EQU     $3E2
  61. LN_NAME         EQU     $A
  62. LN_PRI            EQU     $9
  63. LN_TYPE         EQU     $8
  64. MP_FLAGS        EQU     $E
  65. MP_MSGLIST        EQU     $14
  66. MP_SIGBIT        EQU     $F
  67. MP_SIGTASK        EQU     $10
  68. MP_SIZE         EQU     $22
  69. NT_MSGPORT        EQU     $4
  70. PA_SIGNAL        EQU     $0
  71.  
  72. * Library offsets
  73.     XLVO    AddPort
  74.     XLVO    AddTail
  75.     XLVO    AllocMem
  76.     XLVO    AllocSignal
  77.     XLVO    CopyMem
  78.     XLVO    Debug
  79.     XLVO    Examine
  80.     XLVO    FindTask
  81.     XLVO    FreeMem
  82.     XLVO    FreeSignal
  83.     XLVO    GetMsg
  84.     XLVO    Input
  85.     XLVO    Insert
  86.     XLVO    IsInteractive
  87.     XLVO    Output
  88.     XLVO    ParentDir
  89.     XLVO    PutMsg
  90.     XLVO    RawDoFmt
  91.     XLVO    Read
  92.     XLVO    RemPort
  93.     XLVO    WaitForChar
  94.     XLVO    WaitPort
  95.     XLVO    Write
  96.     XLVO    UnLock
  97.  
  98. * External constants
  99.     XREF    @AllocFib
  100.     XREF    @stpcpy
  101.     XREF    @strcat
  102.     XREF    @strlen
  103.     XREF    baddatestr
  104.     XREF    badtimestr
  105.     XREF    ColonStr
  106.     XREF    datepat
  107.     XREF    dayspermonth
  108.     XREF    DOSBase
  109.     XREF    gwbrstr
  110.     XREF    LSFlags
  111.     XREF    RamNameStr
  112.     XREF    SlashStr
  113.     XREF    sortkey
  114.     XREF    timepat
  115.  
  116.     SECTION CODE
  117. * --------------------------------------------------------------------- *
  118. * VOID *myalloc (LONG)
  119. *   d0          d0
  120. * --------------------------------------------------------------------- *
  121.     XDEF    @myalloc
  122. @myalloc:
  123.     movem.l d2/a6,-(sp)
  124.     addq.l    #4,d0            ;Include sizeof(LONG)
  125.     move.l    d0,d2            ;Copy to survive AllocMem
  126.     moveq    #0,d1            ;MEMF_ANYTHING
  127.     SYS    AllocMem,4        ;AllocMem(size + 4, 0L)
  128.     tst.l    d0            ;Got it?
  129.      beq.s    1$
  130.     movea.l d0,a6            ;Copy pointer
  131.     move.l    d2,(a6)+                ;Stash size in first 4 bytes
  132.     move.l    a6,d0            ;return final pointer in d0
  133. 1$
  134.     movem.l (sp)+,d2/a6
  135.     rts
  136.  
  137. * --------------------------------------------------------------------- *
  138. * VOID myfree (VOID *)
  139. *        a0
  140. * --------------------------------------------------------------------- *
  141.     XDEF    @myfree
  142. @myfree:
  143.     move.l    a6,-(sp)
  144.  
  145.     lea    -4(a0),a1               ;Put in sys reg
  146.     move.l    (a1),d0                 ;d0 = size to free
  147.     SYS    FreeMem,4
  148.  
  149.     movea.l (sp)+,a6
  150.     rts
  151.  
  152. * --------------------------------------------------------------------- *
  153. * void asprintf(wstr, formatstring, args)
  154. *   char *wstr;
  155. *   char *formatstring;
  156. *   char **args;
  157. *
  158. * Synopsis: Given formatstring and args to format, formats output to wstr.
  159. * Similar to sprintf(), except doesn't handle floats.
  160. * --------------------------------------------------------------------- *
  161.     XDEF    asprintf
  162. asprintf:
  163.     link    a5,#0
  164.     movem.l d0-d2/a0-a3/a6,-(sp)    ;Save everything we might clobber
  165.  
  166. * Call format function to convert fmtstring and args to buffer on the stack
  167.     movea.l 12(a5),a0               ;Grab format string
  168.     lea    16(a5),a1               ;Grab EA of arguments
  169.     lea    kput1,a2        ;Grab EA of output subroutine
  170.     movea.l 8(a5),a3                ;Grab EA of dest workspace
  171.     SYS    RawDoFmt,4        ;Format it into workspace
  172.  
  173.     movem.l (sp)+,d0-d2/a0-a3/a6    ;Restore registers
  174.     unlk    a5            ;And stack frame
  175.     rts
  176.  
  177. * --------------------------------------------------------------------- *
  178. * RawDoFmt() output routine for xprintf, called for each formatted char.
  179. * Takes byte in d0 and puts in buffer pointed to by a3, then increments a3.
  180. * --------------------------------------------------------------------- *
  181.     XDEF    kput1
  182. kput1:
  183.     move.b    d0,(a3)+
  184.     rts
  185.  
  186. * --------------------------------------------------------------------- *
  187. * void GetWinBounds(width, height)
  188. *   long *width, *height;
  189. *       a0        a1
  190. * Find current console window, determine width and height
  191. * in terms of current font, update width and height VPARMS passed.
  192. * --------------------------------------------------------------------- *
  193. height    EQU    -4
  194. width    EQU    -8
  195. conid    EQU    -12
  196. packet    EQU    -16
  197. rpport    EQU    -20
  198. rpstr    EQU    -40
  199.  
  200.     XDEF    @GetWinBounds
  201. @GetWinBounds:
  202.     link    a5,#-44
  203.     movem.l d2-d4/a2/a6,-(sp)
  204.  
  205.     move.l    a0,width(a5)            ;Save width/height pointers on stack
  206.     move.l    a1,height(a5)
  207.  
  208.     SYS    Input,DOSBase(a4)       ;Grab Input filehandle
  209.     move.l    d0,d1
  210.     SYS    IsInteractive        ;IsInteractive(Input())?
  211.     tst.l    d0
  212.      beq.s    gwbnowbrep        ;Nope, can't get a bounds report
  213.     SYS    Output
  214.     move.l    d0,d1
  215.     SYS    IsInteractive        ;IsInteractive(Output())?
  216.     tst.l    d0
  217.      beq.s    gwbnowbrep        ;Nope, don't clutter output stream
  218.  
  219.     suba.l    a1,a1
  220.     SYS    FindTask,4        ;d0 = FindTask(0L), our process
  221.     movea.l d0,a0            ;Transfer to address reg
  222.     move.l    pr_ConsoleTask(a0),conid(a5) ;Save proc->pr_ConsoleTask
  223.     tst.l    conid(a5)               ;Is there really a console there?
  224.      bne.s    gwbgotcon        ;Yep
  225.  
  226. gwbnowbrep:
  227. * Else we cannot get a window bounds report from this source
  228.     moveq    #23,d1            ;return H=23
  229.     moveq    #77,d2            ;    W=77
  230.     bra    gwbupdate
  231.  
  232. gwbgotcon:
  233.     moveq    #0,d4            ;Clear our success status register
  234.  
  235.     moveq    #0,d0
  236.     movea.l d0,a0
  237.     jsr    CreatePort
  238.     move.l    d0,rpport(a5)           ;rpport = CreatePort(0L, 0L)
  239.      beq    gwbdone         ;Oops, no signals or ram available!
  240.     moveq    #sp_SIZEOF,d0
  241.     jsr    @myalloc
  242.     move.l    d0,packet(a5)           ;packet = AllocBlock(sizeof(*packet))
  243.      beq    gwbfreeport        ;Oops, no ram, free up port
  244.  
  245. * Okay, we got our process id, reply port, and packet
  246. * Now toggle the console into raw mode
  247.     movea.l rpport(a5),a2
  248.     movea.l d0,a1
  249.     movea.l conid(a5),a0
  250.     moveq    #1,d0
  251.     jsr    SetConsoleType        ;SetConsoleType(1L, conid, packet, rpport)
  252.  
  253. * Request a window bounds report
  254.     SYS    Output,DOSBase(a4)
  255.     move.l    d0,d1
  256.     moveq    #4,d3
  257.     lea    gwbrstr(a4),a0
  258.     move.l    a0,d2
  259.     SYS    Write,DOSBase(a4)       ;Write(Output(), "\2330 q", 4L);
  260.     cmpi.l    #$0004,d0        ;Did the console choke on it?
  261.      bne    gwbsetcook        ;hmmm, see if we can back out gracefully
  262.  
  263. * Read the report string into stack buffer, if there is one
  264.     move.l    #10000,d2
  265.     SYS    Input
  266.     move.l    d0,d1
  267.     SYS    WaitForChar        ;WaitForChar(Input(), 10000L) (.01 secs)
  268.     tst.l    d0            ;Did we get the report?
  269.      beq    gwbsetcook        ;Nope, must not be a report coming
  270.  
  271.     SYS    Input
  272.     move.l    d0,d1
  273.     moveq    #16,d3            ;Don't let it get longer than 16 characters
  274.     lea    rpstr(a5),a0            ;Point to input string area
  275.     move.l    a0,d2
  276.     SYS    Read            ;Read(Input(), rpstr, 16L)
  277.     move.l    d0,d4            ;Save read length while we close shop
  278.  
  279. * Turn the console back to cooked mode pronto to avoid cursor blink
  280. gwbsetcook:
  281.     movea.l rpport(a5),a2
  282.     movea.l packet(a5),a1
  283.     movea.l conid(a5),a0
  284.     moveq    #0,d0
  285.     jsr    SetConsoleType        ;SetConsoleType(0L, conid, packet, rpport)
  286.  
  287. * Release resources we borrowed
  288. gwbfreepack:
  289.     move.l    packet(a5),d0           ;Did we allocate a packet?
  290.      beq.s    gwbfreeport        ;nay, check for port to free
  291.     movea.l d0,a0
  292.     jsr    @myfree         ;Else FreeBlock(packet)
  293.  
  294. gwbfreeport:
  295.     move.l    rpport(a5),d0           ;if (rpport)...
  296.      beq    gwbdone         ;nope
  297.     jsr    DeletePort        ;Else DeletePort(rpport)
  298.  
  299. * Finally, sanity check window bounds report string
  300. * d4 = length of report string according to Read()
  301.     cmpi.l    #9,d4            ;Less than 8 characters returned?
  302.      ble    gwbdone         ;hmmm, phonky bounds report from DOS?
  303.     lea    rpstr(a5),a2            ;a2 = rpstr
  304.     cmpi.b    #';',4(a2)              ;Matches a typical report template?
  305.      bne    gwbdone         ;nope, got some weird junk back?
  306.     cmpi.b    #'r',-1(a2,d4.w)        ;Last byte is 'r' for report?
  307.      bne    gwbdone         ;Nope, message fubar!
  308.  
  309. * Parse the height and width variables from the field now
  310. * Our report format looks like this in hex:
  311. *    9b 31 3b 31 3b y2 y1 3b x2 x1 20 72
  312. * Or in ascii:
  313. *    <0x9b>1;1;20;77 r
  314. * Which would indicate a width of 77 cols and a height of 20 rows for
  315. * the current console device
  316. *
  317. * REGS: a2 points to beginning of 'r' terminated string
  318.  
  319.     addq.w    #5,a2            ;Point to first char of Y size
  320.     moveq    #0,d1            ;Clear out work reg
  321.  
  322. * Convert ascii rows value to LONG, update host data
  323.     move.b    (a2)+,d1                ;Grab a Y
  324.     subi.w    #'0',d1                 ;Less ascii offset
  325.     cmpi.b    #';',(a2)               ;Any more Y digits?
  326.      beq.s    1$            ;Nope
  327.     mulu    #10,d1            ;Else shift by 10
  328.     add.b    (a2)+,d1                ;Add least significant Y digit
  329.     subi.b    #'0',d1                 ;Less ascii offset
  330.     cmpi.b    #';',(a2)               ;Any more Y digits?
  331.      beq.s    1$            ;Nope
  332.     mulu    #$000a,d1        ;Else shift by 10
  333.     add.b    (a2)+,d1                ;Add least significant Y digit
  334.     subi.b    #'0',d1                 ;Less ascii offset
  335.                     ;We'll assume screen height < 999 rows
  336. 1$
  337. * Convert ascii columns value to LONG, update host data
  338.     addq.w    #1,a2            ;Move past the ';' separator
  339.     moveq    #0,d2            ;Zap work reg
  340.     move.b    (a2)+,d2                ;Grab msd of X
  341.     cmpi.b    #' ',d2                 ;Premature end?
  342.      beq    gwbdone         ;Huh, must be garbage - don't update VPARMS
  343.     cmpi.b    #';',d2                 ;Also a possible error
  344.      beq    gwbdone
  345.     cmpi.b    #'r',d2                 ;And what about this?
  346.      beq    gwbdone
  347.  
  348.     subi.b    #'0',d2                 ;Okay, adjust ascii offset
  349.     cmpi.b    #' ',(a2)               ;Hit end of report?
  350.      beq.s    2$            ;Yep
  351.     mulu    #$000a,d2        ;Else shift by 10
  352.     add.b    (a2)+,d2                ;Add next digit
  353.     subi.b    #'0',d2                 ;Ascii adjust
  354.     cmpi.b    #' ',(a2)               ;Hit end of report?
  355.      beq.s    2$            ;Yep
  356.     mulu    #$000a,d2        ;Else shift by 10
  357.     add.b    (a2),d2                 ;Add next digit
  358.     subi.b    #'0',d2                 ;Ascii adjust
  359.  
  360. 2$
  361. gwbupdate:
  362. * Finally, update parameters by reference
  363.     movea.l height(a5),a0           ;Grab height VPARM
  364.     move.l    d1,(a0)                 ;*height = d1
  365.     movea.l width(a5),a0            ;Grab width VPARM
  366.     move.l    d2,(a0)                 ;*width = d2
  367.  
  368. gwbdone:
  369.     movem.l (sp)+,d2-d4/a2/a6
  370.     unlk    a5
  371.     rts
  372.  
  373. * --------------------------------------------------------------------- *
  374. * void __asm SetConsoleType(flag, id, packet, port)
  375. *   register __d0 long flag;
  376. *   register __a0 struct Process *id;
  377. *   register __a1 struct StandardPacket *packet;
  378. *   register __a2 struct MsgPort *port;
  379. *
  380. * Flag = 1L -- Raw mode
  381. *      = 0L -- Cooked mode
  382. * --------------------------------------------------------------------- *
  383.     XDEF    SetConsoleType
  384. SetConsoleType:
  385.     movem.l a2/a3/a5/a6,-(sp)
  386.  
  387.     movea.l a0,a3            ;Copy process pointer
  388.     movea.l a1,a5            ;Copy packet pointer
  389.     lea    sp_Pkt(a5),a0           ;a0 = &packet->sp_Pkt
  390.     move.l    a0,sp_Msg+LN_NAME(a5)   ;p->sp_Msg.mn_Node.ln_Name = &p->sp_Pkt
  391.     lea    sp_Msg(a5),a0           ;a0 = &packet->sp_Msg
  392.     move.l    a0,sp_Pkt+dp_Link(a5)   ;p->sp_Pkt.dp_Link = &p->sp_Msg
  393.     move.l    a2,sp_Pkt+dp_Port(a5)   ;p->sp_Pkt.dp_Port = replyport
  394.     move.l    #ACTION_SCREEN_MODE,sp_Pkt+dp_Type(a5)  ;Set function
  395.  
  396.     tst.w    d0            ;On or Off?
  397.      beq    1$
  398.     move.l    #-1,sp_Pkt+dp_Arg1(a5)  ;RAW ON
  399.     bra.s    2$
  400. 1$
  401.     clr.l    sp_Pkt+dp_Arg1(a5)      ;RAW OFF
  402. 2$
  403.     movea.l a3,a0
  404.     movea.l a5,a1
  405.     SYS    PutMsg,4        ;PutMsg(proc, packet)
  406.  
  407.     movea.l a2,a0
  408.     SYS    WaitPort        ;WaitPort(port)
  409.     movea.l a2,a0
  410.     SYS    GetMsg            ;(void)GetMsg(port)
  411.  
  412.     movem.l (sp)+,a2/a3/a5/a6
  413.     rts
  414.  
  415. * ------------------------------------------------------------------------- *
  416. * struct MsgPort *CreatePort(name, pri) (a0/d0)
  417. * ------------------------------------------------------------------------- *
  418.     XDEF    CreatePort
  419. CreatePort:
  420.     movem.l d5/d7/a2/a5/a6,-(sp)
  421.  
  422.     move.l    a0,a5            ;Save Name
  423.     move.l    d0,d5            ;Save Pri
  424.  
  425. * Allocate a free signal, crap out if we can't
  426.     moveq    #-1,d0
  427.     SYS    AllocSignal,4
  428.     cmp.l    #-1,d0            ;Did we get a signal?
  429.      bne.s    cpgotsig        ;Yep
  430.     moveq    #0,d0            ;Otherwise return NULL
  431.     bra    cpdone
  432.  
  433. cpgotsig:
  434.     move.l    d0,d7            ;Save our signal
  435.  
  436. * Allocate memory for MsgPort
  437.     moveq    #MP_SIZE,d0        ;Size of MsgPort
  438.     jsr    @myalloc        ;Allocate it
  439.     tst.l    d0            ;Did we get it?
  440.      bne.s    cpgotport        ;Yep
  441.  
  442.     move.l    d7,d0            ;Otherwise crap out, free signal
  443.     SYS    FreeSignal
  444.     moveq    #0,d0            ;Return NULL
  445.     bra    cpdone
  446.  
  447. cpgotport:
  448.     move.l    d0,a2            ;This is our new port!
  449.     move.l    a5,LN_NAME(a2)          ;port->mp_Node.ln_Name = name
  450.     move.b    d5,LN_PRI(a2)           ;port->mp_Node.ln_Pri = priority
  451.     move.b    #NT_MSGPORT,LN_TYPE(a2) ;port->mp_Node.ln_Type = NT_MSGPORT
  452.     move.b    #PA_SIGNAL,MP_FLAGS(a2) ;port->mp_Flags = PA_SIGNAL
  453.     move.b    d7,MP_SIGBIT(a2)        ;port->mp_SIGBIT = sigBit
  454.     suba.l    a1,a1
  455.     SYS    FindTask
  456.     move.l    d0,MP_SIGTASK(a2)       ;port->mp_SIGTASK = FindTask(0L)
  457.  
  458.     cmpa.l    #0,a5            ;Is this a new name?
  459.     beq.s    cpnoname        ;Nope, add it to the msg list
  460.  
  461.     movea.l a2,a1
  462.     SYS    AddPort         ;Otherwise add this port
  463.     move.l    a2,d0            ;Return port pointer
  464.     bra.s    cpdone
  465.  
  466. cpnoname:
  467. * Initialized New List head
  468.     lea    MP_MSGLIST(a2),a0       ;a0 = &port->mp_MsgList
  469.     move.l    a0,(a0)                 ;list->lh_Head = list
  470.     addq.l    #4,(a0)                 ;list->lh_Head += 4L
  471.     clr.l    4(a0)                   ;list->lh_Tail = 0L
  472.     move.l    a0,8(a0)                ;list->lh_TailPred = list
  473.     move.l    a2,d0            ;Return port pointer
  474.  
  475. cpdone:
  476.     movem.l (sp)+,d5/d7/a2/a5/a6
  477.     rts
  478.  
  479. * ------------------------------------------------------------------------- *
  480. * DeletePort(port)(d0)
  481. * ------------------------------------------------------------------------- *
  482.     XDEF    DeletePort
  483. DeletePort:
  484.     movem.l a5/a6,-(sp)
  485.  
  486.     move.l    d0,a5
  487.     movea.l $4,a6
  488.     tst.l    LN_NAME(a5)             ;Is there a name?
  489.     beq.s    dpnoname
  490.  
  491.     move.l    d0,a1
  492.     SYS    RemPort         ;RemPort(port)
  493.  
  494. dpnoname:
  495.     move.b    #$ff,LN_TYPE(a5)        ;port->mp_Node.ln_Type = 0xff
  496.     move.l    #-1,MP_MSGLIST(a5)      ;port->mp_MsgList.lh_Head = -1L
  497.  
  498.     moveq    #0,d0
  499.     move.b    MP_SIGBIT(a5),d0        ;d0 = port->mp_SigBit
  500.     SYS    FreeSignal        ;FreeSignal(d0)
  501.  
  502.     movea.l a5,a0
  503.     jsr    @myfree         ;FreeBlock(port)
  504.  
  505.     movem.l (sp)+,a5/a6
  506.     rts
  507.  
  508. * ------------------------------------------------------------------------
  509. * FibFileDate(fib_date, datestr, timestr)
  510. *        a0      a1       8(a5)
  511. *   struct DateStamp *fib_date;
  512. *   char *datestr, *timestr;
  513. *   Calculate date based on DateStamp structure and return a pointer
  514. * to the formatted date string.
  515. * ------------------------------------------------------------------------
  516.     XDEF    @FibFileDate
  517. @FibFileDate:
  518.     link    a5,#0
  519.     movem.l d3-d7/a2-a3/a6,-(sp)
  520.  
  521.     movea.l a1,a3            ;a3 = datestr, 8(a5) = timestr
  522.     movea.l a0,a1            ;Grab datestamp pointer
  523.     moveq    #78,d7            ;Initial year = 1978
  524.  
  525.     move.l    (a1),d5                 ;days = fib_date->ds_Days
  526.      blt    ffdbaddate        ;Hey! you can't be negative! Invalid date...
  527.  
  528. * Determine what year it is
  529.     divu    #1461,d5
  530.     move.l    d5,d0            ;Stash it
  531.     ext.l    d5
  532.     lsl.l    #2,d5
  533.     add.l    d5,d7            ;year += (days / 1461) * 4
  534.  
  535. * Count how many months into that year
  536. ffdgetmo:
  537.     swap    d0            ;days %= 1461
  538.     move.w    d0,d5
  539.  
  540. 1$    tst.w    d5            ;Out of days yet?
  541.      beq.s    3$            ;Yep, done here
  542.  
  543.     move.w    #365,d6         ;Else month_days = 365
  544.     move.w    d7,d0            ;Grab year
  545.     andi.w    #3,d0            ;if (year & 3) == 0 Leap year?
  546.      bne.s    2$            ;Nope
  547.     addq.w    #1,d6            ;Otherwise bump month_days
  548.  
  549. 2$    cmp.w    d6,d5            ;is day < month_days?
  550.      blt.s    3$            ;yep, done here
  551.     sub.w    d6,d5            ;otherwise day -= month_days
  552.  
  553.     addq.l    #1,d7            ; year++
  554.     bra    1$
  555. 3$
  556.  
  557. * Count how many days into that month of that year
  558. ffdgetday:
  559. ;for (i = 0, day++; i < 12; i++)
  560.     moveq    #0,d4            ;current month = 0
  561.     moveq    #0,d6            ;Zap hinybs
  562.     addq.w    #1,d5
  563.     lea    dayspermonth(a4),a0
  564.  
  565. 1$
  566.     move.b    0(a0,d4.w),d6           ;month_days = dayspermonth[i]
  567.  
  568.     cmpi.w    #1,d4            ;if (i == 1 && (year & 3) == 0)
  569.      bne.s    2$
  570.     move.w    d7,d0
  571.     andi.w    #3,d0
  572.      bne.s    2$
  573.     addq.w    #1,d6            ;month_days++
  574.  
  575. 2$    cmp.w    d6,d5            ;if (day <= month_days)
  576.      ble.s    4$            ;Break out, found the right month
  577.  
  578.     sub.w    d6,d5            ;Else, day -= month_days
  579.  
  580.     addq.w    #1,d4            ;i++
  581. 3$    cmpi.w    #12,d4            ;Done all months yet?
  582.      blt    1$            ;Nope
  583.  
  584. 4$
  585. ffdprint:
  586. 1$    cmpi.l    #99,d7            ;while (year >= 100)
  587.      ble.s    2$
  588.     subi.l    #100,d7         ;year -= 100
  589.     bra    1$
  590. 2$
  591. ;asprintf(datestr, "%02d-%02d-%02d %02d:%02d:%02d", i + 1, day, year, hour, min, sec)
  592.     move.l    8(a1),d0                ;sec = fib_date->ds_Tick / 50;
  593.     divu    #50,d0
  594.     ext.l    d0
  595.     move.l    d0,-(sp)                ;Push secs
  596.     move.l    4(a1),d0                ;min = fib_date->ds_Minute
  597.     move.l    d0,d1            ;Clone it
  598.     divu    #60,d0
  599.     moveq    #0,d3
  600.     move.w    d0,d3            ;hour = min / 60
  601.     mulu    #60,d0
  602.     sub.w    d0,d1            ;min -= hour * 60
  603.     move.l    d1,-(sp)                ;Push mins
  604.     move.l    d3,-(sp)                ;Push hours
  605.     pea    timepat(a4)             ;Push the format pattern
  606.     move.l    8(a5),-(sp)             ;Push destination buffer, datestr
  607.     jsr    asprintf
  608.     lea    20(sp),sp
  609.  
  610.     move.l    d5,-(sp)                ;Push day
  611.     addq.w    #1,d4            ;Push month (offset by 1!)
  612.     move.l    d4,-(sp)
  613.     move.l    d7,-(sp)                ;Push year
  614.     pea    datepat(a4)             ;Push the format pattern
  615.     move.l    a3,-(sp)                ;Push destination buffer
  616.     jsr    asprintf
  617.     lea    20(sp),sp
  618.  
  619. ffddone:
  620.     movem.l (sp)+,d3-d7/a2-a3/a6
  621.     unlk    a5
  622.     rts
  623.  
  624. ffdbaddate:
  625.     lea    badtimestr(a4),a1       ;stpcpy (timestr, "00:00:00");
  626.     movea.l 8(a5),a0
  627.     jsr    @stpcpy
  628.     lea    baddatestr(a4),a1       ;stpcpy (datestr, "00-00-00");
  629.     movea.l a3,a0
  630.     jsr    @stpcpy
  631.     bra    ffddone
  632.  
  633. *----------------------------------------------------------------------
  634. * LONG iswild(name)
  635. *   char *name;
  636. *       a0
  637. * Search a string for wild characters, return 1 if found
  638. *----------------------------------------------------------------------
  639.     XDEF    @iswild
  640. @iswild:
  641.     moveq    #0,d0            ;Clear out our character register
  642. ischk1:
  643.     move.b    (a0)+,d0                ;Grab a char
  644.      beq.s    iwdone            ;Might be end of string?
  645.     cmpi.b    #'*',d0                 ;Is it *?
  646.      beq.s    iswdone         ;yep, is wild
  647.     cmpi.b    #'?',d0                 ;Is it a qmark
  648.      bne.s    ischk1            ;Nope, check next character
  649.  
  650. iswdone:
  651.     moveq    #1,d0
  652. iwdone:
  653.     rts
  654.  
  655. * ------------------------------------------------------------------------
  656. ; Compare a wild card name with a normal name
  657. ; LONG wildmatch (name, wild)
  658. ;   char *name, *wild;
  659. ;       a0      a1
  660. * ------------------------------------------------------------------------
  661.     XDEF    @wildmatch
  662. @wildmatch:
  663.     link    a5,#-64
  664.     movem.l d2-d3/a2-a3,-(sp)
  665.  
  666.     move.l    LSFlags(a4),d2          ;Grab flags
  667.     movea.l a0,a2            ;Grab name
  668.     movea.l a1,a3            ;Grab pattern
  669.     lea    -64(a5),a0              ;back[0][0]
  670.     lea    -60(a5),a1              ;back[0][1]
  671.  
  672.     moveq    #0,d3            ;bi = 0
  673.  
  674. wmloop1:
  675.     tst.b    (a2)                    ;End of name?
  676.     bne.s    wmnoteon
  677.     tst.b    (a3)                    ;End of pattern?
  678.     beq    wmmatched        ;Yep, we matched
  679.  
  680. wmnoteon:
  681.     cmpi.b    #'*',(a3)               ;Is it a splat?
  682.     bne.s    wmnotstar        ;Nope, maybe '?'
  683.  
  684.     cmpi.w    #64,d3            ;Have we hit max expression depth?
  685.     beq    wmnomatch        ;Yep, ran out of room in recursion table
  686.  
  687. ;back[bi][0] = w
  688.     move.l    a3,0(a0,d3.w)           ;Stash pointer to this '*' in table
  689.  
  690. ;back[bi][1] = n
  691.     move.l    a2,0(a1,d3.w)
  692.  
  693.     addq.w    #8,d3            ;++bi
  694.     addq.w    #1,a3            ;++w
  695.     bra.s    wmloop1         ;Check next
  696.  
  697. wmgoback:
  698.     subq.w    #8,d3            ;--bi
  699.     move.l    a0,d0
  700. wmback1:
  701.     tst.w    d3            ;while (bi >= 0 && *back[bi][1] == '\x0')
  702.     blt.s    wmbacked
  703.     movea.l 0(a1,d3.l),a0
  704.     tst.b    (a0)
  705.     bne.s    wmbacked
  706.  
  707.     subq.w    #8,d3            ;--bi
  708.     bra.s    wmback1
  709.  
  710. wmbacked:
  711.     tst.w    d3            ;if (bi < 0)
  712.     blt.s    wmnomatch        ;return (0)
  713.  
  714.     movea.l d0,a0
  715.     movea.l 0(a0,d3.w),a3           ;w = back[bi][0] + 1
  716.     addq.w    #1,a3
  717.  
  718.     addq.l    #1,0(a1,d3.w)
  719.     movea.l 0(a1,d3.l),a2           ;n = ++back[bi][1]
  720.  
  721.     addq.w    #8,d3            ;++bi
  722.     bra.s    wmloop1
  723.  
  724. wmnotstar:
  725.     cmpi.b    #'?',(a3)               ;Is it '?'
  726.     bne.s    wmnotqmark
  727.  
  728.     tst.b    (a2)                    ;Reached end of string?
  729.     bne.s    wmincpoint        ;Nope, move on to next char
  730.  
  731.     tst.w    d3            ;Are we at top level of expression?
  732.     beq.s    wmnomatch        ;Yep, expression didn't match
  733.     bra.s    wmgoback        ;Otherwise pop a level and try to match
  734.  
  735. wmnotqmark:
  736.     move.b    (a2),d0                 ;Grab a char from bstr
  737.     move.b    (a3),d1                 ;Grab a char from astr
  738.     btst.l    #21,d2            ;LSFlags & IGNORECASEWILD?
  739.     beq.s    2$            ;Nope, blow off lowercasing crap
  740.  
  741.     cmpi.b    #$40,d0         ;less than @ character?  (for bstr)
  742.     bls.s    1$            ;Yep
  743.     cmpi.b    #$5a,d0         ;Greater than Z?
  744.     bhi.s    1$            ;Yep
  745.     addi.b    #$20,d0
  746. 1$
  747.     cmpi.b    #$40,d1         ;less than @ character?  (for astr)
  748.     bls.s    2$            ;Yep
  749.     cmpi.b    #$5a,d1         ;Greater than Z?
  750.     bhi.s    2$            ;Yep
  751.     addi.b    #$20,d1
  752. 2$
  753.     cmp.b    d0,d1            ;*n = *w?
  754.     beq.s    wmincpoint        ;Yep, move on past
  755.  
  756.     tst.w    d3            ;Are we at top expression level?
  757.     beq.s    wmnomatch        ;Yep, they didn't match
  758.     bra.s    wmgoback        ;Nope, process next part
  759.  
  760. wmincpoint:
  761.     tst.b    (a2)                    ;Done with name?
  762.     beq.s    wmnamend        ;Yep
  763.     addq.w    #1,a2            ;Otherwise increment name pointer
  764.  
  765. wmnamend:
  766.     tst.b    (a3)                    ;End of pattern?
  767.     beq.s    wmmatched        ;Yep, we matched
  768.     addq.w    #1,a3            ;Otherwise inc wild pointer, match next char
  769.     bra    wmloop1
  770.  
  771. wmmatched:
  772.     moveq    #1,d0
  773.     bra.s    wmdone
  774.  
  775. wmnomatch:
  776.     moveq    #0,d0
  777.  
  778. wmdone:
  779.     movem.l (sp)+,d2-d3/a2-a3
  780.     unlk    a5
  781.     rts
  782.  
  783. * --------------------------------------------------------------------- *
  784. * BOOL CompFibs (keytype, a,   b)
  785. *            d0     a0   a1
  786. *   LONG keytype;
  787. *   struct FileInfoBlock *a, *b;
  788. *
  789. * Used by SortFibs to determine precedence of Fibs.
  790. * keytype is one of 0, 1, 2, or 3:
  791. *   0=alpha, 1=size, 2=date, 3=diskkey
  792. * --------------------------------------------------------------------- *
  793.     XDEF    @CompFibs
  794. @CompFibs:
  795.     movem.l d2-d3/a2,-(sp)
  796.  
  797.     move.l    d0,d2            ;Stash keytype
  798.  
  799. * Prioritize Dirs/Files?
  800.     move.l    LSFlags(a4),d3          ;Grab flags
  801.  
  802.     btst.l    #17,d3            ;LSFlags & SEPFILESDIRS?
  803.     beq.s    cftstsort        ;No, don't bother comparing EntryTypes
  804.  
  805.     move.l    fib_DirEntryType(a0),d0
  806.     cmp.l    fib_DirEntryType(a1),d0
  807.     blt.s    1$            ;a0 is < a1, (dir < file)
  808.     beq.s    cftstsort        ;a0 is == a1, try next test
  809.  
  810.     moveq    #0,d0            ;a0 is > a1, (file > dir)
  811.     bra.s    2$
  812. 1$
  813.     moveq    #1,d0            ;greater than, (dir < file)
  814.  
  815. 2$    btst.l    #16,d3            ;LSFlags & FILESFIRST?
  816.     beq    cfexit0         ;Nope, default Dirs first
  817.     bchg.l    #0,d0            ;Else d0 ^= 1, reverse sense
  818.     bra    cfexit0
  819.  
  820. * Both entries are the same type, now see about sorting them
  821. cftstsort:
  822.     btst.l    #6,d3            ;LSFlags & NOSORTFLAG set?
  823.     bne    cffalse         ;Yep, always AddTail to list
  824.  
  825. * Switch keytype
  826.     tst.w    d2            ;Alphabetize?
  827.     bne.s    cfnalpha        ;Nope
  828.  
  829. * Compare lexigraphically, optionally ignoring case differences
  830. cfalpha:
  831.     lea    fib_FileName(a0),a0     ;a = &Fipb->fib_FileName
  832.     lea    fib_FileName(a1),a1     ;b = &Fipb->fib_FileName
  833.  
  834. ; for(; *a && tolower(*a) == tolower(*b); a++, b++); [tolower() crap optional]
  835. lccstart:
  836.     tst.b    (a0)                    ;Is there a char here at source?
  837.     beq.s    lcceostr        ;Nope, fell off the end
  838.  
  839.     move.b    (a1)+,d1                ;Grab a char from bstr
  840.     move.b    (a0)+,d0                ;Grab a char from astr
  841.     btst.l    #20,d3            ;LSFlags & IGNORECASELIST?
  842.     beq.s    2$            ;Nope, blow off lowercasing crap
  843.  
  844.     cmpi.b    #$40,d1         ;less than @ character?  (for bstr)
  845.     bls.s    1$            ;Yep
  846.     cmpi.b    #$5a,d1         ;Greater than Z?
  847.     bhi.s    1$            ;Yep
  848.     addi.b    #$20,d1
  849. 1$
  850.     cmpi.b    #$40,d0         ;less than @ character?  (for astr)
  851.     bls.s    2$            ;Yep
  852.     cmpi.b    #$5a,d0         ;Greater than Z?
  853.     bhi.s    2$            ;Yep
  854.     addi.b    #$20,d0
  855. 2$
  856.     cmp.b    d0,d1            ;are they the same?
  857.     beq.s    lccstart        ;Yep, compare next pair of chars
  858.  
  859. lcceostr:
  860.     sub.b    d1,d0            ;return([tolower](*astr) - [tolower](*bstr))
  861.     bgt.s    cftrue            ; > 0?, return TRUE
  862.     bra.s    cffalse         ;Else return FALSE
  863.  
  864. cfnalpha:
  865.     subq.w    #1,d2            ;Size?
  866.     bne.s    cfnsize         ;Nope
  867.  
  868. * Compare fib_Sizes
  869.     move.l    fib_Size(a0),d0         ;d0 = afib->fib_Size
  870.     cmp.l    fib_Size(a1),d0         ;b->fib_Size < a->fib_Size?
  871.     blt.s    cftrue            ;Yep, return TRUE
  872.     bgt.s    cffalse         ;>, return FALSE
  873.     bra.s    cfalpha         ;Else it's a tie, alphabetize
  874.  
  875. cfnsize:
  876.     subq.w    #1,d2            ;Date?
  877.     bne.s    cfndate         ;No
  878.  
  879. * Compare fib_DateStamps
  880.     lea    fib_DateStamp(a0),a0    ;a = &afib->fib_DateStamp
  881.     lea    fib_DateStamp(a1),a1    ;b = &bfib->fib_DateStamp
  882.     jsr    @CompareDateStamps
  883.     tst.l    d0
  884.     blt.s    cftrue
  885.     bgt.s    cffalse
  886.     bra.s    cfalpha         ;same date; alphabetize
  887.  
  888. cfndate:
  889. *Compare fib_DiskKeys
  890.     move.l    fib_DiskKey(a0),d0      ;d0 = afib->fib_DiskKey
  891.     cmp.l    fib_DiskKey(a1),d0      ;b->fib_DiskKey < a->fib_DiskKey?
  892.     beq.s    cfalpha         ;shouldn't happen [bad filesys if so]
  893.     blt.s    cffalse         ;<, return FALSE
  894.  
  895. cftrue:
  896.     moveq    #1,d0
  897.     bra.s    cfexit
  898. cffalse:
  899.     moveq    #0,d0
  900. cfexit:
  901.     btst.l    #9,d3            ;LSFlags & REVFLAG?
  902.     beq.s    1$            ;Nope
  903.     bchg.l    #0,d0            ;Else invert boolean result
  904. 1$
  905. cfexit0:
  906.     movem.l (sp)+,d2-d3/a2
  907.     rts
  908.  
  909. * --------------------------------------------------------------------- *
  910. * LONG CompareDateStamps(adate, bdate)
  911. *  d0              a0      a1
  912. *   struct DateStamp *adate, *bdate;
  913. * --------------------------------------------------------------------- *
  914.     XDEF    @CompareDateStamps
  915. @CompareDateStamps:
  916.     move.l    ds_Days(a0),d0          ;d0 = adate->ds_Days
  917.     sub.l    ds_Days(a1),d0          ;b->ds_Days > a->ds_Days?
  918.     bne.s    1$            ;Return b->day - a->day
  919.  
  920. ;They are the same day, check min/tick
  921.     move.l    ds_Minute(a0),d0
  922.     sub.l    ds_Minute(a1),d0        ;d0 = amin - bmin
  923.     muls    #3000,d0        ;     * 3000
  924.     add.l    ds_Tick(a0),d0
  925.     sub.l    ds_Tick(a1),d0          ;     + atick - btick
  926. 1$
  927.     rts
  928.  
  929. * --------------------------------------------------------------------- *
  930. * VOID InsertFibNode(hfib, newfib)
  931. *              a0     a1
  932. *   struct List *hfib;
  933. *   struct FibEntry *newfib;
  934. *
  935. * Compare data in newfib->Fib with nodes in the list until we
  936. * find the insertion point.
  937. * --------------------------------------------------------------------- *
  938.     XDEF    @InsertFibNode
  939. @InsertFibNode:
  940.     movem.l d2/a2-a3/a5/a6,-(sp)
  941.  
  942.     move.l    sortkey(a4),d2
  943.     movea.l a0,a3            ;a3 = hfib
  944.     movea.l a1,a2            ;a2 = newfib
  945.  
  946.     movea.l LH_HEAD(a3),a5          ;afib = hfib->lh_Head
  947.  
  948. 1$    tst.l    fe_Node+LN_SUCC(a5)     ;afib->fe_Node.mln_Succ != 0?
  949.     beq.s    4$
  950.  
  951.     movea.l fe_Fib(a2),a1
  952.     movea.l fe_Fib(a5),a0
  953.     move.l    d2,d0
  954.     jsr    @CompFibs        ;CompFibs(sortkey, afib->Fib, newfib->Fib)
  955.     tst.w    d0
  956.     bne.s    4$
  957.     movea.l fe_Node+LN_SUCC(a5),a5  ;afib = afib->fe_Node.mln_Succ
  958.     bra    1$
  959.  
  960. 4$    movea.l a3,a0            ;a0 = List *
  961.     movea.l a2,a1            ;a1 = Node *
  962.     movea.l fe_Node+LN_PRED(a5),a2  ;a2 = Pred *
  963.     SYS    Insert,4        ;Insert(hfib, newfib, afib->fe_Node.mln_Succ)
  964.  
  965.     movem.l (sp)+,d2/a2-a3/a5/a6
  966.     rts
  967.  
  968. * --------------------------------------------------------------------- *
  969. * LONG FillFibEntry (headfib, fibp)
  970. *               a0      a1
  971. *   struct List *headfib;
  972. *   struct FileInfoBlock *fibp;
  973. * --------------------------------------------------------------------- *
  974.     XDEF    @FillFibEntry
  975. @FillFibEntry:
  976.     movem.l a2-a3/a5/a6,-(sp)
  977.     movea.l a0,a2            ;a2 = head of list
  978.     movea.l a1,a3            ;a3 = fileinfoblock
  979.  
  980.     jsr    @AllocFib        ;Allocate a new fib
  981.     tst.l    d0            ;Got it?
  982.     beq.s    3$            ;Nope, return 0
  983.     movea.l d0,a5            ;a5 = tfibp = AllocFib()
  984.  
  985.     move.l    #fib_SIZEOF,d0
  986.     movea.l fe_Fib(a5),a1
  987.     movea.l a3,a0
  988.     SYS    CopyMem,4        ;CopyMem(fibp, tfibp->Fib, sizeof(struct fib))
  989.  
  990.     movea.l a5,a1
  991.     movea.l a2,a0
  992.  
  993.     jsr    @InsertFibNode        ;InsertFibNode(headfib, tfibp)
  994.  
  995.     moveq    #1,d0            ;return(1)
  996. 3$
  997.     movem.l (sp)+,a2-a3/a5/a6
  998.     rts
  999.  
  1000. * --------------------------------------------------------------------- *
  1001.     XDEF    @nullstub
  1002. @nullstub:
  1003.     moveq    #0,d0
  1004.     rts
  1005.  
  1006. * --------------------------------------------------------------------- *
  1007. * LONG GetPathString (dest, src)
  1008. *  d0               a0    a1
  1009. *   BYTE *dest, *src;
  1010. * --------------------------------------------------------------------- *
  1011.     XDEF    @GetPathString
  1012. @GetPathString:
  1013.     move.l    a2,-(sp)
  1014.  
  1015.     moveq    #0,d0            ;Zero return dest length
  1016.  
  1017. * Find end of src string
  1018.     movea.l a1,a2            ;Save src start address
  1019. 1$    tst.b    (a1)+                   ;while (*src++ != 0)
  1020.     bne.s    1$
  1021.  
  1022. * Work backwards till we find a ':' or a '/'
  1023. 2$    move.b    -(a1),d1                ;c = *(--src)
  1024.     cmpi.b    #':',d1                 ;Hit a colon?
  1025.     beq.s    4$            ;Yep, found our path end
  1026.     cmpi.b    #'/',d1                 ;Hit a slash?
  1027.     bne.s    3$            ;Nope, try next char
  1028.     cmpa.l    a2,a1            ;At first char?
  1029.     beq.s    4$            ;Yep, leave the single slash
  1030.     cmpi.b    #'/',-1(a1)             ;Next char back is also a '/'?
  1031.     beq.s    4$            ;Yep, allow multiple slashes
  1032.     subq.w    #1,a1            ;Else backup to previous char, eliminate '/'
  1033.     bra.s    4$
  1034. 3$
  1035.     cmpa.l    a2,a1            ;Back at start of src?
  1036.     bhi.s    2$            ;Nope, try previous src char
  1037.     bra.s    gpsdone         ;Else no dest, return
  1038. 4$
  1039. * Copy path portion to dest
  1040. gpscpy:
  1041.     cmpa.l    a2,a1            ;Past end address?
  1042.     bcs.s    gpsdone         ;Yep, terminate
  1043.     move.b    (a2)+,(a0)+             ;Copy a char from src to dest
  1044.     addq.w    #1,d0            ;Bump dest length count
  1045.     bra.s    gpscpy            ;Check end address
  1046. gpsdone:
  1047.     clr.b    (a0)                    ;Null terminate dest
  1048.  
  1049.     movea.l (sp)+,a2
  1050.     rts
  1051.  
  1052. * --------------------------------------------------------------------- *
  1053. * LONG GetFileString (dest, src)
  1054. *  d0               a0    a1
  1055. *   BYTE *dest, *src;
  1056. * --------------------------------------------------------------------- *
  1057.     XDEF    @GetFileString
  1058. @GetFileString:
  1059.     move.l    a2,-(sp)
  1060.  
  1061.     moveq    #0,d0            ;Zero return dest length
  1062.  
  1063. * Find end of src string
  1064.     movea.l a1,a2            ;Save src start address
  1065. 1$    tst.b    (a1)+                   ;while (*src++ != 0)
  1066.     bne.s    1$
  1067.  
  1068. * Work backwards till we find a ':' or a '/'
  1069. 2$    move.b    -(a1),d1                ;c = *(--src)
  1070.     cmpi.b    #':',d1                 ;Hit a colon?
  1071.     beq.s    4$            ;Yep, found our path end
  1072.     cmpi.b    #'/',d1                 ;Hit a slash?
  1073.     beq.s    4$            ;Nope, try next char
  1074. 3$
  1075.     cmpa.l    a2,a1            ;Back at start of src?
  1076.     bhi.s    2$            ;Nope, try previous src char
  1077.     bra.s    gfscpy            ;Else no path, entire src is filename
  1078. 4$
  1079.     addq.w    #1,a1            ;Move past ':' or '/'
  1080.  
  1081. * Copy name portion to dest
  1082. gfscpy:
  1083.     move.b    (a1)+,(a0)+             ;Copy a char from src to dest
  1084.     beq.s    2$
  1085.     addq.w    #1,d0            ;Bump dest length count
  1086.     bra.s    gfscpy            ;Check end address
  1087. 2$
  1088.     movea.l (sp)+,a2
  1089.     rts
  1090.  
  1091. * ------------------------------------------------------------------------- *
  1092. * BYTE *astrncpy(dst, src, len)
  1093. * d0/a0      a0   a1    d0
  1094. * Takes text in a1, copies d0 bytes to text in a0.
  1095. * a0 returns pointing to null at end of final text.
  1096. * Dest text is always null terminated.
  1097. * ------------------------------------------------------------------------- *
  1098.     XDEF    @astrncpy
  1099. @astrncpy:
  1100. 1$    subq.l    #1,d0            ;Dec count
  1101.     blt.s    2$            ;Done!
  1102.  
  1103.     move.b    (a1)+,(a0)+             ;Copy a byte
  1104.     bne.s    1$            ;Do until end of src or cnt < 0
  1105. 2$
  1106.     clr.b    (a0)                    ;Null terminate dest
  1107.     move.l    a0,d0            ;Return in d0 also
  1108.     rts
  1109.  
  1110. * ------------------------------------------------------------------------- *
  1111. * VOID amovmem(src, dst, len)
  1112. *           a0    a1   d0
  1113. * Takes text in a0, copies d0 bytes to text in a1. Correctly handles
  1114. * overlapping memory.
  1115. * ------------------------------------------------------------------------- *
  1116.     XDEF    amovmem
  1117. amovmem:
  1118.     cmpa.l    a0,a1            ;Low to high or high to low?
  1119.      bcs.s    2$            ;High to low, copy forward
  1120.     adda.w    d0,a0            ;Else start at end, copy backward
  1121.     adda.w    d0,a1
  1122.  
  1123. 1$    move.b    -(a0),-(a1)
  1124.     subq.w    #1,d0
  1125.      bgt    1$
  1126.     bra.s    amdone
  1127.  
  1128. 2$    move.b    (a0)+,(a1)+
  1129.     subq.w    #1,d0
  1130.      bgt    2$
  1131. amdone:
  1132.     rts
  1133.  
  1134. * --------------------------------------------------------------------- *
  1135. * BYTE *aindex(BYTE *, BYTE);
  1136. *  d0        a0    d0
  1137. * --------------------------------------------------------------------- *
  1138.     XDEF    @aindex
  1139. @aindex:
  1140. 1$    cmp.b    (a0),d0
  1141.      beq.s    aifound
  1142.     tst.b    (a0)+
  1143.      beq.s    ainomatch
  1144.     bra    1$
  1145.  
  1146. ainomatch:
  1147.     moveq    #0,d0
  1148.     rts
  1149.  
  1150. aifound:
  1151.     move.l    a0,d0
  1152.     rts
  1153.  
  1154. * --------------------------------------------------------------------- *
  1155. * LONG MakePathString(lock, dest)
  1156. *               a0     a1
  1157. *   struct FileLock *lock;
  1158. *   BYTE *dest;
  1159. *
  1160. * DESCRIPTION:
  1161. *   Given text and a filelock, construct entire pathname and
  1162. * return in dest.
  1163. * --------------------------------------------------------------------- *
  1164.     XDEF    @MakePathString
  1165. @MakePathString:
  1166.     movem.l d2-d5/d7/a2-a3/a6,-(sp)
  1167.  
  1168. * Grab pointer to lock and dest text to fill
  1169.     move.l    a0,d3            ;d3 = lock
  1170.     movea.l a1,a2            ;a2 = dest
  1171.     clr.b    (a2)                    ;NULL terminate dest
  1172.     moveq    #0,d5            ;LockFlag = 0
  1173.  
  1174. * Allocate a FileInfoBlock for local use
  1175.     move.l    #fib_SIZEOF,d0
  1176.     jsr    @myalloc
  1177.     move.l    d0,d7            ;d7 = *fib
  1178.      beq    mpsfailed        ;Whoops no mem? return!
  1179.  
  1180.     movea.l DOSBase(a4),a6          ;DOSBase calls from here on
  1181.  
  1182. * while (lock != 0)
  1183. 1$
  1184.     tst.l    d3            ;Got a lock?
  1185.      beq.s    mpsokay         ;Nope, must be at root
  1186.  
  1187. * Examine the current lock
  1188.     move.l    d3,d1
  1189.     move.l    d7,d2
  1190.     SYS    Examine         ;Examine(lock, fib)
  1191.     tst.l    d0            ;Okay?
  1192.      beq.s    mpsfailed        ;Nope, some sort of dos failure?
  1193.  
  1194.     movea.l d7,a1
  1195.     cmpi.b    #' ',fib_FileName(a1)   ;if (fib->fib_FileName[0] >= ' ')
  1196.      bcs.s    3$            ;Nope, don't bother inserting?
  1197.  
  1198.     tst.b    (a2)                    ;if (dest[0] != 0)
  1199.      beq.s    2$
  1200.     lea    SlashStr(a4),a1
  1201.     movea.l a2,a0
  1202.     jsr    @InsertPathString    ;InsertPathString(dest, "/");
  1203. 2$
  1204.     movea.l d7,a1
  1205.     lea    fib_FileName(a1),a1
  1206.     movea.l a2,a0
  1207.     jsr    @InsertPathString    ;InsertPathString(dest, fib->fib_FileName)
  1208. 3$
  1209. * Okay, move up one directory
  1210.     move.l    d3,d4            ;oldlock = lock
  1211.  
  1212.     move.l    d3,d1
  1213.     SYS    ParentDir
  1214.     move.l    d0,d3            ;lock = ParentDir(lock)
  1215.  
  1216.     tst.w    d5            ;LockFlag set?
  1217.      bne.s    4$            ;Yep, unlock
  1218.     moveq    #1,d5            ;Else LockFlag = 1, unlock next time
  1219.      bra    1$            ;Next directory up
  1220. 4$
  1221.     move.l    d4,d1
  1222.     SYS    UnLock            ;UnLock(oldlock)
  1223.     bra    1$            ;Examine
  1224.  
  1225. mpsokay:
  1226. * See if root was RAM:, special case
  1227.     movea.l d7,a1            ;a1 = fib
  1228.     cmpi.b    #' ',fib_FileName(a1)   ;if (fib->fib_FileName[0] >= ' ')
  1229.      bcc.s    1$            ;Yep, not 1.1/1.2 RAM:
  1230.     lea    RamNameStr(a4),a1       ;Else...
  1231.     movea.l a2,a0
  1232.     jsr    @InsertPathString    ;InsertPathString(dest, "RAM:")
  1233.     bra.s    mpsdone
  1234. 1$
  1235. * Find last slash we tacked on, change to a colon, or, add a colon
  1236.     moveq    #'/',d0
  1237.     movea.l a2,a0
  1238.     jsr    @aindex         ;d0 = strchr(dest, '/')
  1239.     tst.l    d0            ;Do we have a slash?
  1240.      beq.s    2$            ;Nope, at root....
  1241.     movea.l d0,a0
  1242.     move.b    #':',(a0)               ;Else change first '/' to a ':'
  1243.     bra.s    mpsdone
  1244.  
  1245. * No slash, must be locked at the root.  Append a colon to the dest.
  1246. 2$
  1247.     lea    ColonStr(a4),a1
  1248.     movea.l a2,a0
  1249.     jsr    @strcat         ;strcat (dest, ":")
  1250.     bra.s    mpsdone
  1251.  
  1252. * Come here if an error occured, return empty text to caller
  1253. mpsfailed:
  1254.     clr.b    (a2)                    ;dest[0] = (BYTE)0
  1255.     moveq    #0,d3            ;return (0L)
  1256.     bra.s    mpsdeall
  1257.  
  1258. * Come here if everything is okay, deallocate FileInfoBlock
  1259. mpsdone:
  1260.     moveq    #1,d3            ;return (1L)
  1261.  
  1262. mpsdeall:
  1263.     tst.l    d7            ;Did we allocate a fib?
  1264.      beq.s    mpsfinis        ;nope
  1265.     movea.l d7,a0            ;Else free the memory
  1266.     jsr    @myfree
  1267.  
  1268. mpsfinis:
  1269.     move.l    d3,d0            ;Put return value in d0
  1270.     movem.l (sp)+,d2-d5/d7/a2-a3/a6
  1271.     rts
  1272.  
  1273. * --------------------------------------------------------------------- *
  1274. * VOID InsertPathString(dest, source)
  1275. *             a0    a1
  1276. *   BYTE *dest, *source;
  1277. *
  1278. * DESCRIPTION:
  1279. *   Insert source text into dest text.
  1280. * Special case for source length == 0, source must be RAM.
  1281. * --------------------------------------------------------------------- *
  1282.     XDEF    @InsertPathString
  1283. @InsertPathString:
  1284.     movem.l d7/a2-a3,-(sp)
  1285.  
  1286.     movea.l a1,a3            ;a3 = source
  1287.     move.l    a0,a2            ;a2 = dest
  1288.  
  1289.     movea.l a3,a0
  1290.     jsr    @strlen
  1291.     move.l    d0,d7            ;d7 = strlen(source)
  1292.  
  1293. 1$    movea.l a2,a0
  1294.     jsr    @strlen         ;d0 = strlen(dest)
  1295.  
  1296.     addq.w    #1,d0            ;Bump the length to include zero byte at end
  1297.     movea.l a2,a1
  1298.     adda.w    d7,a1            ;Push dest + slen
  1299.     movea.l a2,a0            ;Push dest
  1300.     jsr    amovmem         ;amovmem(dest, dest + slen, strlen(dest) + 1)
  1301.  
  1302.     move.w    d7,d0
  1303.     movea.l a2,a1
  1304.     movea.l a3,a0
  1305.     jsr    amovmem         ;amovmem(source, dest, slen)
  1306.  
  1307.     movem.l (sp)+,d7/a2-a3
  1308.     rts
  1309.  
  1310. * --------------------------------------------------------------------- *
  1311.     END
  1312. * --------------------------------------------------------------------- *
  1313.