packages feed

language-Modula2-0.1: examples/Modula-2_Libraries/C.-Lins_Modula-2_Software_Component_Library/Vol1/UTILS/STRINGUT.MOD

IMPLEMENTATION MODULE StringUtils;
(*==========================================================
    Version  : 1.0  Sat, Mar 4, 1989  C. Lins
    Compiler : JPI TopSpeed Modula-2
    Component: Tool - String Utilities
    Code Size: R-  bytes

    Revision History
    v1.0  Sat, Mar 4, 1989  C. Lins
      Initial JPI implementation.

    Introduction
    This module provides elementary String operations.

    Proprietary Notices
      Copyright (C) 1989 Charles A. Lins. All rights reserved. 
==========================================================*)

FROM Str IMPORT
    (*--Proc*) Insert, Delete, Length, Compare;

IMPORT CharUtils;

       (*--------------------*)

PROCEDURE MakeUppercase  (VAR theString    : ARRAY OF CHAR (*--inout*));

VAR   index: CARDINAL; (*-- loop index over characters in the string *)

BEGIN
  index := 0;
  WHILE (index <= HIGH(theString)) & (theString[index] # EOS) DO
    CharUtils.MakeUppercase(theString[index]);
    INC(index);
  END (*--while*);
END MakeUppercase;
(*--------------------*)

PROCEDURE MakeLowercase  (VAR theString    : ARRAY OF CHAR (*-- inout *));

VAR   index: CARDINAL; (*-- loop index over characters in the string *)

BEGIN
  index := 0;
  WHILE (index <= HIGH(theString)) & (theString[index] # EOS) DO
    CharUtils.MakeLowercase(theString[index]);
    INC(index);
  END (*--while*);
END MakeLowercase;
(*--------------------*)

PROCEDURE Replace	 (    theChar	   : CHAR	   (*--in   *);
			      withChar	   : CHAR	   (*--in   *);
			  VAR theString    : ARRAY OF CHAR (*--inout*);
			      caseSensitive: BOOLEAN	   (*--in   *));
VAR   index: CARDINAL;
BEGIN
  index := 0;
  WHILE (index <= HIGH(theString)) & (theString[index] # EOS) DO
    IF CharUtils.IsEqual(theChar, theString[index], caseSensitive) THEN
      theString[index] := withChar;
    END (*--if*);
    INC(index);
  END (*--while*);
END Replace;
(*--------------------*)

PROCEDURE Append	 (    theString    : ARRAY OF CHAR (*--in   *);
			  VAR toTheString  : ARRAY OF CHAR (*--inout*));

VAR   srcLimit : CARDINAL; (*-- Source string high index bound *)
      srcIndex : CARDINAL; (*-- Source string working index *)
      destLimit: CARDINAL; (*-- Destination string high index bound *)
      destIndex: CARDINAL; (*-- Destination string working index *)

BEGIN
  destLimit := HIGH(toTheString);
  destIndex := 0;

  (*-- Find the end of the string that is being appended to *)
  WHILE (destIndex <= destLimit) & (toTheString[destIndex] # EOS) DO
    INC(destIndex);
  END(*--while*);

  srcLimit := HIGH(theString);
  srcIndex := 0;

  (*-- Append source to end of destination *)
  WHILE (destIndex < destLimit) & (srcIndex <= srcLimit) &
	(theString[srcIndex] # EOS) DO
    toTheString[destIndex] := theString[srcIndex];
    INC(destIndex);
    INC(srcIndex);
  END(*--while*);
  toTheString[destIndex] := EOS;
END Append;
(*--------------------*)

PROCEDURE Fill		 (    theChar	   : CHAR	   (*--in   *);
			  VAR inTheString  : ARRAY OF CHAR (*--out  *));

VAR   index : INTEGER; (*-- loop index over characters in the string *)

BEGIN
  FOR index:= 0 TO HIGH(inTheString) DO
    inTheString[index] := theChar;
  END(*--for*);
END Fill;
(*--------------------*)

PROCEDURE FillSpaces	 (VAR inTheString  : ARRAY OF CHAR (*--out   *));

VAR   index : INTEGER; (*-- loop index over characters in the string *)

BEGIN
  FOR index:= 0 TO HIGH(inTheString) DO
    inTheString[index] := ' ';
  END(*--for*);
END FillSpaces;
(*--------------------*)

PROCEDURE FillPartial	 (    withTheChar  : CHAR	   (*--in   *);
			      atTheIndex   : CARDINAL	   (*--in   *);
			      forTheLength : CARDINAL	   (*--in   *);
			  VAR inTheString  : ARRAY OF CHAR (*--out  *));

VAR   lastIndex: CARDINAL;

BEGIN
  lastIndex := HIGH(inTheString);
  WHILE (atTheIndex <= lastIndex) & (inTheString[atTheIndex] # EOS) &
	(forTheLength > 0) DO
    inTheString[atTheIndex] := withTheChar;
    INC(atTheIndex);
    DEC(forTheLength);
  END (*--while*);
END FillPartial;
(*--------------------*)

PROCEDURE InsertChar	 (    withTheChar  : CHAR	   (*--in   *);
			      atTheIndex   : CARDINAL	   (*--in   *);
			      forTheLength : CARDINAL	   (*--in   *);
			  VAR inTheString  : ARRAY OF CHAR (*--out  *));

VAR   insertCount     : CARDINAL;
      insertCharString: ARRAY [0..0] OF CHAR;

BEGIN
  IF atTheIndex <= VAL(CARDINAL,HIGH(inTheString)) THEN
    insertCharString[0] := withTheChar;
    insertCount := 0;
    WHILE insertCount < forTheLength DO
      Insert(insertCharString, inTheString, atTheIndex);
      INC(insertCount);
    END (*--while*);
  END (*--if*);
END InsertChar;
(*--------------------*)

PROCEDURE Centered	 (VAR theString    : ARRAY OF CHAR (*--inout*);
			      inWidth	   : CARDINAL	   (*--in   *);
			      withTheFiller: CHAR	   (*--in   *));

VAR   leftMargin : CARDINAL;
      rightMargin: CARDINAL;
      sourceLen  : CARDINAL;
      sourceLimit: CARDINAL;

BEGIN
  sourceLen := Length(theString);

  IF inWidth > sourceLen THEN
    sourceLimit := HIGH(theString);
    IF (inWidth > sourceLimit) THEN
      inWidth := sourceLimit;
    END (*--if*);

    leftMargin	:= (inWidth - sourceLen) DIV 2;
    rightMargin := inWidth - sourceLen - leftMargin;

    (*-- Fill at the left *)
    InsertChar(withTheFiller,0,leftMargin,theString);

    (*-- Fill at the right *)
    InsertChar(withTheFiller,sourceLen+leftMargin,rightMargin,theString);

  END (*--if*);
END Centered;
(*--------------------*)

PROCEDURE LeftJustified  (VAR theString    : ARRAY OF CHAR (*--inout*);
			      inWidth	   : CARDINAL	   (*--in   *);
			      withTheFiller: CHAR	   (*--in   *));

VAR   index: CARDINAL; (*-- loop index over characters of the string *)

BEGIN
  index := 0;
  WHILE (index < HIGH(theString)) & (theString[index] # EOS) DO
    INC(index);
  END (*--while*);

  WHILE (index < HIGH(theString)) & (VAL(CARDINAL, index) < inWidth) DO
    theString [index] := withTheFiller;
    INC(index);
  END (*--while*);

  theString[index] := EOS;
END LeftJustified;
(*--------------------*)

PROCEDURE RightJustified (VAR theString    : ARRAY OF CHAR (*--inout*);
			      inWidth	   : CARDINAL	   (*--in   *);
			      withTheFiller: CHAR	   (*--in   *));
VAR   srcIndex : CARDINAL;
      srcLength: CARDINAL;
      moveWidth: CARDINAL;

BEGIN
  srcLength := Length(theString);

  IF (srcLength < inWidth) THEN

    (*-- If given width exceeds limit of string, readjust to the limit *)
    IF VAL(CARDINAL,HIGH(theString)) < inWidth THEN
      inWidth := HIGH(theString);
    END (*--if*);

    (*-- Calculate how many positions to added to the string *)
    moveWidth := inWidth - srcLength;

    (*-- Shift the input string right, based on given width *)
    FOR srcIndex := inWidth TO moveWidth BY -1 DO
      theString[srcIndex] := theString[srcIndex-moveWidth];
    END (*--for*);

    (*-- Fill the front of the string with the given filler character *)
    DEC(moveWidth);
    FOR srcIndex := 0 TO moveWidth DO
      theString[srcIndex] := withTheFiller;
    END (*--for*);
  END (*--if*);
END RightJustified;
(*--------------------*)

PROCEDURE Stripped	 (VAR fromTheString: ARRAY OF CHAR (*--inout*);
			      theChar	   : CHAR	   (*--in   *);
			      caseSensitive: BOOLEAN	   (*--in   *));

VAR   srcIndex	 : CARDINAL;
      maxIndex	 : CARDINAL;
      stripIndex : CARDINAL;
      stripCount : CARDINAL;

BEGIN
  maxIndex := HIGH(fromTheString);
  srcIndex := 0;
  WHILE (srcIndex <= maxIndex) & (fromTheString[srcIndex] # EOS) DO
    IF CharUtils.IsEqual(theChar, fromTheString[srcIndex], caseSensitive) THEN
      stripIndex := srcIndex;
      stripCount := 1;
      INC(srcIndex);
      WHILE (srcIndex <= maxIndex) & (fromTheString[srcIndex] # EOS) &
	    CharUtils.IsEqual(theChar, fromTheString[srcIndex], caseSensitive) DO
	INC(stripCount);
	INC(srcIndex);
      END (*--while*);
      Delete(fromTheString, stripIndex, stripCount);
      DEC(srcIndex, stripCount);

    ELSE
      INC(srcIndex);
    END (*--if*);
  END (*--while*);
END Stripped;
(*--------------------*)

PROCEDURE StripLeading	 (VAR fromTheString: ARRAY OF CHAR (*--inout*);
			      theChar	   : CHAR	   (*--in   *);
			      caseSensitive: BOOLEAN	   (*--in   *));

VAR   srcIndex	 : CARDINAL;
      maxIndex	 : CARDINAL;
      stripIndex : CARDINAL;
      stripCount : CARDINAL;

BEGIN
  maxIndex   := HIGH(fromTheString);
  srcIndex   := 0;
  stripCount := 0;
  WHILE (srcIndex <= maxIndex) & (fromTheString[srcIndex] # EOS) &
	CharUtils.IsEqual(theChar, fromTheString[srcIndex], caseSensitive) DO
    INC(stripCount);
    INC(srcIndex);
  END (*--while*);
  Delete(fromTheString, 0, stripCount);
END StripLeading;
(*--------------------*)

PROCEDURE StripTrailing  (VAR fromTheString: ARRAY OF CHAR (*--inout*);
			      theChar	   : CHAR	   (*--in   *);
			      caseSensitive: BOOLEAN	   (*--in   *));

VAR   srcIndex: CARDINAL;
      srcLen  : CARDINAL;
      newEOS  : CARDINAL;

BEGIN
  srcIndex := Length(fromTheString);
  IF srcIndex > 0 THEN
    REPEAT
      newEOS := srcIndex;
      DEC(srcIndex);
    UNTIL (srcIndex = 0) OR
	  ~CharUtils.IsEqual(theChar, fromTheString[srcIndex], caseSensitive);
    IF newEOS <= VAL(CARDINAL,HIGH(fromTheString)) THEN
      fromTheString[newEOS] := EOS;
    END (*--if*);
  END (*--if*);
END StripTrailing;
(*--------------------*)


PROCEDURE Uppercase	 (    theString    : ARRAY OF CHAR (*--in   *);
			  VAR newString    : ARRAY OF CHAR (*--out  *));

VAR   index: CARDINAL; (*-- loop index over characters of theString *)

BEGIN
  index := 0;
  WHILE (index <= HIGH(theString)) & (theString[index] # EOS) &
	(index <= HIGH(newString)) DO
    newString[index] := CharUtils.Uppercase(theString[index]);
    INC(index);
  END (*--while*);
  newString[index] := EOS;
END Uppercase;
(*--------------------*)

PROCEDURE Lowercase	 (    theString    : ARRAY OF CHAR (*--in   *);
			  VAR newString    : ARRAY OF CHAR (*--out  *));

VAR   index: CARDINAL; (*-- loop index over characters of theString *)

BEGIN
  index := 0;
  WHILE (index <= HIGH(theString)) & (theString[index] # EOS) &
	(index <= HIGH(newString)) DO
    newString[index] := CharUtils.Lowercase(theString[index]);
    INC(index);
  END (*--while*);
  newString[index] := EOS;
END Lowercase;
(*--------------------*)

PROCEDURE Capitalized	 (    theString    : ARRAY OF CHAR (*--in   *);
			  VAR newString    : ARRAY OF CHAR (*--out  *));

VAR   index: CARDINAL; (*-- loop index over characters of theString *)

BEGIN
  index := 0;
  WHILE (index <= HIGH(theString)) & (theString[index] # EOS) &
	(index <= HIGH(newString)) DO
    INC(index);
  END (*--while*);
  newString[index] := EOS;
END Capitalized;
(*--------------------*)

PROCEDURE Uncapitalized  (    theString    : ARRAY OF CHAR (*--in   *);
			  VAR newString    : ARRAY OF CHAR (*--out  *));

VAR   index: CARDINAL; (*-- loop index over characters of theString *)

BEGIN
  index := 0;
  WHILE (index <= HIGH(theString)) & (theString[index] # EOS) &
	(index <= HIGH(newString)) DO
    INC(index);
  END (*--while*);
  newString[index] := EOS;
END Uncapitalized;
(*--------------------*)

PROCEDURE Replaced	 (    theChar	   : CHAR	   (*--in   *);
			      withChar	   : CHAR	   (*--in   *);
			      inTheString  : ARRAY OF CHAR (*--in   *);
			      caseSensitive: BOOLEAN	   (*--in   *);
			  VAR newString    : ARRAY OF CHAR (*--out  *));

VAR   index: CARDINAL; (*-- loop index over characters of theString *)

BEGIN
  index := 0;
  WHILE (index <= HIGH(inTheString)) & (inTheString[index] # EOS) &
	(index <= HIGH(newString)) DO
    IF CharUtils.IsEqual(theChar, inTheString[index], caseSensitive) THEN
      newString[index] := withChar;
    ELSE
      newString[index] := inTheString[index];
    END (*--if*);
    INC(index);
  END (*--while*);
  newString[index] := EOS;
END Replaced;
(*--------------------*)

PROCEDURE IsEmpty	 (    theString    : ARRAY OF CHAR (*--in   *))
					   : BOOLEAN	   (*--out  *);
BEGIN
  RETURN (HIGH(theString) = 0) & (theString[0] = EOS);
END IsEmpty;
(*--------------------*)

PROCEDURE IsAscii	 (    theString    : ARRAY OF CHAR (*--in   *))
					   : BOOLEAN	   (*--out  *);

VAR   index: CARDINAL; (*-- loop index over characters of theString *)

BEGIN
  index := 0;
  WHILE (index <= HIGH(theString)) & (theString[index] # EOS) DO
    IF ~CharUtils.IsAscii(theString[index]) THEN
      RETURN FALSE;
    END (*--if*);
    INC(index);
  END (*--while*);
  RETURN TRUE;
END IsAscii;
(*--------------------*)

PROCEDURE IsControl	 (    theString    : ARRAY OF CHAR (*--in   *))
					   : BOOLEAN	   (*--out  *);

VAR   index: CARDINAL; (*-- loop index over characters of theString *)

BEGIN
  index := 0;
  WHILE (index <= HIGH(theString)) & (theString[index] # EOS) DO
    IF ~CharUtils.IsControl(theString[index]) THEN
      RETURN FALSE;
    END (*--if*);
    INC(index);
  END (*--while*);
  RETURN TRUE;
END IsControl;
(*--------------------*)

PROCEDURE IsGraphic	 (    theString    : ARRAY OF CHAR (*--in   *))
					   : BOOLEAN	   (*--out  *);

VAR   index: CARDINAL; (*-- loop index over characters of theString *)

BEGIN
  index := 0;
  WHILE (index <= HIGH(theString)) & (theString[index] # EOS) DO
    IF ~CharUtils.IsGraphic(theString[index]) THEN
      RETURN FALSE;
    END (*--if*);
    INC(index);
  END (*--while*);
  RETURN TRUE;
END IsGraphic;
(*--------------------*)

PROCEDURE IsLowercase	 (    theString    : ARRAY OF CHAR (*--in   *))
					   : BOOLEAN	   (*--out  *);

VAR   index: CARDINAL; (*-- loop index over characters of theString *)

BEGIN
  index := 0;
  WHILE (index <= HIGH(theString)) & (theString[index] # EOS) DO
    IF ~CharUtils.IsLowercase(theString[index]) THEN
      RETURN FALSE;
    END (*--if*);
    INC(index);
  END (*--while*);
  RETURN TRUE;
END IsLowercase;
(*--------------------*)

PROCEDURE IsUppercase	 (    theString    : ARRAY OF CHAR (*--in   *))
					   : BOOLEAN	   (*--out  *);

VAR   index: CARDINAL; (*-- loop index over characters of theString *)

BEGIN
  index := 0;
  WHILE (index <= HIGH(theString)) & (theString[index] # EOS) DO
    IF ~CharUtils.IsUppercase(theString[index]) THEN
      RETURN FALSE;
    END (*--if*);
    INC(index);
  END (*--while*);
  RETURN TRUE;
END IsUppercase;
(*--------------------*)

PROCEDURE IsDigit	 (    theString    : ARRAY OF CHAR (*--in   *))
					   : BOOLEAN	   (*--out  *);

VAR   index: CARDINAL; (*-- loop index over characters of theString *)

BEGIN
  index := 0;
  WHILE (index <= HIGH(theString)) & (theString[index] # EOS) DO
    IF ~CharUtils.IsDigit(theString[index]) THEN
      RETURN FALSE;
    END (*--if*);
    INC(index);
  END (*--while*);
  RETURN TRUE;
END IsDigit;
(*--------------------*)

PROCEDURE IsAlphabetic	 (    theString    : ARRAY OF CHAR (*--in   *))
					   : BOOLEAN	   (*--out  *);

VAR   index: CARDINAL; (*-- loop index over characters of theString *)

BEGIN
  index := 0;
  WHILE (index <= HIGH(theString)) & (theString[index] # EOS) DO
    IF ~CharUtils.IsAlphabetic(theString[index]) THEN
      RETURN FALSE;
    END (*--if*);
    INC(index);
  END (*--while*);
  RETURN TRUE;
END IsAlphabetic;
(*--------------------*)

PROCEDURE IsAlphanumeric (    theString    : ARRAY OF CHAR (*--in   *))
					   : BOOLEAN	   (*--out  *);

VAR   index: CARDINAL; (*-- loop index over characters of theString *)

BEGIN
  index := 0;
  WHILE (index <= HIGH(theString)) & (theString[index] # EOS) DO
    IF ~CharUtils.IsAlphanumeric(theString[index]) THEN
      RETURN FALSE;
    END (*--if*);
    INC(index);
  END (*--while*);
  RETURN TRUE;
END IsAlphanumeric;
(*--------------------*)

PROCEDURE IsSpecial	 (    theString    : ARRAY OF CHAR (*--in   *))
					   : BOOLEAN	   (*--out  *);

VAR   index: CARDINAL; (*-- loop index over characters of theString *)

BEGIN
  index := 0;
  WHILE (index <= HIGH(theString)) & (theString[index] # EOS) DO
    IF ~CharUtils.IsSpecial(theString[index]) THEN
      RETURN FALSE;
    END (*--if*);
    INC(index);
  END (*--while*);
  RETURN TRUE;
END IsSpecial;
(*--------------------*)

PROCEDURE NumberOf	 (    theChar	   : CHAR	   (*--in   *);
			      inTheString  : ARRAY OF CHAR (*--in   *);
			      caseSensitive: BOOLEAN	   (*--in   *))
					   : CARDINAL	   (*--out  *);

VAR   index: CARDINAL;  (*-- loop index over characters of theString *)
      count: CARDINAL;

BEGIN
  count := 0;
  index := 0;
  WHILE (index <= HIGH(inTheString)) & (inTheString[index] # EOS) DO
    IF CharUtils.IsEqual(theChar, inTheString[index], caseSensitive) THEN
      INC(count);
    END (*--if*);
    INC(index);
  END (*--while*);
  RETURN count;
END NumberOf;
(*--------------------*)

PROCEDURE LocationOf	 (    theChar	   : CHAR	   (*--in   *);
			      inTheString  : ARRAY OF CHAR (*--in   *);
			      caseSensitive: BOOLEAN	   (*--in   *);
			      forward	   : BOOLEAN	   (*--in   *))
					   : CARDINAL	   (*--out  *);

VAR   index: CARDINAL; (*-- loop index over characters of theString *)

BEGIN
  IF forward THEN
    index := 0;
    WHILE (index <= HIGH(inTheString)) & (inTheString[index] # EOS) DO
      IF CharUtils.IsEqual(theChar, inTheString[index], caseSensitive) THEN
	RETURN index;
      END (*--if*);
      INC(index);
    END (*--while*);
  ELSE
    index := Length(inTheString);
    WHILE (index >= 0) DO
      IF CharUtils.IsEqual(theChar, inTheString[index], caseSensitive) THEN
	RETURN index;
      END (*--if*);
      DEC(index);
    END (*--while*);
  END (*--if*);
  RETURN 0;
END LocationOf;
(*--------------------*)

PROCEDURE Scan		 (    theString    : ARRAY OF CHAR (*--in   *);
			      forAnyChar   : ARRAY OF CHAR (*--in   *);
			      matchEqual   : BOOLEAN	   (*--in   *);
			  VAR atIndex	   : CARDINAL	   (*--inout*))
					   : BOOLEAN	   (*--out  *);

VAR   length,		(*-- maximum index of source string array *)
      initialIndex,	(*-- index upon entry to the routine *)
      cindex,		(*-- current index of pattern array *)
      clength: CARDINAL;(*-- maximum index of pattern array *)

BEGIN
  length      :=HIGH(theString);
  clength     :=HIGH(forAnyChar);
  initialIndex:=atIndex;

  (*-- Traverse the input string *)
  WHILE (atIndex <= length) & (theString[atIndex] # EOS) DO

    cindex:=0;
    IF matchEqual THEN

      (*-- Traverse the scanning string to find first match *)
      WHILE (cindex <= clength) & (forAnyChar[cindex] # EOS) DO
	IF (theString[atIndex] = forAnyChar[cindex]) THEN
	  RETURN TRUE;
	END (*--if*);
	INC(cindex);
      END (*--while*);

    ELSE
      (*-- Traverse the scanning string to find first non-match  *)
      WHILE (cindex <= clength) & (forAnyChar[cindex] # EOS) DO
	IF (theString[atIndex] # forAnyChar[cindex]) THEN
	  RETURN TRUE;
	END (*--if*);
	INC(cindex);
      END (*--while*);
    END (*--if*);

    INC(atIndex);	   (*-- Advance to next character of the input string *)
  END (*--while*);

  atIndex := initialIndex; (*-- restore index value upon failure *)
  RETURN FALSE;
END Scan;
(*--------------------*)

PROCEDURE IsEqual	 (    left	   : ARRAY OF CHAR (*--in   *);
			      right	   : ARRAY OF CHAR (*--in   *);
			      caseSensitive: BOOLEAN	   (*--in   *))
					   : BOOLEAN	   (*--out  *);
BEGIN
  IF ~caseSensitive THEN
    MakeLowercase(left);
    MakeLowercase(right);
  END (*--if*);
  RETURN Compare(left, right) = 0;
END IsEqual;
(*--------------------*)

PROCEDURE IsLessThan	 (    left	   : ARRAY OF CHAR (*--in   *);
			      right	   : ARRAY OF CHAR (*--in   *);
			      caseSensitive: BOOLEAN	   (*--in   *))
					   : BOOLEAN	   (*--out  *);
BEGIN
  IF ~caseSensitive THEN
    MakeLowercase(left);
    MakeLowercase(right);
  END (*--if*);
  RETURN Compare(left, right) = -1;
END IsLessThan;
(*--------------------*)

PROCEDURE IsGreaterThan  (    left	   : ARRAY OF CHAR (*--in   *);
			      right	   : ARRAY OF CHAR (*--in   *);
			      caseSensitive: BOOLEAN	   (*--in   *))
					   : BOOLEAN	   (*--out  *);
BEGIN
  IF ~caseSensitive THEN
    MakeLowercase(left);
    MakeLowercase(right);
  END (*--if*);
  RETURN Compare(left, right) = +1;
END IsGreaterThan;
(*--------------------*)

END StringUtils.