ROM file system source. By Lee Davison. |
; constants for the file system none = $00 ; no flags ; flags: deleted = $80 ; file is deleted but not removed directory = $40 ; file is really a directorySelf explanitory really, the deleted flag is not used yet.
; variables for the file system ; zero page filesys_l .ds 1 ; file system pointer low byte filesys_h .ds 1 ; file system pointer high byte lensys_l .ds 1 ; file system length low byte lensys_h .ds 1 ; file system length high byte file_l .ds 1 ; current file pointer low byte file_h .ds 1 ; current file pointer high byte length_l .ds 1 ; current file length low byte length_h .ds 1 ; current file length high byte fileflags .ds 1 ; current file's flag byte findname_l .ds 1 ; filename to find pointer low byte findname_h .ds 1 ; filename to find pointer high bytefilesys is the pointer returned by the find routine, it is only valid if a file was found, i.e. Cb is = 1.
lensys is the length of the returned file and like filesys is only valid if a file was found.
file and length are used internally by the find routine.
fileflags is used internally by the find routine.
findname points to the start of the null yerminated path/name of the file to find. Like the HTTP "GET" it must start with "/" and "/" is used to separate directories so "/",$00 is valid as is "/index.html",$00 but "o.html",$00 isn't.
; file format is .. f_start .ds 1 ; flag byte ; bit function ; --- -------- ; 7 deleted ; 6 directory ; 5-0 unassigned f_length .ds 2 ; file payload length word f_name .ds 1 ; filename and null terminator byte ; .ds length ; here to here+length-1 is the payloadThis is used to define the header, f_name is used realtive to f_start and will remain correct even if other parameters, such as a parent pointer for reverse tree searches, are added to the header.
; find file, searches the file system for the filename pointed to by the find ; name pointer. returns with Cb = 1 and the pointer to the file payload in ; filesys, if found. ; ; file name to search for should be "/[path[path]][name]" where path is the ; directory name followed by a "/". the path may be many deep and both the ; path and the name may be null. if the name is null then the default_file ; name will be searched for the path given. LAB_find LDA root+1 ; get root payload length low byte STA lensys_l ; save payload length low byte LDA root+2 ; get root payload length high byte STA lensys_h ; save payload length high byte LDA #<root_b ; get root body pointer low byte STA filesys_l ; set file system pointer low byte LDA #>root_b ; get body pointer high byte STA filesys_h ; set file system pointer high byte LDY #$00 ; clear index LDA (findname_l),Y ; get the first byte of the find name CMP #'/' ; compare with separator BNE LAB_exit_n_found ; exit if not "/" at start JSR LAB_directory ; search the root for the file BIT fileflags ; get the flags for this file BVC LAB_exit_find ; exit if it's a file JSR LAB_find_default ; a directory so find the default file LAB_exit_find RTSThe routine above returns either a found file pointer and it's length or flags not found. If the match turns out to be a directory, e.g. "/images", then the search routine is re-entered at the find default file entry so the file searched becomes effectively "/images/index.html"
; flag file found and exit LAB_exit_found BIT fileflags ; test the flags, set Vb for a directory SEC ; flag found RTS ; flag file not found and exit LAB_exit_n_foun CLV ; flag not a directory CLC ; flag not found RTS ; increment filesys to the next file pointer in the directory LAB_nextfile CLC ; clear carry for add LDA filesys_l ; get filesys low byte ADC #$02 ; increment to next pointer STA filesys_l ; save filesys low byte BCC ni_inc_h ; branch if no rollover INC filesys_h ; else increment filesys high byte ni_inc_h SEC ; set carry for subtract LDA lensys_l ; get remaining length low byte SBC #$02 ; increment to next pointer STA lensys_l ; save remaining length low byte BCS LAB_comparefile ; branch if no rollunder DEC lensys_h ; decerment remaining length high byte LAB_comparefile LDA lensys_l ; get remaining length low byte ORA lensys_h ; OR remaining length high byte BEQ LAB_exit_n_found ; exit if no more directory entries LDY #$00 ; clear index LDA (filesys_l),Y ; get file pointer low byte STA file_l ; save this file pointer low byte INY ; increment index LDA (filesys_l),Y ; get file pointer high byte STA file_h ; save this file pointer high byte DEY ; clear index LDA (file_l),Y ; get the file's flags STA fileflags ; save the file's flag byte INY ; point to payload length low byte LDA (file_l),Y ; get file's payload length low byte STA length_l ; save file's length low byte INY ; point to payload length high byte LDA (file_l),Y ; get file's payload length high byte STA length_h ; save file's length high byte CLC ; clear carry for add LDA file_l ; get this file pointer low byte ADC #f_name-f_start ; add offset to the file name STA file_l ; save this file pointer low byte BCC nf_inc_h ; branch if no rollover INC file_h ; increment this file pointer high byte nf_inc_h LDY #$FF ; set so first increment clears index ; compare this file's name, pointed to by file, with the find file ; name pointed to by findname. exits with Y indexed to the next byte ; in the name if the whole name matched. LAB_comparename INY ; increment index LDA (file_l),Y ; get next byte of name to test BEQ LAB_cnameexit ; exit if end of name (match) EOR (findname_l),Y ; compare with next byte of name to find BEQ LAB_comparename ; loop if character match BNE LAB_nextfile ; branch if not this file LAB_cnameexit LDA (findname_l),Y ; get next byte of name to find BEQ LAB_end_find ; branch if end of name to find CMP #'/' ; compare with separator BNE LAB_nextfile ; branch if not end of name to find LAB_end_find PHA ; save next byte of name to find ; name matched so update lensys LDA length_l ; get length low byte STA lensys_l ; save length low byte LDA length_h ; get length high byte STA lensys_h ; save length high byte ; name matched so update filesys SEC ; set carry for add +1 TYA ; copy offset ADC file_l ; add this file pointer low byte STA filesys_l ; save as file system pointer low byte LDA file_h ; get this file pointer high byte ADC #$00 ; add in the carry STA filesys_h ; save as file system pointer high byte PLA ; restore next byte of name to find BEQ LAB_exit_found ; branch if end of name to find BIT fileflags ; else test the flags byte BVC LAB_exit_n_found ; branch if not a directory ; searches the directory pointed to by the file system pointer for the ; filename pointed to by the find name pointer. the routine is entered ; with filesys pointing to the first directory byte after the file header ; and lensys holding the remaining directory size LAB_directory SEC ; set carry for add +1 TYA ; copy offset LDY #$00 ; clear index ADC findname_l ; add offset to findname low byte STA findname_l ; save findname low byte TYA ; set $00 for add carry ADC findname_h ; add findname high byte STA findname_h ; save findname high byte LDA (findname_l),Y ; get next byte of name to find BNE LAB_comparefile ; go compare file if not null filename LAB_find_default LDA #<default_file ; get default filename pointer low byte STA findname_l ; set pointer of name to find low byte LDA #>default_file ; get default filename pointer high byte STA findname_h ; set pointer of name to find high byte BNE LAB_comparefile ; go compare file (branch always)The routine above is the main file tree search routine. The path/name to find is compared byte at a time with each filename in turn until a file is found that is a complete match to it's end. Once there the find string is tested and if it's at a separator, "/", a directory change is made (assuming the found file was a directory), the search then continues.
If the find string ends in "/" then the pointer is changed to point to the default file name "index.html" and this file is searched for in the target directory. So "/" as a find string will search for, and return, the pointer and size for "/index.html", where as "/images/" as a find string will search for, and fail to find, "/images/index.html" as there is no index.html file in the images directory.
default_file .byte "index.html",$00 ; default filename for "/xxx/" findsFinally the test filesystem files. There is one additional, zero payload length, file "index" which is to test that matches with partial names don't trigger false matches.
; this is the test data for the filesystem. it is made up of the HTML ; pages and other files for the Vic 20 mini web server plus a dummy ; file to test the file match. ; structure for this trial is .. ; root+--errors+--404 ; error 404, really an html file ; | ; +--images+--e.gif ; small .gif image ; | ; +--b.html ; button page ; +--index ; dummy file for test ; +--index.html ; default page ; +--o.html ; other page ; ********************************************************************* ; the root file is always a directory root .byte directory ; flags .word root_end-root_b ; file payload length .byte $00 ; filename, null in this case root_b .word errors ; errors directory .word images ; images directory ; done directories, now do files .word b_html ; the button page .word index_html ; default web page .word o_html ; other web page root_end ; ********************************************************************* ; dummy file for test index .byte none ; flags .word $0000 ; file payload length .byte "index",$00 ; filename, null terminator ; ********************************************************************* ; default web page, served for "GET / " index_html .byte none ; flags .word index_end-index_html_b ; file payload length .byte "index.html",$00 ; filename, null terminator ; rest is file payload index_html_b .byte "HTTP/1.0 200 OK",$0D,$0A,"Content-Type: text/html" .byte $0D,$0A,$0D,$0A .byte "<HTML><HEAD><TITLE>Vic 20 WEB Server</TITLE>" .byte "</HEAD><BODY BGCOLOR=#CC6502 TEXT=WHITE>" .byte "<TABLE ALIGN=CENTER WIDTH=80% HEIGHT=90%>" .byte "<TR><TD VALIGN=CENTER>" .byte "<FONT SIZE=+1>Vic 20 WEB Server </FONT>" .byte "- <A HREF=b.html>The button page</A>" .byte " - <A HREF=o.html>The other page</A>" .byte "<P><FONT SIZE=+4><B>Welcome</B></FONT>" .byte "<FONT FACE=Courier> - to the default page</FONT>" .byte "<P>" .byte "<A HREF=http://forum.6502.org/viewtopic.php?f=5&t=3024> e-mail " .byte "me <IMG SRC=images/e.gif BORDER=0 ALT=e-mail></A>" .byte "</TD></TR></TABLE></BODY></HTML>" index_end ; ********************************************************************* ; other web page, served for "GET /o.html" o_html .byte none ; flags .word o_html_end-o_html_b ; file payload length .byte "o.html",$00 ; filename, null terminator ; rest is file payload o_html_b .byte "HTTP/1.0 200 OK",$0D,$0A,"Content-Type: text/html" .byte $0D,$0A,$0D,$0A .byte "<HTML><HEAD><TITLE>Vic 20 WEB Server</TITLE>" .byte "</HEAD><BODY BGCOLOR=#65CC02 TEXT=WHITE>" .byte "<TABLE ALIGN=CENTER WIDTH=80% HEIGHT=90%>" .byte "<TR><TD VALIGN=CENTER>" .byte "<FONT SIZE=+1>Vic 20 WEB Server </FONT>" .byte "- <A HREF=>The home page</A>" .byte " - <A HREF=b.html>The button page</A>" .byte "<P>" .byte "<FONT SIZE=+4><B>Welcome</B></FONT>" .byte "<FONT FACE=Courier> - to the other page</FONT>" .byte "<P>" .byte "<A HREF=http://forum.6502.org/viewtopic.php?f=5&t=3024> e-mail " .byte "me <IMG SRC=images/e.gif BORDER=0 ALT=e-mail></A>" .byte "</TD></TR></TABLE></BODY></HTML>" o_html_end ; ********************************************************************* ; the button page, served for "GET /b.html" b_html .byte none ; flags .word b_html_end-b_html_b ; file payload length .byte "b.html",$00 ; filename, null terminator ; rest is file payload b_html_b .byte "HTTP/1.0 200 OK",$0D,$0A,"Content-Type: text/html" .byte $0D,$0A,$0D,$0A .byte "<HTML><HEAD><TITLE>Vic 20 WEB Server</TITLE>" .byte "</HEAD><BODY BGCOLOR=#065C02 TEXT=WHITE>" .byte "<TABLE ALIGN=CENTER WIDTH=90% HEIGHT=90%>" .byte "<TR><TD VALIGN=CENTER>" .byte "<FONT SIZE=+1>Vic 20 WEB Server </FONT>" .byte "- <A HREF=>The home page</A>" .byte " - <A HREF=o.html>The other page</A>" .byte "<P>" .byte "<FONT SIZE=+4><B>Welcome</B></FONT>" .byte "<FONT FACE=Courier> - to the button page</FONT>" .byte "<P>" .byte "<A HREF=http://forum.6502.org/viewtopic.php?f=5&t=3024> e-mail " .byte "me <IMG SRC=images/e.gif BORDER=0 ALT=e-mail></A></TD>" .byte "<TD WIDTH=20% ALIGN=CENTER>Are you easily confused?" .byte "<FORM METHOD=GET ACTION=b.html>" .byte "<PRE>" .byte "yes <INPUT TYPE=RADIO NAME=4 VALUE=0>",$0D,$0A .byte "no <INPUT TYPE=RADIO NAME=4 VALUE=1>",$0D,$0A .byte "fish<INPUT TYPE=RADIO NAME=4 VALUE=2 CHECKED>" .byte "</PRE>" .byte "<INPUT TYPE=SUBMIT VALUE=Submit>" .byte "</FORM></TD></TR></TABLE></BODY></HTML>" b_html_end ; ********************************************************************* ; errors directory errors .byte directory ; flags .word errors_end-errors_b ; file payload length .byte "errors",$00 ; filename, null terminator errors_b .word e_404 ; error 404 errors_end ; error 404, served for not found files e_404 .byte none ; flags .word e_404_end-e_404_b ; file payload length .byte "404",$00 ; filename, null terminator ; rest is file payload e_404_b .byte "HTTP/1.0 200 OK",$0D,$0A,"Content-Type: text/html" .byte $0D,$0A,$0D,$0A .byte "<HTML><HEAD><TITLE>Error 404</TITLE>" .byte "</HEAD><BODY BGCOLOR=#CC0265 TEXT=WHITE>" .byte "<TABLE ALIGN=CENTER WIDTH=80% HEIGHT=90%>" .byte "<TR><TD VALIGN=CENTER>" .byte "<FONT SIZE=+1>Vic 20 WEB Server </FONT>" .byte "- <A HREF=>The home page</A>" .byte "<P>" .byte "<FONT SIZE=+4><B>Error 404</B></FONT>" .byte "<FONT FACE=Courier> - File not found</FONT>" .byte "<P>" .byte "<A HREF=http://forum.6502.org/viewtopic.php?f=5&t=3024> e-mail " .byte "me <IMG SRC=images/e.gif BORDER=0 ALT=e-mail></A>" .byte "</TD></TR></TABLE></BODY></HTML>" e_404_end ; ********************************************************************* ; images directory images .byte directory ; flags .word images_end-images_b ; file payload length .byte "images",$00 ; filename, null terminator images_b .word e_gif ; small image images_end ; small image, served for "GET /email.gif" e_gif .byte none ; flags .word e_gif_end-e_gif_b ; file payload length .byte "e.gif",$00 ; filename, null terminator ; rest is file payload e_gif_b .byte "HTTP/1.0 200 OK",$0D,$0A,"Content-Type: image/gif",$0D,$0A .byte $0D,$0A,$47,$49,$46,$38,$39,$61,$10,$00,$10,$00,$C4,$00,$00 .byte $F7,$00,$5F,$33,$03,$9A,$33,$03,$CA,$03,$03,$83,$5F,$5F,$F7 .byte $33,$63,$FA,$63,$9B,$FB,$63,$CB,$FB,$03,$9B,$CB,$63,$FA,$FA .byte $FA,$FA,$CB,$97,$00,$00,$CB,$03,$03,$FA,$FA,$FA,$63,$63,$63 .byte $03,$03,$03,$FF,$FF,$FF,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$21,$F9,$04,$01,$00,$00,$10,$00,$2C .byte $00,$00,$00,$00,$10,$00,$10,$00,$00,$05,$69,$20,$24,$8E,$C6 .byte $91,$24,$63,$9A,$96,$49,$11,$18,$AA,$28,$40,$85,$59,$40,$46 .byte $A0,$3A,$8E,$20,$20,$07,$01,$6F,$38,$7C,$38,$1A,$3F,$84,$40 .byte $C1,$6C,$36,$8D,$C8,$02,$62,$E0,$64,$02,$18,$0A,$E8,$60,$BB .byte $AD,$32,$16,$D9,$63,$A3,$51,$2D,$43,$C9,$E5,$EA,$B9,$2C,$28 .byte $B8,$A9,$D0,$B4,$42,$70,$82,$3B,$E4,$F3,$7A,$F8,$C1,$EF,$F3 .byte $05,$26,$5B,$7C,$2A,$2F,$10,$02,$25,$37,$03,$31,$10,$04,$01 .byte $05,$06,$06,$37,$8B,$23,$01,$03,$6D,$31,$21,$00,$3B e_gif_end
Last page update: 24th February, 2004. | e-mail me |