Login

Subversion Repositories NedoOS

Rev

Rev 1865 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

        DEVICE ZXSPECTRUM128
        include "../_sdk/sys_h.asm"

STACK=0x4000

LISTBUF         equ     0x4400
LISTBUFsz       equ     0x200

DISKBUF=0xc000
DISKBUFsz=0x4000


        org PROGSTART
cmd_begin
        ld sp,STACK
        call initstdio

                call    CS_PREPARE


                ;get name of the prog as it was called from shell
                ld      hl,COMMANDLINE
       
                call    skipspaces
                or      a
                jp      z,fatal_err     ;can't find first non-' ' char -- fatal error

                ld      [name_ptr],hl   ;program name

                call    skipword
                or      a
                jp      z,got_no_args
                ld      [hl],0          ;zero-terminate program name
                inc     hl
                call    skipspaces
                or      a
                jp      z,got_no_args

                ;now HL points to first real arg, start arg parsing loop
parse_args:
                ld      [curr_arg],hl
                ;find end of arg and zero-terminate
                call    skipword
                or      a
                push    af
                push    hl
                ld      [hl],0

                call    process_arg

                pop     hl
                pop     af
                jr      z,successful_exit
                inc     hl
                call    skipspaces
                or      a
                jr      nz,parse_args
successful_exit:
                ld      hl,0
                QUIT


AST_DFLT        equ     0
AST_FILES       equ     1
AST_CHK         equ     2

process_arg:    ;args parsing routine, has state
                ;in: HL=asciiz of current argument

                ld      a,[argp_state]
                or      a
                jr      nz,.no_dflt

;DFLT - wait for switches

                ; check for -h or --help
                ld      hl,[curr_arg]
                push    hl
                ld      de,help_arg
                call    strcmp
                jr      z,.arg_help

                pop     hl
                ld      de,chk_arg
                call    strcmp
                jr      z,.arg_chk

                ; set FILES mode
                ld      a,AST_FILES
                ld      [argp_state],a
.chksum_arg
                ld      hl,[curr_arg]
                xor     a
                jp      process_file
.no_dflt
                dec     a
                jr      z,.chksum_arg
                ; FILES mode -- go to .chksum_arg
.no_files
                dec     a
                jr      nz,.no_check
                ;CHECK mode
                call    process_list
                ret
.no_check
                jp      error_exit



.arg_help       ;print help, exit
                ld      hl,help_msg1
                call    prtext
                ld      hl,[name_ptr]
                call    prtext
                ld      hl,help_msg2
                call    prtext
                ld      hl,CS_NAME
                call    prtext
                ld      hl,help_msg3
                call    prtext
                jr      successful_exit


.arg_chk        ;check mode

                ld      a,AST_CHK
                ld      [argp_state],a
                ret




process_list:   ;argument = filename, open it, read crcs and filenames, check

                ;open file by name
                ;
                ld      de,[curr_arg]
                OS_OPENHANDLE
                ;b - handle, a!=0 - error
                or      a
                jp      nz,.error_open
                ld      a,b
                ld      [list_hndl],a

                ;initialize getc/ungetc state
                xor     a
                ld      [lpush],a       ;nothing ungetc'ed
                ld      h,a
                ld      l,a
                ld      [lsz],hl        ;nothing in buffer



                ;main loop: FSM to parse the file with checksums and filenames.
                ;format:
                ;
                ;<BOL>XXXXXXXX<space><space><filename><EOL>
                ;
                ;<BOL> -- not a real symbol, just an indication that this is the beginning of line
                ;XXXXXXXX -- checksum in hex, must be of predefined length (8 for CRC32)
                ;<space> -- 0x20
                ;<filename> -- file that will be attempted to open.
                ;<EOL> -- <crlf> or <cr> or <lf>, last line from file is not obliged to end with these

.new_line
                ;check for EOF
                call    my_getc
                jr      nc,.have_bytes

.full_end       ;correct end of the file
                ld      a,[list_hndl]
                ld      b,a
                OS_CLOSEHANDLE
                ret

.have_bytes     call    my_ungetc

                ;parse checksum
                ld      b,CS_SYMLEN
                ld      hl,CHKSUM
.chksum_loop
                call    my_getc
                jp      c,.line_unexp_end
                call    is_hex
                jp      c,.line_format_error

                ld      [hl],a
                inc     hl
                djnz    .chksum_loop
                ld      [hl],0

                ;parse >=1 spaces
                call    my_getc
                jr      c,.line_unexp_end2
                cp      ' '
                jr      nz,.line_format_error
.chkspc_loop
                call    my_getc
.line_unexp_end2
                jr      c,.line_unexp_end
                cp      ' '
                jr      z,.chkspc_loop
                call    my_ungetc



                ;parse filepath/name
                ld      b,MAXPATH_sz&255 ;now it is 256
                ld      hl,FNAME
.chkfname_loop
                call    my_getc
                jr      c,.line_last_end
                cp      ' '     ;space -- end of path/fname
                jr      z,.end_fname
                cp      13      ;13 or 10 -- end of path/fname
                jr      z,.end_fname
                cp      10
                jr      z,.end_fname
               
                ld      [hl],a
                inc     hl
                djnz    .chkfname_loop
                ld      [hl],0

                ;check whether there's more in input stream
                call    my_getc
                jr      c,.line_last_end
                cp      ' '
                jr      z,.end_fname
                cp      13
                jr      z,.end_fname
                cp      10
                jr      z,.end_fname

.fname_error    ;if path/filename seems to be greater than MAXPATH_sz or zero-sized
                jr      $       ;STUB

.line_last_end  ;here if EOF condition while parsing '-c filename'
                ld      [hl],0

                ;check for zero-length path/filename
                exd    
                ld      hl,FNAME
                or      a
                sbc     hl,de
                exd
                jr      z,.fname_error
                jr      .no_errs

.end_fname
                call    my_ungetc       ;return space/13/10 to the input stream;
                                        ;will be used later as to look for a new line
               
                ;check for zero-length path/filename
                exd
                ld      hl,FNAME
                or      a
                sbc     hl,de
                exd
                jr      z,.fname_error

                ;no errors here
.no_errs        ;hl=FNAME
                ld      [hl],0
                ld      hl,FNAME
                ld      a,1
                call    process_file

.skip_line      ;scan till end of filename/whatever, skip extra spaces/etc., skip line end
                call    my_getc
                jp      c,.full_end
                cp      13
                jr      z,.eol_13
                cp      10
                jr      nz,.skip_line
.eol_10
                jr      .new_line2
.eol_13
                call    my_getc
                cp      10
                jr      z,.new_line2
                call    my_ungetc
.new_line2
                jp      .new_line



.line_format_error
.line_unexp_end
                ld      hl,[name_ptr]
                call    prtext
                ld      hl,name_to_file
                call    prtext
                ld      hl,[curr_arg]
                call    prtext
                ld      hl,format_error
                jr      .prtext2



.error_open
                ld      hl,[name_ptr]
                call    prtext
                ld      hl,name_to_file
                call    prtext
                ld      hl,[curr_arg]
                call    prtext
                ld      hl,file_error
.prtext2
                jp      prtext





my_getc:        ;get a symbol from list_hdnl:lptr:lsz:etc. construction
                ;
                ;out: A - symbol
                ;     cy=1 - no more symbols or error

                ld      a,[lpush]       ;was smth ungetc'ed?
                or      a
                jr      z,.no_ununget
                ;
                xor     a
                ld      [lpush],a
                ld      a,[lpbyte]      ;if was, getc it back
                ret
.no_ununget
                push    hl
                ld      hl,[lsz]
                ld      a,h
                or      l
                jr      z,.buf_empty    ;smth in the buffer?
.no_ununget2
                dec     hl              ;get from buffer
                ld      [lsz],hl
                ld      hl,[lptr]
                ld      a,[hl]
                inc     hl
                ld      [lptr],hl
                pop     hl
                ret
.buf_empty
                push    ix              ;was nothing in buffer, read from file
                push    iy
                push    bc
                push    de
               
                ld      a,[list_hndl]
                ld      b,a
                ld      de,LISTBUF
                ld      [lptr],de
                ld      hl,LISTBUFsz
                OS_READHANDLE
                ;currently there's only single indication of both error and EOF:
                ; HL=0, A!=0
.noerr
                ld      a,h
                or      l
                ld      [lsz],hl
               
                pop     de
                pop     bc
                pop     iy
                pop     ix
               
                jr      nz,.no_ununget2
.nothing_more
                pop     hl
                scf
                ret



my_ungetc:      ;'ungetc' a symbol (there can be only a single ungot symbol!)
                ;in: A - symbol

                push    af
                ld      a,[lpush]
                or      a
                jr      nz,$
                inc     a
                ld      [lpush],a
                pop     af
                ld      [lpbyte],a
                ret



is_hex:         ;check that A is hex, i.e. [0-9][A-F][a-f]
                ;in: A
                ;out: cy=1: *NOT* hex. A is saved

                cp      '0'
                ret     c
                cp      '9'+1
                ccf
                ret     nc

                cp      'A'
                ret     c
                cp      'F'+1
                ccf
                ret     nc
               
                cp      'a'
                ret     c
                cp      'f'+1
                ccf
                ret


process_file:   ;hl - asciiz filename
                ;a  - mode, 0 print, 1 check

                ld      [.mode+1],a
                ld      [file_name],hl

                ;in mode 0 (print CRCs), the name '-'
                ; is treated as stdin
                or      a
                jr      nz,.dofile

                ld      de,stdin_arg
                call    strcmp
                jr      nz,.dofile

                ;get STDIN
                OS_GETSTDINOUT
                ld      a,e
                ld      [file_hndl],a
                jr      .dohandle
.dofile
                ld      de,[file_name]
                OS_OPENHANDLE
                or      a
                jp      nz,.file_error
                ld      a,b
                ld      [file_hndl],a
.dohandle
                call    CS_START

.readloop0
        ld de,DISKBUF
        ld hl,DISKBUFsz
;de=buf
;hl=size
        ld      a,[file_hndl]
        ld      b,a
        OS_READHANDLE
        ;no difference between EOF and error in nedoos, so always treat as an EOF
        ld a,h
        or l
        jr z,.closequit
        ld b,h
        ld c,l
       
        ;BC -- size
        ld      hl,DISKBUF
        call    CS_APPEND

        jr      .readloop0
.closequit
                ld      a,[file_hndl]
                ld      b,a
                OS_CLOSEHANDLE


                ld      hl,CALCSUM
                push    hl
                call    CS_FINALIZE


.mode           ld      a,#2E
                or      a

                jr      z,.print

                ;compare: first print filename
                ld      hl,[file_name]
                call    prtext
                ld      hl,txtcds
                call    prtext

                pop     hl
                ld      de,CHKSUM
                call    strcasecmp

                ld      hl,txtOK
                jr      z,.nofail
                ld      hl,txtFAIL
.nofail
                jr      .prtext
.print
                pop     hl
                call    prtext

                ld      hl,txtdblspc
                call    prtext

                ld      hl,[curr_arg]
                call    prtext

                ld      hl,txtcrlf
                jr      .prtext

.file_error
                ld      hl,[file_name]
                call    prtext
                ld      hl,file_error
.prtext
                jp      prtext



fatal_err:              ; fatal error so that we can't print even error message
                ld      hl,2
                QUIT



got_no_args:    ; no args given, print short help
       
                ld      hl,[name_ptr]
                push    hl
                call    prtext
                ld      hl,noargs_msg1
                call    prtext
                pop     hl
                call    prtext
                ld      hl,noargs_msg2
                call    prtext
error_exit:
                ld      hl,1
                QUIT


noargs_msg1:    db      ": no args given",13,10
                db      "Try '",0
noargs_msg2:    db      " -h' for more information",13,10,0

help_msg1:      db      "CRC rev."

SV=SVNREVISION+1
BEG=$
        WHILE   SV>0
                db      '0'+(SV%10)
SV=SV/10
        ENDW
CONTINUE=$
END=$-1
        WHILE   BEG<END
V1={b BEG}
V2={b END}
        org     BEG
        db      V2
        org     END
        db      V1
BEG=BEG+1
END=END-1
        ENDW

                org     CONTINUE
                db      13,10

                db      "Usage: ",0
help_msg2:      db      " [OPTION] [FILE]...",13,10
                db      "Print ",0
help_msg3:      db      " checksums.",13,10,13,10
                db      "When filename is -, read standard input.",13,10
                db      "Options:",13,10
                db      "  -c   read checksums from the FILE(s) (but not stdin) and check them.",13,10
                db      "       file format: ^<CHKSUM><spaces><filename><EOL>",13,10
                db      "  -h   display this help and exit",13,10
                db      13,10
                db      0

stdin_arg:      db      "-",0
help_arg:       db      "-h",0
chk_arg:        db      "-c",0

txtcds:         db      ":"     ;colon, double space
txtdblspc:      db      "  ",0
txtcrlf:        db      13,10,0

txtOK:          db      "OK!",13,10,0
txtFAIL:        db      "fail!",13,10,0

file_error:     db      ": Error opening or reading file",13,10,0
format_error:   db      ": File format error",13,10,0

name_to_file:   db      ": ",0



strcmp:         ;compare strings pointed by HL and DE, case-sensitive.
                ;in: hl, de -- ptr to asciiz,
                ;out: Z,NC if equal, NZ,NC if str(DE)>str(HL), NZ,C if str(DE)<str(HL)
                ;kills: af,de,hl
                ;
                ld      a,[hl]
                or      a
                ld      a,[de]
                jr      z,.lastcmp
                or      a
                jr      z,.lastcmp
               
                cp      [hl]
                inc     hl
                inc     de
                jr      z,strcmp
                ret
.lastcmp
                cp      [hl]
                ret

strcasecmp:     ;same as strcmp, but english letters are compared without case
                ;kills: af,bc,de,hl

                ld      c,'a'
.loop
                ld      a,[hl]
                or      a
                jr      z,.hl_zero

                cp      c       ;'a'
                jr      c,.hl_nonlower
                cp      'z'+1
                jr      nc,.hl_nonlower
                sub     'a'-'A'
.hl_nonlower
                ld      b,a

                ld      a,[de]
                or      a
                jr      z,.de_zero

                cp      c       ;'a'
                jr      c,.de_nonlower
                cp      'z'+1
                jr      nc,.de_nonlower
                sub     'a'-'A'
.de_nonlower
                cp      b
                inc     hl
                inc     de
                jr      z,.loop
                ret
.hl_zero
                ld      a,[de]
                cp      [hl]    ;cp 0
                ret
.de_zero
                cp      b
                ret






skipword
;hl=string
;out: hl=terminator/space addr
getword0
        ld a,(hl)
        or a
        ret z
        cp ' '
        ret z
        inc hl
        jr getword0

skipspaces
;hl=string
;out: hl=after last space
        ld a,(hl)
        cp ' '
        ret nz
        inc hl
        jr skipspaces


prtext
        ld a,(hl)
        or a
        ret z
        push hl
        push iy
        PRCHAR_
        pop iy
        pop hl
        inc hl
        jr prtext
       


name_ptr:       dw      0
curr_arg:       dw      0
file_name:      dw      0
argp_state:     db      0

file_hndl:      db      0
list_hndl:      db      0

lpush:          db      0
lpbyte:         db      0
lptr:           dw      0
lsz:            dw      0





        include "../_sdk/file.asm"
        include "../_sdk/stdio.asm"

CALCSUM ds      CS_SYMLEN+1     ;checksum calculated by algorithm

CHKSUM  ds      CS_SYMLEN+1     ;checksum to check, taken from '-c filename' file
FNAME   ds      MAXPATH_sz+1    ;file/path to check, taken from '-c filename' file

        IFNDEF  MODULE
        define  MODULE "crc.asm"
        ENDIF
        include MODULE ;"crc.asm"

cmd_end

        display "Size ",/d,cmd_end-cmd_begin," bytes"

        IFNDEF  OUTFNAME
        define  OUTFNAME "crc.com"
        ENDIF
        savebin OUTFNAME,cmd_begin,cmd_end-cmd_begin
       
;;      LABELSLIST "../../us/user.l"