(*
    Title: 	Strings - Definitions
    LastEdit:   "Mon Sep 17 15:37:42 1984"
    Author: 	Mick Jordan/Lee Smith
                Acorn Computers.
*)

DEFINITION MODULE Strings;
(*
  This module manages strings in `standard language form'.
  That is, as an ARRAY OF CHAR, where the end of the string
  is denoted either by HIGH of the array or by a trailing 
  null character (0C).  The null is not part of the string.
  
  In order to allow strings whose upper bound can vary at
  run-time, other than as arguments to procedures, this
  module provides support for a type called STRING, which
  is conceptually defined as
  
      TYPE String = POINTER TO ARRAY OF CHAR;
  
  Since such a declaration is illegal Modula-2, the actual
  type is declared as a pointer to a very large array.
  However, when such an object is created it is made 
  an exact size, specified at the time of call.
  The HIGH value of the array is consequently meaningless
  and such a string must be terminated by a 0C character.
  It is clearly wrong to deference such a pointer 
  and use the object in an array context.
  Furthermore the programmer must be prepared to handle
  the storage management of run-time strings.

  Choosing whether to use a static ARRAY OF CHAR or the
  pointer form depends on the application.  Short-lived
  strings are usually best handled as static arrays.
  This module provides procedures which allow the two
  forms to be mixed in all the important combinations.

  All ARRAY OF CHAR results (VAR) are in 'standard language form'.
  An array-bounds fault may occur if the target
  array is not large enough to hold the string.
  All String results allocate a new String to hold the characters.
  NIL does not represent a valid String object.

  In the following, the last one or two capital letters of the procedure
  names denote the type(s) of the most significant parameters. 
  Thus CopyCS is copy from ARRAY OF CHAR to String.
  
*)

IMPORT SystemTypes;

EXPORT QUALIFIED
    String, 
    New, Dispose,            (* String creation and destruction *)
    LengthS, LengthC,        (* Length functions *)
    CopyCS,    CopySC,       (* concatenation and copying functions *)
    CopyCC,    CopySS,
    ConcatSS,  ConcatCS, ConcatCC,  ConcatSC,
    EqualSS, EqualCC,        (* equality and comparison functions *)
    EqualCS, CompareSS, CompareCC, CompareCS, CaseMode, Comparison,
    FindS, FindC,            (* CHAR finding procedures *)
    ExtractCC, ExtractSS, ExtractSC;    
                             (* sub-string extraction functions *)

TYPE
    String = SystemTypes.String;
    Comparison = SystemTypes.Comparison;
    CaseMode = (IgnoreCase, ConsiderCase);

(*  Creation/Deletion of String types *)

PROCEDURE New(n: CARDINAL): String;
(*  create a string which can hold 'n' characters excluding the terminator. *)

PROCEDURE Dispose (VAR s: String);
(*  destroys 's', and sets 's' to NIL. *)

(*  Length functions *)

PROCEDURE LengthC(chars: ARRAY OF CHAR): CARDINAL;
PROCEDURE LengthS(s: String): CARDINAL;
                
(*  Copy functions *)

PROCEDURE CopyCS(from: ARRAY OF CHAR): (* to *) String;
PROCEDURE CopySC(from: String;  VAR to: ARRAY OF CHAR);
(*  the reverse of 'CopyCS', in that 'chars' contains those characters 
    in 'from'. This function must be used in preference
    to dereferencing 's', when calling a procedure which requires
    an ARRAY OF CHAR as argument. 
*)
PROCEDURE CopyCC(from: ARRAY OF CHAR; VAR to: ARRAY OF CHAR);
PROCEDURE CopySS(from: String): (* to *) String;

(*  Concatenation primitives  *)
(*  This is the useful set of cross-products.
    If an 'S' appears in the procedure name, then the result
    is always a String.
*)

PROCEDURE ConcatSS(head, tail: String): (* to *) String;
PROCEDURE ConcatCS(head: ARRAY OF CHAR;  tail: String):  (* to *) String;
PROCEDURE ConcatCC(head, tail: ARRAY OF CHAR; VAR to: ARRAY OF CHAR);
(*  It is legal for 'head' or 'tail' to be the same array
    as that passed as the 'to' argument.
*)
PROCEDURE ConcatSC(head: String; tail: ARRAY OF CHAR): (* to *) String; 

(*  Equality primitives  *)
(*  defined as:
    1)  Length(l) = Length(r), and
    2)  l[i] = r[i], for 0 <= i < Length(l)
*)

PROCEDURE EqualSS(l, r: String): BOOLEAN;
PROCEDURE EqualCC(l, r: ARRAY OF CHAR): BOOLEAN;
PROCEDURE EqualCS(l: ARRAY OF CHAR;  r: String): BOOLEAN;

(*  Comparison primitives
    The comparison is 'l' op 'r'.
    If 'c' = IgnoreCase, the comparison is
    CharsCodes.CapitalCh(l[i]) = CharCodes.CapitalCh(r[i])
    If the strings are different length and equal up to the
    length of the shorter one, the shorter is defined to be less
    than (LT) the longer.
*)

PROCEDURE CompareSS(l, r: String; c: CaseMode): Comparison;
PROCEDURE CompareCC(l, r: ARRAY OF CHAR; c: CaseMode): Comparison;
PROCEDURE CompareCS(l: ARRAY OF CHAR;  r: String; c: CaseMode): Comparison;

(*  Search functions  *)

PROCEDURE FindS(s: String;  ch: CHAR;  VAR index: CARDINAL): BOOLEAN;
PROCEDURE FindC(s: ARRAY OF CHAR; ch: CHAR; VAR index: CARDINAL): BOOLEAN;
(*  searches 's' from the 'index' position, returning TRUE if 'ch'
    is found and setting 'index' to the associated position.
    The first element of the string is at 'index=0'.
*)

(*   
    Sub-string Extraction primitives

    In each case, the result is source[i], lwb <= i < upb.  
    NOTE: the upper bound is NOT included. 
    This is essential if from and to are to be of 
    CARDINAL type AND a leading null string is to be extractable.  
*)
PROCEDURE ExtractCC(from: ARRAY OF CHAR;  lwb, upb: CARDINAL;
                                      VAR to: ARRAY OF CHAR);

PROCEDURE ExtractSS(source: String;  lwb, upb: CARDINAL): String;

PROCEDURE ExtractSC(from: String;  lwb, upb: CARDINAL;
                    VAR to: ARRAY OF CHAR);

END Strings.
