; ; Davex by David A. Lyons ; ; Begun 31-Aug-85 ; ;*********************************************** ; ; Converted to ca65 09/2011 (from 1.30 source) ; -Tabs set at 8 characters ; -Refactored to run on SOS as well as ProDOS ; ; Davex 1.30 2-Dec-99 ; -Changed shareware notice to Freeware notice. ; -Removed serial number support. ; -Y2K compliant ; -Prints a warning if the clock's year number is >99. ; -Help mentions "?topics". ; -Command line: Apple-left, Apple-right, Control-A. ; -Yes/No questions: Q = abort (like Esc/Cmd-Period). ; ; Converted to MPW IIgs 13-Sep-92 DAL (from 1.27 source) ; asmiigs davex.aii ; linkiigs davex.aii.obj -o davex ; makebiniigs davex -org $2000 ; setfile davex -c pdos -t PSYS ; dup Davex : ; ;*********************************************** ; Message with string .macro message_cstr Arg jsr mess cstr Arg .endmacro ; Message with string, trailing Return .macro message_cstr_cr Arg jsr mess cstr_cr Arg .endmacro ;*********************************************** copyright: jsr crout jsr pDavexVer jsr mess dollar: asc "Copyright (c) 1988-1990, 1999-2011" .byte cr asc "by David A. Lyons" .byte cr,cr asc " https://github.com/david-schmidt/Davex" .byte cr,cr asc "Davex is Freeware. If you find it useful, please let me know." .byte cr asc "If you want to send money or M&Ms I won't argue with you, but it's" .byte cr asc "not necessary." .byte cr,cr asc "Davex is Y2K compliant if you use ProDOS 8 2.0.3 or later." .if Proto .byte cr,cr asc "PROTOTYPE VERSION FOR TESTING ONLY - NOT A STABLE RELEASE." .endif .byte cr,0 rts ;*********************************************** ; ; RESTART (come here on RESET or Ctrl-Y or whatever) ; restart: lda #0 sta remslot ; %%% ? .if IsDavex3 ; Respond to the configuration setting of column numbers lda cfg40 jsr config_set_columns .else ; IsDavex2 jsr on80 .endif ; IsDavex3 jsr finish_oredir lda #0 sta fudgeCR sta redir_susplv sta redir_out sta redir_in SET_LEVEL jsr close jsr finish_iredir jsr spool_zap lda #0 ldx #6 prclz: sta SlotsOpen,x dex bpl prclz lda #<-1 sta dir_level lda #>dirstack ldy #wNotQuiet ldy #string ldy #command ldy #(command-1) ldy #<(command-1) jsr fixup_path_ay lda #>(command-1) ldy #<(command-1) jsr scanall bcs huh ; ; HERE IS WHERE TO DO "APPL" STUFF. ; cmp #tDIR beq gotoDIR jsr run_something sec ror externalc clc found_cmd: rts gotoDIR: CALLOS mli_setpfx, gdParms CALLOS_BRANCH_POS wentD jmp ProDOS_err wentD: lda #>nullcmd ldy #nullentr ldy #cmdtbl ldy #(command-1) ldy #<(command-1) jmp print_path ; ; compare command string with cmd_ptr^ ; cmp_cmd: ldy #0 ;points into cmd_ptr^ ldx #0 ;points into command compcmd1: lda command,x cmp (cmd_ptr),y bne no_match cmp #0 beq yes_match inx iny bne compcmd1 no_match: rts yes_match: iny lda (cmd_ptr),y sta cmd_addr iny lda (cmd_ptr),y sta cmd_addr+1 lda #0 ;BEQ rts ; ; munch up to a nonspace or end of line ; ms0: jsr chrget munch_space: jsr chrgot beq :+ cmp #$80+' ' beq ms0 : jmp chrgot parse_exec: jsr parse_cmd bcc execit jmp fix_stack execit: jsr parse_parms ; ; expand wildcards here & call routine ; until there are no more expandions ; lsr some_flag jsr wild_begin wild_again: jsr wild_next bcs wild_done sec ror some_flag ; ; repeat command rep_count times (0 ==> 1) ; Note: the REP command has to cheat to avoid ; an infinite loop; it changes the return address ; from JSR JMPCMD to return to REPEATED ; rep_again: lda #stdlevel SET_LEVEL lda #0 jsr getparm_n jsr jmpcmd jsr check_wait bcc rep_noAbort jmp yn_abort rep_noAbort: lda #stdlevel SET_LEVEL lda #0 jsr close jsr restore80 ; ; repeat until rep_count == 0 ; lda rep_count+1 ora rep_count beq repeated lda rep_count bne :+ dec rep_count+1 : dec rep_count jmp rep_again repeated: ; ; repeat cmd with next wildcard expansion ; jmp wild_again wild_done: bit some_flag bmi did_some message_cstr_cr "(no files matched)" did_some: rts jmpcmd: jmp (cmd_addr) ;*********************************************** ; ; parse_parms -- parse command's parameters from ; command line into PARMS. ; ; cmd_ptr points to the command's name ; parse_parms: bit externalc bmi parseparms2 ;already found find_parms: jsr adv_cmdptr bne find_parms jsr adv_cmdptr ;pt at addr jsr adv_cmdptr ;pt at addr+1 jsr adv_cmdptr ;pt at parm1 parseparms2: lda #0 sta num_parms lda #<-1 ;don't confuse wildcards sta parmtypes sta parmtypes+1 lda #>string_buffs ldy #(string_buffs-$300) ;only 6 buffers available bcc s2many sta strbuf+1 sty strbuf rts s2many: ldx #der_outroom jmp ProDOS_err ; ; free_sbuff -- deallocate last string buff ; free_sbuff: clc lda strbuf adc #128 sta strbuf bcc fsbxx inc strbuf+1 fsbxx: rts ; ; parse a "y" or "n" parameter ; pv_yesno: jsr chrgot jsr downcase cmp #$80+'y' beq @yes cmp #$80+'n' beq @no lda #der_ynexp jmp ProDOS_err @no: lda #0 beq @yn ;always taken @yes: lda #<-1 @yn: pha jsr calc_pindex pla sta parms+3,x jmp chrget ; ; parse an integer parameter (1, 2, or 3 bytes) ; pv_int: lda #0 sta num sta num+1 sta num+2 sta num+3 jsr chrgot cmp #$80+'$' bne not_hex jmp hex_num not_hex: jsr chk_dig bcs num_exp int_1: pha jsr mult10num pla and #%00001111 clc adc num sta num bcc num_ok inc num+1 bne num_ok inc num+2 beq overflow num_ok: jsr chrget jsr chk_dig bcc int_1 return_chk: lda num+3 ;17-Oct-89 bne overflow ;17-Oct-89 ldy ptype cpy #t_int2 bne num_ok2 lda num+2 bne overflow num_ok2: cpy #t_int1 bne num_ok3 lda num+1 ora num+2 bne overflow return_num: num_ok3: jsr calc_pindex lda num+2 sta parms+3,x lda num+1 sta parms+2,x lda num sta parms+1,x clc rts num_exp: lda #der_badnum der3: jmp ProDOS_err overflow: lda #der_bignum bne der3 chk_dig: cmp #'9'+1+$80 bcs chkdig_no cmp #$80+'0' bcc chkdig_no clc rts chkdig_no: sec rts ; ; mult10um - multiply num (4 bytes) by 10 ; ; destroys temp (4 bytes) ; ; Overflow: Bails out, does not return. ; mult10num: lda num ldx num+1 ldy num+2 sta temp stx temp+1 sty temp+2 lda num+3 sta temp+3 jsr mult2num ; *2 jsr mult2num ; *4 clc lda num adc temp sta num lda num+1 adc temp+1 sta num+1 lda num+2 adc temp+2 sta num+2 lda num+3 adc temp+3 sta num+3 ; *5 bcs overflow mult2num: asl num rol num+1 rol num+2 rol num+3 bcs overflow rts ; ; hex_num - parse a hex number ; ; Overflow: Bails out, does not return. ; hex_num: jsr chrget ;skip past "$" jsr chk_hex bcs hex_exp hex_1: pha jsr mult2num jsr mult2num jsr mult2num jsr mult2num pla clc adc num sta num bcc hnum_ok inc num+1 bcc hnum_ok inc num+2 bne hnum_ok jmp overflow hnum_ok: jsr chrget jsr chk_hex bcc hex_1 jmp return_chk hex_exp: lda #der_badnum jmp ProDOS_err chk_hex: jsr downcase cmp #$80+'0' bcc hex_x cmp #'f'+1+$80 bcs hex_x cmp #'9'+1+$80 bcc is_hex cmp #$80+'a' bcs is_hex0 hex_x: sec rts is_hex0: sec sbc #'a'-':' is_hex: and #%00001111 clc rts ; ; Parse a path or string parm (possibly null, ; and possibly quoted); path possibly followed ; by a Type specifier (:xxx) ; ; Single (') or double (") quotes can be used, ; and a quote mark may be doubled inside the ; string to get just one quote (like Pascal ; does for single quotes) ; pv_string: jsr get_strbuf sta p+1 sty p sta parms+3,x tya sta parms+1,x lda #0 sta parms+2,x ;file type sta quotechr tay sta (p),y sty string_index jsr munch_space jsr chrgot cmp #$80+'-' beq strdun cmp #$A7 beq gotqch cmp #$A2 ;double quote bne pstr_1 gotqch: sta quotechr pstr_0: jsr chrget pstr_1: jsr chrgot beq strdun ldx quotechr bne sep_allowed ; if unquoted, check for blank, ";", comma cmp #$80+' ' beq strdun cmp #$80+',' beq strdun0 cmp #$80+';' beq strdun ldy ptype cpy #t_string beq sep_allowed cmp #$80+':' beq typespec sep_allowed: cmp quotechr beq strdun0 StrChar: inc string_index ldy string_index and #%01111111 sta (p),y bne pstr_0 strdun0: jsr chrget beq strdun ;23-Feb-88 cmp quotechr ; beq StrChar ; strdun: lda string_index ldy #0 sta (p),y rts typespec: lda string_index ldy #0 sta (p),y jsr calc_pindex lda parms+1,x pha lda parms+3,x pha jsr chrget ;skip past colon jsr pv_ftype jsr calc_pindex lda num+2 sta parms+2,x pla sta parms+3,x pla sta parms+1,x rts ; ; parse a file type -- xxx or 1-byte integer ; ftyp_int: jsr pv_int lda num+1 ora num+2 beq ftyp_ok jmp overflow ftyp_ok: lda num sta num+2 jmp return_num pv_ftype: jsr munch_space cmp #$80+'$' beq ftyp_int jsr chk_dig bcc ftyp_int jsr calc_pindex jsr pv_string ldy #0 lda (strbuf),y cmp #3 beq is3 lda #der_needs3 jmp ProDOS_err is3: jsr free_sbuff ldx #0 ;index into filetyp lda #>fileasc ldy #fileasc0 ldy #(string-1) ldy #<(string-1) ldx #mli_write jsr HistoryMgr dont_keep: ldx string-1 rts ; ; print_pfx -- get prefix and print it ; print_pfx: jsr get_pfx ldx string2-1 beq :+ dec string2-1 : jmp print_path ; ; get_pfx ; get_pfx: CALLOS mli_getpfx, get_pfx_parms CALLOS_BRANCH_NEG pfx_err jsr pmgr .byte pm_downcase .addr string2-1 lda #>(string2-1) ldy #<(string2-1) rts pfx_err: jmp ProDOS_err ; ; set_pfx ; set_pfx: CALLOS mli_setpfx, set_pfx_parms CALLOS_BRANCH_NEG pfx_err rts ; ; print_p ; print_p: ldy #0 pp1: lda (p),y beq :+ ora #$80 jsr cout iny bne pp1 : rts ; ; upcase ; upcase: ora #%10000000 cmp #$80+'a' bcc uc_x cmp #'z'+1+$80 bcs uc_x and #%11011111 uc_x: rts ; ; downcase ; downcase: ora #%10000000 cmp #$80+'A' bcc :+ cmp #'Z'+1+$80 bcs :+ ora #%00100000 : rts ;*********************************************** ; ; clear screen and print title ; clear_sc: .if IsDavex2 lda #$80+'L'-ctrl jsr cout lda #0 jsr redirect bmi nohome .endif jsr home nohome: rts ; ; welcome ; welcome: lda cfgquiet beq wNotQuiet cmp #2 beq Quiet bit speech bmi Quiet wNotQuiet: jsr pDavexVer jsr mess .byte cr cstr_cr "Type ? for help, $ for Freeware notice." jmp print_time pDavexVer: message_cstr "Davex " lda #myversion jsr print_ver lda #AuxVersion+$80+'0' jsr cout jsr mess .if Proto asc "p" .endif cstr " " Quiet: rts ;*********************************************** ; ; shell_info -- ; X = request code ; Exit: CLC if okay, info in registers ; shell_info: txa bne shinf1 ; shell_info(0) = version(AY) lda #myversion ldy #AuxVersion clc rts shinf1: dex bne shinf2 ; shell_info(1) = alias buffer(AY=adr,X=pages) lda #>Aliases ldy #History ldy #filetyp0 ldy #fileasc0 ldy # ; ; ::= ; name $00 ; cmd address ; list of ; list of ; ; ::= ; $00 (no option character) ; ; ; ::= ; ; ; ;************************************ cmdtbl: asc_hi "bye" .byte 0 .addr go_quit .byte 0,0 asc_hi "$" .byte 0 .addr copyright .byte 0,0 asc_hi "version" .byte 0 .addr wNotQuiet .byte 0,0 asc_hi "rep" .byte 0 .addr go_repeat .byte 0,t_int2 .byte 0,0 asc_hi "config" .byte 0 .addr go_config .byte $80+'p',t_int1 .byte $80+'4',t_yesno .byte $80+'c',t_yesno .byte $80+'b',t_yesno .byte $80+'q',t_int1 .byte $80+'h',t_string .byte 0,0 asc_hi "como" .byte 0 .addr go_como .byte 0,t_wildpath .byte 0,0 asc_hi "exec" .byte 0 .addr go_exec .byte 0,t_wildpath .byte 0,0 asc_hi "prefix" .byte 0 .addr go_prefix .byte 0,t_wildpath .byte 0,0 asc_hi "boot" .byte 0 .addr go_boot .byte $80+'s',t_int1 .byte $80+'i',t_nil ;ice cold! .byte 0,0 asc_hi "mon" .byte 0 .addr go_mon .byte 0,0 asc_hi "up" .byte 0 .addr go_up .byte 0,0 asc_hi "top" .byte 0 .addr go_top .byte 0,0 asc_hi "help" .byte 0 .addr go_help .byte 0,t_string .byte 0,0 asc_hi "?" .byte 0 .addr go_help .byte 0,t_string .byte 0,0 asc_hi "online" .byte 0 .addr go_online .byte $80+'o',t_nil .byte 0,0 asc_hi "cls" .byte 0 .addr clear_sc .byte 0,0 asc_hi "type" .byte 0 .addr go_type .byte 0,t_wildpath .byte $80+'h',t_nil .byte $80+'f',t_nil .byte $80+'u',t_nil .byte $80+'l',t_nil .byte $80+'p',t_nil .byte $80+'t',t_string .byte 0,0 asc_hi "pg" .byte 0 .addr go_more .byte 0,t_wildpath .byte $80+'h',t_nil .byte $80+'f',t_nil .byte $80+'u',t_nil .byte $80+'l',t_nil .byte $80+'p',t_nil .byte $80+'t',t_string .byte 0,0 asc_hi "rename" .byte 0 .addr go_rename .byte 0,t_wildpath .byte 0,t_path .byte 0,0 asc_hi "filetype" .byte 0 .addr go_ctype .byte 0,t_wildpath .byte 0,t_ftype .byte $80+'x',t_int2 .byte 0,0 asc_hi "create" .byte 0 .addr go_create .byte 0,t_path .byte 0,0 asc_hi "dt" .byte 0 .addr print_time .byte 0,0 asc_hi "delete" .byte 0 .addr go_del .byte 0,t_wildpath .byte $80+'u',t_nil .byte 0,0 asc_hi "lock" .byte 0 .addr go_lock .byte 0,t_wildpath .byte 0,0 asc_hi "unlock" .byte 0 .addr go_unlock .byte 0,t_wildpath .byte 0,0 asc_hi "prot" .byte 0 .addr go_prot .byte 0,t_wildpath .byte $80+'r',t_nil .byte $80+'w',t_nil .byte $80+'d',t_nil .byte $80+'n',t_nil .byte 0,0 asc_hi "scan" .byte 0 .addr go_scan .byte $80+'a',t_string .byte $80+'r',t_string .byte $80+'z',t_nil .byte $80+'i',t_string .byte 0,0 asc_hi "cat" .byte 0 .addr go_cat .byte 0,t_wildpath .byte $80+'a',t_string .byte $80+'t',t_nil .byte $80+'s',t_nil .byte $80+'f',t_ftype .byte $80+'i',t_nil .byte 0,0 asc_hi "spool" .byte 0 .addr go_spool .byte 0,t_wildpath ;dfb $80+'h',t_string ;header ;dfb $80+'l',t_int1 ;lines/page ;dfb $80+'w',t_int1 ;page width .byte $80+'x',t_int1 ;cancel 1 .byte $80+'z',t_nil ;zap (cancel all) .byte 0,0 asc_hi "info" .byte 0 .addr go_info .byte 0,t_wildpath .byte 0,0 asc_hi "update" .byte 0 .addr go_update .byte 0,t_wildpath .byte 0,t_wildpath .byte $80+'f',t_nil .byte $80+'b',t_nil .byte 0,0 asc_hi "copy" .byte 0 .addr go_copy .byte 0,t_wildpath .byte 0,t_wildpath .byte $80+'d',t_nil ;delete orig .byte $80+'f',t_nil ;force delete .byte $80+'b',t_nil ;clr bkup bit .byte 0,0 asc_hi "move" .byte 0 .addr go_move .byte 0,t_wildpath .byte 0,t_wildpath .byte $80+'f',t_nil ;force delete .byte 0,0 asc_hi "touch" .byte 0 .addr go_touch .byte 0,t_wildpath .byte $80+'b',t_yesno .byte $80+'d',t_yesno .byte $80+'i',t_yesno .byte 0,0 .if IsDavex2 asc_hi "dev" .byte 0 .addr go_dev .byte $80+'r',t_devnum .byte $80+'a',t_devnum .byte $80+'z',t_nil .byte 0,0 .endif asc_hi "ftype" .byte 0 .addr go_ftype .byte $80+'r',t_ftype .byte $80+'a',t_string .byte $80+'v',t_ftype .byte $80+'z',t_nil .byte 0,0 ; [TODO] what was "appl" going to do if implemented? Maybe assign filetypes to applications, ; so you can launch something by document path and automatically have the right app ; use the document? ;;;;; ; asc_hi "appl" ; .byte 0 ; .addr go_appl ; .byte $80+'r',t_ftype ; .byte $80+'a',t_ftype ; .byte $80+'p',t_string ; .byte 0,0 asc_hi "err" .byte 0 .addr go_err .byte 0,t_int1 .byte 0,0 asc_hi "=" .byte 0 .addr go_equal .byte 0,t_wildpath .byte 0,t_path .byte 0,0 asc_hi "size" .byte 0 .addr go_size .byte 0,t_wildpath .byte 0,0 asc_hi "echo" .byte 0 .addr go_echo .byte 0,t_string .byte $80+'n',t_nil ;no CR .byte 0,0 asc_hi "eject" .byte 0 .addr go_eject .byte 0,t_path .byte 0,0 asc_hi "wait" .byte 0 .addr go_wait .byte 0,0 asc_hi "num" .byte 0 .addr go_num .byte 0,t_int3 .byte 0,0 .if RemoteImp asc_hi "remote" .byte 0 .addr go_remote .byte 0,t_int1 .byte 0,0 .endif ; asc_hi "mem" ; .byte 0 ; .addr go_mem ; .byte 0,0 ; end of command table .byte 0,0 ;******************************************** notspool: bit spooling bmi ouchspool rts ouchspool: lda #der_waitspool jmp ProDOS_err ;******************************************** go_num: sta num+2 stx num+1 sty num message_cstr " $" lda num+2 jsr prbyte lda num+1 jsr prbyte lda num jsr prbyte message_cstr " = " jsr prdec jmp crout ;******************************************** go_wait: bit spooling bpl :+ jsr poll_io bit keyboard bpl go_wait sta kbdstrb jmp yn_abort : rts ;******************************************** s16_flag: .byte 0 go_quit: .if IsDavex3 lda #0 SET_LEVEL jsr close clc ; [TODO] why? .else clc ror s16_flag sta s16_name+1 sty s16_name jsr notspool lda #0 SET_LEVEL jsr close jsr off80 lda #$ff ldy #$59 sta $3fd sty $3fc lda $3f3 sta $3f4 ; quitting to S16? bit s16_flag bmi quit_s16 .endif os_quit: CALLOS mli_bye, bye_parms jmp ProDOS_err .if IsDavex2 quit_s16: CALLOS mli_bye, quit2_parms jmp ProDOS_err quit2_parms: .byte 4,$ee s16_name: .addr 0 .byte 0,0,0 .endif ;********************************************* ; ; boot [-s slot#] [-i] ; ; -i = ice-cold boot (IIgs) ; go_boot: .if IsDavex2 lda reset+1 sta reset+2 ; If IIgs, do what the ProDOS-16 PQUIT thinger does ; on 'Reboot system' sec jsr $fe1f ;CLC on IIgs bcs rb_NotGS sei lda #0 .P816 sta $E0C035 ; Shadow register .P02 sta $c047 ;clear VBL/3_75Hz int flags sta $c041 ;disable lots of ints lda #9 sta $c039 ;SCC channel A cmd reg lda #$c0 sta $c039 ; if -i, trash $5f in the Keyboard Micro's RAM lda #$80+'i' jsr getparm_ch bcs no_ice jsr ice_it no_ice: rb_NotGS: jsr off80 jsr home start_normal lda #$80+'i' ; jsr getparm_ch ; bcc badslot ; lda #$80+'s' jsr getparm_ch bcc boot_slot badslot: jmp ($fffc) boot_slot: lda #0 sta p tya beq badslot cmp #7+1 bcs badslot ora #$C0 sta p+1 jmp (p) ; ; ice_it: (OpenApple V3#6, p3_48) ; .P816 ice_it: clc XCE rep #$30 .A16 .I16 lda #$0051 sta $0000 pea $0002 ; send 2 bytes pea $0000 pea $0000 pea $0008 ; write Key Micro RAM ldx #$0909 ; send to ADB jsl $e10000 ; Stores $00 into $51 (Key Micro RAM) sec XCE rts .P02 .else ; IsDavex3 lda #$53 ; Switch in ROM#1, I/O, disable reset switch sta e_reg ; Set the environment register jmp boot ; Jump to boot code in ROM .endif ; ; handle an NMI ; NMIouch: sec bcs mon2 ; ; enter monitor ; go_mon: .if IsDavex2 jsr notspool clc mon2: php jsr off80 jsr home start_normal plp bcc no_nmi message_cstr_cr "Ouch!" no_nmi: jmp monitor .else ; IsDavex3 mon2: lda #columns40 sta INIT_SCREEN_COLUMNS jsr set_columns jsr home jmp monitor .endif ; ; prefix ; go_prefix: setthepfx: sta pfxstradr+1 sty pfxstradr .if IsDavex3 ; SOS won't change directory to a relative path. ; So, if a request is made without a leading slash, ; prefix it with the current directory. sty p sta p+1 ldy #$01 lda (p),y ; Check out the first character cmp #'/' ; Is it a slash? beq set_prefix_literal ; Yes - then just set the request literally jsr get_pfx ; Otherwise, get current prefix - AY points to string2 jsr xpmgr .byte pm_slashif ; Append a trailing slash, if needed .addr string2-1 lda pfxstradr+1 ldy pfxstradr jsr xpmgr .byte pm_appay ; Append the requested prefix string at ay to string2 .addr string2-1 ldy #<(string2-1) sty pfxstradr lda #>(string2-1) sta pfxstradr+1 ; Point the set prefix call at the concatenated string set_prefix_literal: .endif ; IsDavex3 CALLOS mli_setpfx, pfxcmdparms CALLOS_BRANCH_POS set_ok jmp ProDOS_err set_ok: rts pfxcmdparms: .byte 1 pfxstradr: .res 2 ; ; up -- leave a subdirectory ; go_up: jsr get_pfx jsr pmgr .byte pm_up .addr string2-1 jmp set_pfx ; ; top ; go_top: jsr get_pfx ldx string2-1 beq topped ldy #0 ;# slashes countSlashes: lda string2-1,x ora #$80 cmp #$80+'/' bne cs_not iny cs_not: dex bne countSlashes cpy #3 bcc topped jsr go_up jmp go_top topped: rts ;********************************************* ; ; 'type' command -- show contents of a file (without pausing like 'pg' and 'more') ; case_flags: .res 1 pause_flag: .res 1 line_count: .res 1 saved_tchr: .res 1 go_type: clc type_pg: ror pause_flag lda #$80+'f' jsr getparm_ch ror a sta filter lda #$80+'l' jsr getparm_ch ror case_flags lda #$80+'u' jsr getparm_ch ror case_flags lda #0 jsr getparm_n more2: pha tya pha ; don't prompt if output redirected lda #0 jsr redirect bpl :+ lsr pause_flag : pla tay pla jsr fman_open bcc typeopened type_err: jmp ProDOS_err typeopened: sta type_readref sta tyeofr CALLOS mli_geteof, tyeof CALLOS_BRANCH_NEG type_err lda #23 sta line_count ; ; print header if -h given ; lda #$80+'h' jsr getparm_ch bcs no_head message_cstr "******* " lda p+1 ldy p jsr print_path message_cstr "--modified " lda p+1 ldy p jsr getinfo lda info_moddat+1 ldy info_moddat jsr pr_date_ay lda info_modtim+1 ldy info_modtim jsr pr_time_ay jsr mess asc " *******" .byte cr,cr,0 dec line_count dec line_count no_head: lda scr_width sta temp type_1: jsr poll_io lda type_readref jsr fman_read bcc treadok cmp #err_eof bne typerr9 jmp type_finish typerr9: jmp ProDOS_err treadok: ora #%10000000 sta saved_tchr cmp #$80+'M'-ctrl bne not_typeret typeret: ldx scr_width inx stx temp jsr check_wait bcc type_chk1 jmp type_finish type_chk1: lda saved_tchr dec line_count bne print_char lda #23 sta line_count lda saved_tchr bit pause_flag bpl print_char jsr suspend jsr TalkCont jsr mess .byte cr cstr "--- " jsr type_percent jsr prdec_1 message_cstr "% --- more" lda #$80+'y' ;default = Yes jsr yesno2 jsr restore beq type_finish lda saved_tchr jmp print_char not_typeret: cmp #$89 bne not_TAB lda #$80+'t' jsr getparm_ch bcs not_TAB0 jsr print_path jmp type_1 not_TAB0: lda #$89 not_TAB: bit filter bpl print_char cmp #$a0 bcs print_char jmp type_1 print_char: .if IsDavex3 cmp #$8d bne :+ lda #$0d : .endif dec temp beq typeret bit case_flags bmi t_no_up jsr upcase t_no_up: bit case_flags bvs t_no_down jsr downcase t_no_down: jsr cout jmp type_1 type_finish: lda #$80+'p' jsr getparm_ch bcs type_done jsr clear_sc type_done: lda type_readref jsr close rts type_percent: lda tyeofr sta tymarkr CALLOS mli_getmark, tymark lda tymarkval+2 ldx tymarkval+1 ldy tymarkval sta num+2 stx num+1 sty num lda tyeofval+2 ldx tyeofval+1 ldy tyeofval jmp percent tymark: .byte 2 tymarkr: .res 1 .if IsDavex3 tymarkval: .res 4 ; SOS has a four-byte tymarkval result. .else tymarkval: .res 3 .endif tyeof: .byte 2 tyeofr: .res 1 tyeofval: .if IsDavex3 .res 4 ; SOS has a four-byte result .else .res 3 .endif type_readref: .res 1 filter: .res 1 ; ; pg and more commands -- show contents of file; ; pause between pages ; go_more: sec jmp type_pg ;**************************************************** ; ; rename command: rename ; go_rename: sta rename_1+1 sty rename_1 lda #1 jsr getparm_n sta rename_2+1 sty rename_2 CALLOS mli_rename, rename_parms CALLOS_BRANCH_NEG rename_err rts rename_err: jmp ProDOS_err rename_parms: .byte 2 rename_1: .res 2 rename_2: .res 2 ; ; ctype command: ctype (-x auxtype) ; ; Change filetype. ; ctype_typ: .res 1 go_ctype: sta p+1 sty p jsr getinfo lda #1 jsr getparm_n sta info_type ; if -x given, change aux type lda #$80+'x' jsr getparm_ch bcs same_aux stx info_auxtype+1 sty info_auxtype same_aux: lda p+1 ldy p jmp setinfo ;**************************************** ; ; create [:type] ; go_create: sta cr_path+1 sty cr_path cpx #0 bne :+ ldx #tDIR : stx cr_type ldy #1 ;storage type for seedling cpx #tDIR bne cr_seed ldy #$d ;storage type for directory cr_seed: sty cr_stype CALLOS mli_create, cr_parms CALLOS_BRANCH_NEG cr_err rts cr_err: jmp ProDOS_err ; ; unlock ; go_unlock: lda #%11111111 ;AND mask ldy #%11000011 ;OR mask: RWND bne protect ; ; lock ; go_lock: lda #%00111100 ;AND mask ldy #%00000001 ;OR mask: R bne protect protect: sta and_mask sty or_mask ; get file access lda #0 jsr getparm_n sta p+1 sty p jsr getinfo lda info_acc and and_mask ora or_mask sta info_acc lda p+1 ldy p jmp setinfo ;******************************************* ; ; prot -r -w -n -d ; go_prot: lda #%00000000 pha lda #$80+'r' jsr getparm_ch bcs protp1 pla ora #%00000001 ;R pha protp1: lda #$80+'w' jsr getparm_ch bcs protp2 pla ora #%00000010 ;W pha protp2: lda #$80+'n' jsr getparm_ch bcs protp3 pla ora #%01000000 ;N pha protp3: lda #$80+'d' jsr getparm_ch bcs protp4 pla ora #%10000000 pha protp4: pla tay lda #%00111100 ;AND: clear RWND jmp protect ;*************************************************** ; ; scan [-a add_path] [-r remove_path] ; [-z defaults] [-i insert] ; go_scan: lda num_parms bne scan_parms ; show list of cmd directories lda scanlist bne somedirs message_cstr_cr "no command dirs" rts somedirs: message_cstr_cr "command dirs:" ldx #0 scan_show1: lda scanlist,x beq scan_shown stx temp message_cstr " " ldx temp lda scanlist,x ;length tay scanshowch: inx lda scanlist,x ora #%10000000 jsr cout dey bne scanshowch inx stx temp jsr crout jmp scan_show1 scan_shown: rts ; Default scan-path entries scan_dflt: pstr "%" pstr "*" .byte 0 scan_zap: ldy #<-1 scanz1: iny lda scan_dflt,y sta scanlist,y bne scanz1 jmp makedirt scan_parms: lda #$80+'z' jsr getparm_ch bcs @notz jsr scan_zap @notz: lda #$80+'r' jsr getparm_ch bcs @notrem jsr findscan_x bcc :+ lda #der_notfnd jmp ProDOS_err : txa sec adc scanlist,x tay @squish: lda scanlist,y sta scanlist,x inx iny bpl @squish @notrem: lda #$80+'a' jsr getparm_ch bcs scan_notadd jsr findscan_x bcc scan_notadd ldy #0 lda (p),y sta count ;;; sec txa adc count bpl scan_fits lda #der_outroom jmp ProDOS_err scan_fits: scappend: lda (p),y sta scanlist,x iny inx dec count bpl scappend lda #0 sta scanlist,x scan_notadd: sec ror config_dirty rts count: .res 1 findscan_x: sta p+1 sty p ldy #0 lda (p),y cmp #1 beq noslash tay lda (p),y cmp #$2f beq noslash ;don't add one iny tya lda #$2f sta (p),y tya ldy #0 sta (p),y ;update len noslash: ldx #0 fsx1: stx temp ldy #0 lda (p),y ;length of target cmp scanlist,x ;same lengths? bne fsxnext sta count fsxcomp: iny inx lda (p),y jsr downcase sta scchar lda scanlist,x jsr downcase cmp scchar bne fsxnext dec count bne fsxcomp clc ldx temp rts scchar: .byte 0 fsxnext: ldx temp lda scanlist,x beq scanx txa sec adc scanlist,x tax lda scanlist,x bne fsx1 scanx: sec ;not found rts ;************************************************** ; ; info -- print info on file & volume ; go_info: jsr empty_prefix sta p+1 sty p sta info_path+1 sty info_path jsr getinfo ; devnum may change if output redirected lda devnum pha jsr mess .byte cr cstr "name: " lda #0 jsr getparm_n jsr empty_prefix jsr prnt_compl message_cstr " " pla ;get devnum jsr print_sd jsr mess .byte cr cstr "strg type: " lda info_stype jsr print_stype jsr mess .byte cr cstr "type: " lda info_type jsr print_ftype jsr mess cstr " access: " lda info_acc jsr print_access jsr mess .byte cr cstr "aux type: " lda info_auxtype+1 ldy info_auxtype jsr prdec_2 jsr mess cstr " ($" lda info_auxtype+1 jsr prbyte lda info_auxtype jsr prbyte jsr mess .byte ')',cr cstr "blocks: " lda info_blocks+1 ldy info_blocks jsr prdec_2 jsr crout lda info_crdat+1 ora info_crdat ora info_crtim+1 ora info_crtim beq info_nullcr jsr mess cstr "created: " lda info_crdat+1 ldy info_crdat jsr pr_date_ay lda info_crtim+1 ldy info_crtim jsr pr_time_ay jsr crout info_nullcr: lda info_moddat+1 ora info_moddat ora info_modtim+1 ora info_modtim beq info_nullmod message_cstr "modified: " lda info_moddat+1 ldy info_moddat jsr pr_date_ay lda info_modtim+1 ldy info_modtim jsr pr_time_ay jsr crout info_nullmod: info_nbin: rts startup_size: sta info_path+1 sty info_path lda #0 tay zrpgbf: sta pagebuff,y dey bne zrpgbf ;in case file is short! CALLOS mli_open, info_op CALLOS_BRANCH_NEG info_err zrpgbfOK: lda inforef sta inforef2 CALLOS mli_read, info_rd ; a short read is not an error (no CALLOS_BRANCH_NEG info_err) lda inforef jsr close lda pagebuff cmp #$4c bne cbuf0 lda #$ee cmp pagebuff+3 bne cbuf0 cmp pagebuff+4 bne cbuf0 lda pagebuff+5 rts cbuf0: lda #0 rts info_err: jmp ProDOS_err info_rd: .byte 4 inforef2: .res 1 .addr pagebuff .addr 256 .addr 0 print_stype: cmp #1 beq st_seed cmp #2 beq st_sap cmp #3 beq st_tree cmp #4 beq st_pasc cmp #5 beq st_extended cmp #$D beq stp_dir cmp #$F beq st_vol jmp prdec_1 st_seed: message_cstr "seedling" rts st_sap: message_cstr "sapling" rts st_tree: message_cstr "tree" rts st_pasc: message_cstr "pascal area" rts st_extended: message_cstr "extended" rts stp_dir: message_cstr "subdirectory" rts st_vol: message_cstr "volume" rts ; ; repeat ; go_repeat: stx rep_count+1 sty rep_count tya ora rep_count+1 beq rc_eq0 cpy #0 bne nodecrc1 dec rep_count+1 nodecrc1: dec rep_count rc_eq0: pla pla ; pop RTS address jmp repeated ; must cheat instead of returning normally ; [TODO] What was the 'remote' command going to do, if ever implemented? Control Davex from a serial card? .if RemoteImp go_remote: cpy #1 bcc remote0 cpy #7+1 bcs badrem sty remslot ; %%% only if not exec?! jsr finish_iredir rts badrem: lda #der_badnum jmp ProDOS_err remote0: sty remslot ; %%% ? jsr finish_iredir jsr finish_oredir rts .endif ;************************************************* ;************************************************ ; ; cmds2 -- lots more Davex commands ; ;************************************************ indent_level: .byte 0 cat_ftype: .byte 0 cat_devnum: .byte 0 ; show_invis: .byte 0 ; ; go_cat -- Catalog command ; go_cat: lda #0 sta indent_level sta cat_ftype lda #$80+'i' jsr getparm_ch ror a eor #$80 sta show_invis lda #$80+'f' jsr getparm_ch bcs c_noftp sta cat_ftype c_noftp: lda #0 jsr getparm_n jsr empty_prefix sta ptr+1 sty ptr jsr getinfo lda devnum sta cat_devnum lda info_type .if IsDavex3 cmp #$00 bne c_cmp_tdir lda #tDIR .endif c_cmp_tdir: cmp #tDIR beq cat_isdir lda #der_notdir jmp ProDOS_err cat_isdir: lda #$80+'a' ;arrange jsr getparm_ch bcs cat_unsort sta sort_str+1 sty sort_str jmp cat_sorted cat_unsort: jsr push_level lda ptr+1 ldy ptr jsr dir_setup jsr crout jsr cat_header dir_1: jsr read1dir_vis bcs dir_x jsr print1dir bcs dir_xx lda catbuff+16 ;type cmp #tDIR bne cat_xnest lda #$80+'t' jsr getparm_ch bcs cat_xnest jsr push_level lda catbuff and #%00001111 sta catbuff lda #>catbuff ldy #" nest_fail: cat_xnest: jmp dir_1 dir_x: bit speech bpl dirdec lda indent_level beq dirdec message_cstr_cr "<" dirdec: dec indent_level dec indent_level jsr dir_finish lda indent_level bpl dir_1 jmp cat_trailer dir_xx: jsr dir_finish dec indent_level dec indent_level bpl dir_xx rts ; ; -arrange the dir listing ; cat_sorted: jsr push_level lda ptr+1 ldy ptr jsr dir_setup jsr crout jsr cat_header lda #0 sta keep_count+1 sta keep_count jsr keep_init catsrt1: jsr read1dir_vis bcs catsrt2 jsr keep1dir jmp catsrt1 catsrt2: jsr dir_finish jsr sortdir jsr keep_init catsrt3: jsr get1kept bcs catsrt_x jsr print1dir bcc catsrt3 catsrt_x: jmp cat_trailer keep_count: .addr 0 ; ; sort directory entries (length = entrylen) at ; 'keepbuff'. There are keep_count(2 by) files ; swapped: .byte 0 srt_count: .byte 0 sortdir: ldy #0 ;if sort_str is empty, sort by name lda (sort_str),y bne sort_given lda #1 sta (sort_str),y iny lda #$80+'n' sta (sort_str),y sort_given: lda keep_count+1 bne dont_srt lda keep_count pha nextpass: lda #0 sta swapped jsr sort1pass dec keep_count lda swapped bne nextpass pla sta keep_count dont_srt: rts sort1pass: lda keep_count sta srt_count beq sort_x lda #>keepbuff ldy #keepbuff ldy #(catbuff-1) ldy #<(catbuff-1) jmp getinfo ; ; print this entry if: ; no -f type was given OR ; the type matches the -f type OR ; it's a DIR and -t was given ; print1dir: lda cat_ftype beq dothis2 cmp catbuff+16 beq dothis2 lda catbuff+16 cmp #tDIR bne notthis2 lda #$80+'t' jsr getparm_ch bcc dothis2 notthis2: clc rts dothis2: ldx indent_level jsr indent_x lda catbuff and #%00001111 tax ldy #1 prcat1: lda catbuff,y ora #%10000000 ; asl case_mask+1 ; rol case_mask ; bcc no_dcase ; jsr downcase ;no_dcase jsr cout iny dex bne prcat1 clc tya adc indent_level tay tabType: cpy #18+10 bcs tabbedType jsr pr_sp iny bne tabType tabbedType: ldx #$80+' ' lda catbuff and #$f0 cmp #$50 bne not_xtnd ldx #$80+'+' not_xtnd: txa jsr cout lda catbuff+16 jsr print_ftype ; short form -s? lda #$80+'s' jsr getparm_ch bcs longcat jsr crout jmp check_wait longcat: ; print ' $xxxx' (auxtype) message_cstr " $" lda catbuff+$20 jsr prbyte lda catbuff+$1f jsr prbyte ; print a comma for Speech users jsr speech_comma ; blocks lda catbuff+$14 ldy catbuff+$13 ldx #0 stx num+2 sta num+1 sty num jsr prdec_pad lda #$80+' ' bit speech bpl store_char lda #$80+',' store_char: sta spComma jsr mess spComma: cstr " " ; first char MODIFIED above lda catbuff+$22 ldy catbuff+$21 jsr pr_date_ay jsr pr_sp lda catbuff+$24 ldy catbuff+$23 jsr pr_time_ay message_cstr " " lda catbuff+$1E jsr print_access jsr crout jmp check_wait ; ; Calculate mask of uppercase/lowercase letters in the filename. ; ; Three filetypes use their auxtype to store this information: ; 19 ADB UprLwr AppleWorks Database ; 1A AWP UprLwr AppleWorks Word Processing ; 1B ASP UprLwr AppleWorks Spreadsheet ; ; But in general, the ProDOS FST stores it in two other bytes. ; calc_cmask: ldx catbuff+16 ;type cpx #$19 ; < ADB ? bcc cm_ProFST cpx #$1B+1 ; >= ASP+1 ? bcs cm_ProFST lda catbuff+$20 ldy catbuff+$1f cm_store: sta case_mask+1 sty case_mask rts ; check for ProDOS FST lowercase bits cm_ProFST: lda catbuff+$1d bpl no_case lda catbuff+$1c asl a rol catbuff+$1d ldy catbuff+$1d jmp cm_store no_case: lda #$ff tay bne cm_store case_mask: .res 2 indent_x: beq @exit : jsr pr_sp dex bne :- @exit: rts ;************************************************ ;************************************************ ; ; ftype [-r] [-a -v] [-z] ; go_ftype: lda num_parms bne ftype_p ; display all filetype names lda #7 ldx scr_width cpx #80 bcs :+ lsr a : sta ftyp_mask clc jsr displayFTs jsr crout sec displayFTs: ror ftInternal ldx #0 ldy #0 ftype1: lda filetyp,x bit ftInternal bpl ftExt1 lda filetyp0,x ftExt1: cmp #0 beq ftypex pha jsr pr_sp jsr oneFTchar jsr oneFTchar jsr oneFTchar lda #$80+'=' jsr cout lda #$80+'$' jsr cout pla jsr prbyte jsr pr_sp inx txa and ftyp_mask bne ftype1 jsr crout jmp ftype1 ftypex: jmp crout ftyp_mask: .byte 0 ftInternal: .byte 0 oneFTchar: lda fileasc,y bit ftInternal bpl oneFTch lda fileasc0,y oneFTch: iny ora #%10000000 jmp cout ftype_p: lda #$80+'z' jsr getparm_ch bcs no_zapft lda #0 sta filetyp jsr makedirt no_zapft: lda #$80+'r' jsr getparm_ch bcs ftype_add ; remove type A sta temp ldx #0 ftr1: lda filetyp,x beq ftr_nf cmp temp beq ftr_f inx cpx #63 bcc ftr1 ftr_nf: lda #der_notfnd jmp ProDOS_err ftr_f: txa sta temp asl a adc temp tay ftr_f1: lda filetyp+1,x sta filetyp,x lda fileasc+5,y sta fileasc+2,y lda fileasc+4,y sta fileasc+1,y lda fileasc+3,y sta fileasc,y iny iny iny inx cpx #63 bcc ftr_f1 jsr makedirt ftype_add: lda #$80+'a' jsr getparm_ch bcs ftype_x sta p2+1 sty p2 ldy #0 lda (p2),y cmp #3 beq fta3 lda #der_needs3 der2: jmp ProDOS_err fta3: lda #$80+'v' jsr getparm_ch bcc fta4 lda #der_missopt bne der2 fta4: sta temp ldx #0 fta1: lda filetyp,x beq fta_f inx cpx #63 bcc fta1 lda #der_outroom bne der2 fta_f: lda temp sta filetyp,x lda #0 sta filetyp+1,x stx temp txa asl a adc temp tax inx inx ldy #3 ftacopy: lda (p2),y sta fileasc,x dex dey bne ftacopy jsr makedirt ftype_x: rts ;************************************************ ; ; err -- print xProDOS error ; go_err: tya beq all_errs jmp ProDOS_er all_errs: lda #0 next_err: pha ldy #3 sta num lda #0 sta num+1 sta num+2 jsr prdec_pady message_cstr ": " pla pha jsr ProDOS_er2 jsr check_wait pla bcs :+ ;;; clc adc #1 bcc next_err : rts ;************************************************ ; ; '=' -- print a pathname ; go_equal: nop ;disables wildcard expansion echo sta p2+1 sty p2 lda #1 jsr getparm_n sta p+1 sty p ldy #0 lda (p),y bne goeq2 ldy #0 lda (p2),y beq eqx iny lda (p2),y ora #%10000000 cmp #$80+'/' beq eq_compl jsr print_pfx lda #$80+'/' jsr cout eq_compl: lda p2+1 ldy p2 jsr print_path jmp crout eqx: rts goeq2: lda p+1 ldy p jsr print_path jmp crout ;************************************************ ; ; appl)ications ; .if 0 go_appl: message_cstr_cr "(appl not implemented)" rts .endif ;************************************************ ; ; > | como ; go_como: sta p+1 sty p jsr begin_oredir lda redir_out beq :+ cmp #refSlot0 bcs :+ jsr append : rts ;************************************************ ; ; < | exec ; go_exec: jsr finish_iredir lda #0 jsr getparm_n jmp begin_iredir ;************************************************ ; ; go_echo -- type a string (-n = no CR) ; go_echo: sta p+1 sty p ldy #0 lda (p),y ; length byte beq echoed tax echo1: iny lda (p),y ora #%10000000 jsr cout dex bne echo1 echoed: lda #$80+'n' jsr getparm_ch bcc echo_noCR jsr crout echo_noCR: rts ;************************************************ ; ; touch -- update the mod date of a file, ; or set/clear backup bit or ; invisible bit, or enable/disable ; go_touch: jsr getinfo jsr touch_b jsr touch_d jsr touch_i jsr getnump cmp #1 bne nTouchDate lda date+1 ldy date sta info_moddat+1 sty info_moddat lda time+1 ldy time sta info_modtim+1 sty info_modtim nTouchDate: touch_set: lda #0 jsr getparm_n jmp setinfo touch_b: lda #$80+'b' jsr getparm_ch bcs touch_bx tax beq touch_bn lda info_acc ora #%00100000 bne do_bub touch_bn: lda info_acc and #%11011111 do_bub: sta info_acc lda #$ff sta bubit ;allow fiddling w/ bkup bit touch_bx: rts touch_i: lda #$80+'i' jsr getparm_ch bcs touch_ix tax beq touch_in lda info_acc ora #%00000100 sta info_acc rts touch_in: lda info_acc and #%11111011 sta info_acc touch_ix: rts touch_d: lda #$80+'d' jsr getparm_ch bcs touch_dx tax lda info_type cmp #$c7 ;CDEV beq okDisable cmp #$b6 bcc bad_disable cmp #$bd+1 bcs bad_disable cmp #$ba beq bad_disable cmp #$bc beq bad_disable okDisable: txa bne tDISABLE lda info_auxtype+1 and #$7f ;enable sta info_auxtype+1 rts tDISABLE: lda info_auxtype+1 ora #$80 ;disable sta info_auxtype+1 touch_dx: rts bad_disable: jsr mess .byte cr cstr_cr "*** bad filetype for enable/disable" jmp main_err ;************************************************ ; ; config ; go_config: lda num_parms beq cfg_show lda #$80+'p' jsr getparm_ch bcs cfg2 cpy #7+1 bcs cfgperr cpy #0 beq cfgperr sty print_slot jsr makedirt cfg2: lda #$80+'4' jsr getparm_ch bcs cfg3 sta cfg40 .if IsDavex3 jsr config_set_columns .endif jsr makedirt cfg3: lda #$80+'b' jsr getparm_ch bcs cfg4 sta cfgbell jsr makedirt cfg4: lda #$80+'c' jsr getparm_ch bcs cfg5 sta cfgclock jsr makedirt cfg5: lda #$80+'q' jsr getparm_ch bcs cfg6 cpy #3 bcs cfgperr sty cfgquiet jsr makedirt cfg6: lda #$80+'h' jsr getparm_ch bcs cfg7 sta p+1 sty p sta hp1+1 sty hp1 ldy #0 lda (p),y cmp #64 bcc HelpPok lda #der_outroom jmp ProDOS_err HelpPok: jsr pmgr .byte pm_copy hp1: .addr 0,cfghelp jsr makedirt cfg7: rts cfgperr: lda #der_badnum jmp ProDOS_err cfg_show: message_cstr " Printer slot: " lda print_slot ora #$80+'0' jsr cout jsr mess .byte cr cstr "Use system bell: " lda cfgbell jsr showyn jsr mess .byte cr cstr "40 columns only: " lda cfg40 jsr showyn jsr mess .byte cr cstr "Show IIgs clock: " lda cfgclock jsr showyn jsr mess .byte cr cstr " Quiet level: " lda cfgquiet ora #$80+'0' jsr cout jsr mess .byte cr cstr " Help directory: " lda #>cfghelp ldy # [-f] [-d] [-b] ; ; -f = force replacement of existing file ; -d = delete original after successful copy ; -b = clear backup bit after copy (both files) ; ;******************************************************* ; ; copy(pn1,pn2,options) ; { ; if null(pn2) pn2 = GetPrefix(); ; GetInfo(pn1); ; Open(pn1); ; GetEOF(pn1); ; repeat ; GetInfo(pn2); ; .if type=DIR concat(pn2,filename(pn1)); ; until type<>DIR; ; If not found(pn2) ; create(pn2,"BAD",unlocked) ; else ; ask("okay to replace",pn2); ; ... ; } ; ;******************************************************* copydir: lda cp_pn2+1 ldy cp_pn2 sta cpd_cr+2 sty cpd_cr+1 jsr geti2 bcs cpd_cre lda info_stype cmp #$f beq cpdok3 cpd_cre: CALLOS mli_create, cpd_cr CALLOS_BRANCH_NEG cpd_err cpdok3: jsr push_level lda cp_pn1+1 ldy cp_pn1 jsr dir_setup cdir1: jsr read1dir bcs cdirx lda catbuff and #%00001111 sta catbuff ; append name to path1, path2 jsr cp_appboth jsr cp_report jsr cp_recurse ; remove last seg from path1, path2 lda cp_pn1+1 ldy cp_pn1 jsr up_ay lda cp_pn2+1 ldy cp_pn2 jsr up_ay jmp cdir1 cdirx: jmp dir_finish cpd_err: jmp ProDOS_err cpd_cr: .byte 7,0,0,%11000011,tDIR,0,0,$D,0,0,0,0 ;******************************************* up_ay: sta upay+1 sty upay jsr pmgr .byte pm_up upay: .addr 0 rts cp_appboth: lda cp_pn1+1 ldy cp_pn1 sta cpapp+1 sty cpapp sta cpsl1+1 sty cpsl1 lda cp_pn2+1 ldy cp_pn2 sta cpapp2+1 sty cpapp2 sta cpsl2+1 sty cpsl2 jsr pmgr .byte pm_slashif cpsl1: .addr 0 jsr pmgr .byte pm_slashif cpsl2: .addr 0 lda #>catbuff ldy #catbuff ldy #cpgeof_result sta p+1 lda #cpseof_result sta p2+1 lda (p),y sta (p2),y dey bne :- .endif ; ; GetInfo on the dest file ; cp_getdesti: lda #$ff sta desti_acc sta desti_stt CALLOS mli_gfinfo, destinfo CALLOS_BRANCH_POS cp_goti cmp #err_filnotfnd beq cp_create cp_err0: jmp ProDOS_err cp_goti: lda desti_stt cmp #$f ;is it a volume? beq cp_isdir cmp #$d ;is it a subdirectory? bne cp_ask cp_isdir: ; ; append filename of path1 onto path2 and go back to see ; if the file exists ; jsr cp_intodir jmp cp_getdesti ; cp_create: CALLOS mli_create, cp_creatp CALLOS_BRANCH_POS cp_created jmp ProDOS_err ; cp_ask: lda desti_acc and #%11000011 cmp #%11000011 bne ask_anyway lda #$80+'f' jsr getparm_ch bcc cp_created ask_anyway: jsr suspend jsr TalkCont message_cstr "Okay to replace " lda cp_pn2+1 ldy cp_pn2 jsr prnt_compl lda desti_acc and #%11000011 cmp #%11000011 beq cpyn message_cstr " [LOCKED] " cpyn: lda #$80+'n' ;default = No jsr yesno2 jsr restore ;must save N! bmi cp_created lda cpref1 jmp close cp_created: lda info_type pha lda info_acc pha lda #tBAD sta info_type lda #%11000011 sta info_acc lda cp_pn2+1 ldy cp_pn2 jsr setinfo pla sta info_acc pla sta info_type CALLOS mli_open, cp_op2 CALLOS_BRANCH_NEG cp_er lda cpref2 sta cpref2b ; ; the main copy loop! (Read a bufferfull, write it..._) ; copy1: CALLOS mli_read, cp_rd1 CALLOS_BRANCH_POS copy2 cmp #err_eof beq copied cp_er: jmp ProDOS_err copy2: lda cp_xfer+1 ldy cp_xfer sta cp_xfer2+1 sty cp_xfer2 CALLOS mli_write, cp_wr2 CALLOS_BRANCH_NEG cp_er jmp copy1 copied: ; set EOF of file2 lda cpref2 sta cpeof_r .if IsDavex2 CALLOS mli_seteof, cpeof_p .else CALLOS mli_seteof, cpseof_p ; Need a slightly different parm structure in SOS .endif CALLOS_BRANCH_NEG cp_er ; close both files lda cpref1 jsr close lda cpref2 jsr close ; ; clr backup bit on original if -b ; lda #$80+'b' jsr getparm_ch bcs no_clearbb lda #$ff sta bubit ;allow bit to clear lda info_acc and #%11011111 sta info_acc lda cp_pn1+1 ldy cp_pn1 jsr setinfo lda #$ff sta bubit no_clearbb: ; ; set info on copy ; lda cp_pn2+1 ldy cp_pn2 jsr setinfo ; ; if -d, delete 1st file %%% should unlock first??? ; lda del_flag bmi cp_notrm lda cp_pn1+1 ldy cp_pn1 sta cprm_p+1 sty cprm_p CALLOS mli_destroy, cprm CALLOS_BRANCH_POS cp_notrm jmp ProDOS_err cp_notrm: rts cp_rd1: .byte 4 cpref1b: .byte 0 .addr copybuff .addr cbufflen cp_xfer: .addr 0 cprm: .byte 1 cprm_p: .addr 0 ; ; ; append last seg of path1 onto path2 ; cp_intodir: lda cp_pn1+1 ldy cp_pn1 sta p+1 sty p lda cp_pn2+1 ldy cp_pn2 sta cp_appnm+1 sty cp_appnm sta cp_appnm0+1 sty cp_appnm0 ; ; add a '/' onto path2 if it doesn't end in one already ; jsr pmgr .byte pm_slashif cp_appnm0: .addr 0 ldy #0 lda (p),y ;length of pn1 tay sta pn1len beq intodx cpsrch: dey beq cpigot lda (p),y and #$7f cmp #$2f bne cpsrch cpigot: iny cpi1: tya pha lda (p),y jsr pmgr .byte pm_appch cp_appnm: .addr 0 pla tay iny cpy pn1len bcc cpi1 beq cpi1 intodx: rts pn1len: .byte 0 ;********************************************* cp_report: lda cp_pn1+1 ldy cp_pn1 jsr print_path message_cstr " --> " lda cp_pn2+1 ldy cp_pn2 jsr print_path jsr crout jmp check_wait ;********************************************* ;********************************************* ; ; size -- print size of file or tree of files ; szpath: .addr 0 go_size: nop ;disable wildcard expansion display jsr empty_prefix sta szpath+1 sty szpath jsr print_path message_cstr ": " lda szpath+1 ldy szpath jsr size_ay lda num+1 ldy num sta num3+1 sty num3 jsr prdec_2 message_cstr " block" lda num3+1 ldy num3 jsr plural message_cstr "; " lda num2+2 ldx num2+1 ldy num2 sta num+2 stx num+1 sty num jsr print_dec message_cstr " byte" lda num2+2 ora num2+1 ldy num2 jsr plural jmp crout ; ; return # blocks in NUM*2 and # bytes ; in NUM2*3 ; size_ay: sta p+1 sty p sta sz_path+1 sty sz_path jsr getinfo lda info_blocks+1 ldy info_blocks sta num+1 sty num lda #0 sta sz_eof+2 sta sz_eof+1 sta sz_eof CALLOS mli_open, sz_open CALLOS_BRANCH_NEG sz0 lda sz_ref sta sz_ref2 CALLOS mli_geteof, sz_geteof ;CALLOS_BRANCH_NEG sz_err ;just use 0 if it returns an error lda sz_ref jsr close sz0: lda sz_eof+2 ldx sz_eof+1 ldy sz_eof sta num2+2 stx num2+1 sty num2 ; ; calc volume block size from EOF ; ldx info_stype cpx #15 bne sznvol lda num2+2 lsr a sta num+1 lda num2+1 ror a sta num sznvol: lda info_type cmp #tDIR beq szdir rts ; compute size of everything in dir szdir: jsr push_level lda p+1 ldy p jsr dir_setup sz1: jsr read1dir bcs sz_x lda num2+2 pha lda num2+1 pha lda num2 pha lda num+1 pha lda num pha jsr build_szpath ldx catbuff+16 cpx #tDIR beq slowsize ; ; kwiksize routine -- just look in the DIR entry! ; ; Put blocks --> NUM (2 bytes) ; EOF --> NUM2 (3 bytes) ; lda catbuff+$14 sta num+1 lda catbuff+$13 sta num lda catbuff+$17 sta num2+2 lda catbuff+$16 sta num2+1 lda catbuff+$15 sta num2 jmp anysize slowsize: jsr size_ay anysize: clc pla adc num sta num pla adc num+1 sta num+1 clc pla adc num2 sta num2 pla adc num2+1 sta num2+1 pla adc num2+2 sta num2+2 jmp sz1 sz_x: jmp dir_finish sz_err: jmp ProDOS_err build_szpath: ldy #127 bszp: lda direcpath,y sta pagebuff,y dey bpl bszp lda catbuff and #%00001111 sta catbuff lda #>catbuff ldy #pagebuff ldy #catbuff ldy #] [-a] [-z] ; ; -z)ap removes all devices that don't ; currently have volumes online ; ; Should have an option to reconstruct ; the dev table from the BF-page driver ; addresses & slot ROMs. ; ;**************************************** rm_which: .byte 0 dv_done: rts go_dev: lda num_parms bne dv_some ldx devcnt bmi dv_done dv_list: lda devlst,x pha jsr pr_sp pla jsr print_sd dex bpl dv_list rts dv_some: lda #$80+'r' jsr getparm_ch bcs dv_notr jsr dev_rm1 jmp dv_nota dv_notr: lda #$80+'a' jsr getparm_ch bcs dv_nota ldx devcnt cpx #15 bcc devcntok lda #der_outroom jmp ProDOS_err devcntok: inc devcnt inx sta devlst,x dv_nota: lda #$80+'z' jsr getparm_ch bcs dv_notz ; ; zap all unused volumes ; ldx #0 stx rm_which zap1: lda devcnt bmi dv_notz beq dv_notz ldx rm_which lda devlst,x sta zap_dev cpx devcnt beq zok bcs dv_notz zok: CALLOS mli_online, zap_p CALLOS_BRANCH_POS zapnext lda zap_dev jsr dev_rm1 jmp zap1 ;don't increment! (would miss 1) zapnext: inc rm_which bne zap1 dv_notz: rts zap_p: .byte 2 zap_dev: .byte 1 .addr pagebuff ; ; dev_rm1 -- remove device in A ; dev_rm1: and #%11110000 sta temp ; sta dvUnit ldx devcnt bmi dvrx beq dvrx dv_finda: lda devlst,x and #%11110000 cmp temp beq dv_found dex bpl dv_finda rts dv_found: lda devlst+1,x sta devlst,x inx cpx devcnt bcc dv_found dec devcnt dvrx: rts ;****************************** ; ; update command for Davex ; go_update: sta up_pn1+1 sty up_pn1 lda #1 jsr getparm_n jsr empty_prefix sta up_pn2+1 sty up_pn2 upd_recurse: jsr check_wait jsr upd_report lda up_pn1+1 ldy up_pn1 jsr getinfo sta up_type1 lda info_moddat+1 ldy info_moddat sta up_date1+1 sty up_date1 lda info_modtim+1 ldy info_modtim sta up_time1+1 sty up_time1 lda up_pn2+1 ldy up_pn2 jsr geti2 bcc upd_ok2 cmp #err_filnotfnd bne uperr message_cstr_cr "new file" lda #$80+'f' jsr getparm_ch bcc crenew jsr TalkCont message_cstr "Okay to create " lda up_pn2+1 ldy up_pn2 jsr print_path jsr yesno beq nonew crenew: jmp upd_copy nonew: rts uperr: jmp ProDOS_err upd_ok2: ; ; check filetypes ; lda info_type cmp up_type1 beq types_match message_cstr "filetypes differ (" lda up_type1 jsr print_ftype lda #$80+',' jsr cout lda info_type jsr print_ftype message_cstr ")" lda #tDIR cmp info_type beq cantRepl cmp up_type1 beq cantRepl ; ask message_cstr ". Continue" lda #$80+'n' ;default = No jsr yesno2 bne match0 rts cantRepl: jsr crout jmp check_wait match0: jsr upd_report types_match: ; ; compare mod dates of old/new files, or of all files within ; a directory ; lda up_type1 cmp #tDIR bne updndir jmp update_dir updndir: ; ; cmp moddate/modtime; info_xxx is file 2, up_xxx for file 1 ; .if 1 ; Y2K-happy date comparison lda info_moddat+1 ;compare year numbers jsr ExtractAndNormalizeYear sta tempDate lda up_date1+1 jsr ExtractAndNormalizeYear cmp tempDate bne up_cmp lda info_moddat+1 ;compare high bit of month and #1 sta tempDate lda up_date1+1 and #1 cmp tempDate bne up_cmp lda up_date1 cmp info_moddat bne up_cmp .else ;not Y2K happy lda up_date1+1 cmp info_moddat+1 bne up_cmp lda up_date1 cmp info_moddat bne up_cmp .endif lda up_time1+1 cmp info_modtim+1 bne up_cmp lda up_time1 cmp info_modtim up_cmp: beq up_done bcc up_warn message_cstr_cr "outdated" jsr check_wait upd_copy: lda up_pn1+1 ldy up_pn1 sta cp_pn1+1 sty cp_pn1 lda up_pn2+1 ldy up_pn2 jmp go_copy2 up_done: message_cstr_cr "current" jmp check_wait up_warn: message_cstr "master file is older [" lda up_pn1+1 ldy up_pn1 jsr print_path message_cstr_cr "]" jmp check_wait ; ; Y2K-happy year utility: ; ; Input = high byte of Date value in A ; Output = normalized year number in A (40..139 = 1940..2039) ; WrapAroundYear = 40 ExtractAndNormalizeYear: lsr a cmp #WrapAroundYear bcs @noWrap1 adc #100 ;map 0..39 --> 100..139 @noWrap1: rts tempDate: .byte 0 ; ; update recursively on all files within ; directory ; update_dir: message_cstr_cr "scanning directory" jsr push_level lda up_pn2+1 ldy up_pn2 sta upd_up2+1 sty upd_up2 lda up_pn1+1 ldy up_pn1 sta upd_up+1 sty upd_up jsr dir_setup ;open the subdir updd1: ;update recursively for each file jsr read1dir bcs upddx lda catbuff and #%00001111 sta catbuff jsr up_appboth jsr upd_recurse ; ; remove last seg of both pathnames ; jsr pmgr .byte pm_up upd_up: .addr 0 jsr pmgr .byte pm_up upd_up2: .addr 0 jmp updd1 ;go back for more files this dir upddx: jmp dir_finish ;close the subdir, return from recursion ; ; append a filename to both pathnames ; up_appboth: lda up_pn1+1 ldy up_pn1 sta upapp+1 sty upapp sta upsl1+1 sty upsl1 lda up_pn2+1 ldy up_pn2 sta upapp2+1 sty upapp2 sta upsl2+1 sty upsl2 jsr pmgr .byte pm_slashif upsl1: .addr 0 jsr pmgr .byte pm_slashif upsl2: .addr 0 lda #>catbuff ldy #catbuff ldy #0 params! ; ; This is a public entry point (xgetnump). ; getnump: lda num_parms rts ;****************************************************** ; ; directory-scanning subroutine ; ; scanall -- scan through all command directories for ; a file (path in AY). Return BCS if not found; ; otherwise path is at $280 and A=file type. ; scanptr: .res 1 scanall: sta p+1 sty p ldy #0 lda (p),y beq cmd_err cmp #63 bcc cmd_ok cmd_err: sec rts cmd_ok: iny lda (p),y ora #%10000000 cmp #$80+'/' bne part_path ; ; full pathname specified; try once ; ldy #127 copyfull: lda (p),y sta cmdpath,y dey bpl copyfull jmp cmdinfo part_path: ; ; try all the prefixes in ScanList ; ldx #0 stx scanptr scan1: ldx scanptr lda scanlist,x bne scan_more ; we scanned them all and didn't find it sec rts scan_more: sta count cmp #1 bne not_curdir lda scanlist+1,x ora #%10000000 cmp #$80+'*' bne not_curdir ldy #0 sty cmdpath beq trycurdir not_curdir: ldy #0 copy_part: lda scanlist,x sta cmdpath,y inx iny dec count bpl copy_part trycurdir: lda p+1 ldy p jsr pmgr .byte pm_appay .addr cmdpath lda p+1 pha lda p pha lda ptr+1 pha lda ptr pha lda #>cmdpath ldy #config_pn ldy #config_pn ldy #mypath ldy #exec_pn ldy #exec_pn ldy #1, print 's' ; plural: cmp #0 bne plur_s cpy #1 bne plur_s rts plur_s: lda #'s'+$80 jmp cout ; ; prnt_compl -- print_path, but print prefix first ; if pn is partial ; prnt_compl: sta p+1 sty p ldy #1 lda (p),y ora #%10000000 cmp #$80+'/' beq fullpn lda p+1 pha lda p pha jsr print_pfx lda #$80+'/' jsr cout pla sta p pla sta p+1 fullpn: lda p+1 ldy p jmp print_path ; ; check_wait -- pause display & allow abort (SEC) ; ; For Textalker (Echo) users: Ctrl-X STAYS on kbd ; stepping: .byte 0 check_wait: jsr poll_io bit stepping bmi cw_wait lda keyboard bpl cw_x cmp #$80+'X'-ctrl beq cw_x cmp #$9b ;esc beq cw_xxx cmp #$80+'C'-ctrl beq cw_abort cmp #$80+'S'-ctrl beq cw_wait jsr chk_appleper cmp #$80+' ' bne cw_x sta kbdstrb cw_wait: jsr poll_io lda keyboard bpl cw_wait sta kbdstrb ;munch bad chars in case type-ahead active jsr CheckHC bcc cw_wait cmp #$9b beq cw_xxx cmp #$80+'C'-ctrl beq cw_abort cmp #$80+'X'-ctrl beq cw_xx cmp #$80+'S'-ctrl beq cw_done cmp #$80+'Q'-ctrl beq cw_done jsr chk_appleper cmp #$a0 bne cw_x ;was cw_wait ror stepping clc rts cw_done: sta kbdstrb cw_x: clc cw_xx: php lsr stepping plp rts cw_xxx: jsr crout sta kbdstrb lsr stepping sec rts cw_abort: sta kbdstrb lsr stepping jmp yn_abort chk_appleper: cmp #$80+'.' bne notAper bit button0 ;Apple bpl notAper ldx machine cpx #6 beq cw_abort notAper: rts close: sta mycl_r CALLOS mli_close, mycls close_done: rts mycls: .byte 1 mycl_r: .res 1 ; ; empty_prefix -- used after call to getparm. ; If string AY points to is empty, load AY ; with pointer to prefix instead ; empty_prefix: sta ptr+1 sty ptr ldy #0 lda (ptr),y beq ep_usepfx lda ptr+1 ldy ptr rts ep_usepfx: jmp get_pfx ; ; percent -- return A=percent ; that NUM(*3) is of AXY ; percent: sta num3+2 stx num3+1 sty num3 lda #0 sta num+3 sta num3+3 sta num2+3 sta num2+2 sta num2+1 sta num2 sta perc jsr mult10num jsr mult10num ; while num2 % is shell directory ; .sd --> .sd is volume name ; .. --> .. is parent directory ; . --> . is current directory ; fixup_path_ay: sta p+1 sty p sta ptr+1 sty ptr ldy #0 lda (p),y beq :+ iny jsr pchar cmp #$80+'%' beq fp_shelld cmp #$80+'.' beq fixup_dot : rts fp_shelld: jsr shorten_p ldy #1 jsr pchar cmp #$80+'/' bne fpsh2 jsr shorten_p fpsh2: lda p+1 ldy p jsr build_local ldy mypath fpcopy: lda mypath,y sta (ptr),y dey bpl fpcopy rts fixup_dot: ldy #0 lda (p),y cmp #2 bcc not_parent ldy #2 jsr pchar cmp #$80+'.' bne not_parent ; .. = parent directory jsr shorten_p jsr shorten_p ldy #0 lda (ptr),y beq parent_nosl iny jsr pchar cmp #$80+'/' bne parent_nosl jsr shorten_p parent_nosl: sec ;flag '..' .byte $24 ; Hide next byte (skip over the CLC) singleDOT: clc ;flag '.' php CALLOS mli_getpfx, dotdotPARMS jsr pmgr .byte pm_downcase .addr pagebuff plp bcc not_dotdot jsr pmgr .byte pm_up .addr pagebuff lda pagebuff cmp #1 bne not_dotdot dec pagebuff not_dotdot: jmp splice_dot not_parent: ; check for .sd ldy #0 lda (p),y cmp #3 bcc chk_dot ldy #2 jsr pchar cmp #$80+'1' bcc chk_dot cmp #$80+'8' bcs chk_dot and #%00001111 asl a asl a asl a asl a sta temp iny jsr pchar cmp #$80+'1' bcc :+ cmp #$80+'3' bcs :+ and #%00000001 ror a ror a ora temp eor #%10000000 jsr online1 jmp splice_sd : rts chk_dot: jsr shorten_p ldy #0 lda (ptr),y beq singleDOT iny jsr pchar cmp #$80+'/' bne singleDOT jsr shorten_p jmp singleDOT online1: sta o1_dev CALLOS mli_online, o1_parms CALLOS_BRANCH_POS o1ok jmp ProDOS_err o1ok: lda pagebuff+1 and #%00001111 tax inx inx stx pagebuff lda #'/' sta pagebuff+1 sta pagebuff,x jsr pmgr .byte pm_downcase .addr pagebuff rts o1_parms: .byte 2 o1_dev: .res 1 .addr pagebuff+1 splice_dot: ldy #0 lda (ptr),y sta temp inc temp ldy #1 bne splpth2 splice_sd: ldy #0 lda (ptr),y sta temp inc temp ldy #4 lda (ptr),y ora #%10000000 cmp #$80+'/' bne splpth2 iny splpth2: cpy temp bcs splpth3 lda (ptr),y inc pagebuff ldx pagebuff sta pagebuff,x iny bne splpth2 splpth3: ldy #127 : lda pagebuff,y sta (ptr),y dey bpl :- rts ; ; shorten_p -- remove 1st character of ; path at P ; shorten_p: ldy #0 lda (p),y beq :+ tax @loop: iny iny lda (p),y dey sta (p),y dex bne @loop lda (p,x) sec sbc #1 sta (p,x) : rts ; ; pchar -- get (p),y in lowercase, high bit on ; pchar: lda (p),y jmp downcase ;************************************* ; ; memory manager (crude but useful) ; ; commands (x): MLI_xxx ; close -- free all dynamic mem ; ; open -- alloc A pages from low ; mem; SEC=out of mem; ; return A=1st page ; ; read -- # free pages --> A (Y=0) ; ; gfinfo-- get low page --> A (Y=0) ; ; write -- set high page to A ; mmgr: cpx #mli_close bne mm_ncl ; ; close: free dynamic mem ; lda #>highmem sta mmgr_hi lda #>copybuff sta mmgr_lo clc rts mm_ncl: cpx #mli_write bne mm_nwr ; ; write: set high page ; cmp mmgr_lo bcc mmw_err cmp #>highmem bcs mmw_err sta mmgr_hi clc rts mmw_err: lda #der_outmem sec rts mm_nwr: cpx #mli_gfinfo bne mm_ninfo ; ; getinfo: A=low page ; lda #0 ;open 0 pages beq mmopen ;always taken mm_ninfo: cpx #mli_open bne mm_nopen ; ; open: reserve A pages ; mmopen: ldy mmgr_lo ;reserve here clc adc mmgr_lo cmp mmgr_hi bcs mmw_err sta mmgr_lo tya ldy #0 clc rts mm_nopen: cpx #mli_read bne mm_nrd ; ; read: get free pages ; sec lda mmgr_hi sbc mmgr_lo ldy #0 clc rts mm_nrd: lda #err_badcall sec rts ;*********************************** ; ; off80 ; off80: jsr finish_oredir .if IsDavex2 jsr mess .byte $80+'U'-ctrl,$80+'T'-ctrl,$80+'A',$80+'1',0 jsr $fe89 jsr $fe93 jsr hook_speech .else ; isDavex3 jsr on40 .endif ; isDavex2 lda #40 sta scr_width jmp home ;******************************************** ; ; wildcard expansion routines for ; Davex ; ; 28-Jun-86 ; ;******************************************* ;******************************************* ; ; wild_state : ; 0 = not expanding wildcards ; 1 = returning original path; no wildcards ; 2 = scanning directory ; 3 = scanning volume list ; wild_state: .res 1 ; ; wild_begin -- start a wildcard ; expansion ; wild_begin: lda #1 sta wild_state lda num_parms beq wbx jsr grab_wstrings jsr contains_wild bcs wbx inc wild_state ; = 2 bit wild_flags bvc :+ ; branch if no wildcards in volume name portion inc wild_state ; = 3 : jsr push_level lda #>wildstring1 ldy #wildstring1 ldy # [] except ; for commands beginning with NOP ; jsr suspend bit wild_flags bmi ask_path ldy #0 lda (cmd_addr),y cmp #$ea beq no_askpath bne askpath2 ask_path: jsr TalkCont askpath2: jsr print_cmd jsr pr_sp lda #0 jsr getparm_n jsr print_path lda parmtypes+1 cmp #t_path beq do2 cmp #t_wildpath bne skip2 do2: jsr pr_sp lda #1 jsr getparm_n jsr print_path skip2: bit wild_flags bpl noquery lda #$80+'n' ;default = No jsr yesno2 jsr restore beq nxtwld clc rts noquery: jsr crout no_askpath: jsr restore clc rts wnfin1: jsr dir_finish dec wild_state wn_done: sec rts ;******************************************* ; ; directory reading routines ; ; push_level -- close old dir level (do this ; before calling dir_setup) ; ; dir_setup -- open dir (ay=path) ; ; read1dir -- get next active entry from ; open directory; BCS if no more ; entries ; ; dir_finish -- close level ; ;******************************************* dir_setup: ldx #0 stx direcpath jsr dir_setup2 bcc :+ jmp ProDOS_err : rts dir_setup2: ; partial path in AY pha tya pha lda dir_level bpl :+ lda #0 sta direcpath : pla tay pla jsr buildcatpath lda #wildlevel SET_LEVEL CALLOS mli_open, opendir_p pha lda #stdlevel SET_LEVEL pla CALLOS_BRANCH_POS dset_opened sec rts dset_opened: lda dir_ref sta dir_ref2 sta dir_ref3 sta dir_ref4 .if IsDavex3 sta dir_ref5 .endif lda #0 ldy #$23 jsr setmark bcs wld_err jsr read1byte bcc wld_did1 rts wld_did1: sta EntryLen jsr read1byte sta EntPerBlock jsr read1byte sta file_count jsr read1byte sta file_count+1 lda EntPerBlock sta filecntr lda #4 clc adc EntryLen tay lda #0 jsr setmark dec filecntr lda dir_ref clc rts wld_err: jmp ProDOS_err ; ; read next active entry & dec file_count ; read1dir: lda EntryLen sta rc_len CALLOS mli_read, readcat_parms CALLOS_BRANCH_POS rc_ok cmp #err_eof beq eoDIR jmp ProDOS_err eoDIR: ;;; sec ; carry is already set from CMP+BEQ ( sec for >= ) rts rc_ok: dec filecntr bne rc_sameblk jsr getmark ldy #4 and #%11111110 clc adc #2 jsr setmark lda EntPerBlock sta filecntr rc_sameblk: lda catbuff and #%11110000 beq read1dir ;not active lda file_count bne :+ dec file_count+1 : dec file_count jsr calc_cmask ldy #1 ldx #15 niceCase: asl case_mask+1 rol case_mask bcc NoLcase lda catbuff,y jsr downcase and #$7f sta catbuff,y NoLcase: iny dex bne niceCase ; zero out unused name bytes (for sorting) lda catbuff and #$f tay lda #0 : cpy #15 bcs @out sta catbuff+1,y iny bne :- @out: clc rts ; ; close file & pop level of dirstack ; dir_finish: jmp pop_level readcat_parms: .byte 4 dir_ref2: .res 1 .addr catbuff rc_len: .addr 0 .res 2 ; do not change order or insert file_count: .res 2 filecntr: .res 1 ;counts down to 0 for each block ; end of do-not-change EntryLen: .res 1 EntPerBlock: .res 1 ; ; getmark into ay ; getmark: CALLOS mli_getmark, get_mark_parms lda pmark+1 ldy pmark rts setmark: .if IsDavex2 sta pmark+1 sty pmark lda #0 sta pmark+2 .else sta pmark_set+1 sty pmark_set lda #0 sta pmark_set+2 .endif setmark2: CALLOS mli_setmark, set_mark_parms CALLOS_BRANCH_POS :+ sec rts : clc rts read1byte: CALLOS mli_read, read1p CALLOS_BRANCH_NEG r1x2 dcheat: lda #0 r1x: clc rts r1x2: sec rts read1p: .byte 4 dir_ref4: .res 1 .addr dcheat+1 .addr 1 .addr 0 buildcatpath: sta p+1 sty p ldy #1 lda (p),y and #%01111111 cmp #$2f beq bcp_full ; append to old direcpath ldy #0 lda (p),y ;len tax appdirp: iny lda (p),y cpx #0 beq appdirpx stx appdpx inc direcpath ldx direcpath sta direcpath,x ldx appdpx dex bne appdirp needslash: ldx direcpath lda direcpath,x and #%01111111 cmp #$2f beq slashed inc direcpath lda #$2f ldx direcpath sta direcpath,x slashed: appdirpx: rts appdpx: .res 1 bcp_full: ldy #64 bcpf2: lda (p),y sta direcpath,y dey bpl bcpf2 jmp needslash ;******************************************* push_level: lda dir_level bmi pl_nolevel jsr getmark lda #wildlevel SET_LEVEL lda dir_ref jsr close ;close this level lda #stdlevel SET_LEVEL lda dir_level cmp #dstkmax bcc dlevelok lda #der_levels jmp ProDOS_err dlevelok: ldy #64 pushpn: lda direcpath,y sta (dstk_ptr),y dey bpl pushpn ldy #dstk_mark lda pmark sta (dstk_ptr),y lda pmark+1 iny sta (dstk_ptr),y lda pmark+2 iny sta (dstk_ptr),y ldy #dstk_fcount pushmore: lda file_count-dstk_fcount,y sta (dstk_ptr),y iny cpy #dstk_recsiz bcc pushmore clc lda dstk_ptr adc #dstk_recsiz sta dstk_ptr bcc dstkpok inc dstk_ptr+1 dstkpok: pl_nolevel: inc dir_level rts ;******************************************* pop_level: lda dir_ref jsr close lda #0 sta direcpath lda dir_level cmp #1 bpl pop_lev2 lda #<-1 sta dir_level sec rts pop_lev2: sec lda dstk_ptr sbc #dstk_recsiz sta dstk_ptr bcs dstkpok2 dec dstk_ptr+1 dstkpok2: lda dstk_ptr+1 ldy dstk_ptr sta p+1 sty p ldy #64 popdirp: lda (p),y sta direcpath,y dey bpl popdirp lda p+1 ldy p jsr dir_setup ldy #dstk_mark lda (dstk_ptr),y sta pmark iny lda (dstk_ptr),y sta pmark+1 iny lda (dstk_ptr),y sta pmark+2 jsr setmark2 ldy #dstk_fcount lda (dstk_ptr),y sta file_count iny lda (dstk_ptr),y sta file_count+1 ldy #dstk_filecntr lda (dstk_ptr),y sta filecntr dec dir_level clc rts ;******************************************* ; ; wildcard string routines ; ;******************************************* ; ; contains_wild -- return CLC if WILDSTRING1 ; is wild ; ; wild_index = position in wildstring1 of ; wildcard_ ; ; wild_flags: Q V x x x x x x ; Q=query (?) ; V=wild in volume name ; wild_index: .res 1 wild_flags: .res 1 contains_wild: ldy #0 sty wild_index sty wild_flags sty temp ;true if hit '/' lda wildstring1,y tay beq cw_no cw1: lda wildstring1,y ora #%10000000 cmp #$80+'/' bne cwnslsh ;;; sec ror temp cwnslsh: cmp #$80+'*' beq cwyes0 cmp #$80+'=' beq cwyes cmp #$80+'?' bne cwno lda #%10000000 ;query flag ora wild_flags sta wild_flags cwyes0: lda #$80+'=' sta wildstring1,y cwyes: ldx wild_index bne extra_wild bit temp bmi bad_place sty wild_index cwno: dey bne cw1 lda wild_index bne cw_yes cw_no: sec rts cw_yes: ldy #1 lda wildstring1,y ora #%10000000 cmp #$80+'/' bne not_wvol ldx #1 ;'/' count wvolchk: iny cpy wild_index bcs wvchecked lda wildstring1,y ora #%10000000 cmp #$80+'/' bne wvolchk inx bne wvolchk wvchecked: cpx #2 bcs not_wvol lda #%01000000 ;wc in volname ora wild_flags sta wild_flags not_wvol: jsr build_wpath clc rts ; extra_wild: lda #der_1wild der5: jmp ProDOS_err ; bad_place: bad_wild: lda #der_badwild bne der5 ; ; build_wpath -- copy part of wildstring1 before ; segment with wildcard into wdirpath ; build_wpath: ldy wild_index bwp2: lda wildstring1,y ora #%10000000 cmp #$80+'/' beq bwp_len dey bne bwp2 ; wc in seg1 of partial path; use prefix ldx wildstring1 wseg2: lda wildstring1,x sta wildseg,x dex bpl wseg2 CALLOS mli_getpfx, wildpfx jsr pmgr .byte pm_downcase .addr wildstring1 rts bwp_len: sty temp sec lda wildstring1 sbc temp sta wildseg ;length of last seg ldx #0 wseg1: iny inx lda wildstring1,y sta wildseg,x cpy wildstring1 bcc wseg1 ldy temp sty wildstring1 rts ; ; compare_wild -- returns CLC if string in CATBUFF ; matches string at WILDSEG ; ; May have to ask the user (for '?' wildcards) ; matchstr_left: .res 1 matchstr_r: .res 1 compare_wild: bit wild_flags bvc cmpw_notvol ; we could allow wildcards in volume names someday, but now it's an error jmp bad_wild cmpw_notvol: jsr cmp_wseg bcs cmpwno lda #0 jsr getparm_n txa beq cmpw_notyp cmp catbuff+16 bne cmpwno cmpw_notyp: clc rts cmpwno: sec rts ; ; CLC=matches: compare path at catbuff to ; wildseg (containing '=' for any wc) ; cmp_wseg: ; an '=' must match at least 0 characters ldx catbuff inx cpx wildseg bcc cmppw_no jsr cmp_left bcs cmppw_no ; calculate matchstr_r sec lda catbuff sbc wildseg sec adc matchstr_left sta matchstr_r jmp cmp_right cmppw_no: sec rts ; ; cmp_left -- return CLC if chars in WILDSEG ; before wildcard match chars at beginning ; of path at CATBUFF ; cmp_left: ldy #0 cleft1: lda wildseg+1,y jsr downcase cmp #$80+'=' beq cleftok sta temp lda catbuff+1,y jsr downcase cmp temp bne cleftno iny cpy wildseg bcc cleft1 cleftok: iny sty matchstr_left clc rts cleftno: sec rts ; ; cmp_right -- return CLC if chars in WILDSEG ; after wildcard match chars at end of path ; at CATBUFF ; cmp_right: ldy wildseg ldx catbuff cright1: lda wildseg,y jsr downcase cmp #$80+'=' beq crightok sta temp lda catbuff,x jsr downcase cmp temp bne crightno dex dey bne cright1 crightok: clc rts crightno: sec rts ; ; grab_wstrings -- copy 1st (and possibly 2nd) ; path parameters into wildstring1 (and ; wildstring2) ; grab_wstrings: lda #0 sta wildstring1 sta wildstring2 lda parmtypes cmp #t_wildpath bne grabbed lda #0 jsr getparm_n sta p+1 sty p ldy #127 grab1: lda (p),y sta wildstring1,y dey cpy #<-1 bne grab1 lda parmtypes+1 cmp #t_path beq grab2a cmp #t_wildpath bne grabbed grab2a: lda #1 jsr getparm_n sta p+1 sty p ldy #127 grab2: lda (p),y sta wildstring2,y dey cpy #<-1 bne grab2 grabbed: rts ; ; expand_wild -- generate first path from ; catbuff & wildstring1. If there's a second ; path, replace any wild character in it with the ; same string the wild character in the 1st ; path replaces ; expand_wild: lda #0 jsr getparm_n sta p+1 sty p sta ew_p+1 sty ew_p ldy #127 ew1: lda wildstring1,y sta (p),y dey bpl ew1 lda #>catbuff ldy # eject all rts callSP3: jsr $ffff .byte 1 ;readblock .addr ej_rb2 bcs decid_no lda #$80+'/' sta pagebuff+1 lda filebuff+4 and #%00001111 tax inx stx pagebuff ejBldN: dex beq ejBilt lda filebuff+4,x jsr downcase sta pagebuff+1,x jmp ejBldN ejBilt: jsr pmgr .byte pm_slashif .addr pagebuff lda p+1 ldy p sta ejslif+1 sty ejslif jsr pmgr .byte pm_slashif ejslif: .addr 0 ldy #0 lda (p),y tax cmp pagebuff bne decid_no : iny dex beq decid_yes lda (p),y jsr downcase cmp pagebuff,y beq :- decid_no: sec rts decid_yes: clc rts ej_rb2: .byte 3 rb2unit: .byte 0 .addr filebuff .byte 2,0,0 ;block # ; ; isSmartPort -- return SEC if no card in slot A ; isSmartPort: cmp #8 bcs ispNO cmp #0 beq ispNO ora #$C0 sta temp+1 lda #0 sta temp ldy #1 lda (temp),y cmp #$20 bne ispNO ldy #3 lda (temp),y bne ispNO ldy #5 lda (temp),y cmp #3 bne ispNO ldy #7 lda (temp),y bne ispNO clc rts ispNO: sec rts ; EjParms: .byte 3 ej_unitnm: .byte 0 .addr EjCtrl .byte 4 EjCtrl: .addr 0 ;********************************************* ; ; ERR.TEXT for ProDOS and Davex errors ; ;********************************************* ; ; Format: ; Code*1, String $00 ; Code*1, String $00 ... ; $00 ; ; Codes for ProDOS are $00..$7F ; Codes for Davex are $80..$FF ; ;********************************************** err_text: .byte $2f asc_hi "no disk" .byte 0 .byte err_badcall asc_hi "bad ProDOS call" .byte 0 .byte err_badcnt asc_hi "bad pcount" .byte 0 .byte err_ifull asc_hi "inttbl full" .byte 0 .byte err_io asc_hi "disk I/O" .byte 0 .byte err_nodev asc_hi "no device connected" .byte 0 .byte err_wrprot asc_hi "disk write-protected" .byte 0 .byte err_switched asc_hi "disk switched" .byte 0 .byte err_2slow asc_hi "drive too slow" .byte 0 .byte err_2fast asc_hi "drive too fast" .byte 0 .byte err_pnsyntax asc_hi "bad pathname syntax" .byte 0 .byte err_fcbfull asc_hi "FCB full" .byte 0 .byte err_ivlref asc_hi "bad refnum" .byte 0 .byte err_dirnotfnd asc_hi "directory not found" .byte 0 .byte err_volnotfnd asc_hi "volume not found" .byte 0 .byte err_filnotfnd asc_hi "file not found" .byte 0 .byte err_dupfil asc_hi "duplicate file" .byte 0 .byte err_full asc_hi "volume full" .byte 0 .byte err_dirfull asc_hi "directory full" .byte 0 .byte err_filfmt asc_hi "file format error" .byte 0 .byte err_strgtype asc_hi "bad storage type" .byte 0 .byte err_eof asc_hi "end of file" .byte 0 .byte err_badpos asc_hi "bad file pos" .byte 0 .byte err_locked asc_hi "file locked" .byte 0 .byte err_filopen asc_hi "file open" .byte 0 .byte err_dircnt asc_hi "dir count" .byte 0 .byte err_notprodos asc_hi "volume is not ProDOS" .byte 0 .byte err_ivlparm asc_hi "invalid param" .byte 0 .byte err_vcbtfull asc_hi "VCB full" .byte 0 .byte err_badbufadr asc_hi "bad buff addr" .byte 0 .byte err_dupvol asc_hi "duplicate volume" .byte 0 .byte err_badmap asc_hi "baked bit-map" .byte 0 ;======================================= ; ; Part II of error table: Davex errors ; .byte der_illegparm asc_hi "illegal option" .byte 0 .byte der_toomany asc_hi "too many parameters" .byte 0 .byte der_badtype asc_hi "bad parm type" .byte 0 .byte der_unknftyp asc_hi "unknown filetype" .byte 0 .byte der_dupopt asc_hi "duplicate option" .byte 0 .byte der_baddev asc_hi "devnum format is .61" .byte 0 .byte der_abort asc_hi "aborted" .byte 0 .byte der_waitspool asc_hi "wait for files to print or use spool -z" .byte 0 .byte $88 asc_hi "illegal block read/write" .byte 0 .byte der_needs3 asc_hi "filetype needs 3 chars" .byte 0 .byte der_missopt asc_hi "missing option" .byte 0 .byte der_badhware asc_hi "missing hardware" .byte 0 .byte der_badnum asc_hi "bad number" .byte 0 .byte der_bignum asc_hi "number too big" .byte 0 .byte der_ynexp asc_hi "y' or 'n' expected" .byte 0 .byte der_nosbf asc_hi "no startup buffer" .byte 0 .byte der_smallsbf asc_hi "startup buffer too small" .byte 0 .byte der_notxtn asc_hi "not an external command" .byte 0 .byte der_adrlow asc_hi "cmd address too low" .byte 0 .byte der_notfnd asc_hi "not found" .byte 0 .byte der_semiexp asc_hi "missing ';'" .byte 0 .byte der_nottxt asc_hi "not script file" .byte 0 .byte der_notdir asc_hi "not DIR" .byte 0 .byte der_levels asc_hi "too many dir levels" .byte 0 .byte der_1wild asc_hi "1 wildcard only" .byte 0 .byte der_badwild asc_hi "bad wildcard" .byte 0 .byte der_outmem asc_hi "out of memory" .byte 0 .byte der_outroom asc_hi "out of room" .byte 0 ;==================================== .byte 0 ; ; 'filetypes' -- default filetypes for Davex ; ; Last mod 24-Mar-90 DAL (March 1990 File Type notes) ; filetyp0: .byte $01,$03,$04,$06,$08,$0B,$0F,$16 .byte $19,$1A,$1B,$20,$2a,$2b,$2c,$2d .byte $2e,$42,$50,$51,$52,$53,$54,$55 .byte $56,$57,$58,$59,$5a,$5b,$5c,$5d .byte $5e,$6b,$6d,$6e,$6f,$a0,$ab,$ac .byte $ad,$b0,$b1,$b2,$b3,$b4,$b5,$b6 .byte $b7,$b8,$b9,$ba,$bb,$bc,$bd,$bf .byte $c0,$c1,$c2,$c3,$c5,$c6,$c7,$c8 .byte $c9,$ca,$d5,$d6,$d7,$d8,$db,$e0 .byte $e2,$ee,$ef,$f0,$f9,$fa,$fb,$fc .byte $fd,$fe,$ff .byte $00 fileasc0: asc "badptxtxtbinfotwpfdirpfs" asc "adbawpasptdmsc8ob8ic8ld8" asc "p8cftdgwpgssgdbdrwgdphmd" asc "edustnhlpcomcfganmmument" asc "dvubiotdrprehdvwp gsbtdf" asc "bdfsrcobjlibs16rtlexepif" asc "tifndacdatoldvrldffstdoc" asc "pntpicanipaloogscrcdvfon" asc "fndicnmusinsmdisnddbmlbr" asc "atkr16pascmdos intivrbas" asc "varrelsys" listend: ; ; talkstuff -- misc routines for speech (Textalker, Echo II) ; ; Last mod 28-Jul-87 DL ; hook_speech: jsr hook_ispeech jsr hook_ospeech jsr is_txtt beq ini_tt jsr is_slotb beq ini_sb rts ; init textalker ini_tt: ldx #$ff stx $37d ldy $c01f lda $bf98 jsr $3a9 rts ; init SCAT ini_sb: lda #0 jsr $3b2 rts hook_ispeech: jsr hooki2 lda ksw+1 ldy ksw sta speechi+1 sty speechi rts hooki2: jsr is_txtt beq hooki_tt jsr is_slotb bne no_speek ; hook in SlotBuster ($3ac) lda #3 sta ksw+1 lda #$ac sta ksw lda #$ff sta speech rts hooki_tt: lda #3 sta ksw+1 lda #$a9 sta ksw lda #$ff sta speech rts no_speek: lda #0 sta speech rts hook_ospeech: jsr is_txtt beq hooko_tt jsr is_slotb bne no_speek ; hook out slotbuster == same as textalker ($3A6) hooko_tt: lda #3 sta csw+1 lda #$a6 sta csw lda #$ff sta speech rts ; ; is_txtt -- return BEQ if TextTalker routines present ; is_txtt: lda $3a6 cmp #$ee bne isttx lda $3a9 cmp #$8e isttx: rts ; ; is_slotb -- return BEQ if SlotBuster II routines present ; is_slotb: lda #$d8 cmp $3a6 bne issbx cmp $3ac issbx: rts ; ; load Textalker from disk ; no_tt: rts load_txttalk: lda $bf98 and #$30 cmp #$30 bne no_tt lda #$60 sta ttcheat+2 jsr is_slotb beq no_tt ; if Apple down, force reload PT_OBJ bit button0 bmi loadtt jsr is_txtt beq no_tt loadtt: lda #>tt_name ldy #AliasName ldy #Aliases ldy #pagebuff ldy #pagebuff ldy #IndexName ldy #pagebuff ldy #pagebuff ldy #