{***********************************************************************}
{									}
{ __CvtStr    Conversion of a string					}
{									}
{ function  __CvtStr(Source : string; CvtCode : word) : string; 	}
{									}
{	      Source	The string to be converted based upon the value }
{			of the conversion code, CvtCode.		}
{	      CvtCode	The conversion code.				}
{									}
{ Description __CvtStr returns a converted string.  The possible con-	}
{	      versions are:						}
{									}
{	      Code  String Conversion					}
{	      ----- --------------------------------------------------- }
{	      $0001 (_REM_WHITE_STR)  Discard all spaces and tab	}
{		    characters. 					}
{	      $0002 (_REM_LEAD_WHITE_STR) Discard all leading spaces	}
{		    and tab characters. 				}
{	      $0004 (_REM_TRAIL_WHITE_STR) Discard all trailing spaces	}
{		    and tab characters. 				}
{	      $0008 (_REDUCE_WHITE_STR) Reduce all consecutive spaces	}
{		    and tabs to a single blank character.		}
{	      $0010 (_SAVE_QUOTED_STR) Characters enclosed in quotes	}
{		    are not to be altered during string conversion	}
{	      $0020 (_TO_UPCASE_STR) Convert all characters to upper	}
{		    case.						}
{	      $0040 (_TO_LOWCASE_STR) Convert all characters to lower	}
{		    case.						}
{	      $0080 (_DISCARD_STR) Discard all NUL (#0), carriage	}
{		    return (#13), line feed (#10), form feed (#12) and	}
{		    vertical tab (#11) characters.			}
{									}
{	      CvtCode can be any combination of the above values, even	}
{	      though some combinations are logically inconsistent.  Any }
{	      ambiguity is resolved by executing the conversion request }
{	      codes in numerical order.  The only exception is that	}
{	      code 16 (do not alter quoted strings) is always checked.	}
{	      Multiple requests are obtained by adding the code values; }
{	      for example, 33 instructs __CvtStr to discard all spaces	}
{	      and tabs and convert all characters to upper case.	}
{									}
{ Version     4.00 (C)Copyright Blaise Computing Inc.  1987		}
{_______________________________________________________________________}

function  __CvtStr(Source : string; CvtCode : word) : string;

  const
    BLANK    = #32;		       { Blank (ASCII 32) character	}
    TAB      = #9;		       { Horizontal Tab (ASCII 9)	}
    QUOTE    = #39;		       { Single quote (ASCII 39)	}
    DQUOTE   = #34;		       { Double quote character 	}
    NUL      = #0;		       { Null character 		}
    LINEFEED = #10;		       { Line feed character		}
    VTAB     = #11;		       { Vertical Tab character 	}
    FORMFEED = #12;		       { Form feed character		}
    CRETURN  = #13;		       { Carriage return		}


  {+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
  { QuoteCheck	Return TRUE if processing inside a quoted string.	}
  {_____________________________________________________________________}

  function QuoteCheck(var LastQuote : char; Ch : char) : boolean;

    begin {QuoteCheck}

      if ((Ch = QUOTE) or (Ch = DQUOTE)) then
	 begin
	   if (Ch = LastQuote) then    { The quoted string is closed.	}
	      begin
		QuoteCheck := FALSE;
		LastQuote  := BLANK    { No current quoted string.	}
	      end
	   else if ((LastQuote <> QUOTE) and (LastQuote <> DQUOTE)) then
	      begin		       { Have a new quoted string.	}
		QuoteCheck := TRUE;
		LastQuote  := Ch
	      end
	 end
      else
	 if ((LastQuote = QUOTE) or (LastQuote = DQUOTE)) then
	    QuoteCheck := TRUE
	 else
	    QuoteCheck := FALSE

    end;  {QuoteCheck}


  var
    Target    : string; 	       { Converted string.		}
    IsQuote   : boolean;	       { TRUE  when quotes checked.	}
    QuoteOn   : boolean;	       { TRUE  when in a quoted string. }
    LastQuote : char;		       { Quote char used.		}
    DeleteOn  : boolean;	       { TRUE when blanks are reduced	}
    I,J,Len   : word;
    Ch	      : char;

  begin {__CvtStr}

    Target    := Source;		 { If no request made, just	}
					 { the source string.		}
    IsQuote   := (CvtCode and 16) <> 0;  { Check for quoted strings?	}
    QuoteOn   := FALSE;
    LastQuote := ' ';

    { First discard all white space (blanks and tabs)			}

    if ((CvtCode and _REM_WHITE_STR) <> 0) then
       begin
	 Len := Length(Source);
	 I   := 1;
	 J   := 0;
	 while (I <= Len) do
	   begin
	     Ch := Source[I];
	     if (IsQuote) then	       { Check if we have a quote	}
		QuoteOn := QuoteCheck(LastQuote,Ch);
	     if (((Ch <> BLANK) and (Ch <> TAB)) or QuoteOn) then
		begin		       { Copy the character to Target.	}
		  Inc(J);
		  Target[J] := Ch
		end;
	     Inc(I);		       { Now move to the next character }
	   end;
	 Target[0] := Chr(J)	       { The new string length		}
       end;

    { Now remove all leading white space if requested.	We count the	}
    { white space characters until a non white space character is	}
    { encountered; those characters are deleted.			}

    if ((CvtCode and _REM_LEAD_WHITE_STR) <> 0) then
       begin
	 Len := Length(Target);
	 I   := 1;
	 while ((I <= Len) and
			   ((Target[I] = BLANK) or (Target[I] = TAB))) do
	   Inc(I);
	 Delete(Target,1,I - 1)
       end;

    { Remove all trailing white space.	 The last non blank, non tabs	}
    { character position is found and the preceding portion is copied.	}

    if ((CvtCode and _REM_TRAIL_WHITE_STR) <> 0) then
       begin
	 Len := Length(Target);
	 I   := Len;
	 while ((I >= 1) and
			   ((Target[I] = BLANK) or (Target[I] = TAB))) do
	     Dec(I);
	 Target := Copy(Target,1,I)
       end;

    { Reduce all blanks and tabs to a single blank.  For each character }
    { in the string we check for a blank or tab.  If it is the "first"	}
    { one encountered, a boolean flag is set, and all subsequent ones	}
    { are skipped.  When a non blank, non tab is encountered the flag	}
    { is reset. 							}

    if ((CvtCode and _REDUCE_WHITE_STR) <> 0) then
       begin
	 DeleteOn  := FALSE;	       { Not deleting blanks		}
	 LastQuote := BLANK;
	 Len	   := Length(Target);
	 I	   := 1;
	 J	   := 0;
	 while (I <= Len) do
	   begin
	     Ch := Target[I];
	     if (IsQuote) then	       { Check if we have a quote	}
		QuoteOn := QuoteCheck(LastQuote,Ch);
	     if (((Ch <> BLANK) and (Ch <> TAB)) or QuoteOn) then
		begin		       { Just copy the character	}
		  Inc(J);
		  Target[J] := Ch;
		  DeleteOn  := FALSE
		end
	     else if (not DeleteOn) then
		begin		       { Have a white space char, and	}
		  Inc(J);	       { have not previously deleted,	}
		  Target[J] := BLANK;  { so output the blank and turn	}
		  DeleteOn  := TRUE    { the flag on.			}
		end;
	     Inc(I)
	   end;
	 Target[0] := Chr(J)
       end;

    { Convert lower case characters to upper case.  If a character is	}
    { in the set LowerCase, just subtract 32 from the ASCII code.	}

    if ((CvtCode and _TO_UPCASE_STR) <> 0) then
       begin
	 LastQuote := BLANK;
	 for I := 1 to Length(Target) do
	   begin
	     Ch := Target[I];
	     if (IsQuote) then	       { Check if we have a quote	}
		QuoteOn := QuoteCheck(LastQuote,Ch);
	     if (((Ord(Ch) >= $61) and (Ord(Ch) <= $7A))
						 and (not QuoteOn)) then
		Target[I] := Chr(Ord(Ch) - 32)
	   end
       end;

    { Convert upper case characters to lower case.  If a character is	}
    { in the set UpperCase, just add 32 to the ASCII code.		}

    if ((CvtCode and _TO_LOWCASE_STR) <> 0) then
       begin
	 LastQuote := BLANK;
	 for I := 1 to Length(Target) do
	   begin
	     Ch := Target[I];
	     if (IsQuote) then	       { Check if we have a quote	}
		QuoteOn := QuoteCheck(LastQuote,Ch);
	     if (((Ord(Ch) >= $41) and (Ord(Ch) <= $5A))
						 and (not QuoteOn)) then
		Target[I] := Chr(Ord(Ch) + 32)
	   end
       end;

    { Discard all excess characters.  Simply pass through the string	}
    { copying all characters except those in the set ExcessChars.	}

    if ((CvtCode and _DISCARD_STR) <> 0) then
       begin
	 LastQuote := BLANK;
	 Len	   := Length(Target);
	 I	   := 1;
	 J	   := 0;
	 while (I <= Len) do
	   begin
	     Ch := Target[I];
	     if (IsQuote) then	       { Check if we have a quote	}
		QuoteOn := QuoteCheck(LastQuote,Ch);
	     if ( QuoteOn or
		   ((Ch <> NUL)  and
			     ((Ch < LINEFEED) or (Ch > CRETURN))) ) then
		begin		       { Just copy the character	}
		  Inc(J);
		  Target[J] := Ch
		end;
	     Inc(I)
	   end;
	 Target[0] := Chr(J)
       end;

    __CvtStr := Target

  end;	{__CvtStr}
