diff --git a/compiler/res/prog8lib/diskio.p8 b/compiler/res/prog8lib/diskio.p8 index 4130739fc..250ba2fd1 100644 --- a/compiler/res/prog8lib/diskio.p8 +++ b/compiler/res/prog8lib/diskio.p8 @@ -60,8 +60,6 @@ io_error: ; internal variables for the iterative file lister / loader - ubyte list_suffixmatch - ubyte list_pattern_size ubyte list_skip_disk_name uword list_pattern uword list_blocks @@ -71,12 +69,12 @@ io_error: ; ----- get a list of files (uses iteration functions internally ----- - sub list_files(ubyte drivenumber, uword pattern, ubyte suffixmatch, uword name_ptrs, ubyte max_names) -> ubyte { + sub list_files(ubyte drivenumber, uword pattern_ptr, uword name_ptrs, ubyte max_names) -> ubyte { ; -- fill the array 'name_ptrs' with (pointers to) the names of the files requested. uword names_buffer = memory("filenames", 512) uword buffer_start = names_buffer ubyte files_found = 0 - if lf_start_list(drivenumber, pattern, suffixmatch) { + if lf_start_list(drivenumber, pattern_ptr) { while lf_next_entry() { @(name_ptrs) = lsb(names_buffer) name_ptrs++ @@ -96,18 +94,13 @@ io_error: ; ----- iterative file lister functions ----- - sub lf_start_list(ubyte drivenumber, uword pattern, ubyte suffixmatch) -> ubyte { - ; -- start an iterative file listing with optional prefix or suffix name matching. + sub lf_start_list(ubyte drivenumber, uword pattern_ptr) -> ubyte { + ; -- start an iterative file listing with optional pattern matching. ; note: only a single iteration loop can be active at a time! lf_end_list() - list_pattern = pattern - list_suffixmatch = suffixmatch + list_pattern = pattern_ptr list_skip_disk_name = true iteration_in_progress = true - if pattern==0 - list_pattern_size = 0 - else - list_pattern_size = strlen(pattern) c64.SETNAM(1, "$") c64.SETLFS(12, drivenumber, 0) @@ -177,15 +170,9 @@ io_error: void c64.CHRIN() if not list_skip_disk_name { - if list_pattern_size { - ; do filename matching - if list_suffixmatch - rightstr(list_filename, filename, list_pattern_size) - else - leftstr(list_filename, filename, list_pattern_size) - if strcmp(filename, list_pattern)==0 - return true - } else + if not list_pattern + return true + if prog8_lib.pattern_match(list_filename, list_pattern) return true } list_skip_disk_name = false diff --git a/compiler/res/prog8lib/prog8_lib.p8 b/compiler/res/prog8lib/prog8_lib.p8 index 18a9f7436..430bac265 100644 --- a/compiler/res/prog8lib/prog8_lib.p8 +++ b/compiler/res/prog8lib/prog8_lib.p8 @@ -7,4 +7,76 @@ prog8_lib { %asminclude "library:prog8_lib.asm", "" %asminclude "library:prog8_funcs.asm", "" + + + asmsub pattern_match(str string @AY, str pattern @R0) clobbers(Y) -> ubyte @A { + %asm {{ +; pattern matching of a string. +; Input: cx16.r0: A NUL-terminated, <255-length pattern +; AY: A NUL-terminated, <255-length string +; +; Output: A = 1 if the string matches the pattern, A = 0 if not. +; +; Notes: Clobbers A, X, Y. Each * in the pattern uses 4 bytes of stack. +; +; see http://6502.org/source/strings/patmatch.htm + +str = P8ZP_SCRATCH_W1 + + stx P8ZP_SCRATCH_REG + sta str + sty str+1 + lda cx16.r0 + sta modify_pattern1+1 + sta modify_pattern2+1 + lda cx16.r0+1 + sta modify_pattern1+2 + sta modify_pattern2+2 + jsr _match + lda #0 + adc #0 + ldx P8ZP_SCRATCH_REG + rts + + +_match + ldx #$00 ; x is an index in the pattern + ldy #$ff ; y is an index in the string +modify_pattern1 +next lda $ffff,x ; look at next pattern character MODIFIED + cmp #'*' ; is it a star? + beq star ; yes, do the complicated stuff + iny ; no, let's look at the string + cmp #'?' ; is the pattern caracter a ques? + bne reg ; no, it's a regular character + lda (str),y ; yes, so it will match anything + beq fail ; except the end of string +reg cmp (str),y ; are both characters the same? + bne fail ; no, so no match + inx ; yes, keep checking + cmp #0 ; are we at end of string? + bne next ; not yet, loop +found rts ; success, return with c=1 + +star inx ; skip star in pattern +modify_pattern2 + cmp $ffff,x ; string of stars equals one star MODIFIED + beq star ; so skip them also +stloop txa ; we first try to match with * = "" + pha ; and grow it by 1 character every + tya ; time we loop + pha ; save x and y on stack + jsr next ; recursive call + pla ; restore x and y + tay + pla + tax + bcs found ; we found a match, return with c=1 + iny ; no match yet, try to grow * string + lda (str),y ; are we at the end of string? + bne stloop ; not yet, add a character +fail clc ; yes, no match found, return with c=0 + rts + }} + } } diff --git a/docs/source/libraries.rst b/docs/source/libraries.rst index f85cc4e7b..17475385c 100644 --- a/docs/source/libraries.rst +++ b/docs/source/libraries.rst @@ -58,7 +58,7 @@ diskio ------ Provides several routines that deal with disk drive I/O, such as: -- list files on disk, optionally filtering by prefix or suffix +- list files on disk, optionally filtering by a simple pattern with ? and * - show disk directory as-is - display disk drive status - load and save data from and to the disk diff --git a/examples/cx16/imageviewer/imageviewer.p8 b/examples/cx16/imageviewer/imageviewer.p8 index 9e137cdd6..ef28a2f09 100644 --- a/examples/cx16/imageviewer/imageviewer.p8 +++ b/examples/cx16/imageviewer/imageviewer.p8 @@ -38,7 +38,7 @@ main { ; this only works in the emulator V38 with an sd-card image with the files on it. str[40] filename_ptrs - ubyte num_files = diskio.list_files(8, 0, false, &filename_ptrs, len(filename_ptrs)) + ubyte num_files = diskio.list_files(8, 0, &filename_ptrs, len(filename_ptrs)) if num_files { while num_files { num_files-- diff --git a/examples/dirlist.p8 b/examples/dirlist.p8 index 093b10529..08736e47c 100644 --- a/examples/dirlist.p8 +++ b/examples/dirlist.p8 @@ -10,8 +10,8 @@ main { void diskio.directory(8) txt.chrout('\n') - if diskio.lf_start_list(8, "nier", false) { - txt.print("\nfiles starting with 'nier':\n") + if diskio.lf_start_list(8, "cub*") { + txt.print("\nfiles starting with 'cub':\n") while diskio.lf_next_entry() { txt.print(diskio.list_filename) txt.print(" ") @@ -23,8 +23,8 @@ main { txt.print("error\n") } - if diskio.lf_start_list(8, "pcx", true) { - txt.print("\nfiles ending with 'pcx':\n") + if diskio.lf_start_list(8, "*gfx") { + txt.print("\nfiles ending with 'gfx':\n") while diskio.lf_next_entry() { txt.print(diskio.list_filename) txt.print(" ") @@ -36,7 +36,7 @@ main { txt.print("error\n") } - if diskio.lf_start_list(8, 0, false) { + if diskio.lf_start_list(8, 0) { txt.print("\nfirst 10 files:\n") ubyte counter=0 while counter < 10 and diskio.lf_next_entry() { diff --git a/examples/line-circle-gfx.p8 b/examples/line-circle-gfx.p8 index f8471254b..03cf262d7 100644 --- a/examples/line-circle-gfx.p8 +++ b/examples/line-circle-gfx.p8 @@ -10,6 +10,7 @@ main { draw_lines() draw_circles() + draw_rects() ; graphics.disable_bitmap_mode() ; test_stack.test() @@ -18,6 +19,14 @@ main { } } + sub draw_rects() { + graphics.rect(220,10,80,10) + graphics.rect(20,180,80,10) + graphics.fillrect(220,30,80,10) + graphics.fillrect(20,160,80,10) + } + + sub draw_circles() { ubyte xx for xx in 3 to 7 {