(********************************************************************)
(*                                                                  *)
(*  bstring.s7i   Byte string support library                       *)
(*  Copyright (C) 1991 - 1994, 2004, 2005, 2012  Thomas Mertes      *)
(*                2014, 2018, 2019, 2021, 2022  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.                       *)
(*                                                                  *)
(********************************************************************)


include "bigint.s7i";


(**
 *  Type for byte strings.
 *)
const type: bstring is newtype;


IN_PARAM_IS_REFERENCE(bstring);

const proc: destroy (ref bstring: aValue)                               is action "BST_DESTR";
const proc: (ref bstring: dest) ::= (in bstring: source)                is action "BST_CREATE";
const proc: (inout bstring: dest) := (in bstring: source)               is action "BST_CPY";

const func bstring: _GENERATE_EMPTY_BSTRING                             is action "BST_EMPTY";


(**
 *  Default value of ''bstring'' (bstring("")).
 *)
const bstring: (attr bstring) . value                                   is _GENERATE_EMPTY_BSTRING;


(**
 *  Convert a ''bstring'' value to a [[string]].
 *  @return the [[string]] result of the conversion.
 *  @exception MEMORY_ERROR  Not enough memory to represent the result.
 *)
const func string: str (in bstring: bstri)                              is action "BST_STR";


(**
 *  Convert a ''bstring'' value to a ''bstring'' literal.
 *  @return the ''bstring'' literal.
 *  @exception MEMORY_ERROR  Not enough memory to represent the result.
 *)
const func string: literal (in bstring: bstri) is
    return "bstring(" & literal(str(bstri)) & ")";


(**
 *  Convert a ''bstring'' value to a [[string]].
 *  @return the [[string]] result of the conversion.
 *  @exception MEMORY_ERROR  Not enough memory to represent the result.
 *)
const func string: string (in bstring: bstri)                           is action "BST_STR";


(**
 *  Convert a [[string]] to a ''bstring'' value.
 *  @return the ''bstring'' result of the conversion.
 *  @exception RANGE_ERROR If characters beyond '\255;' are present.
 *  @exception MEMORY_ERROR  Not enough memory to represent the result.
 *)
const func bstring: bstring (in string: stri)                           is action "BST_PARSE1";


(**
 *  Convert a [[string]] to a ''bstring'' value.
 *  @return the ''bstring'' result of the conversion.
 *  @exception RANGE_ERROR If characters beyond '\255;' are present.
 *  @exception MEMORY_ERROR  Not enough memory to represent the result.
 *)
const func bstring: (attr bstring) parse (in string: stri) is
    return bstring(stri);


(**
 *  Get a character, identified by an index, from a ''bstring''.
 *  The first character has the index 1.
 *  @return the character specified with the index.
 *  @exception INDEX_ERROR If the index is less than 1 or
 *             greater than the length of the ''bstring''.
 *)
const func char: (in bstring: bstri) [ (in integer: index) ]            is action "BST_IDX";


(**
 *  Determine the length of a ''bstring''.
 *  @return the length of the ''bstring''.
 *)
const func integer: length (in bstring: bstri)                          is action "BST_LNG";


(**
 *  Check if two bstrings are equal.
 *  @return TRUE if both bstrings are equal,
 *          FALSE otherwise.
 *)
const func boolean: (in bstring: bstri1) = (in bstring: bstri2)         is action "BST_EQ";


(**
 *  Check if two bstrings are not equal.
 *  @return FALSE if both bstrings are equal,
 *          TRUE otherwise.
 *)
const func boolean: (in bstring: bstri1) <> (in bstring: bstri2)        is action "BST_NE";


(**
 *  Compare two bstrings.
 *  @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 bstring: bstri1, in bstring: bstri2)    is action "BST_CMP";


(**
 *  Compute the hash value of a ''bstring''.
 *  @return the hash value.
 *)
const func integer: hashCode (in bstring: bstri)                        is action "BST_HASHCODE";


(**
 *  For-loop which loops over the [[char|characters]] of a ''bstring''.
 *)
const proc: for (inout char: forVar) range (in bstring: bstri) do
              (in proc: statements)
            end for is func
  local
    var integer: number is 0;
  begin
    for number range 1 to length(bstri) do
      forVar := bstri[number];
      statements;
    end for;
  end func;


(**
 *  Convert a [[bstring]] (interpreted as big-endian) to a [[bigint|bigInteger]].
 *  @param bstri Bstring to be converted. The bytes are interpreted
 *         as binary big-endian representation with a base of 256.
 *  @param isSigned Defines if ''bstri'' is interpreted as signed value.
 *         If ''isSigned'' is TRUE the twos-complement representation
 *         is used. In this case the result is negative if the most
 *         significant byte (the first byte) has an ordinal >= 128.
 *  @return a bigInteger created from the big-endian bytes.
 *)
const func bigInteger: bStriBe2BigInt (in bstring: bstri,
    in boolean: isSigned)                                     is action "BIG_FROM_BSTRI_BE";


(**
 *  Convert a [[bstring]] (interpreted as little-endian) to a [[bigint|bigInteger]].
 *  @param bstri Bstring to be converted. The bytes are interpreted
 *         as binary little-endian representation with a base of 256.
 *  @param isSigned Defines if ''bstri'' is interpreted as signed value.
 *         If ''isSigned'' is TRUE the twos-complement representation
 *         is used. In this case the result is negative if the most
 *         significant byte (the last byte) has an ordinal >= 128.
 *  @return a bigInteger created from the little-endian bytes.
 *)
const func bigInteger: bStriLe2BigInt (in bstring: bstri,
    in boolean: isSigned)                                     is action "BIG_FROM_BSTRI_LE";


(**
 *  Convert a [[bigint|bigInteger]] into a big-endian [[bstring]].
 *  The result uses binary representation with a base of 256.
 *  @param number BigInteger number to be converted.
 *  @param isSigned Determines the signedness of the result.
 *         If ''isSigned'' is TRUE the result is encoded with the
 *         twos-complement representation. In this case a negative
 *         ''number'' is converted to a result where the most significant
 *         byte (the first byte) has an ordinal >= 128.
 *  @return a bstring with the big-endian representation.
 *  @exception RANGE_ERROR If ''number'' is negative and ''isSigned'' is FALSE.
 *  @exception MEMORY_ERROR Not enough memory to represent the result.
 *)
const func bstring: bStriBe (in bigInteger: number,
    in boolean: isSigned)                                     is action "BIG_TO_BSTRI_BE";


(**
 *  Convert a [[bigint|bigInteger]] into a little-endian [[bstring]].
 *  The result uses binary representation with a base of 256.
 *  @param number BigInteger number to be converted.
 *  @param isSigned Determines the signedness of the result.
 *         If ''isSigned'' is TRUE the result is encoded with the
 *         twos-complement representation. In this case a negative
 *         ''number'' is converted to a result where the most significant
 *         byte (the last byte) has an ordinal >= 128.
 *  @return a bstring with the little-endian representation.
 *  @exception RANGE_ERROR If ''number'' is negative and ''isSigned'' is FALSE.
 *  @exception MEMORY_ERROR Not enough memory to represent the result.
 *)
const func bstring: bStriLe (in bigInteger: number,
    in boolean: isSigned)                                     is action "BIG_TO_BSTRI_LE";


enable_io(bstring);
DECLARE_TERNARY(bstring);