;; Copyright (c) 1999, 2000, 2001, 2002, 2005 Michael Stumpf
;; All rights reserved.
;;
;; Redistribution and use in source and binary forms, with or without
;; modification, are permitted provided that the following conditions are met:
;;
;; * Redistributions of source code must retain the above copyright
;;   notice, this list of conditions and the following disclaimer.
;; * Redistributions in binary form must reproduce the above copyright
;;   notice, this list of conditions and the following disclaimer in
;;   the documentation and/or other materials provided with the
;;   distribution.
;; * Neither the name of the copyright holders nor the names of
;;   contributors may be used to endorse or promote products derived
;;   from this software without specific prior written permission.
;;
;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
;; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
;; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
;; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
;; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
;; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
;; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
;; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
;; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
;; POSSIBILITY OF SUCH DAMAGE.

;; $Id: ctype.S 1944 2009-04-01 23:12:20Z arcanum $

#if !defined(__DOXYGEN__)

#include "gasava.inc"
#include "macros.inc"
;================================================================================
; ctype.s
;
; Character handling - ctype.h
;
; Author : Michael Stumpf  (c) 1999
;          Michael.Stumpf@t-online.de
;
; Versions : V0.1.0
;
; adapted to avr-as
;          Michael Rickmann, Feb. 2000
;          **changed**: changes to code
;
; int isalnum(int c)      Letter or digit equality.
; int isalpha(int c)      Letter equality.
; int iscntrl(int c)      Control code equality.
; int isdigit(int c)      Digit equality.
; int isgraph(int c)      Printable non-space character equality.
; int islower(int c)      Lower case equality.
; int isprint(int c)      Printable character equality.
; int ispunct(int c)      Punctuation character equality.
; int isspace(int c)      White-space character equality.
;
; int isupper(int c)      Upper case equality.
; int isxdigit(int c)     Hex digit equality.
; int tolower(int c)      Converts to lower case.
; int toupper(int c)      Converts to upper case.
; int isblank(int c)      Blank-space character test.
;
; realized as functions, not as macro with a 256 - byte large bit-table
;
; gives a total of 182 bytes code and short function calls
;
;================================================================================

#define rHigh    rP0
#define rLow     rP1

#if defined (Lisascii)
          ASSEMBLY_CLIB_SECTION
          FUNCTION(isascii)

GLOBAL(isascii)
          CPSE    rHigh,__zero_reg__
          RJMP    _U(__ctype_isfalse)
          COM     rLow
          ANDI    rLow, 0x80
          RET

          ENDFUNC
#endif

#if defined (Ltoascii)
          ASSEMBLY_CLIB_SECTION
          FUNCTION(toascii)

GLOBAL(toascii)
          CLR     rHigh
          ANDI    rLow, 0x7F
          RET

          ENDFUNC
#endif

#if defined (Lisalnum)
          ASSEMBLY_CLIB_SECTION
          FUNCTION(isalnum)

GLOBAL(isalnum)
	cpse	rHigh, __zero_reg__
	rjmp	_U(__ctype_isfalse)
	subi	rLow, '0'
	subi	rLow, '9'-'0'+1
	brlo	2f			; rLow is digit, return negative val.
	subi	rLow, lo8(-'9'-1)	; restore rLow
	rjmp	_U(isalpha)
2:	ret

          ENDFUNC
#endif

#if defined (Lcty_isfalse)
          ASSEMBLY_CLIB_SECTION
          FUNCTION(__ctype_isfalse)

GLOBAL(__ctype_isfalse)
          CLR   rHigh
          CLR   rLow
GLOBAL(__ctype_istrue)
          RET

          ENDFUNC
#endif

;-------------------------------------------------------------------

#if defined (Lisalpha)
          ASSEMBLY_CLIB_SECTION
          FUNCTION(isupper)

GLOBAL(isupper)
          ;CPSE  rHigh,__zero_reg__
          ;RJMP  _U(__ctype_isfalse)    ; checked by _islower later on
          SBRC  rLow,5       ; if bit 5 is set it is no upper
          RJMP  _U(__ctype_isfalse)     ; bit 5 is clear, so if isalpha is true it is an upper
GLOBAL(isalpha)
          ORI     rLow,0x20        ; make a lower out of an upper (all others are changed but do not get alpha)
GLOBAL(islower)
          CPSE  rHigh,__zero_reg__
1:
          RJMP  _U(__ctype_isfalse)
          SUBI	rLow, 'a'
          SUBI	rLow, 'z'-'a'+1
          BRSH	1b
          RET			; TRUE: rLow is in -26..-1

          ENDFUNC
#endif

;-------------------------------------------------------------------

#if defined (Lisdigit)
          ASSEMBLY_CLIB_SECTION
          FUNCTION(isdigit)

GLOBAL(isdigit)
          CPSE  rHigh,__zero_reg__
1:        
          RJMP  _U(__ctype_isfalse)
          SUBI  rLow,'0'
          SUBI  rLow,10
          BRSH  1b
          RET                      ; rLow: -10..-1

          ENDFUNC
#endif

;-------------------------------------------------------------------

#if defined (Lisxdigit)
          ASSEMBLY_CLIB_SECTION
          FUNCTION(isxdigit)

; This fact is used below.
.if	'a' - 'A' - 0x20
  .err
.endif

GLOBAL(isxdigit)
	cpse	rHigh, __zero_reg__
1:	rjmp	_U(__ctype_isfalse)
	subi	rLow, '0'
	subi	rLow, '9'-'0'+1
	brlo	2f			; decimal digit
	subi	rLow, lo8(-'9'-1)	; restore rLow
	ori	rLow, 'a' - 'A'		; rLow := tolower(rLow)
	subi	rLow, 'a'
	subi	rLow, 'f'-'a'+1
	brsh	1b
2:	ret				; OK: return a negative value

          ENDFUNC
#endif

;-------------------------------------------------------------------

#if defined (Liscntrl)
          ASSEMBLY_CLIB_SECTION
          FUNCTION(iscntrl)

GLOBAL(iscntrl)
          CPSE  rHigh,__zero_reg__
1:
          RJMP  _U(__ctype_isfalse)
          CPI   rLow,0x7F
          BREQ  2f
          SUBI  rLow, ' '
          BRSH  1b		; iscntrl('\0') --> true
2:
          RET			; TRUE: rLow is 0x7F or negative value

          ENDFUNC
#endif

;-------------------------------------------------------------------

#if defined (Lisprint)
          ASSEMBLY_CLIB_SECTION
          FUNCTION(isgraph)

GLOBAL(isgraph)
          CPI   rLow,' '
          BREQ  1f
GLOBAL(isprint)
	  CPSE	rHigh, __zero_reg__
1:	  RJMP	_U(__ctype_isfalse)
	  SUBI	rLow, ' '
	  SUBI	rLow, 0x7E - ' ' + 1
	  BRSH	1b
	  RET			; TRUE: rlow is negative value

          ENDFUNC
#endif

;-------------------------------------------------------------------

#if defined (Lisspace)
          ASSEMBLY_CLIB_SECTION
          FUNCTION(isspace)

/* This fact is used below.	*/
.if	('\t'-9) | ('\n'-10) | ('\f'-12) | ('\r'-13)	; '\v' is 11
  .err
.endif

GLOBAL(isspace)
          CPSE  rHigh,__zero_reg__
1:
          RJMP  _U(__ctype_isfalse)
          CPI   rLow,' '           ; blank
          BREQ  2f
	  SUBI	rLow, '\t'
	  SUBI	rLow, '\r'-'\t'+1
	  BRSH	1b
2:	  RET			; TRUE result: rLow is -5..-1 or ' '

          ENDFUNC
#endif

;-------------------------------------------------------------------

#if defined (Lispunct)
          ASSEMBLY_CLIB_SECTION
          FUNCTION(ispunct)

GLOBAL(ispunct)
	cpse	rHigh, __zero_reg__
1:	rjmp	_U(__ctype_isfalse)
	subi	rLow, ' ' + 1
	subi	rLow, 0x7e - ' '
	brsh	1b			; if (!isgraph(c)) return 0
	subi	rLow, lo8(-0x7e - 1)	; restore rLow
	rcall	_U(isalnum)
	tst	rLow
	brne	1b			; if (isalnum(c)) return 0
	ldi	rLow, 1
	ret

          ENDFUNC
#endif

;-------------------------------------------------------------------

#if defined (Lisblank)
          ASSEMBLY_CLIB_SECTION
          FUNCTION(isblank)

GLOBAL(isblank)
          CPSE  rHigh,__zero_reg__
1:
          RJMP  _U(__ctype_isfalse)
          CPI   rLow,' '           ; blank
          BREQ  2f
          CPI   rLow,0x09    ;'\t' ; tab
          BRNE  1b
2:
          RET

          ENDFUNC
#endif

;-------------------------------------------------------------------

#if defined (Ltolower)
          ASSEMBLY_CLIB_SECTION
          FUNCTION(tolower)

GLOBAL(tolower)
	cpse	rHigh, __zero_reg__
	ret				; return as is
	subi	rLow, 'A'
	subi	rLow, 'Z'-'A'+1
	brsh	1f			; return as is
	subi	rLow, lo8('A'-'a')	; conversion
1:	subi	rLow, lo8(-'Z'-1)	; restore
	ret

          ENDFUNC
#endif

;-------------------------------------------------------------------

#if defined (Ltoupper)
          ASSEMBLY_CLIB_SECTION
          FUNCTION(toupper)

GLOBAL(toupper)
	cpse	rHigh, __zero_reg__
	ret				; return as is
	subi	rLow, 'a'
	subi	rLow, 'z'-'a'+1
	brsh	1f			; return as is
	subi	rLow, lo8('a'-'A')	; conversion
1:	subi	rLow, lo8(-'z'-1)	; restore
	ret

          ENDFUNC
#endif

#endif /* not __DOXYGEN__ */
