(**************************************************************************)
(*                                                                        *)
(*  PMOS library                                                          *)
(*  Copyright (C) 2024   Peter Moylan                                     *)
(*                                                                        *)
(*  This program is free software: you can redistribute it and/or modify  *)
(*  it under the terms of the GNU General Public License as published by  *)
(*  the Free Software Foundation, either version 3 of the License, or     *)
(*  (at your option) any later version.                                   *)
(*                                                                        *)
(*  This program 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 General Public License for more details.                          *)
(*                                                                        *)
(*  You should have received a copy of the GNU General Public License     *)
(*  along with this program.  If not, see <http://www.gnu.org/licenses/>. *)
(*                                                                        *)
(*  To contact author:   http://www.pmoylan.org   peter@pmoylan.org       *)
(*                                                                        *)
(**************************************************************************)

DEFINITION MODULE VarStrings;

        (********************************************************)
        (*                                                      *)
        (*                Variable-length strings               *)
        (*                                                      *)
        (*  Programmer:         P. Moylan                       *)
        (*  Last edited:        6 October 2024                  *)
        (*  Status:             OK                              *)
        (*                                                      *)
        (********************************************************)


FROM SYSTEM IMPORT CARD8, LOC, ADDRESS;
FROM BigNum IMPORT BN;


TYPE
    VarStringPtr = POINTER TO ARRAY [0..65535] OF CHAR;
    CharStringPtr = POINTER TO ARRAY [0..65535] OF CHAR;
    ByteStringPtr = POINTER TO ARRAY [0..65535] OF CARD8;

    ByteStr = RECORD
                  allocated, size: CARDINAL;
                  data: ByteStringPtr;
              END;

    CharStr = RECORD
                  allocated, size: CARDINAL;
                  data: CharStringPtr;
              END;


PROCEDURE WriteVarString (VAR (*IN*) str: ARRAY OF CHAR;  N: CARDINAL);

    (* Write character string of length N to standard output.   *)
    (* Convention: we treat LF as the newline character, and    *)
    (* ignore any CR encountered.                               *)

PROCEDURE CopyOfBS (src: ByteStr): ByteStr;

    (* Creates and returns a copy of src.  *)

PROCEDURE CopyOfCS (src: CharStr): CharStr;

    (* Creates and returns a copy of src.  *)

PROCEDURE MakeBS (VAR (*INOUT*) A: ByteStr;  N: CARDINAL);

    (* Allocates enough space to hold N bytes.  *)

PROCEDURE MakeCS (VAR (*INOUT*) A: CharStr;  N: CARDINAL);

    (* Allocates enough space to hold N characters plus a trailing Nul. *)

PROCEDURE TrimBS (VAR (*INOUT*) A: ByteStr);

    (* Deallocates the unused part of allocaed space.  *)

PROCEDURE DiscardBS (VAR (*INOUT*) A: ByteStr);

    (* Discards the data in the string.  *)

PROCEDURE DiscardCS (VAR (*INOUT*) A: CharStr);

    (* Discards the data in the string.  *)

PROCEDURE GenStrToByteStr (p: ADDRESS;  N: CARDINAL): ByteStr;

    (* Creates a ByteStr from N bytes at address p.   *)

PROCEDURE StrToCharStr (str: ARRAY OF CHAR): CharStr;

    (* Creates a CharStr from a character string.   The result includes *)
    (* a Nul terminator, which is not counted in the size field.        *)

PROCEDURE StrToByteStr (str: ARRAY OF CHAR): ByteStr;

    (* Like StrToCharStr, except for the type of the result.    *)

PROCEDURE ByteStrToStr (VAR (*INOUT*) src: ByteStr;  VAR (*OUT*) result: ARRAY OF CHAR);

    (* Converts ByteStr to ordinary character string, deallocates the source.   *)

PROCEDURE BNtoByteStr(A: BN): ByteStr;

    (* Converts a Bignum to a ByteStr, using twos complement for negative   *)
    (* numbers, with a leading 00 or FF inserted if needed to ensure that   *)
    (* the high-order bit agrees with the sign.  Does not deallocate the source.*)

PROCEDURE BSDelete (VAR (*INOUT*) bs: ByteStr;  from, N: CARDINAL);

    (* Deletes a substring of length N, starting at bs.data^[from]. *)

PROCEDURE CSDelete (VAR (*INOUT*) cs: CharStr;  from, N: CARDINAL);

    (* Deletes a substring of length N, starting at cs.data^[from]. *)

PROCEDURE CSExtract (source: CharStr;  start, N: CARDINAL;
                        VAR (*OUT*) destination: ARRAY OF CHAR);

    (* Copies at most N characters from source to destination,      *)
    (* starting at position startIndex in source.                   *)

PROCEDURE BSExpand (VAR (*INOUT*) bs: ByteStr;  N: CARDINAL);

    (* Ensures, by a new allocation if necessary, that bs can hold  *)
    (* N extra bytes.  We don't yet update bs.size.                 *)

PROCEDURE CSExpand (VAR (*INOUT*) bs: CharStr;  N: CARDINAL);

    (* Ensures, by a new allocation if necessary, that cs can hold  *)
    (* N extra bytes.  We don't yet update bs.size.                 *)

PROCEDURE BSAppend (VAR (*INOUT*) bs: ByteStr;
                        N: CARDINAL;  VAR (*IN*) bytes: ARRAY OF LOC);

    (* Appends N bytes to the original string. *)

PROCEDURE BSAppendStr (VAR (*INOUT*) bs: ByteStr;  str: ARRAY OF CHAR);

    (* Appends new text str to the original string. *)

PROCEDURE CSAppendStr (VAR (*INOUT*) bs: CharStr;  str: ARRAY OF CHAR);

    (* Appends new text str to the original string. *)

PROCEDURE CSAppendStrV (VAR (*INOUT*) bs: CharStr;
                                    VAR (*IN*) str: ARRAY OF CHAR);

    (* Appends new text str to the original string. *)

PROCEDURE GetCard (pkt: ByteStr;  VAR (*INOUT*) pos: CARDINAL): CARDINAL;

    (* Returns 4-byte number at position pos, updates pos.   *)

PROCEDURE GetByteChunk (pkt: ByteStr;  VAR (*INOUT*) pos: CARDINAL;
                              VAR (*OUT*) str: ARRAY OF LOC;  N: CARDINAL);

    (* Extracts a string of N bytes without preceding count, updates pos. *)

PROCEDURE GetByteString (pkt: ByteStr;  VAR (*INOUT*) pos: CARDINAL;
                              VAR (*OUT*) str: ARRAY OF CARD8): CARDINAL;

PROCEDURE GetCharString (pkt: ByteStr;  VAR (*INOUT*) pos: CARDINAL;
                                        VAR (*OUT*) str: ARRAY OF CHAR);

PROCEDURE AddByte (pkt: ByteStr;  VAR (*INOUT*) pos: CARDINAL;  value: CARD8);

    (* Stores 1-byte number (uint32) at position pos, updates pos.  *)

PROCEDURE AddCard (pkt: ByteStr;  VAR (*INOUT*) pos: CARDINAL;  value: CARDINAL);

    (* Stores 4-byte number (uint32) at position pos, updates pos.  *)

PROCEDURE AddByteChunk (pkt: ByteStr;  VAR (*INOUT*) pos: CARDINAL;
                              VAR (*IN*) str: ARRAY OF LOC;  N: CARDINAL);

    (* Stores N bytes of data at position pos, updates pos.  The        *)
    (* difference between this and AddByteString, below, is that no     *)
    (* length field is put ahead of the chunk.                          *)

PROCEDURE AddByteString (pkt: ByteStr;  VAR (*INOUT*) pos: CARDINAL;
                              VAR (*IN*) str: ARRAY OF LOC;  N: CARDINAL);

    (* Stores N-byte string at position pos, updates pos.  *)

PROCEDURE AddCharString (pkt: ByteStr;  VAR (*INOUT*) pos: CARDINAL;
                                                    str: ARRAY OF CHAR);

    (* Stores character string at position pos, updates pos.  *)

END VarStrings.

