* CD.Asm * * Written 1/7/87 by C.Heath * * Copyright (c) 1986 by C.Heath of Microsmiths Inc. * * This program may be freely copied for individual use. It may * also be freely distributed with the following restrictions: * * 1) No modifications to the source code are made. If an executable * version of the program is distributed, use assem and blink 6.7, which * should result in an executable of 600 bytes. * 2) Please verify that the most current version is distributed. * This can be verified by contacting "cheath" on BIX, or 74216,2117 on CIS, * or write to Microsmiths, Inc., PO Box 561, Cambridge, MA 02140. * 3) The ARP series may be distributed with commercial software * except as noted in (4) provided it's origin is stated. Please contact * me to insure you have the latest version. * 4) This module may NOT be distributed with any commercial software * which encourages the BCPL program interface without express written * permission. This restriction includes the Metacomco Shell. * This module replaces the ADOS "CD" command. It matches the * ADOS prompt syntax. * In addition, it allows a simple path substitution to be made. This * must work in tandem with the ARP "Prompt" command. * This command is smaller than the ADOS equivalent so runs a bit faster. * This is installment ~8 of the "ARP" series. The're coming fast * and furious now, I've lost count. ****** Equates and publics *************************************** INCLUDE "exec/types.i" INCLUDE "libraries/dos.i" INCLUDE "libraries/dosextens.i" MIN_LIB set $1f ; Library minimum rev level! ; ADOS "stack" command PLENGTH set 60 ; Maximum length of prompt string * The CD hack works by substituting a flag value for the %p * The flag used is a character value of $80. This character will * be IGNORED by the console handler. It is a NOP. Then, when the * ARP version of CD is run, if it finds the flag character in the * prompt it appends the new current dir text at that offset in the * prompt string. CD_FLAG set $80 ; Search for this flag value *** WITH MANX, SUBSTITUTE public FOR xref xlib macro xref _LVO\1 endm *** BEGIN MANX code. Uncomment the next few lines to assemble with MANX * * entry .begin * public .begin *.begin *** END MANX CODE xlib OpenLibrary xlib CloseLibrary xlib FindTask xlib Output xlib Write xlib Lock xlib Examine xlib UnLock xlib CurrentDir xlib ParentDir ****** The Program *************************************** * Register use * * A6 Execbase, then DOSBase through the rest of execution * A5 Pointer to a FIB, at times * A4 Process structure * A3 pr_CLIStruct * A2 Command Line string, until after it is completely processed * D7 Holds new lock for CurrentDir * D6 Saved Stack Pointer for Exit() * D5 Holds the "parent" for this directory * D4 Holds count used while ascending directories in do_dir_text * D3 Used as calling arg length for do_write * D2 Used as calling arg string for do_write Start: move.l sp,D6 ; Save stack pointer move.l 4,A6 ; ExecBase in A6 until DOSBase later move.l A0,A2 ; Register A2 is cmdline henceforth suba.l A1,A1 jsr _LVOFindTask(A6) move.l D0,A4 ; Process base in A4 henceforth move.l pr_CLI(A4),D0 beq.s BadExit ; Not a CLI process. Punt asl.l #2,D0 move.l D0,A3 ; A3 points at CLIStruct henceforth lea DOSName(pc),A1 ; Open DOS.library moveq.l #MIN_LIB,d0 jsr _LVOOpenLibrary(A6) move.l D0,A6 or.l D0,D0 bne.s ok_start ; Continue if library OK, * fall in to BadExit code if DOS library couldn't open ************************************************************************ * * BadExit is where to go if there is an error opening the DOS library * This should only happen if things are really sick * ************************************************************************ BadExit: moveq #20,D0 rts ************************************************************************ * * ok_start * Proceed with normal code, check the input string. * ************************************************************************ ok_start: * * Process the input command string * skpspc: move.b (A2)+,D1 ; Skip spaces cmp.b #$20,D1 beq.s skpspc cmp.b #$0A,D1 ; check for a NULL string ? beq.s show_cd ; Ok, just show the current dir. cmp.b #'"',D1 beq.s do_setdir ; String in Quotes, D1 is EOS test subq #1,A2 ; Back up a char clr D1 ; Clear terminator test char * * Here, set the directory to the string at A2 * do_setdir: move.l A2,A0 moveq #0,D0 lla: move.b (A0)+,D0 beq.s lalala cmp.b D1,D0 beq.s lalala ; End of quoted string cmp.b #$0A,D0 bne.s lla lalala: clr.b -1(A0) ; Turn the terminater into a ; null terminating string move.l A2,D1 move.l #ACCESS_READ,D2 jsr _LVOLock(A6) move.l D0,D7 beq.s no_object ; Can't find directory sub #fib_SIZEOF,sp ; Reserve space on stack for fib move.l sp,D2 move.l D7,D1 jsr _LVOExamine(A6) tst.l D0 beq.s not_dir ; Bad error, couldn't Examine() tst.l fib_DirEntryType(sp) ble.s not_dir ; It's a file, not a dir * Note that the FIB won't be valid after ANY calls or pushes. add #fib_SIZEOF,sp ; Restore stack pointer move.l D7,D1 jsr _LVOCurrentDir(A6) ; Set new currentdir move.l D0,D1 jsr _LVOUnLock(A6) ; Free old currentdir Lock bsr do_dir_text ; Set the new text for currentdir bra.s CleanUp *************************************************************************** * * show_cd * CD was called with no arguement. Just display the current * value of CurrentDir. * *************************************************************************** show_cd: bsr.s do_dir_text ; Update cli_SetName and prompt move.l cli_SetName(A3),D0 asl.l #2,D0 move.l D0,A0 moveq #0,D3 move.b (A0)+,D3 ; Get length of currentdir BSTR in A3 move.l A0,D2 bsr.s do_writex lea LF_str(pc),A0 bsr.s do_write moveq #0,D0 CleanUp: move.l D0,D2 ; Save return value move.l A6,A1 move.l 4,A6 ; AbsExecBase jsr _LVOCloseLibrary(A6) move.l D6,SP ; Restore initial SP move.l D2,D0 ; Restore return value rts ; and exit() *************************************************************************** * * not_dir * Come here if the new requested CD is not a directory! * not_dir: add #fib_SIZEOF,sp ; Restore stack pointer move.l D7,D1 jsr _LVOUnLock(A6) ; Free the new lock. move.l A2,A0 bsr.s do_write lea str_notdir,A0 ; Print this message and exit(20) bra.s err_mrg *************************************************************************** * * no_object * Error can't find the requested directory. * no_object: lea str_noobj(pc),A0 bsr.s do_write move.l A2,A0 bsr.s do_write lea LF_str(pc),A0 *************************************************************************** * * err_msg * Merge point for some error messages. Exits through cleanup * *************************************************************************** err_mrg: bsr.s do_write moveq #20,D0 ; Set to exit(20) bra.s CleanUp *************************************************************************** * * do_write * Simple write string. * * Assumes A6 = DOSBase * Null terminated string is @A0 * Also assumes a reasonable CLI environment with valid COS * * Zaps D0..D3/A0/A1 * *************************************************************************** do_write: move.l A0,D2 moveq #-1,D3 dwl1: addq.l #1,D3 tst.b (A0)+ bne.s dwl1 do_writex: ; BCPL style entry with D2/D3 preset... jsr _LVOOutput(A6) move.l D0,D1 jmp _LVOWrite(A6) *************************************************************************** * * do_dir_text * Set up text version of cli_SetName to reflect current directory * *************************************************************************** do_dir_text: sub #fib_SIZEOF,sp ; Reserve space on stack for fib move.l sp,A5 ; Set A5 pointing to fib moveq #0,D4 ; Set artificial limit of 20 ; directories to avoid endless loop move.l pr_CurrentDir(A4),D7 ; Get terminal directory lock move.l cli_SetName(A3),D0 asl.l #2,D0 move.l D0,A2 clr.b (A2) ; Set string to "null" bsr.s ascend add #fib_SIZEOF,sp * Here, fall into the code to set up prompt string, if %p is selected. *************************************************************************** * * DoKluge * * Test for the special flag value for the Prompt command. * * Here, concatenate the current pathname onto the prompt * string and set the flag, offset bytes. * * NOTE: If the resulting string would be too long, restore the * standard DOS prompt and report that was done. * *************************************************************************** DoKluge: move.l cli_Prompt(A3),D0 ; Get BSTR pointing to prompt asl.l #2,D0 move.l D0,A0 ; A0 = where to store length lea 1(A0),A1 ; A1 = where to store string moveq #0,D1 ; D1 = offset @ start of string move.b (A0),D0 ; Search current prompt string dkl1: addq #1,D1 ; Increment offset cmp.b #CD_FLAG,(A1)+ ; for CD_FLAG value beq.s doklug subq.b #1,D0 ; Loop through all of string bgt.s dkl1 bra.s NoKluge ; Nope, leave prompt alone! doklug: move.b D1,(A0) ; Reset length to start of %p move.l cli_SetName(A3),D0 asl.l #2,D0 move.l D0,A2 ; Get the BSTR for path name move.b (A2),D2 ; Length of path name move.b D2,D0 ; Save length of CD string in D2 add.b D1,D0 ; combined length cmp.b #PLENGTH,D0 bge.s NoKluge ; Safety punt. Extra char for > lea 1(A2),A2 cl1: move.b (A2)+,(A1)+ ; Copy the string addq #1,D1 subq.b #1,D2 bgt.s cl1 move.b #'>',(A1) ; Append a > character addq #1,D1 ; Plus a tally ho move.b D1,(A0) ; Save the length NoKluge: rts *************************************************************************** * * ascend * Recursive routine to create CurrentDir text. * Call with D7 = a valid child lock * ascend: cmp #20,D4 bge.s punt ; Probable disk error looped move.l D7,D1 jsr _LVOParentDir(A6) move.l D0,D5 beq.s no_parent ; D5 is a flag "no parent" if 0 addq #1,D4 ; Bump tally of parents move.l D7,-(sp) ; Save the current directory move.l D5,D7 ; Now go fetch this one move.l D5,-(sp) bsr.s ascend ; Go up another level subq #1,D4 ; Reduce parents level move.l (sp)+,D1 ; Restore parent dir into D1 move.l (sp)+,D7 ; Restore current direcory jsr _LVOUnLock(A6) ; Free the extra ParentDir Lock. moveq #1,D5 * no_parent * Here get the text for this directory and append it. no_parent: move.l A5,D2 move.l D7,D1 jsr _LVOExamine(A6) tst.l D0 beq.s punt ; Bad error, couldn't Examine() tst.l fib_DirEntryType(A5) ble.s punt ; Parent of a dir not a dir. Hmm... lea fib_FileName(A5),A0 ; Append this dir string npl1: move.b (A0)+,D0 beq.s npl2 bsr.s do_putch bra.s npl1 npl2: move.b #':',D0 tst D5 beq.s do_putch ; if ZERO, it's the base move.b #'/',D0 tst D4 bne.s do_putch ; if NZ, it's got a parent npl3: rts *************************************************************************** * * punt * Fatal error while ascending the directory tree. * This should never ever happen. But it might... * punt: lea str_baderr(pc),A0 bra err_mrg ; Merge at string error printer *************************************************************************** * * do_putch * Append the character in D0 to the SetName CD string * @(A2). A2 is a BSTR with maximum length of xxx bytes * do_putch: cmp.b #70,(A2) bgt.s 1$ ; CD string longer than storage ; Just truncate it. addq.b #1,(A2) moveq #0,D1 move.b (A2),D1 move.b D0,0(A2,D1) 1$: rts *************************************************************************** * * Following is just constant data used by the program * *************************************************************************** DOSName: dc.b 'dos.library',0 str_noobj: dc.b 'Can''t find ',0 str_notdir: dc.b ' is a file not a directory' LF_str: dc.b $0A,0 str_baderr: dc.b 'Fatal error in CD',$0A,0 END