home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / newc_dev / ls32.lha / lssup.a < prev    next >
Text File  |  1989-08-09  |  34KB  |  1,343 lines

  1. * --------------------------------------------------------------------- *
  2. * LSSUP.A - Assembly support routines for ls.c
  3. * Written by Justin V. McCormick 89-07-24
  4. * --------------------------------------------------------------------- *
  5.     IFD    CAPE
  6.     CSYMFMT
  7.     BASEREG    B
  8.     SMALLOBJ
  9.     ADDSYM
  10.     OPTIMON
  11.     IDNT    "lssup.a"
  12.     ENDC
  13.  
  14.  
  15. SYS    MACRO    *
  16.     IFGT    NARG-2
  17.     FAIL    !!!
  18.     ENDC
  19.     IFEQ    NARG-2
  20.     MOVE.L    \2,a6
  21.     ENDC
  22.     JSR    LVO\1(a6)
  23.     ENDM
  24.  
  25. XLVO    MACRO    *
  26.     XREF    LVO\1
  27.     ENDM
  28.  
  29. ; Equates
  30. fib_DirEntryType EQU    $4 
  31. fib_FileName    EQU    $8
  32. fib_Size    EQU    $7C
  33. fib_NumBlocks    EQU    $80
  34. fib_DateStamp    EQU    $84
  35. fib_SIZEOF    EQU    $104 
  36.  
  37. ds_Days        EQU    $0
  38. ds_Minute    EQU    $4
  39. ds_Tick        EQU    $8
  40.  
  41. LH_HEAD        EQU    $0
  42. LN_PRED        EQU    $4
  43. LN_SUCC        EQU    $0
  44.  
  45. fe_Node    equ    0
  46. fe_Fib    equ    8
  47. pr_ConsoleTask        EQU    $A4
  48.  
  49. MEMF_CLEAR        EQU    $10000
  50. sp_Msg            EQU    $0
  51. sp_Pkt            EQU    $14
  52. sp_SIZEOF        EQU    $44
  53. dp_Link            EQU    $0
  54. dp_Port            EQU    $4
  55. dp_Arg1            EQU    $14
  56. dp_Type            EQU    $8
  57. ACTION_SCREEN_MODE    EQU    $3E2
  58. LN_NAME            EQU    $A
  59. LN_PRI            EQU    $9
  60. LN_TYPE            EQU    $8
  61. MP_FLAGS        EQU    $E
  62. MP_MSGLIST        EQU    $14
  63. MP_SIGBIT        EQU    $F
  64. MP_SIGTASK        EQU    $10
  65. MP_SIZE            EQU    $22
  66. NT_MSGPORT        EQU    $4
  67. PA_SIGNAL        EQU    $0
  68.  
  69. * Library offsets
  70.     XLVO    AddPort
  71.     XLVO    AddTail
  72.     XLVO    AllocMem
  73.     XLVO    AllocSignal
  74.     XLVO    CopyMem
  75.     XLVO    Debug
  76.     XLVO    Examine
  77.     XLVO    FindTask
  78.     XLVO    FreeMem
  79.     XLVO    FreeSignal
  80.     XLVO    GetMsg
  81.     XLVO    Input
  82.     XLVO    Insert
  83.     XLVO    IoErr
  84.     XLVO    IsInteractive
  85.     XLVO    Output
  86.     XLVO    ParentDir
  87.     XLVO    PutMsg
  88.     XLVO    RawDoFmt
  89.     XLVO    Read
  90.     XLVO    RemPort
  91.     XLVO    WaitForChar
  92.     XLVO    WaitPort
  93.     XLVO    Write
  94.     XLVO    UnLock
  95.  
  96. * External constants
  97.     XREF    @AllocFib
  98.     XREF    @CleanUp
  99.     XREF    @stpcpy
  100.     XREF    @strcat
  101.     XREF    @strlen
  102.     XREF    baddatestr
  103.     XREF    badtimestr
  104.     XREF    ColonStr
  105.     XREF    datepat
  106.     XREF    dayspermonth
  107.     XREF    DOSBase
  108.     XREF    gwbrstr
  109.     XREF    LSFlags
  110.     XREF    NoFindFmtStr
  111.     XREF    NoRAMMsg
  112.     XREF    RamNameStr
  113.     XREF    SlashStr
  114.     XREF    sortkey
  115.     XREF    timepat
  116.  
  117.     SECTION    CODE
  118. * --------------------------------------------------------------------- *
  119. * VOID *myalloc (LONG)
  120. *   d0            d0
  121. * --------------------------------------------------------------------- *
  122.     XDEF    @myalloc
  123. @myalloc:
  124.     movem.l    d2/a6,-(sp)
  125.     addq.l    #4,d0            ;Include sizeof(LONG)
  126.     move.l    d0,d2            ;Copy to survive AllocMem
  127.     moveq    #0,d1            ;MEMF_ANYTHING
  128.     SYS    AllocMem,4        ;AllocMem(size + 4, 0L)
  129.     tst.l    d0            ;Got it?
  130.      beq.s    1$
  131.     movea.l    d0,a6            ;Copy pointer
  132.     move.l    d2,(a6)+        ;Stash size in first 4 bytes
  133.     move.l    a6,d0            ;return final pointer in d0
  134. 1$
  135.     movem.l    (sp)+,d2/a6
  136.     rts
  137.  
  138. * --------------------------------------------------------------------- *
  139. * VOID myfree (VOID *)
  140. *               a0
  141. * --------------------------------------------------------------------- *
  142.     XDEF    @myfree
  143. @myfree:
  144.     move.l    a6,-(sp)
  145.  
  146.     lea    -4(a0),a1        ;Put in sys reg
  147.     move.l    (a1),d0            ;d0 = size to free
  148.     SYS    FreeMem,4
  149.  
  150.     movea.l    (sp)+,a6
  151.     rts
  152.  
  153. * --------------------------------------------------------------------- *
  154. * void asprintf(wstr, formatstring, args)
  155. *   char *wstr;
  156. *   char *formatstring;
  157. *   char **args;
  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    d3/a2-a3,-(sp)
  665.  
  666.     movea.l    a0,a2            ;Grab name
  667.     movea.l    a1,a3            ;Grab pattern
  668.     lea    -64(a5),a0        ;back[0][0]
  669.     lea    -60(a5),a1        ;back[0][1]
  670.  
  671.     moveq    #0,d3            ;bi = 0
  672.  
  673. wmloop1:
  674.     tst.b    (a2)            ;End of name?
  675.      bne.s    wmnoteon
  676.     tst.b    (a3)            ;End of pattern?
  677.      beq    wmmatched        ;Yep, we matched
  678.  
  679. wmnoteon:
  680.     cmpi.b    #'*',(a3)        ;Is it a splat?
  681.      bne.s    wmnotstar        ;Nope, maybe '?'
  682.  
  683.     cmpi.w    #64,d3            ;Have we hit max expression depth?
  684.      beq    wmnomatch        ;Yep, ran out of room in recursion table
  685.  
  686. ;back[bi][0] = w
  687.     move.l    a3,0(a0,d3.w)        ;Stash pointer to this '*' in table
  688.  
  689. ;back[bi][1] = n
  690.     move.l    a2,0(a1,d3.w)
  691.  
  692.     addq.w    #8,d3            ;++bi
  693.     addq.w    #1,a3            ;++w
  694.     bra.s    wmloop1            ;Check next
  695.  
  696. wmgoback:
  697.     subq.w    #8,d3            ;--bi
  698.     move.l    a0,d0
  699. wmback1:
  700.     tst.w    d3            ;while (bi >= 0 && *back[bi][1] == '\x0')
  701.      blt.s    wmbacked
  702.     movea.l    0(a1,d3.l),a0
  703.     tst.b    (a0)
  704.      bne.s    wmbacked
  705.  
  706.     subq.w    #8,d3            ;--bi
  707.     bra.s    wmback1
  708.  
  709. wmbacked:
  710.     tst.w    d3            ;if (bi < 0)
  711.      blt.s    wmnomatch        ;return (0)
  712.  
  713.     movea.l    d0,a0
  714.     movea.l    0(a0,d3.w),a3        ;w = back[bi][0] + 1
  715.     addq.w    #1,a3    
  716.  
  717.     addq.l    #1,0(a1,d3.w)
  718.     movea.l    0(a1,d3.l),a2        ;n = ++back[bi][1]
  719.  
  720.     addq.w    #8,d3            ;++bi
  721.     bra.s    wmloop1
  722.  
  723. wmnotstar:
  724.     cmpi.b    #'?',(a3)        ;Is it '?'
  725.      bne.s    wmnotqmark
  726.  
  727.     tst.b    (a2)            ;Reached end of string?
  728.      bne.s    wmincpoint        ;Nope, move on to next char
  729.  
  730.     tst.w    d3            ;Are we at top level of expression?
  731.      beq.s    wmnomatch        ;Yep, expression didn't match
  732.     bra.s    wmgoback        ;Otherwise pop a level and try to match
  733.  
  734. wmnotqmark:
  735.     move.b    (a2),d0            ;Grab a char from bstr
  736.     cmpi.b    #$40,d0            ;less than @ character?
  737.      bls.s    1$            ;Yep
  738.     cmpi.b    #$5a,d0            ;Greater than Z?
  739.      bhi.s    1$            ;Yep
  740.     addi.b    #$20,d0
  741. 1$
  742.     move.b    (a3),d1            ;Grab a char from bstr
  743.     cmpi.b    #$40,d1            ;less than @ character?
  744.      bls.s    2$            ;Yep
  745.     cmpi.b    #$5a,d1            ;Greater than Z?
  746.      bhi.s    2$            ;Yep
  747.     addi.b    #$20,d1
  748. 2$
  749.     cmp.b    d0,d1            ;*n = *w?
  750.      beq.s    wmincpoint        ;Yep, move on past
  751.  
  752.     tst.w    d3            ;Are we at top expression level?
  753.      beq.s    wmnomatch        ;Yep, they didn't match
  754.     bra.s    wmgoback        ;Nope, process next part
  755.  
  756. wmincpoint:
  757.     tst.b    (a2)            ;Done with name?
  758.      beq.s    wmnamend        ;Yep
  759.     addq.w    #1,a2            ;Otherwise increment name pointer
  760.  
  761. wmnamend:
  762.     tst.b    (a3)            ;End of pattern?
  763.      beq.s    wmmatched        ;Yep, we matched
  764.     addq.w    #1,a3            ;Otherwise inc wild pointer, match next char
  765.     bra    wmloop1
  766.  
  767. wmmatched:
  768.     moveq    #1,d0
  769.     bra.s    wmdone
  770.  
  771. wmnomatch:
  772.     moveq    #0,d0
  773.  
  774. wmdone:
  775.     movem.l    (sp)+,d3/a2-a3
  776.     unlk    a5
  777.     rts
  778.  
  779. * --------------------------------------------------------------------- *
  780. * BOOL CompFibs (keytype, a,   b)
  781. *            d0   a0   a1
  782. *   LONG keytype;
  783. *   struct FileInfoBlock *a, *b;
  784. *
  785. * Used by SortFibs to determine precedence of Fibs.
  786. * keytype is one of 0, 1, or 2:
  787. *   0=alpha, 1=size, 2=date
  788. * --------------------------------------------------------------------- *
  789.     XDEF    @CompFibs
  790. @CompFibs:
  791.     movem.l    d2-d3/a2,-(sp)
  792.  
  793.     move.l    d0,d2            ;Stash keytype
  794.  
  795. * Prioritize Dirs/Files?
  796.     move.l    LSFlags(a4),d3        ;Grab flags
  797.  
  798.     btst.l    #17,d3            ;LSFlags & MIXFILEDIRS?
  799.      bne.s    cftstsort        ;Yep, don't bother comparing EntryTypes
  800.  
  801.     move.l    fib_DirEntryType(a0),d0
  802.     cmp.l    fib_DirEntryType(a1),d0
  803.      blt.s    1$            ;a0 is < a1, (dir < file)
  804.      beq.s    cftstsort        ;a0 is == a1, try next test
  805.  
  806.     moveq    #0,d0            ;a0 is > a1, (file > dir)
  807.     bra.s    2$
  808. 1$
  809.     moveq    #1,d0            ;greater than, (dir < file)
  810.  
  811. 2$    btst.l    #16,d3            ;LSFlags & FILESFIRST?
  812.      beq    cfexit0            ;Nope, default Dirs first
  813.     bchg.l    #0,d0            ;Else d0 ^= 1, reverse sense
  814.     bra    cfexit0
  815.     
  816. * Both entries are the same type, now see about sorting them
  817. cftstsort:
  818.     btst.l    #6,d3            ;LSFlags & NOSORTFLAG set?
  819.      bne    cffalse            ;Yep, always AddTail to list
  820.     
  821. * Switch keytype
  822.     tst.w    d2            ;Alphabetize?
  823.      bne.s    cfnalpha        ;Nope
  824.  
  825. * Compare lexigraphically, ignoring case differences
  826. cfalpha:
  827.     lea    fib_FileName(a0),a0    ;a = &Fipb->fib_FileName
  828.     lea    fib_FileName(a1),a1    ;b = &Fipb->fib_FileName
  829.  
  830. ;  for(; *a && tolower(*a) == tolower(*b); a++, b++);
  831. lccstart:
  832.     tst.b    (a0)            ;Is there a char here at source?
  833.      beq.s    lcceostr        ;Nope, fell off the end
  834.  
  835.     move.b    (a1)+,d1        ;Grab a char from bstr
  836.     cmpi.b    #$40,d1            ;less than @ character?
  837.      bls.s    1$            ;Yep
  838.     cmpi.b    #$5a,d1            ;Greater than Z?
  839.      bhi.s    1$            ;Yep
  840.     addi.b    #$20,d1
  841. 1$
  842.     move.b    (a0)+,d0        ;Grab a char from astr
  843.     cmpi.b    #$40,d0            ;less than @ character?
  844.      bls.s    2$            ;Yep
  845.     cmpi.b    #$5a,d0            ;Greater than Z?
  846.      bhi.s    2$            ;Yep
  847.     addi.b    #$20,d0
  848. 2$
  849.     cmp.b    d0,d1            ;are they the same?
  850.      beq    lccstart        ;Yep, compare next pair of chars
  851.  
  852. lcceostr:
  853.     sub.b    d1,d0            ;return(tolower(*astr) - tolower(*bstr))
  854.      bgt.s    cftrue            ; > 0?, return TRUE
  855.     bra.s    cffalse            ;Else return FALSE
  856.  
  857. cfnalpha:
  858.     subq.w    #1,d2            ;Size?
  859.      bne.s    cfnsize            ;Nope
  860.  
  861. * Compare fib_Sizes
  862.     move.l    fib_Size(a0),d0        ;d0 = afib->fib_Size
  863.     cmp.l    fib_Size(a1),d0        ;b->fib_Size > a->fib_Size?
  864.      bgt.s    cftrue            ;Yep, return TRUE
  865.      blt.s    cffalse            ;<, return FALSE
  866.      bra    cfalpha            ;Else it's a tie, alphabetize
  867.  
  868. cfnsize:
  869. * Compare fib_DateStamps
  870.     lea    fib_DateStamp(a0),a0    ;a = &afib->fib_DateStamp
  871.     lea    fib_DateStamp(a1),a1    ;b = &bfib->fib_DateStamp
  872.     jsr    @CompareDateStamps
  873.     tst.l    d0
  874.      beq    cfalpha            ;its the same date?, alphabetize
  875.      blt.s    cffalse
  876. cftrue:
  877.     moveq    #1,d0
  878.     bra.s    cfexit
  879. cffalse:
  880.     moveq    #0,d0
  881. cfexit:
  882.     btst.l    #9,d3            ;LSFlags & REVFLAG?
  883.      beq.s    1$            ;Nope
  884.     bchg.l    #0,d0            ;Else invert boolean result
  885. 1$
  886. cfexit0:
  887.     movem.l    (sp)+,d2-d3/a2
  888.     rts
  889.  
  890. * --------------------------------------------------------------------- *
  891. * LONG CompareDateStamps(adate, bdate)
  892. *  d0                     a0      a1
  893. *   struct DateStamp *adate, *bdate;
  894. * --------------------------------------------------------------------- *
  895.     XDEF    @CompareDateStamps
  896. @CompareDateStamps:
  897.     move.l    ds_Days(a0),d0        ;d0 = adate->ds_Days
  898.     sub.l    ds_Days(a1),d0        ;b->ds_Days > a->ds_Days?
  899.      bne.s    1$            ;Return b->day - a->day
  900.  
  901. ;They are the same day, check min/tick
  902.     move.l    ds_Minute(a0),d0
  903.     sub.l    ds_Minute(a1),d0    ;d0 = amin - bmin
  904.     muls    #3000,d0        ;     * 3000
  905.     add.l    ds_Tick(a0),d0
  906.     sub.l    ds_Tick(a1),d0        ;     + atick - btick
  907. 1$
  908.     rts
  909.  
  910. * --------------------------------------------------------------------- *
  911. * VOID InsertFibNode(hfib, newfib)
  912. *                     a0     a1
  913. *   struct List *hfib;
  914. *   struct FibEntry *newfib;
  915. *
  916. * Compare data in newfib->Fib with nodes in the list until we
  917. * find the insertion point.
  918. * --------------------------------------------------------------------- *
  919.     XDEF    @InsertFibNode
  920. @InsertFibNode:
  921.     movem.l    d2/a2-a3/a5/a6,-(sp)
  922.  
  923.     move.l    sortkey(a4),d2
  924.     movea.l    a0,a3            ;a3 = hfib
  925.     movea.l    a1,a2            ;a2 = newfib
  926.  
  927.     movea.l    LH_HEAD(a3),a5        ;afib = hfib->lh_Head
  928.  
  929. 1$    tst.l    fe_Node+LN_SUCC(a5)    ;afib->fe_Node.mln_Succ != 0?
  930.      beq.s    4$
  931.  
  932.     movea.l    fe_Fib(a2),a1
  933.     movea.l    fe_Fib(a5),a0
  934.     move.l    d2,d0
  935.     jsr    @CompFibs        ;CompFibs(sortkey, afib->Fib, newfib->Fib)
  936.     tst.w    d0
  937.      bne.s    4$
  938.     movea.l    fe_Node+LN_SUCC(a5),a5    ;afib = afib->fe_Node.mln_Succ
  939.     bra    1$
  940.  
  941. 4$    movea.l    a3,a0            ;a0 = List *
  942.     movea.l    a2,a1            ;a1 = Node *
  943.     movea.l    fe_Node+LN_PRED(a5),a2    ;a2 = Pred *
  944.     SYS    Insert,4        ;Insert(hfib, newfib, afib->fe_Node.mln_Succ)
  945.  
  946.     movem.l    (sp)+,d2/a2-a3/a5/a6
  947.     rts
  948.  
  949. * --------------------------------------------------------------------- *
  950. * LONG FillFibEntry (headfib, fibp)
  951. *               a0      a1          
  952. *   struct List *headfib;
  953. *   struct FileInfoBlock *fibp;
  954. * --------------------------------------------------------------------- *
  955.     XDEF    @FillFibEntry
  956. @FillFibEntry:
  957.     movem.l    a2-a3/a5/a6,-(sp)
  958.     movea.l    a0,a2            ;a2 = head of list
  959.     movea.l    a1,a3            ;a3 = fileinfoblock
  960.  
  961.     jsr    @AllocFib        ;Allocate a new fib
  962.     tst.l    d0            ;Got it?
  963.      beq.s    3$            ;Nope, return 0
  964.     movea.l    d0,a5            ;a5 = tfibp = AllocFib()
  965.  
  966.     move.l    #fib_SIZEOF,d0
  967.     movea.l    fe_Fib(a5),a1
  968.     movea.l    a3,a0
  969.     SYS    CopyMem,4        ;CopyMem(fibp, tfibp->Fib, sizeof(struct fib))
  970.  
  971.     movea.l    a5,a1
  972.     movea.l    a2,a0
  973.  
  974.     jsr    @InsertFibNode        ;InsertFibNode(headfib, tfibp)
  975.  
  976.     moveq    #1,d0            ;return(1)
  977. 3$
  978.     movem.l    (sp)+,a2-a3/a5/a6
  979.     rts
  980.  
  981. * --------------------------------------------------------------------- *
  982.     XDEF    @nullstub
  983. @nullstub:
  984.     moveq    #0,d0
  985.     rts
  986.  
  987. * --------------------------------------------------------------------- *
  988. * LONG GetPathString (dest, src)
  989. *  d0                  a0    a1
  990. *   BYTE *dest, *src;
  991. * --------------------------------------------------------------------- *
  992.     XDEF    @GetPathString
  993. @GetPathString:
  994.     move.l    a2,-(sp)
  995.  
  996.     moveq    #0,d0            ;Zero return dest length
  997.  
  998. * Find end of src string
  999.     movea.l    a1,a2            ;Save src start address
  1000. 1$    tst.b    (a1)+            ;while (*src++ != 0)
  1001.      bne    1$
  1002.  
  1003. * Work backwards till we find a ':' or a '/'
  1004. 2$    move.b    -(a1),d1        ;c = *(--src)
  1005.     cmpi.b    #':',d1            ;Hit a colon?
  1006.      beq.s    4$            ;Yep, found our path end
  1007.     cmpi.b    #'/',d1            ;Hit a slash?
  1008.      bne.s    3$            ;Nope, try next char
  1009.     cmpa.l    a2,a1            ;At first char?
  1010.      beq.s    4$            ;Yep, leave the single slash
  1011.     cmpi.b    #'/',-1(a1)        ;Next char back is also a '/'?
  1012.      beq.s    4$            ;Yep, allow multiple slashes
  1013.     subq.w    #1,a1            ;Else backup to previous char, eliminate '/'
  1014.     bra.s    4$
  1015. 3$
  1016.     cmpa.l    a2,a1            ;Back at start of src?
  1017.      bhi    2$            ;Nope, try previous src char
  1018.     bra.s    gpsdone            ;Else no dest, return
  1019. 4$
  1020. * Copy path portion to dest
  1021. gpscpy:
  1022.     cmpa.l    a2,a1            ;Past end address?
  1023.      bcs.s    gpsdone            ;Yep, terminate
  1024.     move.b    (a2)+,(a0)+        ;Copy a char from src to dest
  1025.     addq.w    #1,d0            ;Bump dest length count
  1026.     bra    gpscpy            ;Check end address
  1027. gpsdone:
  1028.     clr.b    (a0)            ;Null terminate dest
  1029.  
  1030.     movea.l    (sp)+,a2
  1031.     rts
  1032.  
  1033. * --------------------------------------------------------------------- *
  1034. * LONG GetFileString (dest, src)
  1035. *  d0                  a0    a1
  1036. *   BYTE *dest, *src;
  1037. * --------------------------------------------------------------------- *
  1038.     XDEF    @GetFileString
  1039. @GetFileString:
  1040.     move.l    a2,-(sp)
  1041.  
  1042.     moveq    #0,d0            ;Zero return dest length
  1043.  
  1044. * Find end of src string
  1045.     movea.l    a1,a2            ;Save src start address
  1046. 1$    tst.b    (a1)+            ;while (*src++ != 0)
  1047.      bne    1$
  1048.  
  1049. * Work backwards till we find a ':' or a '/'
  1050. 2$    move.b    -(a1),d1        ;c = *(--src)
  1051.     cmpi.b    #':',d1            ;Hit a colon?
  1052.      beq.s    4$            ;Yep, found our path end
  1053.     cmpi.b    #'/',d1            ;Hit a slash?
  1054.      beq.s    4$            ;Nope, try next char
  1055. 3$
  1056.     cmpa.l    a2,a1            ;Back at start of src?
  1057.      bhi    2$            ;Nope, try previous src char
  1058.     bra.s    gfscpy            ;Else no path, entire src is filename
  1059. 4$
  1060.     addq.w    #1,a1            ;Move past ':' or '/'
  1061.  
  1062. * Copy name portion to dest
  1063. gfscpy:
  1064.     move.b    (a1)+,(a0)+        ;Copy a char from src to dest
  1065.      beq.s    2$
  1066.     addq.w    #1,d0            ;Bump dest length count
  1067.     bra    gfscpy            ;Check end address
  1068. 2$
  1069.     movea.l    (sp)+,a2
  1070.     rts
  1071.  
  1072. * ------------------------------------------------------------------------- *
  1073. * BYTE *astrncpy(dst, src, len)
  1074. * d0/a0          a0   a1    d0
  1075. * Takes text in a1, copies d0 bytes to text in a0.
  1076. * a0 returns pointing to null at end of final text.
  1077. * Dest text is always null terminated.
  1078. * ------------------------------------------------------------------------- *
  1079.     XDEF    @astrncpy
  1080. @astrncpy:
  1081. 1$    subq.l    #1,d0            ;Dec count
  1082.      blt.s    2$            ;Done!
  1083.  
  1084.     move.b    (a1)+,(a0)+        ;Copy a byte
  1085.      bne    1$            ;Do until end of src or cnt < 0
  1086. 2$
  1087.     clr.b    (a0)            ;Null terminate dest
  1088.     move.l    a0,d0            ;Return in d0 also
  1089.     rts
  1090.  
  1091. * ------------------------------------------------------------------------- *
  1092. * VOID amovmem(src, dst, len)
  1093. *              a0    a1   d0
  1094. * Takes text in a0, copies d0 bytes to text in a1. Correctly handles
  1095. * overlapping memory.
  1096. * ------------------------------------------------------------------------- *
  1097.     XDEF    amovmem
  1098. amovmem:
  1099.     cmpa.l    a0,a1            ;Low to high or high to low?
  1100.      bcs.s    2$            ;High to low, copy forward
  1101.     adda.w    d0,a0            ;Else start at end, copy backward
  1102.     adda.w    d0,a1
  1103.  
  1104. 1$    move.b    -(a0),-(a1)
  1105.     subq.w    #1,d0
  1106.      bgt    1$
  1107.     bra.s    amdone
  1108.  
  1109. 2$    move.b    (a0)+,(a1)+
  1110.     subq.w    #1,d0
  1111.      bgt    2$
  1112. amdone:
  1113.     rts
  1114.  
  1115. * --------------------------------------------------------------------- *
  1116. * BYTE *aindex(BYTE *, BYTE);
  1117. *  d0           a0      d0
  1118. * --------------------------------------------------------------------- *
  1119.     XDEF    @aindex
  1120. @aindex:
  1121. 1$    cmp.b    (a0),d0
  1122.      beq.s    aifound
  1123.     tst.b    (a0)+
  1124.      beq.s    ainomatch
  1125.     bra    1$
  1126.  
  1127. ainomatch:
  1128.     moveq    #0,d0
  1129.     rts
  1130.  
  1131. aifound:
  1132.     move.l    a0,d0
  1133.     rts
  1134.  
  1135. * --------------------------------------------------------------------- *
  1136. * LONG MakePathString(lock, dest)
  1137. *                      a0     a1
  1138. *   struct FileLock *lock;
  1139. *   BYTE *dest;
  1140. *
  1141. * DESCRIPTION:
  1142. *   Given text and a filelock, construct entire pathname and
  1143. * return in dest.
  1144. * --------------------------------------------------------------------- *
  1145.     XDEF    @MakePathString
  1146. @MakePathString:
  1147.     movem.l    d2-d5/d7/a2-a3/a6,-(sp)
  1148.  
  1149. * Grab pointer to lock and dest text to fill
  1150.     move.l    a0,d3            ;d3 = lock
  1151.     movea.l    a1,a2            ;a2 = dest
  1152.     clr.b    (a2)            ;NULL terminate dest
  1153.     moveq    #0,d5            ;LockFlag = 0
  1154.  
  1155. * Allocate a FileInfoBlock for local use
  1156.     move.l    #fib_SIZEOF,d0
  1157.     jsr    @myalloc
  1158.     move.l    d0,d7            ;d7 = *fib
  1159.      beq    mpsfailed        ;Whoops no mem? return!
  1160.  
  1161.     movea.l    DOSBase(a4),a6        ;DOSBase calls from here on
  1162.  
  1163. * while (lock != 0)
  1164. 1$
  1165.     tst.l    d3            ;Got a lock?
  1166.      beq.s    mpsokay            ;Nope, must be at root
  1167.  
  1168. * Examine the current lock
  1169.     move.l    d3,d1
  1170.     move.l    d7,d2
  1171.     SYS    Examine            ;Examine(lock, fib)
  1172.     tst.l    d0            ;Okay?
  1173.      beq.s    mpsfailed        ;Nope, some sort of dos failure?
  1174.  
  1175.     movea.l    d7,a1
  1176.     cmpi.b    #' ',fib_FileName(a1)    ;if (fib->fib_FileName[0] >= ' ')
  1177.      bcs.s    3$            ;Nope, don't bother inserting?
  1178.  
  1179.     tst.b    (a2)            ;if (dest[0] != 0)
  1180.      beq.s    2$
  1181.     lea    SlashStr(a4),a1
  1182.     movea.l    a2,a0
  1183.     jsr    @InsertPathString    ;InsertPathString(dest, "/");
  1184. 2$
  1185.     movea.l    d7,a1
  1186.     lea    fib_FileName(a1),a1
  1187.     movea.l    a2,a0
  1188.     jsr    @InsertPathString    ;InsertPathString(dest, fib->fib_FileName)
  1189. 3$
  1190. * Okay, move up one directory
  1191.     move.l    d3,d4            ;oldlock = lock
  1192.  
  1193.     move.l    d3,d1
  1194.     SYS    ParentDir
  1195.     move.l    d0,d3            ;lock = ParentDir(lock)
  1196.  
  1197.     tst.w    d5            ;LockFlag set?
  1198.      bne.s    4$            ;Yep, unlock
  1199.     moveq    #1,d5            ;Else LockFlag = 1, unlock next time
  1200.      bra    1$            ;Next directory up
  1201. 4$
  1202.     move.l    d4,d1
  1203.     SYS    UnLock            ;UnLock(oldlock)
  1204.     bra    1$            ;Examine
  1205.  
  1206. mpsokay:
  1207. * See if root was RAM:, special case
  1208.     movea.l    d7,a1            ;a1 = fib
  1209.     cmpi.b    #' ',fib_FileName(a1)    ;if (fib->fib_FileName[0] >= ' ')
  1210.      bcc.s    1$            ;Yep, not 1.1/1.2 RAM:
  1211.     lea    RamNameStr(a4),a1    ;Else...
  1212.     movea.l    a2,a0
  1213.     jsr    @InsertPathString    ;InsertPathString(dest, "RAM:")
  1214.     bra.s    mpsdone
  1215. 1$
  1216. * Find last slash we tacked on, change to a colon, or, add a colon
  1217.     moveq    #'/',d0
  1218.     movea.l    a2,a0
  1219.     jsr    @aindex            ;d0 = strchr(dest, '/')
  1220.     tst.l    d0            ;Do we have a slash?
  1221.      beq.s    2$            ;Nope, at root....
  1222.     movea.l    d0,a0
  1223.     move.b    #':',(a0)        ;Else change first '/' to a ':'
  1224.     bra.s    mpsdone
  1225.  
  1226. * No slash, must be locked at the root.  Append a colon to the dest.
  1227. 2$
  1228.     lea    ColonStr(a4),a1    
  1229.     movea.l    a2,a0
  1230.     jsr    @strcat            ;strcat (dest, ":")
  1231.     bra.s    mpsdone
  1232.  
  1233. * Come here if an error occured, return empty text to caller
  1234. mpsfailed:
  1235.     clr.b    (a2)            ;dest[0] = (BYTE)0
  1236.     moveq    #0,d3            ;return (0L)
  1237.     bra.s    mpsdeall
  1238.  
  1239. * Come here if everything is okay, deallocate FileInfoBlock
  1240. mpsdone:
  1241.     moveq    #1,d3            ;return (1L)
  1242.  
  1243. mpsdeall:
  1244.     tst.l    d7            ;Did we allocate a fib?
  1245.      beq.s    mpsfinis        ;nope
  1246.     movea.l    d7,a0            ;Else free the memory
  1247.     jsr    @myfree
  1248.  
  1249. mpsfinis:
  1250.     move.l    d3,d0            ;Put return value in d0
  1251.     movem.l    (sp)+,d2-d5/d7/a2-a3/a6
  1252.     rts
  1253.  
  1254. * --------------------------------------------------------------------- *
  1255. * VOID InsertPathString(dest, source)
  1256. *                        a0     a1
  1257. *   BYTE *dest, *source;
  1258. *
  1259. * DESCRIPTION:
  1260. *   Insert source text into dest text.
  1261. * Special case for source length == 0, source must be RAM.
  1262. * --------------------------------------------------------------------- *
  1263.     XDEF    @InsertPathString
  1264. @InsertPathString:
  1265.     movem.l    d7/a2-a3,-(sp)
  1266.  
  1267.     movea.l    a1,a3            ;a3 = source
  1268.     move.l    a0,a2            ;a2 = dest
  1269.  
  1270.     movea.l    a3,a0
  1271.     jsr    @strlen
  1272.     move.l    d0,d7            ;d7 = strlen(source)
  1273.  
  1274. 1$    movea.l    a2,a0
  1275.     jsr    @strlen            ;d0 = strlen(dest)
  1276.  
  1277.     addq.w    #1,d0            ;Bump the length to include zero byte at end
  1278.     movea.l    a2,a1
  1279.     adda.w    d7,a1            ;Push dest + slen
  1280.     movea.l    a2,a0            ;Push dest
  1281.     jsr    amovmem            ;amovmem(dest, dest + slen, strlen(dest) + 1)
  1282.  
  1283.     move.w    d7,d0
  1284.     movea.l    a2,a1
  1285.     movea.l    a3,a0
  1286.     jsr    amovmem            ;amovmem(source, dest, slen)
  1287.  
  1288.     movem.l    (sp)+,d7/a2-a3
  1289.     rts
  1290.  
  1291. * --------------------------------------------------------------------- *
  1292. * VOID NoMemExit(VOID)
  1293. * --------------------------------------------------------------------- *
  1294.     XDEF    @NoMemExit
  1295. @NoMemExit:
  1296.     moveq    #103,d1
  1297.     moveq    #20,d0
  1298.     lea    NoRAMMsg(a4),a0
  1299.     jsr    @CleanUp
  1300.     rts
  1301.  
  1302. * --------------------------------------------------------------------- *
  1303. * VOID NoFileExit(name)
  1304. *                  a0
  1305. * BYTE *name;
  1306. * --------------------------------------------------------------------- *
  1307.     XDEF    @NoFileExit
  1308. @NoFileExit:
  1309.     movem.l    d2-d4/a6,-(sp)
  1310.  
  1311.     move.l    a0,d2            ;Save name
  1312.     SYS    IoErr,DOSBase(a4)    ;Get IoError status
  1313.     move.l    d0,d3            ;Save it
  1314.  
  1315.     move.l    #300,d0
  1316.     jsr    @myalloc
  1317.     move.l    d0,d4            ;d3 = myalloc( 300 )
  1318.      bne.s    1$            ;Got it!
  1319.     jsr    @NoMemExit        ;else exit with No Ram message
  1320.     bra.s    2$
  1321. 1$
  1322.     move.l    d2,-(sp)
  1323.     pea    NoFindFmtStr(a4)
  1324.     move.l    d4,-(sp)
  1325.     jsr    asprintf        ;asprintf(tstr, NoFindFmtStr, name)
  1326.     lea    12(sp),sp
  1327.  
  1328.     move.l    d3,d1
  1329.     moveq    #20,d0
  1330.     movea.l    d4,a0
  1331.     jsr    @CleanUp        ;CleanUp(tstr, 20L, IoErr())
  1332.                     ;         a0   d0     d1
  1333.     move.l    d4,a0
  1334.     jsr    @myfree            ;free (tstr)
  1335. 2$
  1336.     movem.l    (sp)+,d2-d4/a6
  1337.     rts
  1338.  
  1339. * --------------------------------------------------------------------- *
  1340.     END
  1341. * --------------------------------------------------------------------- *
  1342.