(********************************************************************)
(*                                                                  *)
(*  char.s7i      Char support library                              *)
(*  Copyright (C) 1989 - 2011  Thomas Mertes                        *)
(*                                                                  *)
(*  This file is part of the Seed7 Runtime Library.                 *)
(*                                                                  *)
(*  The Seed7 Runtime Library is free software; you can             *)
(*  redistribute it and/or modify it under the terms of the GNU     *)
(*  Lesser General Public License as published by the Free Software *)
(*  Foundation; either version 2.1 of the License, or (at your      *)
(*  option) any later version.                                      *)
(*                                                                  *)
(*  The Seed7 Runtime Library is distributed in the hope that it    *)
(*  will be useful, but WITHOUT ANY WARRANTY; without even the      *)
(*  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR *)
(*  PURPOSE.  See the GNU Lesser General Public License for more    *)
(*  details.                                                        *)
(*                                                                  *)
(*  You should have received a copy of the GNU Lesser General       *)
(*  Public License along with this program; if not, write to the    *)
(*  Free Software Foundation, Inc., 51 Franklin Street,             *)
(*  Fifth Floor, Boston, MA  02110-1301, USA.                       *)
(*                                                                  *)
(********************************************************************)


(**
 *  The type ''char'' describes Unicode characters encoded with UTF-32.
 *  A ''char'' can also contain values, which are not Unicode, like EOF.
 *)
const type: char           is subtype DISCRETE;


$ system "char" is char;
IN_PARAM_IS_VALUE(char);

const proc: destroy (ref char: aValue)                        is action "GEN_DESTR";
const proc: (ref char: dest) ::= (in char: source)            is action "CHR_CREATE";
const proc: (inout char: dest) := (in char: source)           is action "CHR_CPY";


(**
 *  Default value of ''char'' (' ').
 *)
const char: (attr char) . value is ' ';


(**
 *  Minimum value of ''char''.
 *)
const char: (attr char) . first is '\0;';


(**
 *  Maximum value of an Unicode character.
 *)
const char: (attr char) . last  is '\16#10ffff;';


(**
 *  Check if two characters are equal.
 *  @return TRUE if both characters are equal,
 *          FALSE otherwise.
 *)
const func boolean: (in char: ch1) = (in char: ch2)           is action "CHR_EQ";


(**
 *  Check if two characters are not equal.
 *  @return FALSE if both characters are equal,
 *          TRUE otherwise.
 *)
const func boolean: (in char: ch1) <> (in char: ch2)          is action "CHR_NE";


(**
 *  Check if ch1 is less than ch2.
 *  @return TRUE if ch1 is less than than ch2,
 *          FALSE otherwise.
 *)
const func boolean: (in char: ch1) < (in char: ch2)           is action "CHR_LT";


(**
 *  Check if ch1 is greater than ch2.
 *  @return TRUE if ch1 is greater than ch2,
 *          FALSE otherwise.
 *)
const func boolean: (in char: ch1) > (in char: ch2)           is action "CHR_GT";


(**
 *  Check if ch1 is less than or equal to ch2.
 *  @return TRUE if ch1 is less than or equal to ch2,
 *          FALSE otherwise.
 *)
const func boolean: (in char: ch1) <= (in char: ch2)          is action "CHR_LE";


(**
 *  Check if ch1 is greater than or equal to ch2.
 *  @return TRUE if ch1 is greater than or equal to ch2,
 *          FALSE otherwise.
 *)
const func boolean: (in char: ch1) >= (in char: ch2)          is action "CHR_GE";


(**
 *  Compare two characters.
 *  @return -1, 0 or 1 if the first argument is considered to be
 *          respectively less than, equal to, or greater than the
 *          second.
 *)
const func integer: compare (in char: ch1, in char: ch2)      is action "CHR_CMP";


(**
 *  Compute the hash value of a character.
 *  @return the hash value.
 *)
const func integer: hashCode (in char: ch)                    is action "CHR_HASHCODE";


(**
 *  Get the ordinal number of a character.
 *  For Unicode characters a value between 0 and 1114111 is returned.
 *  For cursor and function keys a value between 1114112 and 1114500
 *  is returned. For EOF the value -1 is returned.
 *  @return the ordinal number of a character.
 *)
const func integer: ord (in char: ch)                         is action "CHR_ORD";


(**
 *  Get the ordinal number of a character.
 *  For Unicode characters a value between 0 and 1114111 is returned.
 *  For cursor and function keys a value between 1114112 and 1114500
 *  is returned. For EOF the value -1 is returned.
 *  @return the ordinal number of a character.
 *)
const func integer: integer (in char: ch)                     is action "CHR_ORD";


(**
 *  Convert an [[integer]] number to a character.
 *  For values between 0 and 1114111 a Unicode character is returned.
 *  For values between 1114112 and 1114500  a cursor or function key
 *  is returned. For -1 the value EOF is returned.
 *  @return a character which corresponds to the given [[integer]].
 *  @exception RANGE_ERROR If the number does not fit into a 32-bit ''char''.
 *)
const func char: chr (in integer: number)                     is action "CHR_ICONV1";


(**
 *  Convert an [[integer]] number to a character.
 *  For values between 0 and 1114111 a Unicode character is returned.
 *  For values between 1114112 and 1114500 a cursor or function key
 *  is returned. For -1 the value EOF is returned.
 *  @return a character which corresponds to the given [[integer]].
 *  @exception RANGE_ERROR If the number does not fit into a 32-bit ''char''.
 *)
const func char: char (in integer: number)                    is action "CHR_ICONV1";


(**
 *  Convert an [[integer]] number to a character.
 *  For values between 0 and 1114111 a Unicode character is returned.
 *  For values between 1114112 and 1114500 a cursor or function key
 *  is returned. For -1 the value EOF is returned.
 *  @return a character which corresponds to the given [[integer]].
 *  @exception RANGE_ERROR If the number does not fit into a 32-bit ''char''.
 *)
const func char: (attr char) conv (in integer: number)        is action "CHR_ICONV3";


const varfunc char: (attr char) varConv (inout integer: number) is action "TYP_VARCONV";


(**
 *  Successor of a character.
 *  @return chr(ord(ch) + 1)
 *)
const func char: succ (in char: ch)                           is action "CHR_SUCC";


(**
 *  Predecessor of a character.
 *  @return chr(ord(ch) - 1)
 *)
const func char: pred (in char: ch)                           is action "CHR_PRED";


(**
 *  Create a string with one character.
 *  @return a string with the character ''ch''.
 *)
const func string: str (in char: ch)                          is action "CHR_STR";


(**
 *  Convert a character to upper case.
 *  The conversion uses the default Unicode case mapping,
 *  where each character is considered in isolation.
 *  Characters without case mapping are left unchanged.
 *  The mapping is independent from the locale. Individual
 *  character case mappings cannot be reversed, because some
 *  characters have multiple characters that map to them.
 *  @return the character converted to upper case.
 *)
const func char: upper (in char: ch)                          is action "CHR_UP";


(**
 *  Convert a character to lower case.
 *  The conversion uses the default Unicode case mapping,
 *  where each character is considered in isolation.
 *  Characters without case mapping are left unchanged.
 *  The mapping is independent from the locale. Individual
 *  character case mappings cannot be reversed, because some
 *  characters have multiple characters that map to them.
 *  @return the character converted to lower case.
 *)
const func char: lower (in char: ch)                          is action "CHR_LOW";


(**
 *  Determines if the specified character ''ch'' is a letter.
 *  A character is considered to be a letter if the category
 *  from the Unicode specification is any of the following:
 *  * UPPERCASE_LETTER (Lu)
 *  * LOWERCASE_LETTER (Ll)
 *  * TITLECASE_LETTER (Lt)
 *  * MODIFIER_LETTER  (Lm)
 *  * OTHER_LETTER     (Lo)
 *  Examples:
 *   isLetter('A')          returns TRUE
 *   isLetter('\16#4e2d;')  returns TRUE
 *   isLetter('4')          returns FALSE
 *   isLetter('+')          returns FALSE
 *   isLetter('\t')         returns FALSE
 *   isLetter(KEY_LEFT)     returns FALSE
 *   isLetter(EOF)          returns FALSE
 *  @return TRUE if ''ch'' is a letter,
 *          FALSE otherwise.
 *)
const func boolean: isLetter (in char: ch)                    is action "CHR_IS_LETTER";


(**
 *  Number of screen columns occupied by the Unicode character ''ch''.
 *  Non-spacing characters and control characters have width of 0.
 *   width('\n')         returns 0
 *   width('\t')         returns 0
 *   width(KEY_LEFT)     returns 0
 *   width(EOF)          returns 0
 *   width('A')          returns 1
 *   width('\16#4e2d;')  returns 2
 *  @return 0,1 or 2 depending on the width occupied on a terminal.
 *)
const func integer: width (in char: ch)                       is action "CHR_WIDTH";


(**
 *  Increment a character.
 *  This is equivalent to:
 *   ch := succ(ch);
 *)
const proc: incr (inout char: ch)                             is action "CHR_INCR";


(**
 *  Decrement a character.
 *  This is equivalent to:
 *   ch := pred(ch);
 *)
const proc: decr (inout char: ch)                             is action "CHR_DECR";


const func string: c_literal (in char: ch)                    is action "CHR_CLIT";


(**
 *  Compute pseudo-random character in the range [low, high].
 *  The random values are uniform distributed.
 *  @return a random character such that low <= rand(low, high) and
 *          rand(low, high) <= high holds.
 *  @exception RANGE_ERROR The range is empty (low > high holds).
 *)
const func char: rand (in char: low, in char: high) is
  return chr(rand(ord(low), ord(high)));


(**
 *  Character representing end-of-file.
 *  EOF is not an Unicode character.
 *)
const char: EOF is chr(-1);


(**
 *  Convert a [[string]] with a length of 1 to a character.
 *   char parse "a"   returns 'a'
 *   char parse " "   returns ' '
 *   char parse "aa"  raises RANGE_ERROR
 *   char parse "  "  raises RANGE_ERROR
 *   char parse ""    raises RANGE_ERROR
 *  @return the first character of the [[string]].
 *  @exception RANGE_ERROR If the length of the string is not 1.
 *)
const func char: (attr char) parse (in string: stri) is forward;


(**
 *  Convert a [[string]] with a length of 1 to a character.
 *   char("a")   returns 'a'
 *   char(" ")   returns ' '
 *   char("aa")  raises RANGE_ERROR
 *   char("  ")  raises RANGE_ERROR
 *   char("")    raises RANGE_ERROR
 *  @return the first character of the [[string]].
 *  @exception RANGE_ERROR If the length of the string is not 1.
 *)
const func char: char (in string: stri) is
    return char parse stri;


(**
 *  Trim a string such that it can be converted to ''char''.
 *   trimValue(char, " 1 ")             returns "1"
 *   trimValue(char, "   ")             returns " "
 *   trimValue(char, "\t ")             returns "\t"
 *   trimValue(char, "")                returns ""
 *   char parse trimValue(char, " 1 ")  returns '1'
 *   char parse trimValue(char, "   ")  returns ' '
 *   char parse trimValue(char, "\t ")  returns '\t'
 *   char parse trimValue(char, "")     raises RANGE_ERROR
 *  @return the trimmed string.
 *)
const func string: trimValue (attr char, in string: stri) is forward;


(**
 *  Conversion to a ''char'' literal.
 *  @return the character literal of ''ch''.
 *)
const func string: literal (in char: ch) is forward;


DECLARE_TERNARY(char);