diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 8d74776..9e09f5a 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -72,9 +72,9 @@ jobs: - name: Prepare environment for oricutron if: steps.cache-sdk.outputs.cache-hit != 'true' run: | - sudo apt-get install -y xvfb libgtk-3-0 libgtk-3-dev libsdl1.2debian libsdl1.2-dev + sudo apt-get update && sudo apt-get install -y xvfb libgtk-3-0 libgtk-3-dev libsdl1.2debian libsdl1.2-dev && sudo ldconfig git clone https://github.com/pete-gordon/oricutron.git - cd oricutron && make && pwd && cd .. && ls -l && echo ${GITHUB_WORKSPACE} + cd oricutron && make && pwd && cp /usr/lib/x86_64-linux-gnu/libSDL-1.2.so.0 . && ls -l && cd .. && ls -l && echo ${GITHUB_WORKSPACE} echo Timeout oricutron : $secret.TMOUT_ORICUTRON # - name: Compile orix-sdk @@ -134,8 +134,8 @@ jobs: cp build/usr/share/shell/shellsd.rom ${GITHUB_WORKSPACE}/oricutron/roms/shell.rom cat tests/unit-tests/commands.sub > ${GITHUB_WORKSPACE}/oricutron/sdcard/ETC/AUTOBOOT #cat tests/unit_test/xrm.sub >> ${GITHUB_WORKSPACE}/oricutron/sdcard/ETC/AUTOBOOT - cd ${GITHUB_WORKSPACE}/oricutron - timeout --preserve-status 10 ./xvfb.sh || exit 0 + cd ${GITHUB_WORKSPACE}/oricutron && ls -l && sudo ldconfig && sudo apt-get update && sudo apt-get install -y xvfb libgtk-3-0 libgtk-3-dev libsdl1.2debian libsdl1.2-dev + timeout --preserve-status 20 ./xvfb.sh || exit 0 - name: Check unit-test run: | diff --git a/VERSION b/VERSION index 2cf03e5..80e1c8d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2024.1 \ No newline at end of file +2024.3 \ No newline at end of file diff --git a/docs/basic11.md b/docs/basic11.md index badf4af..bd63ddd 100644 --- a/docs/basic11.md +++ b/docs/basic11.md @@ -1,8 +1,41 @@ # basic11 -## Usage +## NAME -basic11 [-g] [-l] [-p defaultpath] +basic11 - start atmos rom + +## SYNOPSYS + +basic11 [OPTION]... ["FILE] + +## DESCRIPTION + +This command starts the atmos rom. This rom did not test RAM and cload/csave are done on sdcard. It means that it calls file from sdcard. + +Cload works with .tap file. Multitap files works too. + +Get a tape file, and place it in the root folder of the sdcard. + +-g + Start interface + +-l + list available .tap + +-p path + Set Default path to find .tap file + +-r [id_rom] + Set type of rom to load (value = 0, 1, 2) + +-v + Displays version + +-h + Displays help + +"MYTAPE + Load MYTAPE ## Introduction @@ -150,21 +183,7 @@ not done. Some others games uses special keys (SHIFT, CTRL) for direction or the first button. Theses cases are not handle yet : but it could in the future. -## SYNOPSYS - -+ basic11 -+ basic11 -g -+ basic11 -l -+ basic11 -p path -+ basic11 "MYTAPE - -## DESCRIPTION - -This command starts the atmos rom. This rom did not test RAM and cload/csave are done on sdcard. It means that it calls file from sdcard. - -Cload works with .tap file. Multitap files works too. - -Get a tape file, and place it in the root folder of the sdcard. +## Example Starts basic11 : diff --git a/src/commands/basic11.asm b/src/commands/basic11.asm index ee467f3..0d01f48 100644 --- a/src/commands/basic11.asm +++ b/src/commands/basic11.asm @@ -1,17 +1,42 @@ .export _basic11 +.export _basic10 -.define BASIC11_OFFSET_ROOT_PATH $FE70 -.define BASIC11_OFFSET_FOR_ID_OF_ROM_TO_LOAD $F2 -.define BASIC11_MAX_LENGTH_DEFAULT_PATH 16 ; MAX : 32 +;; OPTIONS -.define basic11_color_bar $11 -.define BASIC11_PATH_DB "/var/cache/basic11/" -.define BASIC10_PATH_DB "/var/cache/basic10/" -.define BASIC11_MAX_MAINDB_LENGTH 20000 +.define BASIC11_OPTION_DEFAULT_PATH_IS_NOT_SET $00 +.define BASIC11_OPTION_DEFAULT_PATH_IS_SET $01 + +.define BASIC11_OPTION_ROM_ID_IS_NOT_SET $00 +.define BASIC11_OPTION_ROM_ID_IS_SET $01 + +.define BASIC11_MAX_NUMBER_OF_ROM $03 + +.define BASIC11_START_GUI $01 +.define BASIC11_START_LIST $02 +.define BASIC11_DEFAULT_PATH_SET $03 +.define BASIC11_END_OF_ARGS $04 +.define BASIC11_SET_ROM $05 +.define BASIC11_DISPLAY_VERSION $06 +.define BASIC11_DISPLAY_HELP $07 +.define BASIC11_OPTION_UNKNOWN $FF + +.define BASIC11_NMI_VECTOR $F88F +.define BASIC11_OFFSET_ROOT_PATH $FE70 +.define BASIC11_OFFSET_LENGTH_ROOT_PATH BASIC11_OFFSET_ROOT_PATH-1 + +.define BASIC10_OFFSET_ROOT_PATH $FCED +.define BASIC10_OFFSET_LENGTH_ROOT_PATH BASIC10_OFFSET_ROOT_PATH-1 +.define BASIC11_OFFSET_FOR_ID_OF_ROM_TO_LOAD $F2 +.define BASIC11_MAX_LENGTH_DEFAULT_PATH 16 ; MAX : 32 + +.define basic11_color_bar $11 +.define BASIC11_PATH_DB "/var/cache/basic11/" +.define BASIC10_PATH_DB "/var/cache/basic10/" +.define BASIC11_MAX_MAINDB_LENGTH 23000 .define basic11_sizeof_max_length_of_conf_file_bin .strlen(BASIC11_PATH_DB)+1+1+8+1+2+1 ; used for the path but also for the cnf content .define basic11_sizeof_binary_conf_file 9 ; Rom + direction + fire1 + fire2 + fire3 -basic11_tmp := userzp ; One byte (used in gui) +basic11_tmp := userzp ; One byte (used in gui) basic11_ptr1 := userzp+1 ; Two bytes basic11_ptr2 := userzp+3 ; Two bytes @@ -32,7 +57,6 @@ basic11_skip_dec := userzp+8 basic11_fp := userzp+9 basic11_ptr3 := userzp+11 -basic11_mainargs_ptr := userzp+11 ; Avoid 13 because it's device store offset basic11_first_letter_gui := userzp+14 @@ -46,7 +70,9 @@ basic11_argv1_ptr := userzp+21 ; 16 bits basic11_mode := userzp+23 ; 8 bits store if we need to start atmos rom or oric-1 basic11_no_arg_provided := userzp+24 ; 8 bits store if we need to start atmos rom or oric-1 -basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p path" +basic11_option_default_path_set := userzp+26 ; Used when user type "basic11 -p path" +basic11_current_arg_id := userzp+28 ; One byte +basic11_rootpath_ptr := userzp + 29 ; Used to save ptr of the path .define BASIC10_ROM $01 .define BASIC11_ROM $02 @@ -65,11 +91,18 @@ basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p p .proc _basic_main COPY_CODE_TO_BOOT_ATMOS_ROM_ADRESS := $200 + ; Set Default ROM + lda #$02 + sta BASIC11_OFFSET_FOR_ID_OF_ROM_TO_LOAD + lda #$01 + sta basic11_current_arg_id lda #$00 sta basic11_no_arg_provided - sta basic11_default_path_set + + lda #BASIC11_OPTION_DEFAULT_PATH_IS_NOT_SET + sta basic11_option_default_path_set initmainargs basic11_argv_ptr, basic11_argc, 0 ; Get args cpx #$01 @@ -82,8 +115,8 @@ basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p p ldy #$00 lda (basic11_argv1_ptr),y - cmp #'-' ; is it Dash ? - bne @is_a_tape_file_in_arg ; No we check if a .tape file is provieded + cmp #'-' ; is it Dash ? + bne @is_a_tape_file_in_arg ; No we check if a .tape file is provieded jmp @basic11_option_management ; Yes, check options @no_arg: @@ -102,9 +135,9 @@ basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p p sta basic11_no_arg_provided ; Allocating memory to load conf file - lda #basic11_sizeof_max_length_of_conf_file_bin - ldy #$00 - BRK_KERNEL XMALLOC + ; FIXME macro + + malloc #basic11_sizeof_max_length_of_conf_file_bin cmp #$00 bne @no_oom5 cpy #$00 @@ -113,13 +146,10 @@ basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p p crlf - ; FIXME macro - lda #basic11_sizeof_max_length_of_conf_file_bin - ldy #$00 - ldx #$20 ; - stx DEFAFF - ldx #$00 - BRK_KERNEL XDECIM + lda #basic11_sizeof_max_length_of_conf_file_bin + + print_int ,2, 2 ; an arg is skipped because the number is from register rts @no_oom5: @@ -134,7 +164,7 @@ basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p p @L2: lda basic11_mode ; Is it atmos ? cmp #BASIC11_ROM - beq @copy_atmos_db_path ; Yes copy basic path in atmos path offset + beq @copy_atmos_db_path ; Yes copy basic path in atmos path offset lda basic10_conf_str,y ; Copy db path into ptr jmp @continue_copy_path_db @@ -172,7 +202,7 @@ basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p p tay lda (basic11_argv1_ptr),y ldy basic11_save_pos_arg - cmp #$22 ; " char + cmp #'"' ; " char beq @outstrcat cmp #$00 beq @outstrcat @@ -214,7 +244,6 @@ basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p p ; Let's copy BUFEDT jsr copy_bufedt - ldy #$00 lda (basic11_ptr2),y pha @@ -326,16 +355,43 @@ basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p p rts @basic11_option_management: - ldy #$01 - lda (basic11_argv1_ptr),y - cmp #'g' + jsr basic11_manage_option_cmdline + + cmp #BASIC11_START_GUI beq @gui - cmp #'p' + cmp #BASIC11_START_LIST + beq @start_list + + cmp #BASIC11_SET_ROM + beq @set_rom + + cmp #BASIC11_DISPLAY_VERSION + beq @display_version + + cmp #BASIC11_DISPLAY_HELP + beq @display_help + + cmp #BASIC11_DEFAULT_PATH_SET beq @root_path - cmp #'l' + cmp #BASIC11_END_OF_ARGS + beq @start_rom bne @option_not_known + +@display_version: + print version_str + crlf + rts + +@display_help: + getmainarg #0, (basic11_argv_ptr) ; Get first arg + BRK_KERNEL XWSTR0 + print basic11_usage + crlf + rts + +@start_list: mfree (basic11_argv_ptr) jsr basic11_read_main_dbfile @@ -346,16 +402,41 @@ basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p p print str_can_not rts -@root_path: - getmainarg #2, (basic11_argv_ptr) - sta basic11_argv1_ptr - sty basic11_argv1_ptr+1 +@set_rom: + getmainarg basic11_current_arg_id, (basic11_argv_ptr) + sta basic11_ptr2 + sty basic11_ptr2+1 + ;BASIC11_MAX_NUMBER_OF_ROM + ldy #$00 + lda (basic11_ptr2),y + beq @param_empty + sec + sbc #$30 + + cmp #BASIC11_MAX_NUMBER_OF_ROM + bcc @set_rom_id + print str_rom_not_known + crlf + rts +@set_rom_id: + sta BASIC11_OFFSET_FOR_ID_OF_ROM_TO_LOAD + inc basic11_current_arg_id + jmp @basic11_option_management + +@start_rom: + jmp @load_ROM_in_memory_and_start + +@root_path: + getmainarg basic11_current_arg_id, (basic11_argv_ptr) + sta basic11_rootpath_ptr + sty basic11_rootpath_ptr+1 ; Checking if the path is less than 32 chars (Atmos rom can't contains more than 32 chars) + ldy #$00 @check_path: - lda (basic11_argv1_ptr),y + lda (basic11_rootpath_ptr),y beq @end_check iny cpy #BASIC11_MAX_LENGTH_DEFAULT_PATH @@ -366,23 +447,31 @@ basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p p rts @end_check: - lda #$01 - sta basic11_default_path_set - lda #$02 - sta BASIC11_OFFSET_FOR_ID_OF_ROM_TO_LOAD - jmp @load_ROM_in_memory_and_start + cpy #$00 + bne @path_not_empty + +@param_empty: + print str_basic11_missing_arg + crlf + rts + +@path_not_empty: + lda #BASIC11_OPTION_DEFAULT_PATH_IS_SET + sta basic11_option_default_path_set + inc basic11_current_arg_id + jmp @basic11_option_management + + @continue_l_option: ; Search now print basic_str_search - jmp @displays_all @exit_search: print basic_str_last_line @exit: - mfree(basic11_ptr1) ; Open @@ -499,21 +588,17 @@ basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p p ; # Code to load ROM into RAM bank ; ############################################################# @load_ROM_in_memory_and_start: - - malloc 16384,basic11_ptr1 ; Index ptr + malloc #16384, basic11_ptr1 ; Index ptr cmp #$00 bne @no_oom cpy #$00 bne @no_oom print str_enomem - ; FIXME macro - lda #<16384 - ldy #>16384 - ldx #$20 ; - stx DEFAFF - ldx #$00 - BRK_KERNEL XDECIM + lda #<16384 ; 12 + ldy #>16384 ; 0 because the number is 12 (from A) + print_int ,2, 2 ; an arg is skipped because the number is from register + crlf rts @@ -523,7 +608,7 @@ basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p p beq @start_copy_path ; For rom oric-1 we force to rom 2 (why because i don't know :) => it's the only rom available :) lda #$02 - sta $F2 + sta BASIC11_OFFSET_FOR_ID_OF_ROM_TO_LOAD @start_copy_path: ; copy path of the root folder @@ -556,7 +641,7 @@ basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p p iny sta (basic11_ptr1),y - ; Get value + ; Get if kernel default is sdcard or usb device ldx #XVARS_KERNEL_CH376_MOUNT BRK_KERNEL XVARS sta basic11_ptr2 @@ -566,6 +651,7 @@ basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p p lda (basic11_ptr2),y ; cmp #CH376_SET_USB_MODE_CODE_SDCARD beq @sdcard + ; It's usb device, let's load basicusX.rom ldy basic11_tmp0 ; concat 'us' lda #'u' @@ -663,9 +749,6 @@ basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p p BRK_KERNEL XFREAD fclose(basic11_fp) - - - ldy #$00 lda (basic11_ptr2),y sta STORE_CURRENT_DEVICE ; For atmos ROM : it pass the current device () @@ -723,9 +806,11 @@ basic11_default_path_set := userzp+26 ; Used when user type "basic11 -p p code_overlay_switch_sedoric: .byt $08,$48,$78,$a9,$00,$8d,$21,$03,$68,$28,$60 +;******************************************************* +;; This code to + basic11_driver: sei - ldx #$00 @L1000: @@ -750,12 +835,14 @@ basic11_driver: inx cpx #64 bne @loop_copy_rom + ; If the rom id is equal to 0, it means that it's for the hobbit. ; The hobbit rom does not handle path - - lda basic11_default_path_set + lda basic11_option_default_path_set beq @manage_others_cases + +; Clear BUFEDT when we don't need to insert any tape file ldy #$00 lda #$00 @@ -764,10 +851,11 @@ basic11_driver: iny bne @loop_copy_bufedt +; Copy default path into rom path (ram bank) ldy #$00 @copy_rootpath: - lda (basic11_argv1_ptr),y + lda (basic11_rootpath_ptr),y beq @end_start_with_default_path cmp #'a' ; 'a' bcc @do_not_uppercase_copy @@ -776,12 +864,35 @@ basic11_driver: sbc #$1F @do_not_uppercase_copy: + sta basic11_tmp + lda basic11_mode + cmp #BASIC11_ROM + beq @forge_path_for_atmos + + lda basic11_tmp + sta BASIC10_OFFSET_ROOT_PATH,y ; Put char of the path in BASIC10 path + bne @skip_basic11_forge_path + beq @end_start_with_default_path + +@forge_path_for_atmos: + lda basic11_tmp sta BASIC11_OFFSET_ROOT_PATH,y + +@skip_basic11_forge_path: iny bne @copy_rootpath @end_start_with_default_path: - sty $FE6F + ; Store the length of the string + lda basic11_mode + cmp #BASIC11_ROM + beq @set_length_to_atmosrom_path + + sty BASIC10_OFFSET_LENGTH_ROOT_PATH + bne @manage_others_cases + +@set_length_to_atmosrom_path: + sty BASIC11_OFFSET_LENGTH_ROOT_PATH beq @let_s_start_atmos @manage_others_cases: @@ -825,7 +936,7 @@ basic11_driver: @isatmosforpath: lda basic11_saveA ; Rootpath for Atmos - sta $FE70,x + sta BASIC11_OFFSET_ROOT_PATH,x @continue_path: iny @@ -837,6 +948,7 @@ basic11_driver: cmp #BASIC11_ROM beq @isatmos_fix_EOS_and_length + ; Set path for Oric-1 lda basic11_first_letter sta $FCED,x inx @@ -847,11 +959,11 @@ basic11_driver: @isatmos_fix_EOS_and_length: lda basic11_first_letter - sta $FE70,x ; We store the into default path, the first letter + sta BASIC11_OFFSET_ROOT_PATH,x ; We store the into default path, the first letter inx lda #'/' - sta $FE70,x - stx $FE6F ; Store length of the path + sta BASIC11_OFFSET_ROOT_PATH,x + stx BASIC11_OFFSET_ROOT_PATH-1 ; Store length of the path @let_s_start: @@ -870,6 +982,13 @@ basic11_driver: @jmp_basic10_vector: jmp $F42D +end_basic11_driver: + + +;; this end will be in main memory !!! +;******************************************************* + + ; don't move it because it's used in the copy of basic11_driver tapes_path: .asciiz "/usr/share/basic11/" @@ -877,6 +996,11 @@ tapes_path: tapes_path_basic10: .asciiz "/usr/share/basic10/" +.if end_basic11_driver-basic11_driver > 254 + .out .sprintf("Basic11: Size of copy routine = %d", (end_basic11_driver-basic11_driver)) + .error "Basic11: Size of copy routine us greater than 255. Basic11 will crash" +.endif + copy_bufedt: initmainargs basic11_ptr1, basic11_ptr4, 1 @@ -991,12 +1115,18 @@ copy_bufedt: .include "basic11/basic11_gui.asm" +str_rom_not_known: + .asciiz "Rom not known" + str_error_path_too_long: .byte "Path can not longer than ",.string(BASIC11_MAX_LENGTH_DEFAULT_PATH)," chars",0 str_basic11_missing_rom: .asciiz "Missing ROM file : " +str_basic11_missing_arg: + .asciiz "Missing arg " + rom_path: .asciiz "/usr/share/atmos/basic" @@ -1033,6 +1163,9 @@ str_basic10_maindb: .byte BASIC10_PATH_DB .asciiz "basic10.db" +basic11_usage: + .asciiz " [-r rom] [-p path] [-l] [-g] [\"TAPEFILE]" + basic_str_search: .byte "+--------+-----------------------------+" .byte "| key | NAME |" @@ -1044,3 +1177,5 @@ basic_str_last_line: basic_rnd_init: .byte $80,$4F,$C7,$52,$FF,$FF .endproc + +.include "commands/basic11/basic11_manage_option_cmdline.s" diff --git a/src/commands/basic11/basic11_manage_option_cmdline.s b/src/commands/basic11/basic11_manage_option_cmdline.s new file mode 100644 index 0000000..b97190c --- /dev/null +++ b/src/commands/basic11/basic11_manage_option_cmdline.s @@ -0,0 +1,65 @@ +.proc basic11_manage_option_cmdline + lda basic11_current_arg_id + cmp basic11_argc + beq @end_of_arg + + getmainarg basic11_current_arg_id, (basic11_argv_ptr) ; Get first arg + sta basic11_argv1_ptr + sty basic11_argv1_ptr+1 + + ldy #$01 + lda (basic11_argv1_ptr),y + beq @unknown_option + + cmp #'v' + beq @version + + cmp #'h' + beq @help + + cmp #'g' + beq @gui + + cmp #'l' + beq @list + + cmp #'p' + beq @root_path + + cmp #'r' + beq @select_rom + +@unknown_option: + lda #BASIC11_OPTION_UNKNOWN + rts + +@end_of_arg: + lda #BASIC11_END_OF_ARGS + rts + +@select_rom: + inc basic11_current_arg_id + lda #BASIC11_SET_ROM + rts + +@root_path: + inc basic11_current_arg_id + lda #BASIC11_DEFAULT_PATH_SET + rts + +@gui: + lda #BASIC11_START_GUI + rts + +@list: + lda #BASIC11_START_LIST + rts + +@version: + lda #BASIC11_DISPLAY_VERSION + rts + +@help: + lda #BASIC11_DISPLAY_HELP + rts +.endproc diff --git a/src/dependencies/orix-sdk b/src/dependencies/orix-sdk index dafac00..a5640e2 160000 --- a/src/dependencies/orix-sdk +++ b/src/dependencies/orix-sdk @@ -1 +1 @@ -Subproject commit dafac0087c07b09a4711e86ebcc843ce5b951985 +Subproject commit a5640e25fa03be5aaf2e81546eefc61fadf24d62 diff --git a/src/shell.asm b/src/shell.asm index d4ae04a..3aabfba 100644 --- a/src/shell.asm +++ b/src/shell.asm @@ -16,12 +16,15 @@ .include "dependencies/kernel/src/include/memory.inc" .include "dependencies/kernel/src/include/files.inc" + ;---------------------------------------------------------------------- ; Orix SDK includes ;---------------------------------------------------------------------- .include "dependencies/orix-sdk/macros/SDK.mac" +.include "dependencies/orix-sdk/macros/SDK_print.mac" .include "dependencies/orix-sdk/include/SDK.inc" + ;---------------------------------------------------------------------- ; Twilighte board includes ;---------------------------------------------------------------------- @@ -217,8 +220,7 @@ RETURN_BANK_READ_BYTE_FROM_OVERLAY_RAM := $78 ; lda bash_struct_command_line_ptr ; ldy bash_struct_command_line_ptr+1 ; BRK_KERNEL XEXEC - ldx #$00 - exec (bash_struct_command_line_ptr) + system (bash_struct_command_line_ptr) jsr external_cmd jmp loop .endproc @@ -273,8 +275,7 @@ RETURN_BANK_READ_BYTE_FROM_OVERLAY_RAM := $78 ; lda bash_struct_ptr ; ldy bash_struct_ptr+1 ; BRK_KERNEL XEXEC - ldx #$00 - exec (bash_struct_ptr) + system (bash_struct_ptr) jsr external_cmd @@ -1304,7 +1305,7 @@ str_not_found: .byte " : No such file or directory",$0D,$0A,0 str_oom: - .byte "Out of memory",$0D,$0A,0 ; FIXME + .byte "Out of memory",$0D,$0A,0 ; FIXME str_too_many_open_files: .byte "Too many open files",$0D,$0A,0 @@ -1325,7 +1326,10 @@ str_max_malloc_reached: .asciiz "Max number of malloc reached" signature: - .asciiz "Shell v2024.1" + .byte "Shell v" + ; Don't put 0 here +version_str: + .asciiz "2024.3" shellext_found: .byte "Shell extentions found",$0A,$0D,$00