;
; ATTRIB.ASM - Sample API using menu functions.
;
; Fox Software System's Group
;
; Copyright (c) 1991 Fox Software, Inc.
; 134 W. South Boundary
; Perrysburg, Ohio  43551
;
; Description:
;   Change the DOS attributes of a file.  From FoxPro:
;
;        memvar = attrib( <expC1> + " " + <expC2> )
;
;   where <expC2> is a file specification.  <expC1> specifies the
;   desired attributes in the form +|-<attrib>[+|-<attrib>] where
;   <attrib> is R|S|H|A (not case sensitive).  If two contradictory
;   specs are given, e.g. "+a -a", the set ("+") attribute takes
;   precedence.
;
;   Returns 0 if successful.  Return of -1 indicates a parsing error.
;   Any other value is a DOS error number.
;

            .MODEL large
            .STACK 0 ; need no stack of our own

            INCLUDE pro_ext.inc

            .CODE

attrib PROC FAR
;
;   void far attrib(ParamBlk far * parm);
;		    DX:AX
;
            FarEnter

            push    ds
            push    bx
            push    cx
;
;   dx:ax := FoxToC(&parm->p[0].val);  /* add terminating '\0' */
;
            add     ax, 2+sizeof_Parameter*0
            call   FoxToC
;
;   ds:dx = parse(dx:ax)
;
            call    parse

            cmp     bx, 0
            jne     ENDIF_01

            mov     ax, -1                  ; _RetInt(-1, 10)
            cwd
            mov     bx, 10
            call    _RetInt

            jmp     ATTRIB_RET
ENDIF_01:
            mov     ax, 4300h               ; DOS get attributes
            int     21h

            jnc     short ENDIF_02          ; carry means DOS error
THEN_03:
            mov     bx, 10
            call    _RetInt_

            jmp     ATTRIB_RET
ENDIF_02:
            not     bh
            and     cl, bh                  ; reset attributes
            or      cl, bl                  ;  set attributes

            mov     ax, 4301h               ; DOS set attributes
            int     21h

            jc      THEN_03

            xor     ax, ax                  ; _RetInt(0, 10) -- A-OK
            xor     dx, dx
            mov     bx, 10
            call    _RetInt
ATTRIB_RET:
            pop     cx
            pop     bx
            pop     ds

            FarExit
            ret
attrib      ENDP

FoxToC PROC NEAR
;
;   char far * FoxToC(Value far * FoxString);
;   DX:AX	      DX:AX
;
            FarEnter

            push    ds
            push    bx
;
;   if (!_SetHandSize(FoxString->ev_handle, FoxString->length+1))
;
            mov     ds, dx              ; ds:bx := Value far * FoxString
            mov     bx, ax

            mov     ax, [bx.ev_handle]  ; ax := FoxString->ev_handle
            mov     dx, [bx.ev_length]  ; dx := FoxString->ev_length+1
            inc     dx
            call    _SetHandSize

            test    ax, ax
            jne     short ENDIF_00

            mov     ax, 182             ; "Insufficient memory"
            call    _Error

ENDIF_00:
;
;   dx:ax := _HandToPtr(FoxString->ev_handle)
;
            mov     ax, [bx.ev_handle]
            call    _HandToPtr
;
;   string[FoxString->length] = '\0';
;
            mov     bx, [bx.ev_length]
            add     bx, ax
            mov     ds, dx
            mov     byte ptr [bx], 0

            pop     bx
            pop     ds

            FarExit
            ret
FoxToC      ENDP


parse PROC  NEAR
;
;   char far * Parse(char far * string, reset_attrib, set_attrib);
;   DS:DX            DX:AX              BH            BL
;
;   Returns pointer to beginning of file spec within string.
;   If any error is detected BH and BL will both be 0. DF cleared.
;
            push    si

            mov     ds, dx          ; ds:si := string
            mov     si, ax

            mov     bl, 0           ; clear   set attributes
            mov     bh, 0           ; clear reset attributes

            cld

            ALIGN 2
WHILE:
            lodsb                   ; ax := [ds:si], si++

            cmp     al, 0
            jne     short NOT_EOS

            mov     bl, 0           ; end of string is an error
	    mov     bh, 0

            jmp     PARSE_RET
NOT_EOS:
            cmp     al, '+'
            je      NOT_FILE
            cmp     al, '-'
            je      NOT_FILE
            cmp     al, ' '
            je      WHILE

            dec     si
            jmp     PARSE_RET       ; have reached file spec
NOT_FILE:
            mov     ah, al          ; ah := '+' or '-'

            lodsb

            cmp     al, 'a'         ; al := toupper(al)
	    jl	    case_R
            sub     al, 'a' - 'A'
case_R:
            cmp     al, 'R'
	    jne     case_H
            cmp     ah, '+'
	    jne     minus_R
	    or	    bl, 01h
            jmp     WHILE
minus_R:
            or      bh, 01h
            jmp     WHILE
case_H:
            cmp     al, 'H'
	    jne     case_S
            cmp     ah, '+'
	    jne     minus_H
	    or	    bl, 02h
            jmp     WHILE
minus_H:
            or      bh, 02h
            jmp     WHILE
case_S:
            cmp     al, 'S'
	    jne     case_A
            cmp     ah, '+'
	    jne     minus_S
	    or	    bl, 04h
            jmp     WHILE
minus_S:
            or      bh, 04h
            jmp     WHILE
case_A:
            cmp     al, 'A'
	    je	    is_A

	    mov     bl, 0
	    mov     bh, 0
            jmp     PARSE_RET
is_A:
            cmp     ah, '+'
	    jne     minus_A
	    or	    bl, 20h
            jmp     WHILE
minus_A:
            or      bh, 20h
            jmp     WHILE
PARSE_RET:
            mov     dx, si
            pop     si

            ret
parse       ENDP
            .DATA

            PUBLIC  _myFoxInfo
            PUBLIC  __FoxTable

attrib_name	DB "ATTRIB", 0
attrib_parms	DB "C", 0

_myFoxInfo      FoxInfo <attrib_name, attrib, 1, attrib_parms>

sizeof_myFoxInfo = $ - _myFoxInfo

__FoxTable      FoxTable <0, sizeof_myFoxInfo/(TYPE FoxInfo), _myFoxInfo>

            END