unit osparser;

{$MODE Delphi}
{$RANGECHECKS ON}
{$OVERFLOWCHECKS ON}
{$IOCHECKS ON}
//{$OBJECTCHECKS ON}
{$VARSTRINGCHECKS ON}
{$LONGSTRINGS ON}


 (* contains the code that organizes the syntax of scripts *)

// This code is part of the opsi.org project

// Copyright (c) uib gmbh (www.uib.de)
// This sourcecode is owned by the uib gmbh, D55118 Mainz, Germany
// and published under the Terms of the GNU Affero General Public License.
// Text of the AGPL: http://www.gnu.org/licenses/agpl-3.0-standalone.html
// author: Rupert Roeder, detlef oertel
// credits: http://www.opsi.org/credits/



interface

uses
{$IFDEF WINDOWS}
DynLibs, Windows,
//JwaTlHelp32,
registry,
{$IFDEF WIN32}
DSiWin32,
osfuncwin2,
{$ENDIF WIN32}
osfuncwin,
wispecfolder,
shlobj,
VersionInfoX,
{$IFNDEF WIN64}
oslocaladmin,
{$ENDIF WIN64}
osswaudit,
DOM,
{$ENDIF}
{$IFDEF LINUX}
lispecfolder,
osfunclin,
baseunix,
unix,
{$ENDIF}
{$IFDEF GUI}
Dialogs,
osmessagedialog,
osservicepassdlg,
osshowsysinfo,
//osinteractivegui,
//osbatchgui,
Controls,
LCLIntf,
{$ENDIF GUI}
osencoding,
osconf,
//DOM,
//wixml,
//Process,
fileutil,
  sysutils,
   Types,
  oslog,
  osfunc,
  classes,
  contnrs,
  IniFiles,
  //windatamodul,
  ldapsend,
  strutils,
  oslocale,
  base64,
  dateutils,
  synautil,
  synaip,
  synsock,
  oscalc,
  opsihwbiosinfo;


type
  TStatement = (tsNotDefined,
                // start of sectionnames
                tsActions,
                tsProfileActions,
                tsPatchAnyTextFile,
                tsTests, tsPatchIniFile,
                tsHostsPatch, tsRegistryHack, tsXMLPatch, tsIdapiConfig, tsLDAPsearch,
                tsFileActions, tsLinkFolder,
                tsWinBatch, tsDOSBatchFile, tsDOSInAnIcon,
                tsShellBatchFile, tsShellInAnIcon, tsExecutePython,
                tsExecuteWith, tsExecuteWith_escapingStrings,
                tsOpsiServiceCall,
                tsOpsiServiceHashList,
                tsDDEwithProgman,
                // end of section names
                // start of other commands
                tsWorkOnStringList,
        //tsTestCommand,
                tsStayWhileWindowOpen,
                tsCondOpen, tsCondThen, tsCondElse, tsCondClose,
                tsLoopStringList,
                tsMessage, tsMessageFile, tsShowBitmap,
                tsIncludeInsert, tsIncludeAppend,
                tsIncludeLog,
                tsShrinkFileToMB,  //internal undocumented
                tsKillTask,
                tsPause, tsSleep, tsComment,
                tsActionProgress,
                tsLogWarning, tsLogError, tsSetSkinDir,
                tsStop, tsExitWindows,
                tsBlockInput,
                tsLocalAdmin,
                tsChangeDirectory,
                tsAddConnection,
                tsSetOldLogLevel,
                tsSetLogLevel,
                tsSetConfidential,
                tsSetUsercontext,
                tsSaveVersionToProfile,
                tsSetOutputLevel,
                tsSetExitOnError,
                tsSetFatalError, tsSetSuccess, tsSetNoUpdate, tsSetSuspended,
                tsSetMarkerErrorNumber,
                tsSetReportMessages, tsSetTimeMark, tsLogDiffTime,
                tsFatalOnSyntaxError,
                tsFatalOnRuntimeError,
                tsAutoActivityDisplay,
                tsSetTraceMode, tsSetStayOnTop,
                tsIconizeWinst, tsRestoreWinst, tsNormalizeWinst,
                tsWinstVersionRequired,
                tsEncoding,
                tsDefineVar, tsDefineStringList, tsSetVar);



  TStatementNames = Array [TStatement] of String [50];
  TPStatementNames = ^TStatementNames;

  TSectionSpecifier = (tsecNoSection, tsecIncluded, tsecExpected);

  TWaitConditions   = (ttpWaitOnTerminate, ttpWaitForWindowVanished,
                       ttpWaitForWindowAppearing, ttpWaitForProcessEnding,
                       ttpWaitTime,ttpWaitTimeout);

  TSetWaitConditions = Set of TWaitConditions;

  TLDAPsearchCacheRequest  =  (tlcrNone, tlcrCache, tlcrCached, tlcrClear);
  TLDAPsearchOutputRequest =  (tlorNone, tlorObjects, tlorAttributes, tlorValues);

  TSectionResult        = Integer;

  TRegistryFormat = (trnf,trfWinst, trfRegedit, trfSysdiff);

  TExitRequest = (txrNoExit,
                  txrRegisterforLogout,
                  txrRegisterforReboot,
                  txrReboot,
                  txrImmediateLogout,
                  txrImmediateReboot);

  TShutdownRequest = (tsrNoShutdown, tsrRegisterForShutdown);

  TScriptMode = (tsmMachine, tsmLogin);



Const
    tsrFatalError   = -2;
    tsrExitWindows  = -1;
    tsrExitProcess  =  0;
    tsrPositive     =  1;


    TempUserRegKey  = 'PatchNTUserdatTempUser';


    XMLDOMVendor = 'Open XML'; // 'Xerces XML'


type


TWorkSection = class (TuibIniScript) // class (TXStringList)
  private
    FSectionkind : TStatement;
    FStartLineNo    : Integer;
    FSectionName    : String;
    FNestingLevel   : Integer;

  public
    constructor create (const NestLevel : Integer);
    destructor destroy; override;

    property StartLineNo : Integer read FStartLineNo write FStartLineNo;
    property Name : String read FSectionName write FSectionName;
    property NestingLevel : Integer read FNestingLevel write FNestingLevel;
    property SectionKind : TStatement read FSectionKind write FSectionKind;

  end;


{$IFDEF FPC}
{$ELSE}
TuibXMLNodeDescription = class (TObject)
  private
    Fxmldoc : TuibXMLDocument;
    elementname : WideString;
    attributes : TStringList;
    text : WideString;
    positioning : boolean;
    positionOfElement : Integer;
    position : Integer;
  public
    constructor Create (xmldoc : TuibXMLDocument);
    destructor Destroy; override;

    function evaluate (s : String; var Remaining: String; var InfoSyntaxError : String) : Boolean;

    procedure evaluateElementname;
    procedure evaluateAttribute;
    procedure evaluateText;
 end;
{$ENDIF}




TuibInstScript = class (TuibIniScript)
private
  FLogLevel : Integer;
  FOutputLevel : Integer;
  FNumberOfWarnings : Integer;
  FNumberOfErrors : Integer;
  FTraceMode : Boolean;
  FExitOnError : Boolean;
  FReportMessages : Boolean;
  FExtremeErrorLevel : Integer;
  FFatalOnSyntaxError : boolean;
  FFatalOnRuntimeError : boolean;
  FSuspended : boolean;
  FAutoActivityDisplay : boolean;



  FVarList : TStringList;
  listOfStringLists : TStringList;
  FValuesList : TStringList;
  ContentOfStringLists : TObjectList;
  FConstList : TStringList;
  FConstValuesList : TStringList;
  FLastExitCodeOfExe : LongInt;
  FFilename : String;
  FLinesOriginList : TStringList;


  
protected
  function getVarValues : TStringList; //nicht verwendet

public
  constructor create;
  destructor destroy; override;

  (* Properties *)
  property LogLevel : Integer read FLogLevel write FLogLevel;
  property OutputLevel : Integer read FOutputLevel write FOutputLevel;
  property NumberOfWarnings : Integer read FNumberOfWarnings;
  property NumberOfErrors : Integer read FNumberOfErrors;
  property TraceMode : Boolean read FTraceMode write FTraceMode;
  property ExitOnError : Boolean read FExitOnError write FExitOnError;
  property FatalOnSyntaxError : Boolean read FFatalOnSyntaxError write FFatalOnSyntaxError;
  property FatalOnRuntimeError : Boolean read FFatalOnRuntimeError write FFatalOnRuntimeError;
  property Suspended : Boolean read FSuspended write FSuspended;
  property AutoActivityDisplay : Boolean read FAutoActivityDisplay write FAutoActivityDisplay;


  property ReportMessages : Boolean read FReportMessages write FReportMessages;

  property varList : TStringList read FvarList write FvarList;
  property valuesList : TStringList read Fvalueslist write FvaluesList;
  property constList : TStringList read FconstList write FConstList;
  property constValuesList : TStringList read FconstValuesList write FconstValuesList;


  (* Infofunktionen *)
  function doInfo (Meldung : String)                          : TSectionResult;
  function doLogEntries (const Lines : String; EntryLevel : Integer)
                                                              : TSectionResult;
  function reportError (const Sektion: TWorkSection; LineNo : Integer;
                        const Content : String; Comment: String) : TSectionResult;


  (* Skriptvariable setzen, Ausdruecke analysieren und auswerten *)
  function doSetVar (const section: TuibIniScript; const Expression : String;
                     var Remaining : String; var InfoSyntaxError : String) : Boolean;

  function produceStringList
    (const section: TuibIniScript; const s0 : String; var Remaining: String;
     var list : TXStringlist; var InfoSyntaxError : String ) : Boolean;

  function EvaluateString
    (const s0 : String; var Remaining: String;
     var StringResult : String; var InfoSyntaxError : String ) : Boolean;

  function EvaluateBoolean (Input : String; var Remaining : String;
     var BooleanResult : Boolean; NestingLevel : Integer; var InfoSyntaxError : String) : Boolean;

  procedure GetWordOrStringExpression (const s: String;
                           var resultString, Remaining, errorinfo : String);

  function produceExecLine(const s : String;
                        var programfilename, programparas, passparas, winstoption: String;
                        var InfoSyntaxError : String): boolean;


  function doXMLAddNamespace(filename:string;
    const elementname:string;
    const namespace:string):boolean;

  function doXMLRemoveNamespace(filename:string;
    const elementname:string;
    const namespace:string):boolean;



  (* Spezielle Methoden *)
  {$IFDEF WINDOWS}
  function StartConnection (LocalName, NetResourceName: String; WaitTime : LongInt) : TSectionResult;
  {$ENDIF WINDOWS}

  (* Sektion erstellen *)
  procedure loadValidLinesFromFile (FName : String; var Section : TWorkSection);
  //procedure getLinesFromUnicodeFile (Const FName : String; var Section : TWorkSection);
  procedure ApplyTextVariables (var Sektion : TXStringList; CStringEscaping : Boolean);
  procedure ApplyTextConstants (var Sektion : TXStringList; CStringEscaping : Boolean);

  (* Sektionsbearbeitungsmethoden *)
  (* Hilfsmethoden *)
  function initSection (const Sektion: TWorkSection; var SaveErrorNumber, SaveWarningNumber: Integer) : Boolean;
  procedure finishSection (const Sektion: TWorkSection; const SaveErrorNumber, SaveWarningNumber: Integer;
                            var DiffNumberOfErrors, DiffNumberOfWarnings : Integer);

  (* fuer primaere Sektionen *)
  function doAktionen (const Sektion: TWorkSection; const CallingSektion: TWorkSection)
                                                               : TSectionResult;
  (* fuer andere Sektionen *)

  function doTextpatch (const Sektion: TWorkSection; Filename : String; PatchParameter : String)
                                                               : TSectionResult;


  function doTests (const Sektion: TWorkSection; TestParameter : String)
                                                               : TSectionResult;

  function doInifilePatches (const Sektion: TWorkSection; Filename : string;  PatchParameter : String)
                                                                 : TSectionResult;

  function doHostsPatch (const Sektion: TWorkSection; HostsFilename : String)
                                                                 : TSectionResult;
  function doIdapiConfig (const Sektion : TWorkSection; IdapiParameter : String)
                                                               : TSectionResult;

  function doLDAPsearch
          (const Sektion : TWorkSection;
          cacheRequest   : TLDAPsearchCacheRequest;
          outputRequest  : TLDAPsearchOutputRequest;
          var output: TXStringList)
                                                               : TSectionResult;
{$IFDEF WINDOWS}
  function doRegistryHack (const Sektion: TWorkSection; Const RegParameter : String; const flag_force64 : boolean)
                                                               : TSectionResult;
  function doRegistryHackInfSource (const Sektion: TWorkSection; Const RegParameter : String; const flag_force64 : boolean)
                                                               : TSectionResult;
  function doRegistryHackRegeditFormat (const Sektion: TWorkSection;
                                        Const RegParameter : String; const flag_force64 : boolean)
                                                               : TSectionResult;
  function doRegistryAllNTUserDats (const Sektion: TWorkSection;  rfSelected: TRegistryFormat; const flag_force64 : boolean)
                                                               : TSectionResult;
  function doRegistryNTUserDat (const Sektion: TWorkSection;
         rfSelected: TRegistryFormat; const flag_force64 : boolean; const UserPath : string): TSectionResult;


{$ENDIF WINDOWS}

  function doXMLPatch (const Sektion: TWorkSection; Const XMLFilename : String;
           var output: TXStringList)
                                                                 : TSectionResult;

  function doOpsiServiceHashList (const Sektion: TWorkSection;
  Const parameter : String; var output: TXStringList)
                                                                 : TSectionResult;

  function doOpsiServiceCall (const Sektion: TWorkSection; Const parameter : String;
           var output: TXStringList)
                                                                 : TSectionResult;


  function doFileActions (const Sektion: TWorkSection; CopyParameter : String)
                                                                 : TSectionResult;

  {$IFDEF WIN32}
  function doLinkFolderActions (const Sektion: TWorkSection; common : boolean)
                                                                 : TSectionResult;
  {$ENDIF WIN32}
  function doDDEwithProgman (const Sektion: TWorkSection; DDEParameter : String;
                              SaveddeWithProgman : Boolean)      : TSectionResult;
  function execWinBatch (const Sektion: TWorkSection; WinBatchParameter : String;
                 WaitConditions : TSetWaitConditions; ident : String; WaitSecs : Word;
                 runAs : TRunAs;flag_force64:boolean) : TSectionResult;
  function execDOSBatch (const Sektion: TWorkSection; BatchParameter : String;
                 ShowCmd : Integer; catchOut: Boolean;
                 WaitConditions : TSetWaitConditions;
                 var output: TXStringList)                       : TSectionResult;


  function execPython (
        const Sektion: TWorkSection; PythonParameter : String;
        catchOut : Boolean; WaitConditions : TSetWaitConditions;
        var output: TXStringList)                       : TSectionResult;


  function executeWith (
      const Sektion: TWorkSection; ExecParameter : String;
      catchOut : Boolean; 
      var output: TXStringList)                       : TSectionResult;

  function execShellCall (command : String; archparam:string): TStringlist;
end;


procedure CreateAndProcessScript (Const Scriptdatei : String;
                         NestingLevel : Integer; SaveddeWithProgman : Boolean;
                         var extremeErrorLevel : TErrorLevel);

function DefaultHosts : String;

function GetMACAddress2: string;

function FindKindOfStatement (const Statement: String;
       var SectionSpecifier :  TSectionSpecifier;
            const completeCall : String) : TStatement;
          

function GetNetUser (Host : String; Var UserName : String; var ErrorInfo : String) : Boolean;
  (* for Host = '' Username will become the name of the current user of the process *)


function getDecimalCompareSign
   (const decimalString1, decimalString2 : String;
    var sign : Integer;
    var InfoSyntaxError : String;
    stringcomparison: boolean) : Boolean;

const
  NameInitSektion                   = 'Initial';
  NameAktionenSektion               = 'Actions';
  NameProfileActionsSection         = 'ProfileActions';
  //NameAktionenSektion2              = 'Actions';

  (* Registry call parameters *)
  Parameter_SysDiffAddReg           = '/AddReg';
  Parameter_RegeditFormat           = '/Regedit';
  Parameter_AllNTUserDats           = '/AllNTUserDats';
  Parameter_RegistryBaseKey         = '/BaseKey';
  Parameter_RegistryUsercontext     = '/UserContext';
  Parameter_Registry64Bit           = '/64Bit';
  Parameter_Registry32Bit           = '/32Bit';
  Parameter_RegistrySysNative       = '/SysNative';
  Parameter_RegistryNTUserDat       = '/NTUserDat:';

  (* File section parameters *)
  Parameter_AllNTUserSendTo         = '/AllNTUserSendTo';
  Parameter_AllNTUserProfiles       = '/AllNTUserProfiles';
  Parameter_AllNTUser               = '/AllNTUser';
  Parameter_64Bit                     = '/64Bit';
  Parameter_32Bit                     = '/32Bit';
  Parameter_SysNative                = '/SysNative';

  (* 'WinBatch' *)
   ParameterDontWait                = '/LetThemGo';
   ParameterWaitOnTerminate         = '/WaitOnClose';
   ParameterCloseBehindWindow       = '/WaitForWindowVanish';
   ParameterCloseOnWindow           = '/WaitForWindowAppearing';
   ParameterWaitSecs                = '/WaitSeconds';
   ParameterWaitForProcessEnding    = '/WaitForProcessEnding';
   ParameterWaitProcessTimeoutSecs  = '/TimeOutSeconds';
   ParameterRunAsAdmin              = '/RunAsLoggedOnAdmin';
   ParameterRunAsAdmin1             = '/RunAsLoggedOnAdmin1';
   ParameterRunAsAdmin2             = '/RunAsLoggedOnAdmin2';
   ParameterRunAsAdmin3             = '/RunAsLoggedOnAdmin3';
   ParameterRunAsAdmin4             = '/RunAsLoggedOnAdmin4';
   ParameterRunAsInvoker            = '/RunAsInvoker';
   ParameterRunElevated             = '/RunElevated';
   ParameterRunAsLoggedOnUser       = '/RunAsLoggedOnUser';


  DefaultWaitProcessTimeoutSecs = 1200; //20 min

  winst_emptyregkeydat = 'winst_emptyregkey.dat';
  TempBatchfilename           = '_winstbat_';
  TempBatchdatei     = TempBatchfilename + '.cmd';
  TempBatchDatei_UniqueCount : Integer = 0;

  StopInfo             = 'Process stopped';
  AbortedInfo          = 'Process aborted';
  SpaceForEnvVarAsString = '2048';

  RegNoCallLogout = 0;
  RegCallLogout   = 2;
  RegCallReboot   = 4;


  (* Synt-Errors *)
  ErrorRemaining  = 'Char(s) at end of line not interpreted';
  
  (* Keys for ExecWith *)
  optionsSplitter = 'WINST';
  passSplitter = 'PASS';
  parameterEscapeStrings = '/EscapeStrings';


var
  PStatNames : TPStatementNames;
  flag_all_ntuser, flag_ntuser : boolean;
  runLoginScripts: boolean;
  allLoginScripts : boolean;
  inUsercontext: boolean;
  runSilent: boolean;
  scriptMode : TScriptMode;
  runProfileActions : boolean;
  runproductlist : boolean;
  opsiWinstStartdir : string;
  Script : TuibInstScript;
  scriptsuspendstate : boolean;
  scriptstopped : boolean;



  //PreDefinedVariableSkinDirectorybinaryName : String;
  //PreDefinedVariableSkinDirectoryValue : String;


implementation

uses
  {$IFDEF GUI}
  osbatchgui,
  osinteractivegui,
  {$ENDIF GUI}
  oswebservice,
  {NB30,} {for getmacadress2}
  osmain;




var
 ps : String;
 markedTime : TDateTime;

 // Expression, Remaining : String;

 OldNumberOfErrors, DiffNumberOfErrors,
 OldNumberOfWarnings, DiffNumberOfWarnings : Integer;

 local_opsidata : TOpsi4Data;

 cacheRequest   : TLDAPsearchCacheRequest;
 outputRequest  : TLDAPsearchOutputRequest;
 ldapResult : TStringList;

 //labelinfoAlignmentSave : TAlignment;

type
 TConditions = Array [0..100] of Boolean;
var
 Conditions : TConditions;
 ThenBranch : TConditions;

//const
 //zaehler  : Integer = 0;



function getCompareSignStrings (s1 : String; s2 : String) : Integer;
 var s1A, s2A : String;
begin
  s1A := AnsiUpperCase(s1);
  s2A := AnsiUpperCase(s2);
  result := 0;
  if s1A > s2A then result := 1
  else if s1A < s2A then result := -1
end;

function getCompareSign (number1 : Integer; number2 : Integer) : Integer;
begin
  result := 0;
  if number1 > number2 then result := 1
  else if number1 < number2 then result := -1
end;


function getCompareSignDouble (number1 : double; number2 : double) : Integer;
begin
  result := 0;
  if number1 > number2 then result := 1
  else if number1 < number2 then result := -1
end;


function getDecimalCompareSign
   (const decimalString1, decimalString2 : String;
    var sign : Integer;
    var InfoSyntaxError : String;
    stringcomparison: boolean) : Boolean;

var
 decimals1 : TXStringList;
 decimals2 : TXStringList;
 i : Integer;
 comparing : Boolean;
 number1 : Integer;
 number2 : Integer;

 ///partCompareResult : Integer;
 ///isEqual : Boolean;


begin

  result := true;
  if (trim (decimalString1) = '')
    or (trim (decimalString2) = '')

  then
  begin
    result := false;
    InfoSyntaxError := 'Missing value for comparing';
    exit;
  end;


  decimals1 := TXStringlist.create;
  decimals2 := TXStringlist.create;
  stringsplit(trim(decimalString1), '.', decimals1);
  stringsplit(trim(decimalString2), '.', decimals2);


  sign := 0; // we start with assumption equality
  comparing := true;
  i := 1;

  while result and comparing
  do
  Begin

     if (decimals1.count >= i) and (decimals2.count < i)
     then
     Begin
      comparing := false;
      if sign = 0 // components were equal up to now
      then
        sign := 1
     End
     else if (decimals1.count < i) and (decimals2.count >= i)
     then
     Begin
       comparing := false;
       if sign = 0
       then sign := -1
     End
     else if (decimals1.count < i) and (decimals2.count < i)
     then
     Begin
      comparing := false;
     End;


     // we continue comparing
     if comparing
     then
     begin
        if stringcomparison
        then
        begin
          sign := getCompareSignStrings(decimals1[i-1], decimals2[i-1]);
        end

        else
        begin

          try
            number1 := strtoInt (decimals1[i-1]);
            number2 := strtoInt (decimals2[i-1]);
          except
            InfoSyntaxError := 'Expecting a sequence of "." and numbers';
            result := false;
          end;

          if result
          then
            sign := getCompareSign(number1, number2);
        end;

        if sign <> 0 then comparing := false;
     End;

     inc (i);
  end;

end;



function hasRelation (orderrelationSymbol : String; orderSign : Integer; var BooleanResult : boolean; var InfoSyntaxError : String) : Boolean;
begin
   result := true;

   if orderRelationSymbol = '='       then  BooleanResult :=  (orderSign = 0)
   else if orderRelationSymbol = '>'  then  BooleanResult :=  (orderSign > 0)
   else if orderRelationSymbol = '>=' then  BooleanResult :=  (orderSign >= 0)
   else if orderRelationSymbol = '<'  then  BooleanResult :=  (orderSign < 0)
   else if orderRelationSymbol = '<=' then  BooleanResult :=  (orderSign <= 0)

   else
   Begin
     result := false;
     infoSyntaxError := '"=", ">", ">=" or "<", "<=" expected';
   end
end;



procedure adjustBounds (var a1, a2 : Integer; const list1 : TXStringList);
// adjust the lower and upper indices to the limits of the real list
begin
  //a1
   if a1 < 0 then a1 := 0;
  //a2

   if list1.count = 0
   then
     a2 := -1
   else
   begin

     if a2 >= list1.count
     then a2 := list1.count - 1
     else

       while (a2 < 0)
       do
         a2 := a2 + list1.count; // move modulo list1.count

   end;

end;

function getOrderSymbol (const s : String; var ResultString, Remaining, errorinfo : String) : Boolean;
begin
   result := true;
   if Skip ('>=', s, remaining, errorinfo) then resultstring := '>='
   else if Skip ('<=', s, remaining, errorinfo) then resultstring := '<='
   else if Skip ('>', s, remaining, errorinfo) then resultstring := '>'
   else if Skip ('<', s, remaining, errorinfo) then resultstring := '<'
   else if Skip ('=', s, remaining, errorinfo) then resultstring := '='
   else
   Begin
      result := false;
      errorinfo := 'relation symbol ("<", "=", ">" ...) expected';
   end;
end;

function GetString
  (const s : String; var ResultString, Remaining, errorinfo : String;
   StringInStringAllowed : Boolean) : Boolean;
(* reads a string that is delimited either by ' or by "  (citation mark);
   if StringInStringallowed then the function interprets a double mark
   of the appropriate kind as being contained in the string.
   resultstring takes the correctly interpreted chars
   remaining gets the original value s if result is false *)

 var
   TheMark: Char;
   r, Info, DoubleMark : String;
   continue : Boolean;
   PartValue : String='';

   //i : Integer;
   //foundDelimiter : Boolean;

begin
  result := false;
  resultString := '';
  info :='';
  r := s;
  SetLength (r, length (s));


  if (length (r) < 2)
  then
    ErrorInfo := 'String marker expected'
  else
  Begin
    logdatei.DependentAdd('r:'+r,llDebug3);
    TheMark := r[1];
    if (TheMark <> '''') and (TheMark <> '"')
    then
        ErrorInfo := '" or '' expected'
    else
    Begin
      DoubleMark := TheMark + TheMark;
      //skipA(TheMark, r, r, errorinfo);
      logdatei.DependentAdd('r:'+r,llDebug3);
      skipA(TheMark, r, r, errorinfo);
      logdatei.DependentAdd('r:'+r,llDebug3);
      Continue := true;
      while Continue do
      begin
        (*
        if (r = '') or (r[1] = theMark)
        then PartValue := ''
        else
        Begin
           i := 1;
           foundDelimiter := false;
           while not foundDelimiter and (i <= length (r))
           do
           Begin
             if r[i] = theMark
             then foundDelimiter := true
             else inc (i)
           End;

           if foundDelimiter
           then
           Begin
             PartValue := copy (r, 1, i-1);
             r := copy (r, i, length(r));
           End
           else
           Begin
             PartValue := r;
             r := '';
           End;
        End;
        *)
        logdatei.DependentAdd('r:'+r,llDebug3);
        GetWord (r, PartValue, r, [TheMark]);
        ResultString := ResultString + PartValue;
        logdatei.DependentAdd('r:'+r+' ResultString:'+ResultString,llDebug3);

        if StringInStringAllowed then
        Begin
          if SkipA (DoubleMark, r, r, Info)  //SkipA (DoubleMark, r, r, Info)
          then
            ResultString := ResultString + TheMark
          else
            Continue := false;
        End
        else
          Continue := false;
        logdatei.DependentAdd('r:'+r+' ResultString:'+ResultString,llDebug3);
      End;
      if SkipA (TheMark, r, r, ErrorInfo)//SkipA (TheMark, r, r, ErrorInfo)
      then result := true;
    End;
  End;

  if result
  //then Remaining := cutLeftBlanks (r)
  then Remaining := r
  else Remaining := s;
end;


function winstGetTempFileNameWithExt(myext:string): string;
begin
  Randomize;
  result := TempPath + TempBatchfilename + randomstr(False) +myext;
  //inc(TempBatchDatei_UniqueCount);
  //result := TempPath + TempBatchfilename + inttoStr(TempBatchDatei_UniqueCount) +myext;
end;

function winstGetTempFileName: string;
begin
  result := winstGetTempFileNameWithExt('.cmd');
end;


procedure deleteTempBatFiles(const tempfilename : string);
Var
  files : TuibFileInstall;
begin
  if tempfilename <> '' then
  begin
    // delete the actual file
    if SysUtils.DeleteFile(tempfilename) then
      Logdatei.log('The file: '+tempfilename+' has been deleted', LLDebug)
    else
      Logdatei.log('The file: '+tempfilename+' was not deleted', LLDebug);
  end;

  // delete files that are older than 2 days
  files := TuibFileInstall.create;
  try
    if tempfilename <> '' then
      files.alldelete(TempPath + TempBatchfilename + '*', false, true, 2);
  except
    LogDatei.DependentAdd('not all files "' + TempPath + TempBatchdatei + '*"  could be deleted', LLInfo);
  end;
  files.Free;
end;




function GetStringA
  (const s : String; var ResultString, Remaining, errorinfo : String;
   StringInStringAllowed : Boolean) : Boolean;
   (* eliminiert nicht fuehrende Leerzeichen *)
(* reads a string that is delimited either by ' or by "  (citation mark);
   if StringInStringallowed then the function interprets a double mark
   of the appropriate kind as being contained in the string.
   resultstring takes the correctly interpreted chars
   remaining gets the original value s if result is false *)

 var
   TheMark: Char;
   r, Info, DoubleMark : String;
   continue : Boolean;
   PartValue : String='';

   //i : Integer;
   //foundDelimiter : Boolean;

begin
  info:='';
  result := false;
  resultString := '';
  r := s;
  SetLength (r, length (s));


  if (length (r) < 2)
  then
    ErrorInfo := 'string delimiter expected'
  else
  Begin
    TheMark := r[1];
    logdatei.DependentAdd('r:'+r,llDebug2);
    if (TheMark <> '''') and (TheMark <> '"')
    then
        ErrorInfo := '" or '' expected '
    else
    Begin
      DoubleMark := TheMark + TheMark;
      //skipA(TheMark, r, r, errorinfo);
      skipA(TheMark, r, r, errorinfo);
      Continue := true;
      while Continue do
      begin
        (*
        if (r = '') or (r[1] = theMark)
        then PartValue := ''
        else
        Begin
           i := 1;
           foundDelimiter := false;
           while not foundDelimiter and (i <= length (r))
           do
           Begin
             if r[i] = theMark
             then foundDelimiter := true
             else inc (i)
           End;

           if foundDelimiter
           then
           Begin
             PartValue := copy (r, 1, i-1);
             r := copy (r, i, length(r));
           End
           else
           Begin
             PartValue := r;
             r := '';
           End;
        End;
        *)
        GetWord (r, PartValue, r, [TheMark]);
        ResultString := ResultString + PartValue;

        if StringInStringAllowed then
        Begin
          if SkipA (DoubleMark, r, r, Info)  //SkipA (DoubleMark, r, r, Info)
          then
            ResultString := ResultString + TheMark
          else
            Continue := false;
        End
        else
          Continue := false;
      End;
      if SkipA (TheMark, r, r, ErrorInfo)//SkipA (TheMark, r, r, ErrorInfo)
      then result := true;
    End;
  End;

  if result
  then Remaining := r // cutLeftBlanks (r)
  else Remaining := s;
end;

function SeekString
  (const s : String; var ResultString, Remaining, errorinfo : String) : Boolean;
  {looks for next string in s, delimited by ",
   escaping of " by \ possible}

  var
    i : Integer;
    state : Integer;
    goOn : Boolean;
begin
   result := false;
   ResultString := '';
   errorinfo := '';
   i := 1;
   goOn := true;
   state := 0;
   while goOn
   do
   Begin
     if i > length(s)
     then goOn := false
     else

     case state of
          0: // string not started
          Begin
             if s[i] = '"' then Begin state := 1;  End; //string started
          End;

          1 :
          Begin
             if s[i] = '\' then state := -1 // escape char
             else if s[i] = '"' then Begin state := 2; result := true; End //string finished
             else
               ResultString := ResultString + s[i]
          End;

         -1 :
         Begin
            ResultString := ResultString + s[i]; state := 1;
         End;

         2 : // stripping white space
         Begin
           if not ( (s[i] = ' ') or (s[i] = #9))
             then goon := false;
         End
     End;

     inc (i);
   End;



   if not result
   then
     errorinfo := 'string end mark missing';

   Remaining := copy (s, i-1, length(s));
end;


function FindKindOfStatement (const Statement: String;
                              var SectionSpecifier :  TSectionSpecifier;
                              const CompleteCall : String) : TStatement;
  var
   s : TStatement;
   test : String;
   i1, i2 : Integer;
begin
  result := tsNotDefined;
  SectionSpecifier := tsecNoSection;
  for s := tsWorkOnStringList to tsSetVar
  do
    if  UpperCase (Statement) = UpperCase (PStatNames^ [s])
    then
    Begin
      result := s;
      exit;
    End;
  for s := tsActions to tsDDEwithProgman
  do
  Begin
    if copy (UpperCase (Statement), 1, length (PStatNames^[s]))
       = UpperCase(PStatNames^[s])
    then
    Begin
      result := s;
      test := copy (UpperCase (Statement), 1, length (PStatNames^[s]));
      test := UpperCase(PStatNames^[s]);
      if length (PStatNames^[s]) < length (Statement)
      then SectionSpecifier := tsecIncluded
      else SectionSpecifier := tsecExpected;

      //special hack for tsExecuteWith
      if result = tsExecuteWith
      then
      Begin
        i1 := pos (lowercase(OPTIONSSPLITTER) + ' ', lowercase(completecall));
        if (i1 > 0)
        then
        Begin
            i2 :=  pos ( lowercase(parameterEscapeStrings) ,
                         lowercase( copy(completecall, i1, length(completecall) ) ) );
            if i2 > 0
            then result := tsExecuteWith_escapingStrings
        end;
      end;
      exit;
    End;
  End;


end;


function DefaultHosts : String;
begin
  {$IFDEF WINDOWS}
  if UpperCase (ValueOfEnvVar ('OS')) = 'WINDOWS_NT'
  then
    result :=   GetWinDirectory + 'system32\drivers\etc\'
               (* DefaultHostsDir0 *)
  else
    result  :=  GetWinDirectory;
               (* DefaultHostsDir1; *)
  result := result + 'hosts'
  {$ELSE WINDOWS}
  result := '/etc/hosts'
  {$ENDIF WINDOWS}
end;

//from https://github.com/silvioprog/lazsolutions/blob/master/Units/LSUtils.pas
function LSLoadFile(const AFileName: TFileName): string;
begin
  with TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite) do
  begin
    try
      SetLength(Result, Size);
      Read(Pointer(Result)^, Size);
    except
      Result := '';
      Free;
      raise;
    end;
    Free;
  end;
end;

function readFirstLineFromFile(filename : string) : string;
var
  myfile : text;
  myresult : string;
begin
  try
    assignfile(myfile,filename);
    reset(myfile);
    readln(myfile,myresult);
    closefile(myfile);
    result := myresult;
  except
    Result := '';
    raise;
  end;
end;


{$IFDEF FPC}
//function LSGetMACAddress: string;
function GetMACAddress2: string;
{$IFDEF MSWINDOWS}
type
  TCreateGUIDFunction = function(AGUID: PGUID): LongInt; stdcall;
{$ENDIF}
var
{$IFDEF UNIX}
  VPath, VDevice: string;
{$ENDIF}
{$IFDEF MSWINDOWS}
  VLibHandle: TLibHandle;
  VCreateGUIDFunction: TCreateGUIDFunction;
  VGUID1, VGUID2: TGUID;
{$ENDIF}
const
CLSFormatMACMask = '%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x';
begin
{$IFDEF UNIX}
  VDevice := 'eth0';
  VPath := Format('/sys/class/net/%s/address', [VDevice]);
  if FileExists(VPath) then
    Result := readFirstLineFromFile(VPath)
  else
    Result := 'Could not find the device "' + VDevice + '".';
{$ENDIF}
{$IFDEF MSWINDOWS}
  VLibHandle := LoadLibrary('rpcrt4.dll');
  try
    if VLibHandle <> NilHandle then
    begin
      VCreateGUIDFunction := TCreateGUIDFunction(GetProcedureAddress(VLibHandle,
        'UuidCreateSequential'));
      if Assigned(VCreateGUIDFunction) then
        if (VCreateGUIDFunction(@VGUID1) = 0) and
          (VCreateGUIDFunction(@VGUID2) = 0) and (VGUID1.D4[2] = VGUID2.D4[2]) and
          (VGUID1.D4[3] = VGUID2.D4[3]) and (VGUID1.D4[4] = VGUID2.D4[4]) and
          (VGUID1.D4[5] = VGUID2.D4[5]) and (VGUID1.D4[6] = VGUID2.D4[6]) and
          (VGUID1.D4[7] = VGUID2.D4[7]) then
            Result := Format(CLSFormatMACMask, [VGUID1.D4[2], VGUID1.D4[3],
                        VGUID1.D4[4], VGUID1.D4[5], VGUID1.D4[6], VGUID1.D4[7]]);
    end;
  finally
    UnloadLibrary(VLibHandle);
  end;
{$ENDIF}
end;
{$ELSE}

function GetMACAddress2: string;
var
  NCB: PNCB;
  Adapter: PAdapterStatus;

  URetCode: PChar;
  RetCode: char;
  I: integer;
  Lenum: PlanaEnum;
  _SystemID: string;
  TMPSTR: string;
begin
  Result    := '';
  _SystemID := '';
  Getmem(NCB, SizeOf(TNCB));
  Fillchar(NCB^, SizeOf(TNCB), 0);

  Getmem(Lenum, SizeOf(TLanaEnum));
  Fillchar(Lenum^, SizeOf(TLanaEnum), 0);

  Getmem(Adapter, SizeOf(TAdapterStatus));
  Fillchar(Adapter^, SizeOf(TAdapterStatus), 0);

  Lenum.Length    := chr(0);
  NCB.ncb_command := chr(NCBENUM);
  NCB.ncb_buffer  := Pointer(Lenum);
  NCB.ncb_length  := SizeOf(Lenum);
  RetCode         := Netbios(NCB);

  i := 0;
  repeat
    Fillchar(NCB^, SizeOf(TNCB), 0);
    Ncb.ncb_command  := chr(NCBRESET);
    Ncb.ncb_lana_num := lenum.lana[I];
    RetCode          := Netbios(Ncb);

    Fillchar(NCB^, SizeOf(TNCB), 0);
    Ncb.ncb_command  := chr(NCBASTAT);
    Ncb.ncb_lana_num := lenum.lana[I];
    // Must be 16
    Ncb.ncb_callname := '*               ';

    Ncb.ncb_buffer := Pointer(Adapter);

    Ncb.ncb_length := SizeOf(TAdapterStatus);
    RetCode        := Netbios(Ncb);
    //---- calc _systemId from mac-address[2-5] XOR mac-address[1]...
    if (RetCode = chr(0)) or (RetCode = chr(6)) then
    begin
      _SystemId := IntToHex(Ord(Adapter.adapter_address[0]), 2) + ':' +
        IntToHex(Ord(Adapter.adapter_address[1]), 2) + ':' +
        IntToHex(Ord(Adapter.adapter_address[2]), 2) + ':' +
        IntToHex(Ord(Adapter.adapter_address[3]), 2) + ':' +
        IntToHex(Ord(Adapter.adapter_address[4]), 2) + ':' +
        IntToHex(Ord(Adapter.adapter_address[5]), 2);
    end;
    Inc(i);
  until (I >= Ord(Lenum.Length)) or (_SystemID <> '00-00-00-00-00-00');
  FreeMem(NCB);
  FreeMem(Adapter);
  FreeMem(Lenum);
  GetMacAddress2 := _SystemID;
end;
{$ENDIF}


{
Type
 TGUID=record
  A,B:word;
  D,M,S:word;
  MAC:array[1..6] of byte;
 end;

function GetMACAddress1:String;
var
 UuidCreateFunc : function (var guid: TGUID):HResult;stdcall;
 handle : THandle;
 g:TGUID;
 WinVer:_OSVersionInfoA;
 i:integer;
 ErrCode: HResult;
begin
 WinVer.dwOSVersionInfoSize := sizeof(WinVer);
 getversionex(WinVer);

 handle := LoadLibrary('RPCRT4.DLL');
 if WinVer.dwMajorVersion >= 5 then (* Windows 2000 *)
  @UuidCreateFunc := GetProcAddress(Handle, 'UuidCreateSequential')
 else
  @UuidCreateFunc := GetProcAddress(Handle, 'UuidCreate') ;

 UuidCreateFunc(g);
 result:='';
 for i:=1 to 6 do
   result:=result+IntToHex(g.MAC[i],2);
end;

}


{
procedure DeleteRegKey(aRoot : HKey; aPath : String);
var
  SL : TStringList;
  X : Integer;
begin
  SL := TStringList.Create;
  with TRegistry.Create do
  try
    RootKey := aRoot;
    if OpenKey(aPath,true) then begin
      GetKeyNames(SL);
      For X:=0 to SL.Count-1 do DeleteRegKey(aRoot,aPath + '\' + SL[X]);
      CloseKey;
      DeleteKey(aPath);
    end;
  finally
    Free;
    SL.Free;
  end;
end;

}

function GetNetUser (Host : String; Var UserName : String; var ErrorInfo : String) : Boolean;
{$IFDEF WINDOWS}
  (* for Host = '' Username will become the name of the current user of the process *)

var
  pLocalName : PChar;
  pUserName  : PChar;


  function ApiCall (var Username, ErrorInfo : String; BuffSize : DWord) : Boolean;
   var
   errorcode : DWord;
   nBuffSize  : DWord;
   pErrorBuff, pNameBuff : PChar;
   nErrorBuffSize : DWord=0;
   nNameBuffSize : DWord=0;


  begin
    result := false;
    GetMem (pUserName, BuffSize);
    nBuffSize := Buffsize;

    UserName := '';
    errorCode := WNetGetUser(nil, pUserName, nBuffSize);


    case errorCode of
      no_error                  :
        Begin
         ErrorInfo := '';
         SetLength (UserName, StrLen (pUserName));
         UserName := pUserName;
         result := true;
        End;
      ERROR_NOT_CONNECTED      : ErrorInfo :=
      'The device specified by lpszLocalName is not a redirected device or a connected network name.';
      ERROR_MORE_DATA      : ApiCall (UserName, ErrorInfo, nBuffSize + 1);
      ERROR_NO_NETWORK      : ErrorInfo := 'No network is present.';
      ERROR_EXTENDED_ERROR      :
         Begin
           GetMem (pErrorBuff, 300);
           GetMem (pNameBuff, 300);
           WNetGetLastError (errorcode, pErrorBuff, nErrorBuffSize, pNameBuff, nNameBuffSize);
           ErrorInfo := pErrorBuff;
           FreeMem (pErrorBuff);
           FreeMem (pNameBuff);
         End;
      ERROR_NO_NET_OR_BAD_PATH   : ErrorInfo :=
         'None of the providers recognized this local name as having a connection. '
       + 'However, the network is not available for at least one provider to whom the connection may belong';
      else
      errorInfo := 'NT-Error ' + RemoveLineBreaks(SysErrorMessage (errorCode));
    end;

    if errorCode <> no_error then errorInfo := IntToStr (errorCode) + ' ' + errorInfo;

    FreeMem (pUserName);
  end;


Begin
  if Host <> ''
  then pLocalName := PChar (Host)
  else pLocalName := nil;

  if ApiCall (Username, ErrorInfo, 100)
  then result := true
  else result := false;
End;
{$ELSE WINDOWS}
begin
  //###LINUX
  result := true;
  Username := getCommandResult('/bin/bash -c whoami');
end;
{$ENDIF WINDOWS}

constructor TWorkSection.create (const NestLevel : Integer);
begin
  inherited create;
  FStartLineNo  := 0;
  FSectionName  := '';
  FNestingLevel := NestLevel;
end;

destructor TWorkSection.destroy;
begin
  inherited destroy;
end;

{$IFDEF FPC}
{$ELSE}
// *** TuibXMLNodeDescription ****
//

constructor TuibXMLNodeDescription.Create (xmldoc : TuibXMLDocument);
begin
 inherited create;
 fxmldoc := xmldoc;
end;

destructor TuibXMLNodeDescription.Destroy;
begin

 inherited destroy;
end;


function TuibXMLNodeDescription.evaluate (s : String; var Remaining: String;
                                           var  InfoSyntaxError : String) : Boolean;

 var
  r : String;
  syntaxCheck : Boolean;
  syntaxInfo : String;
  elementname : String;

begin
  r := lowercase (s);

  syntaxCheck := false;
  InfoSyntaxError := '';

  if Skip ('(', s, r, syntaxInfo)  // geklammerter Ausdruck
  then
  begin
   if evaluate (r, r, syntaxInfo)
   and Skip (')', r, r, syntaxInfo)
   then
      syntaxCheck := true;
  end


  else if Skip ('elementname', r, r, syntaxInfo)
  then
  Begin

    if GetString (r, elementname, r, InfoSyntaxError, false)
    then
    begin
      syntaxCheck := true;
      //Fxmldoc.filterByChildelement(elementname)
    end;

  end

  else if Skip ('attribute', r, r, syntaxInfo)
  then
  Begin

  end

  else if Skip ('position', r, r, syntaxInfo)
  then
  Begin

  end

  else
  begin
     InfoSyntaxError := 'XML Path description not accepted'
  end;


  Remaining := r;
end;

procedure TuibXMLNodeDescription.evaluateElementname;
begin
end;
procedure TuibXMLNodeDescription.evaluateAttribute;
begin
end;
procedure TuibXMLNodeDescription.evaluateText;
begin
end;
{$ENDIF}



constructor TuibInstScript.create;

Begin
  inherited create;
  FNumberOfErrors := 0;
  FNumberOfWarnings := 0;

  FExtremeErrorLevel := level_not_initialized;

  FLogLevel := LLinfo;
  FExitOnError := false;
  FReportMessages := true;
  FTraceMode := false;
  FFatalOnSyntaxError := true;
  FFatalOnRuntimeError := false;
  FSuspended := false;
  FAutoActivityDisplay := false;
  scriptstopped := false;

  VarList := TStringList.create;
  //VarList.add(PreDefinedVariableSkinDirectory);
  ValuesList := TStringList.create;
  //ValuesList.add(PreDefinedVariableSkinDirectoryValue);

  listOfStringLists := TStringList.create;
  ContentOfStringLists := TObjectList.create;
  ConstList := TStringList.create;
  ConstValuesList := TStringList.create;
  FLinesOriginList := TStringList.create;
End;

destructor TuibInstScript.destroy;
begin
  VarList.free; VarList := nil;
  ValuesList.free; ValuesList := nil;
  listOfStringLists.free; listOfStringLists := nil;
  ContentOfStringLists.free; ContentOfStringLists := nil;
  FLinesOriginList.free; FLinesOriginList := nil;
end;



procedure TuibInstScript.LoadValidLinesFromFile (FName : String; var Section : TWorkSection);
 var
  OriginalList : TXStringList;
  s : String;
  i : Integer;
  Encoding2use,usedEncoding : string;
begin
  Section.Clear;
  OriginalList := TXStringList.create;
  OriginalList.LoadFromFile (ExpandFileName(FName));
  Encoding2use := searchencoding(OriginalList.Text);
  if Encoding2use = '' then Encoding2use := 'system';
  OriginalList.Text:=  reencode(OriginalList.Text, Encoding2use,usedEncoding);
  logdatei.DependentAdd('Loaded sub from: '+FName+' with encoding: '+usedEncoding,LLDebug);
  for i := 1 to OriginalList.count do
  Begin
      s := cutLeftBlanks (OriginalList.Strings [i-1]);
      (* if (s<>'') and  (s[1] <> LineIsCommentChar) then *)
        Section.Add (s);
        script.FLinesOriginList.Append(FName+' line: '+inttostr(i));
  End;
  OriginalList.free;
End;


function TuibInstScript.reportError (const Sektion: TWorkSection; LineNo : Integer;
             Const Content : String; Comment: String) : TSectionResult;

begin
  result := tsrPositive;
  ps := 'Syntax Error in Section: ' + Sektion.Name +
    ' (Command in line ' + IntToStr (Sektion.StartLineNo + LineNo)
      + ' origin: '+FLinesOriginList.Strings[Sektion.StartLineNo + LineNo-1]+'): '
      + Content+' -> '+Comment;
  LogDatei.DependentAdd(ps,LLCritical);
  if FatalOnSyntaxError then
  begin
    FExtremeErrorLevel:=LevelFatal;
    LogDatei.ActionProgress:='Syntax Error';
  end;
  inc(FNumberOfErrors);
  //Topsi4data(opsidata).ActionProgress:= 'Script Syntax Error';
  if ReportMessages then
  Begin
    ps := 'Section   ' + Sektion.Name +
                ' (Command in line ' + IntToStr (Sektion.StartLineNo + LineNo) + '):'
          + LineEnding + Content
          + LineEnding + Comment;
    {$IFDEF GUI}
    if MyMessageDlg.WiMessage (ps, [mrOK, mrAbort]) = mrAbort
      then result := tsrExitProcess;
    {$ELSE GUI}
    writeln(ps);
    //result := tsrExitProcess;
    {$ENDIF GUI}
  End;

end;


function TuibInstScript.getVarValues : TStringList;
var
  k : Integer;
begin
  if FVarList <> nil
  then
  begin
    k := FVarList.IndexOf('%loglevel%');
    if k > -1
    then
      FValuesList.strings[k] := IntToStr (Logdatei.LogLevel);
  end;
  result := FValuesList;
end;


function TuibInstScript.doInfo (Meldung: String) : TSectionResult;
begin
  {$IFDEF GUI}
  result := tsrPositive;
  CentralForm.Label1.Caption := Meldung;

  //FBatchOberflaeche.LabelInfo.alignment := labelinfoAlignmentSave;

  (*
  if FBatchOberflaeche.LabelInfo.Canvas.TextWidth(Meldung) > FBatchOberflaeche.LabelInfo.Width
  then
  Begin
    labelinfoAlignmentSave := FBatchOberflaeche.LabelInfo.alignment;
    FBatchOberflaeche.LabelInfo.alignment := taLeftJustify;
    //FBatchOberflaeche.LabelInfo.Width := FBatchOberflaeche.LabelInfo.Canvas.TextWidth(Meldung);
  End;
  *)

  // do not auto size short labels because this will look ugly
  // use optimalfill to decrease the font only on large labels
  FBatchOberflaeche.LabelInfo.Font.Size := LableInfoDefaultFontSize;
  if FBatchOberflaeche.LabelInfo.Canvas.TextWidth(Meldung) >
    (FBatchOberflaeche.LabelInfo.Width - FBatchOberflaeche.LabelInfo.Width div 5) then
    FBatchOberflaeche.LabelInfo.OptimalFill := True
  else
  begin
    FBatchOberflaeche.LabelInfo.OptimalFill := False;
    FBatchOberflaeche.LabelInfo.Font.Size := LableInfoDefaultFontSize;;
  end;


  FBatchOberflaeche.setInfoLabel(Meldung);
  {$ELSE GUI}
  result := tsrPositive;
  writeln(Meldung);
  {$ENDIF GUI}
end;

function TuibInstScript.doLogEntries (const Lines : String; EntryLevel : Integer)
   : TSectionResult;
var
  ManyLines, line : String;
  i : Byte;
begin
  result := 0;
  ManyLines := Lines;
  repeat
    i := pos (LineEnding, ManyLines);
    if i > 0 then
    Begin
      line := copy (ManyLines, 1, i - 1);
      ManyLines := copy (ManyLines, i+2, length (ManyLines))
    End
    else
      line := ManyLines;
    LogDatei.DependentAdd (Line, EntryLevel);

  until i = 0;
  {$IFDEF GUI}
  if logdatei.LogLevel >= EntryLevel then
  begin
    if Line = PStatNames^ [tsCondOpen] then Line := '|';
    if Line = PStatNames^ [tsCondThen] then Line := '/';
    if Line = PStatNames^ [tsCondElse] then Line := '-';
    if Line = PStatNames^ [tsCondClose] then Line := '\';
    CentralForm.Label2.caption := Line;
    FBatchOberflaeche.setDetailLabel(Line);
  end;

  ProcessMess;
  {$ENDIF GUI}

  result := tsrPositive;
end;


function TuibInstScript.initSection (const Sektion: TWorkSection;
   var SaveErrorNumber, SaveWarningNumber : Integer) : Boolean;
begin
  result := true;
  if Sektion.count = 0 then result := false;

  SaveErrorNumber := LogDatei.NumberOfErrors;
  SaveWarningNumber := LogDatei.NumberOfWarnings;
  //LogDatei.ErrorNumberMarked := SaveErrorNumber;

  (* LogDatei.LogSIndentLevel := Sektion.NestingLevel; *)
  ps := '';
  LogDatei.DependentAdd (ps, LevelWarnings);
  if Sektion.count > 0 then
  begin
    ps := 'Execution of ' + Sektion.Name;
    LogDatei.DependentAdd (ps, LevelWarnings);
  end
  else
  // this case should be captured beforehand
    LogDatei.log ('Warning: Section  "' + Sektion.Name + '"  does not exist or is empty', LLWarning);

  //ps := (*  'Ausfuehrung von ' +  *) copy (Sektion.Name, length (PStatNames^ [Sektion.fSectionKind]) + 1,
  //                                length (Sektion.Name));
  ps := Sektion.Name;
  {$IFDEF GUI}
  CentralForm.Label2.caption := ps;
  FBatchOberflaeche.setDetailLabel(CentralForm.Label2.caption);
  {$ENDIF GUI}
end;

procedure TuibInstScript.finishSection (const Sektion: TWorkSection;
   const SaveErrorNumber, SaveWarningNumber : Integer;
   var DiffNumberOfErrors, DiffNumberOfWarnings : Integer);
begin
  DiffNumberOfErrors := LogDatei.NumberOfErrors - SaveErrorNumber;
  DiffNumberOfWarnings := LogDatei.NumberOfWarnings - SaveWarningNumber;
  FNumberOfErrors := SaveErrorNumber + DiffNumberOfErrors;
  FNumberOfWarnings := SaveWarningNumber + DiffNumberOfWarnings;
  {$IFDEF GUI}
  CentralForm.Label2.caption := CentralForm.Label2.caption + ' finished';
  FBatchOberflaeche.setDetailLabel(CentralForm.Label2.caption);

  (* LogDatei.LogSIndentLevel := Sektion.NestingLevel; *)
  ProcessMess;
  {$ENDIF GUI}
end;

function TuibInstScript.doTextpatch (const Sektion: TWorkSection; Filename : String; PatchParameter : String)
                                                               : TSectionResult;

var
  i, j, insertLineIndx: Integer;
  methodname : String='';
  s : String='';
  r : String='';
  s0 : String='';
  s1 : String='';
  s2 : String='';
  startofline : String='';
  oldLine : String='';
  old_s2 : String='';
  x : String='';
  found : Boolean;
  lastfind : Boolean;
  PatchListe : TpatchList;
  ErrorInfo : String='';
  FileError : String='';
  syntaxCheck : Boolean;
  indx : Integer;
  d, sum : Integer;
  saveToOriginalFile : Boolean;
  working : Boolean;
  goOn : Boolean;
  secondStringList : TStringList;
  PatchFilename : String='';
  Patchdatei : TuibPatchIniFile;
  ProfileList : TStringlist;
  pc: Integer=0;

  procedure CheckRemainder (Var SyntaxCheck : Boolean);
  begin
    if r <> ''
    then
      errorinfo := ErrorRemaining
    else
      syntaxCheck := true;
  end;



  procedure doTextpatchMain(const Section : TXStringList; const presetDir : string);
  var
  i: Integer=0;
  index: Integer=0;
  patchlistcounter : Integer=0;
  workingSection : TXStringList;
  NameValueSeparator : char;

  begin
    //ps := LogDatei.LogSIndentPlus (+3) + 'FILE ' +  PatchdateiName;
    //LogDatei.DependentAdd (ps, LevelWarnings);
    Logdatei.DependentAdd('', LLInfo);
    Logdatei.DependentAdd('Patching: '+PatchFilename, LLInfo);
    ps := LogDatei.LogSIndentPlus (+3) + 'FILE ' +  PatchFilename;
    LogDatei.DependentAdd (ps, LevelWarnings);

    workingSection := TXStringList.Create;
    workingSection.Assign(Section);
    workingSection.GlobalReplace(1, '%userprofiledir%', copy (presetDir, 1, length(presetDir) - 1), false);
    workingSection.GlobalReplace(1, '%currentprofiledir%', copy (presetDir, 1, length(presetDir) - 1), false);


    if not FileExists (ExpandFileName(PatchFilename))
    then
    Begin
      ps := LogDatei.LogSIndentPlus (+3) + 'Info: This file does not exist and will be created ';
      LogDatei.log (ps, LLInfo);
      LogDatei.NumberOfHints := Logdatei.NumberOfHints + 1;

      if CreateTextfile (ExpandFileName(PatchFilename), ErrorInfo)
      then
      Begin
       if ErrorInfo <> ''
       then
       Begin
         ps := LogDatei.LogSIndentPlus (+3) + 'Warning: ' + ErrorInfo;
         LogDatei.log (ps, LLWarning);
       End;
      End
      else
      Begin
         ps := LogDatei.LogSIndentPlus (+3) + 'Error: ' + ErrorInfo;
         LogDatei.log (ps, LLError);
         exit; // ------------------------------  exit
       End;
    End;


    ProcessMess;
    LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;

    // create the list we work on
    PatchListe := TPatchList.Create;
    PatchListe.clear;
    PatchListe.ItemPointer := -1;
    PatchListe.LoadFromFile (ExpandFileName(PatchFilename));
    PatchListe.Text:= reencode(PatchListe.Text,'system');
    saveToOriginalFile := true;
    lastfind := false;

    i := 1;
    syntaxcheck := true;
    while (i <= workingSection.count) and syntaxcheck
    do
    Begin
      ErrorInfo := '';
      syntaxCheck := false;
      r := cutLeftBlanks (workingSection.strings [i-1]);
      if (r = '') or (r [1] = LineIsCommentChar)
      then
        syntaxCheck := true
       // continue
      else
      Begin
        logdatei.log('Patchtextfile: command: '+r,LLDebug3);
        GetWord (r, methodname, r, WordDelimiterSet1);

        if LowerCase (methodname) = 'sorted'
        then
        Begin
          CheckRemainder (syntaxCheck);

          if SyntaxCheck
          then
          Begin
            PatchListe.Sort;
            PatchListe.Sorted := true;
          End;
        End

        else if LowerCase (methodname) = 'findline'
        then
        begin
          if GetString (r, s, r, errorinfo, true)
          then CheckRemainder (syntaxCheck);

          if syntaxCheck
          then
            PatchListe.ItemPointer
             := PatchListe.FindFirstItem (s, false, PatchListe.ItemPointer, lastfind);
        end

        else if LowerCase (methodname) = 'findline_containing'
        then
        Begin
          if GetString (r, s, r, errorinfo, true)
          then CheckRemainder (syntaxCheck);

          if syntaxCheck then
            PatchListe.ItemPointer
              := PatchListe.FindFirstItemWith (s, false, PatchListe.ItemPointer);
        End

        else if LowerCase (methodname) = 'findline_startingwith'
        then
        Begin
          LogDatei.DependentAdd('r:'+r+' s:'+s,LLDebug3);
          if GetString (r, s, r, errorinfo, true)
          then CheckRemainder (syntaxCheck);
          LogDatei.DependentAdd('r:'+r+' s:'+s,LLDebug3);
          if syntaxCheck then
           PatchListe.ItemPointer
           := PatchListe.FindFirstItemStartingWith (s, false, PatchListe.ItemPointer);
        End

        else if LowerCase (methodname) = lowerCase ('DeleteAllLines_StartingWith')
        then
        Begin
          if GetString (r, s, r, errorinfo, true)
          then CheckRemainder (syntaxCheck);

          if syntaxCheck
          then
          Begin
            indx := PatchListe.FindFirstItemWith (s, false, -1);
            while indx > -1
            do
            Begin
              PatchListe.delete (indx);
              indx := PatchListe.FindFirstItemStartingWith (s, false, -1);
            End;
          End;
        End

        else if LowerCase (methodname) = 'advanceline'
        then
        Begin
          syntaxCheck := true;
          if r = ''
          then
            d := 1
          else
            try
              d := StrToInt (r);
            except
              syntaxCheck := false;
              errorInfo := r + ' is not an integer value ';
            end;

          if SyntaxCheck
          then
          Begin
            sum := PatchListe.ItemPointer + d;
            if sum < 0
              then PatchListe.ItemPointer := 0
            else if sum > PatchListe.Count - 1
              then PatchListe.ItemPointer := PatchListe.Count - 1
            else PatchListe.ItemPointer := sum;
          End;
        End

        else if LowerCase (methodname) = lowercase ('GoToTop')
        then
        Begin
          CheckRemainder (syntaxCheck);

          //if PatchListe.count > 0
          //then
          PatchListe.SetItemPointer (-1);
        End

        else if LowerCase (methodname) = LowerCase ('GoToBottom')
        then
        Begin
          CheckRemainder (syntaxCheck);

          if PatchListe.count > 0
          then
            PatchListe.ItemPointer := PatchListe.count - 1
        End

        else if (LowerCase (methodname) = 'insert_line')
           or   (LowerCase (methodname) = 'insertline')
        then
        Begin
          if GetStringA (r, s, r, errorinfo, true)
          then CheckRemainder (syntaxCheck);

          if syntaxCheck
          then
          if (PatchListe.ItemPointer > -1)
          then
            PatchListe.insert (PatchListe.ItemPointer, s)
          else if PatchListe.count = 0
          then
            PatchListe.add (s)
          else
            PatchListe.insert (0, s);

        End

        else if (LowerCase (methodname) = 'append_line')
             or (LowerCase (methodname) = 'appendline')
        then
        Begin
          if GetStringA (r, s, r, errorinfo, true)
          then CheckRemainder (syntaxCheck);

          if syntaxCheck
          then
          if (PatchListe.ItemPointer > -1) and (PatchListe.ItemPointer < PatchListe.count - 1)
          then
          Begin
            PatchListe.ItemPointer := PatchListe.ItemPointer + 1;
            PatchListe.insert (PatchListe.ItemPointer , s)
          End
          else
            PatchListe.add (s);
        End

        else if  (LowerCase (methodname) = 'append_file')
              or (LowerCase (methodname) = 'appendfile')
        then
        Begin
          if GetString (r, s1, r, errorinfo, true)
          then CheckRemainder (syntaxCheck);

          if syntaxCheck
          then
          Begin
            s1 := ExpandFileName(s1);
            working := CheckFileExists (s1, FileError);
            if working
            then
            begin
              try
                 secondStringList := TStringList.create;
                 secondStringList.LoadFromFile (ExpandFileName(s1));
                 secondStringList.Text:= reencode(secondStringList.Text, 'system');
                 PatchListe.addStrings (secondStringList);
                 secondStringList.Free;
              except
                   on ex: Exception
                   do
                   begin
                     FileError := ex.message;
                     working := false;
                   end;
              end;
            End;

            if working
            then
              LogDatei.DependentAdd ('Appended "' + s1 + '"', LevelComplete)
            else
            Begin
              LogDatei.DependentAddError
                         ('Error: Could not append "' + s1 + '" , ' + FileError,
                                      BaseLevel);
            End;
          End;
        End

        else if LowerCase (methodname) = 'deletetheline'
        then
        Begin
          CheckRemainder (syntaxCheck);

          if syntaxCheck
          then
            PatchListe.delete (PatchListe.ItemPointer)
        End

        else if   (LowerCase (methodname) = 'deleteline')
               or (LowerCase (methodname) = 'delete_line')
        then
        Begin
          if GetString (r, s1, r, errorinfo, true)
            then CheckRemainder (syntaxCheck);

            if syntaxCheck
            then
            Begin
              indx := PatchListe.FindFirstItem (s1, false, PatchListe.ItemPointer, lastfind);
              if lastfind then PatchListe.delete (indx);
            End
        End

        else if (LowerCase (methodname) = 'addline')
             or (LowerCase (methodname) = 'add_line')
        then
        Begin
          if GetString (r, s, r, errorinfo, true)
          then CheckRemainder (syntaxCheck);

          if syntaxCheck then
            PatchListe.Add (s)
        End

        else if (LowerCase (methodname) = LowerCase('setKeyValueSeparator'))
        then
        Begin
          if GetString (r, s, r, errorinfo, true)
          then CheckRemainder (syntaxCheck);
          if Length(s) = 1 then
          begin
            NameValueSeparator :=   char(s[1]);
            LogDatei.log('KeyValueSeparator changed from: >'+ PatchListe.NameValueSeparator +
                         '< to : >'+ NameValueSeparator +'<',LLNotice);
          end
          else
          begin
            syntaxCheck := false;
            ErrorInfo := 'KeyValueSeparator has to be a char';
          end;
          if syntaxCheck then
            PatchListe.NameValueSeparator := NameValueSeparator;
        End

        else if (LowerCase (methodname) = LowerCase('setValueByKey'))
        then
        Begin
          if GetStringA (trim(r), s1, r, errorinfo, true) then
          begin
            logdatei.log('key= '+s1,LLDebug2);
            if GetStringA (trim(r), s2, r, errorinfo, true) then
            begin
              logdatei.log('value= '+s2,LLDebug2);
              syntaxCheck := true;
            end
            else  syntaxCheck := false
          end
          else  syntaxCheck := false;
          if syntaxCheck then
          begin
            // the fast way:
            index := PatchListe.IndexOfName(s1);
            if index = -1 then
            begin
              // let us retry with trimed keys
             for patchlistcounter := 0 to PatchListe.Count -1 do
             begin
               if PatchListe.Names[patchlistcounter] <> '' then
                 if lowerCase(trim(PatchListe.Names[patchlistcounter])) = lowerCase(trim(s1)) then
                   index := PatchListe.IndexOfName(PatchListe.Names[patchlistcounter]);
             end;
            end;
            if index = -1 then
            begin
              logdatei.log('Key: '+s1+' not found - creating',LLNotice);
              if (PatchListe.ItemPointer > -1) and (PatchListe.ItemPointer < PatchListe.count - 1)
              then
              Begin
                PatchListe.ItemPointer := PatchListe.ItemPointer + 1;
                PatchListe.insert (PatchListe.ItemPointer , s1+PatchListe.NameValueSeparator+s2);
              End
              else
                PatchListe.add (s1+PatchListe.NameValueSeparator+s2);
            end
            else
            begin
              logdatei.log('Key: '+s1+' found - Value was: >'+PatchListe.ValueFromIndex[index]+
                           '< setting to: >'+s2+'<' ,LLnotice);
              PatchListe.ValueFromIndex[index] := s2;
            end;
          end;
        End

        else if (LowerCase (methodname) = LowerCase('searchAndReplace'))
        then
        Begin
          if GetStringA (trim(r), s1, r, errorinfo, true) then
          begin
            logdatei.log('search string= '+s1,LLDebug2);
            if GetStringA (trim(r), s2, r, errorinfo, true) then
            begin
              logdatei.log('replace string= '+s2,LLDebug2);
              syntaxCheck := true;
            end
            else  syntaxCheck := false
          end
          else  syntaxCheck := false;
          if syntaxCheck then
          begin
           if patchliste.GlobalReplace(1,s1,s2,false) then
             logdatei.log('Replaced all occurrences of  "'+s1+'" by "'+s2+'".',LLNotice)
           else
             logdatei.log('No occurrences of  "'+s1+'" found - nothing replaced.',LLNotice)
          end;
        End

        else if (LowerCase (methodname) = lowerCase ('SaveToFile'))
        then
        Begin
          saveToOriginalFile := false;
          LogDatei.DependentAdd ('saveToOriginalFile = false', LevelComplete);
          if GetString (r, s1, r, ErrorInfo, false)
          then CheckRemainder (syntaxCheck);

          if SyntaxCheck then
          Begin
             s1 := ExpandFileName(s1);
             working := CheckFileExists (s1, FileError) or CreateTextFile (s1, FileError);
             if working then
               try
                  PatchListe.SaveToFile (s1);
               except
                  on ex: Exception do
                  begin
                     FileError := ex.message;
                     working := false;
                  end;
               end;

             if working
             then
               LogDatei.DependentAdd ('The lines are saved to "' + s1 + '"', LevelComplete)
             else
             Begin
               LogDatei.DependentAddError ('Error: Could not save lines to "' + s1 + '" , ' + FileError,
                                       BaseLevel);
             End;
          End;
        End

        else if (LowerCase (methodname) = lowerCase ('Subtract_File'))
        then
        Begin
          if GetString (r, s1, r, ErrorInfo, false)
          then CheckRemainder (syntaxCheck);

          if SyntaxCheck then
          Begin
            s1 := ExpandFileName(s1);
            working := CheckFileExists (s1, FileError);
            if working
            then
            Begin
              try
                 secondStringList := TStringList.create;
                 secondStringList.LoadFromFile (ExpandFileName(s1));
                 secondStringList.Text:= reencode(secondStringList.Text, 'system');
                 patchliste.SetItemPointer(0);

                 j := 0;
                 goOn := true;
                 while (patchliste.count > 0) and (j + 1 <= secondStringList.count) and goOn
                 do
                 Begin
                    if patchliste.strings [0] = secondStringList.strings [j]
                    then
                    Begin
                       patchliste.delete(0);
                       inc (j);
                    end
                    else
                       goOn := false
                 End;
                 secondStringList.free;
              except
                   on ex: Exception
                   do
                   begin
                     FileError := ex.message;
                     working := false;
                   end;
              end;
            End;

            if working
            then
              LogDatei.DependentAdd ('Subtracted "' + s1 + '"', LevelComplete)
            else
              LogDatei.DependentAddError ('Error: Could not substract "' + s1 + '" , ' + FileError,
                                      BaseLevel);
          End;
        End

        else if LowerCase (methodname) = lowercase ('Set_Mozilla_Pref')
        then
        Begin

         //purify layout
         while PatchListe.GlobalReplace(1, ' (', '(', true) do;
         while PatchListe.GlobalReplace(1, '( ', '(', true) do;

         if Skip ('(', r, r, ErrorInfo)
            and GetStringA(r, s0, r, ErrorInfo, false)
            and Skip(',', r, r, ErrorInfo)
            and GetStringA(r, s1, r, ErrorInfo, false)
            and Skip(',', r, r, ErrorInfo)
         then
         begin
            if (length(r) > 0) and (r[length(r)] = ')')
            then
            Begin
                syntaxcheck := true;
                s2 := copy(r, 1, length(r) - 1);
            end
            else
                ErrorInfo := ErrorRemaining;

           if syntaxCheck then
           Begin
              insertLineIndx := -1;
              PatchListe.ItemPointer := PatchListe.FindFirstItemStartingWith (s0 + '("' + s1 + '"', true, -1);
              while PatchListe.ItemPointer  > -1
              do
              begin
                insertLineIndx := PatchListe.ItemPointer;
                PatchListe.Delete (insertLineIndx);
                PatchListe.ItemPointer := PatchListe.FindFirstItemStartingWith (s0 + '("' + s1 + '"', true, -1);
              end;
              if insertLineIndx > -1
              then
                PatchListe.Insert(insertLineIndx, s0 + '("' + s1  + '", ' + s2 + ');')
              else
                PatchListe.add(s0 + '("' + s1  + '", ' + s2 + ');');
           End;
         End
        End

        else if LowerCase (methodname) = lowercase ('Set_Netscape_User_Pref')
        then
        Begin

         if Skip ('(', r, r, ErrorInfo)
            and GetStringA(r, s1, r, ErrorInfo, false)
            and Skip(',', r, r, ErrorInfo)
         then
            if (length(r) > 0) and (r[length(r)] = ')')
            then
            Begin
              syntaxcheck := true;
              s2 := copy(r, 1, length(r) - 1);
            end
            else
              ErrorInfo := ErrorRemaining;

         if syntaxCheck then
          Begin
            //PatchListe.Sort;   --- entfernt wegen Mozilla-Kommentaren in prefs.js
            //PatchListe.Sorted := true;   --- entfernt wegen Mozilla-Kommentaren in prefs.js
            PatchListe.ItemPointer := PatchListe.FindFirstItemWith (s1, false, -1);
            PatchListe.Delete (PatchListe.ItemPointer);
            PatchListe.Add ('user_pref("' + s1  + '", ' + s2 + ');');
          End;
        End

      else if
        (LowerCase (methodname) = lowercase ('AddStringListElement_To_Mozilla_Pref'))
        then
        Begin

      //purify layout
         while PatchListe.GlobalReplace(1, ' (', '(', true) do;
         while PatchListe.GlobalReplace(1, '( ', '(', true) do;

         if Skip ('(', r, r, ErrorInfo)
          and GetStringA(r, s0, r, ErrorInfo, false)
          and Skip(',', r, r, ErrorInfo)
          and GetStringA(r, s1, r, ErrorInfo, false)
          and Skip(',', r, r, ErrorInfo)
          and GetStringA(r, s2, r, ErrorInfo, false)
          and Skip (')', r, r, ErrorInfo)
          then
            if r = ''
            then
                syntaxcheck := true
            else
                ErrorInfo := ErrorRemaining;


         if syntaxCheck then
         Begin
            insertLineIndx := -1;
            startofline := s0 + '("' + s1 + '"';

            PatchListe.ItemPointer := PatchListe.FindFirstItemStartingWith (startofline, true, -1);
            while PatchListe.ItemPointer  > -1
            // we treat only the last line of this type, eliminating all others
            do
            begin
              insertLineIndx := PatchListe.ItemPointer;
              oldline := PatchListe.Strings[insertLineIndx];
              PatchListe.Delete(insertLineIndx);
              PatchListe.ItemPointer := PatchListe.FindFirstItemStartingWith (startofline, true, -1);
            end;

           if insertLineIndx > -1
           then
           Begin
             syntaxCheck := false;

         if
           skip (startofLine, oldLine, oldLine, ErrorInfo)
          and Skip (',', oldLine, oldLine, ErrorInfo)
          and GetStringA(oldLine, old_s2, oldline, ErrorInfo, false)
          and Skip (')', oldLine, oldLine, ErrorInfo)
             then
              syntaxCheck := true;
           End;
         End;


         if syntaxCheck then
         Begin
           if insertLineIndx > -1
           then
           Begin
             //search if s2 already is an element of existing list

             oldLine := old_s2;

             //get first list element
             GetWord (oldLine, x, oldLine, [',']);
             if (oldLine <> '')
             then // list not finished, delete ','
             System.delete (oldLine, 1,1);

             //first element equal to added string?
             found := (lowerCase (x) = lowerCase (s2));

             while (oldLine <> '') and not found
             do
             Begin
               GetWord (oldLine, x, oldLine, [',']);
               if (oldLine <> '') then  System.delete (oldLine, 1,1);
               if lowerCase (x) = lowerCase (s2)
               then found := true;
             End;

             if found
             then
             //reinsert the old line
               PatchListe.Insert(insertLineIndx,
                  startOfLine + ', "' + old_s2 +'");')
             else
             //append s2
               PatchListe.Insert(insertLineIndx,
                  startOfLine + ', "' + old_s2 + ', ' + s2 + '");');
           End
           else
             PatchListe.Add(
                  startOfLine + ', "' +  s2 + '");');

         End;

        end


        else if
        (LowerCase (methodname) = lowercase ('AddStringListElement_To_Netscape_User_Pref'))
        then
        Begin

         if Skip ('("', r, r, ErrorInfo)
         then
         Begin
           GetWord (r, s1, r, ['"']);
           if Skip ('"', r, r, ErrorInfo)
           then if Skip (',', r, r, ErrorInfo)
           then if Skip ('"', r, r, ErrorInfo)
           then
           Begin
             GetWord (r, s2, r, ['"']);
             if Skip ('"', r, r, ErrorInfo)
             then if Skip (')', r, r, ErrorInfo)
             then
               syntaxCheck := true;
           End;
         End;

         if syntaxCheck then
         Begin
           PatchListe.Sort;
           PatchListe.Sorted := true;
           PatchListe.ItemPointer := PatchListe.FindFirstItemWith (s1, false, -1);

           if PatchListe.ItemPointer > -1
           then
           Begin
             oldLine := PatchListe.Strings[PatchListe.ItemPointer];
             syntaxCheck := false;

             if Skip ('user_pref', oldLine, oldLine, ErrorInfo)
             then if Skip ('("', oldLine, oldLine, ErrorInfo)
             then if Skip (s1, oldLine, oldLine, ErrorInfo)
             then if Skip ('"', oldLine, oldLine, ErrorInfo)
             then if Skip (',', oldLine, oldLine, ErrorInfo)
             then if Skip ('"', oldLine, oldLine, ErrorInfo)
             then
             Begin
               GetWord (oldLine, old_s2, oldLine, ['"']);
               if Skip ('"', oldLine, oldLine, ErrorInfo)
               then if Skip (')', oldLine, oldLine, ErrorInfo)
               then
                 syntaxCheck := true;
             End;
           End;
         End;


         if syntaxCheck then
         Begin
           if PatchListe.ItemPointer > -1
           then
           Begin
             oldLine := old_s2;
             GetWord (oldLine, x, oldLine, [',', '"']);
             if (oldLine <> '') then  System.delete (oldLine, 1,1);

             found := false;
             while (oldLine <> '') and not found
             do
             Begin
               GetWord (oldLine, x, oldLine, [',', '"']);
               if (oldLine <> '') then  System.delete (oldLine, 1,1);
               if lowerCase (x) = lowerCase (s2)
               then found := true;
             End;
             if not found
             then
             Begin
               PatchListe.Delete (PatchListe.ItemPointer);
               PatchListe.Add ('user_pref("' + s1  + '", "' + old_s2 + ',' + s2 + '");');
             End;
           End
           else
             PatchListe.Add ('user_pref("' + s1  + '", "' +  s2 + '");');

         End;

        end

        else
          ErrorInfo := methodname + ' not defined';

      End;

      if syntaxcheck then inc(i);

      if not syntaxCheck
      then
         reportError (Sektion, i, Sektion.strings [i-1], errorinfo);
    End;

    if saveToOriginalFile then PatchListe.SaveToFile (PatchFilename);
    PatchListe.free; PatchListe := nil;

    LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;
    workingSection.Free;
  end;   //doTextpatchMain

begin
  result := tsrPositive;
  //Filename := ExpandFileName(Filename);

  if not initSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings) then exit;

  if (lowercase (PatchParameter) = lowercase (Parameter_AllNTUserProfiles))
  or flag_all_ntuser
  then
  Begin
    flag_all_ntuser := false;
    ProfileList := getProfilesDirList;
    for pc:= 0 to ProfileList.Count -1 do
    begin
      PatchFilename := sysutils.StringReplace(Filename, '%userprofiledir%', ProfileList.Strings[pc],[rfReplaceAll,rfIgnoreCase]);
      PatchFilename := ExpandFileName(PatchFilename);
      doTextpatchMain(Sektion,ProfileList.Strings[pc]+PathDelim);
    end;
  End
  else
  begin
    if runLoginScripts then
      PatchFilename := sysutils.StringReplace(Filename, '%userprofiledir%', GetUserProfilePath,[rfReplaceAll,rfIgnoreCase])
    else PatchFilename := Filename;
    PatchFilename := ExpandFileName(PatchFilename);
    doTextpatchMain(Sektion,GetUserProfilePath+PathDelim);
  end;

  finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                 DiffNumberOfErrors, DiffNumberOfWarnings);

  if ExitOnError and (DiffNumberOfErrors> 0)
  then result := tsrExitProcess;

End;



  function TuibInstScript.doTests (const Sektion: TWorkSection; TestParameter : String)
                       : TSectionResult;
   var
   i : Integer;
   FindResultCode : Integer;
   FileRecord : TSearchRec;
   Command : String='';
   Remaining : String='';
   Filename : String='';
   Comment : String='';

  begin
    result := tsrPositive;

    if not initSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings) then exit;

    i := 1;
    while (i <= Sektion.count) and (result > 0)
    do
    Begin
      if (Sektion.Strings [i-1] = '') or (Sektion.Strings [i-1] [1] = LineIsCommentChar)
      then
       (* continue *)
      else
      Begin
        GetWord (Sektion.Strings[i-1], Command, Remaining, WordDelimiterSet0);
        GetWord (Remaining, Filename, Remaining, WordDelimiterSet0);
        Comment := CutRightBlanks (Remaining);

        if length (Comment)
        > 0
        then
          if   ((Comment [1] = '"') and (Comment [length (Comment)] = '"'))
            or ((Comment [1] = '''') and (Comment [length (Comment)] = ''''))
          then
          Begin
            System.delete (Comment, 1, 1);
            if length (Comment) > 0
            then
            System.delete (Comment, length (Comment), 1)
          End;


        FindResultcode := FindFirst (FileName, faAnyFile, FileRecord);


        if UpperCase (Command) = UpperCase ('ExitOnFileNotExist')
        then Begin

          if FindResultCode < 0 (* not FileExists (FileName) *)
          then
          Begin
            ps := LogDatei.LogSIndent  +
                  'Error: File ' + FileName + ' does not exist';
            LogDatei.DependentAddError (ps, BaseLevel);
            if (length (Comment) > 0) then
               LogDatei.DependentAdd (LogDatei.LogSIndentPlus (1) + Comment, BaseLevel);

            result := tsrExitProcess;
          End
          else if FileRecord.Attr and faDirectory = faDirectory
          then
          Begin
            ps := LogDatei.LogSIndent +
                  'File ' + FileName + ' (directory) exists ';
            LogDatei.DependentAdd (ps, LevelComplete);
          End
          else
          Begin
            ps := LogDatei.LogSIndent +
                  'File ' + FileName + ' exists';
            LogDatei.DependentAdd (ps, LevelComplete);
          End
        end

        else if UpperCase (Command) = UpperCase ('ExitOnFileZero')
        then Begin
          if FindResultCode < 0 (* not FileExists (FileName) *)
          then
          Begin
            ps :=  LogDatei.LogSIndent +
                   'Error: File ' + FileName + ' does not exist';
            LogDatei.DependentAddError (ps, BaseLevel);

            if (length (Comment) > 0) then
               LogDatei.DependentAdd (LogDatei.LogSIndentPlus (1) + Comment,
                BaseLevel);

            result := tsrExitProcess;
          End
          else if FileRecord.Attr and faDirectory = faDirectory
          then
          Begin
            ps := LogDatei.LogSIndent +
                  'File ' + FileName + ' (directory) exists ';
            LogDatei.DependentAdd (ps, LevelComplete);
          End
          else if FileRecord.Size = 0
          then
          Begin
            ps := LogDatei.LogSIndent +
                  'Error: File ' + FileName + ' has size 0';
            LogDatei.DependentAddError (ps, BaseLevel);
            if (length (Comment) > 0) then
               LogDatei.DependentAdd (LogDatei.LogSIndentPlus (1) + Comment, BaseLevel);
            result := tsrExitProcess;
          End
          else
          Begin
            ps := LogDatei.LogSIndent +
                  'File ' + FileName + ' exists and has not size 0';
            LogDatei.DependentAdd (ps, LevelComplete);
          End;
        end

        else if UpperCase (Command) = UpperCase ('WarningOnFileNotExist')
        then Begin
          if FindResultCode < 0 (* not FileExists (FileName) *)
          then
          Begin
            ps := LogDatei.LogSIndent +
                  'Warning: File ' + FileName + ' does not exist';
            LogDatei.DependentAddWarning (ps, LevelWarnings);
            if (length (Comment) > 0) then
               LogDatei.DependentAdd (LogDatei.LogSIndentPlus (1) + Comment, LevelWarnings);
          End
          else if FileRecord.Attr and faDirectory = faDirectory
          then
          Begin
            ps := LogDatei.LogSIndent +
                  'File ' + FileName + ' (directory) exists ';
            LogDatei.DependentAdd (ps, LevelComplete);
          End
          else
          Begin
            ps := LogDatei.LogSIndent +
                  'File ' + FileName + ' exists';
            LogDatei.DependentAdd (ps, LevelComplete);
          End;
        end

        else if UpperCase (Command) = UpperCase ('WarningOnFileZero')
        then Begin
          if FindResultCode < 0  (* not FileExists (FileName) *)
          then
          Begin
            ps := LogDatei.LogSIndent +
                  'Warning: File ' + FileName + ' does not exist';
            LogDatei.DependentAddWarning (ps, LevelWarnings);
            if (length (Comment) > 0) then
            Begin
               ps := LogDatei.LogSIndentPlus (1) + Comment;
               LogDatei.DependentAdd (ps, LevelWarnings);
            End;
          End
          else if FileRecord.Attr and faDirectory = faDirectory
          then
          Begin
            ps := LogDatei.LogSIndent +
                  'File ' + FileName + ' (directory) exists ';
            LogDatei.DependentAdd (ps, LevelComplete);
          End

          else if FileRecord.Size = 0
          then
          Begin
            ps := LogDatei.LogSIndent +
                  'Warning: File ' + FileName + ' has size 0';
            LogDatei.DependentAddWarning (ps, LevelWarnings);
            if (length (Comment) > 0) then
            Begin
               ps := LogDatei.LogSIndentPlus (1) + Comment;
               LogDatei.DependentAdd (ps, LevelWarnings);
            End;
          End
          else
          Begin
            ps := LogDatei.LogSIndent +
                  'File ' + FileName + ' exists and has not size 0';
            LogDatei.DependentAdd (ps, LevelComplete);
          End;
        end

        else
          reportError (Sektion, i, Command, 'nicht definiert');;

        sysutils.findclose (FileRecord);
      end;

      inc (i);
    End;

    finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                   DiffNumberOfErrors, DiffNumberOfWarnings);

    if ExitOnError and (DiffNumberOfErrors > 0)
    then result := tsrExitProcess;
  end;



function TuibInstScript.doInifilePatches (const Sektion: TWorkSection; Filename : string; PatchParameter : String)
                  : TSectionResult;
var
  pc: Integer=0;
  Befehlswort : String='';
  Rest : String='';
  Bereich : String='';
  Eintrag : String='';
  AlterEintrag : String='';
  /// Value : String;
  Patchdateiname : String='';
  Patchdatei : TuibPatchIniFile;
  ErrorInfo : String='';
  ProfileList : TStringlist;

  procedure doInifilePatchesMain;
  var
  i: Integer=0;
  begin
    //ps := LogDatei.LogSIndentPlus (+3) + 'FILE ' +  PatchdateiName;
    //LogDatei.DependentAdd (ps, LevelWarnings);
    Logdatei.DependentAdd('', LLInfo);
    Logdatei.DependentAdd('Patching: '+PatchdateiName, LLInfo);


    if not FileExists (PatchdateiName)
    then
    Begin
      ps := LogDatei.LogSIndentPlus (+3) + 'Info: This file does not exist and will be created ';
      LogDatei.DependentAdd (ps, LLInfo);
      LogDatei.NumberOfHints := Logdatei.NumberOfHints + 1;

      if CreateTextfile (PatchdateiName, ErrorInfo)
      then
      Begin
       if ErrorInfo <> ''
       then
       Begin
         ps := LogDatei.LogSIndentPlus (+3) + 'Warning: ' + ErrorInfo;
         LogDatei.DependentAddWarning (ps, LLWarning);
       End;
      End
      else
      Begin
         ps := LogDatei.LogSIndentPlus (+3) + 'Error: ' + ErrorInfo;
         LogDatei.DependentAddError (ps, LLError);
         exit; (* ------------------------------  exit *)
       End;
    End;


    ProcessMess;

    LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;

    (* jetzt Arbeitsstruktur erzeugen *)

    Patchdatei := TuibPatchIniFile.Create;

    Patchdatei.clear;
    if FileExists (PatchdateiName)
    then
      Patchdatei.LoadFromFile (ExpandFileName(PatchdateiName));
      Patchdatei.Text:= reencode(Patchdatei.Text, 'system');

    for i:=1 to Sektion.count
    do
    Begin
      if (Sektion.strings [i-1] = '') or (Sektion.strings [i-1] [1] = LineIsCommentChar)
      then
       (* continue *)
      else
      Begin
        WortAbspalten (cutLeftBlanks(Sektion.strings [i-1]), Befehlswort, Rest);

        if UpperCase (Befehlswort) = 'ADD'
        then Begin
          SectionnameAbspalten (Rest, Bereich, Eintrag);
          Patchdatei.addEntry (Bereich, Eintrag);
        End
        else if UpperCase (Befehlswort) = 'DEL'
        then Begin
          SectionnameAbspalten (Rest, Bereich, Eintrag);
          Patchdatei.delEntry (Bereich, Eintrag);
        End
        else if UpperCase (Befehlswort) = 'SET'
        then Begin
          SectionnameAbspalten (Rest, Bereich, Eintrag);
          Patchdatei.setEntry  (Bereich, Eintrag);
        End
        else if UpperCase (Befehlswort) = 'ADDNEW'
        then Begin
          SectionnameAbspalten (Rest, Bereich, Eintrag);
          Patchdatei.addNewEntry (Bereich, Eintrag);
        End
        else if UpperCase (Befehlswort) = 'DELSEC'
        then begin
          SectionnameAbspalten (Rest, Bereich, Eintrag);
          if Eintrag <> '' then
            reportError (Sektion, i, Sektion.strings [i-1], 'syntax error')
          else
            Patchdatei.delSec (Bereich);
        end
        else if UpperCase (Befehlswort) = 'CHANGE'
        then Begin
          SectionnameAbspalten (Rest, Bereich, Eintrag);
          Patchdatei.changeEntry (Bereich, Eintrag);
        End
        else if UpperCase (Befehlswort) = 'REPLACE'
        then Begin
          WortAbspalten (Rest, AlterEintrag, Eintrag);
          if pos (' ', eintrag) > 0
          then
            reportError (Sektion, i, Sektion.strings [i-1], 'replace string not identified ')
          else
            Patchdatei.replaceEntry (AlterEintrag, Eintrag);
        End
        else
          reportError (Sektion, i, Befehlswort, ' Operation not defined');
      End;
    End;
    Logdatei.DependentAdd('--- ', LLInfo);
    Patchdatei.SaveToFile (PatchdateiName);
    Patchdatei.free; Patchdatei := nil;
  end;

begin
  result := tsrPositive;
  //Filename := ExpandFileName(Filename);

  if not initSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings) then exit;

  if (lowercase (PatchParameter) = lowercase (Parameter_AllNTUserProfiles))
  or flag_all_ntuser
  then
  Begin
    flag_all_ntuser := false;
    ProfileList := getProfilesDirList;
    for pc:= 0 to ProfileList.Count -1 do
    begin
      PatchdateiName := sysutils.StringReplace(Filename, '%userprofiledir%', ProfileList.Strings[pc],[rfReplaceAll,rfIgnoreCase]);
      PatchdateiName := ExpandFileName(PatchdateiName);
      doInifilePatchesMain;
    end;
  End
  else
  begin
    if runLoginScripts then
      PatchdateiName := sysutils.StringReplace(Filename, '%userprofiledir%', GetUserProfilePath,[rfReplaceAll,rfIgnoreCase])
    else PatchdateiName := Filename;
    PatchdateiName := ExpandFileName(PatchdateiName);
    doInifilePatchesMain;
  end;

  LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;

  finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                 DiffNumberOfErrors, DiffNumberOfWarnings);


  if ExitOnError and (DiffNumberOfErrors> 0)
  then result := tsrExitProcess;
end;


function TuibInstScript.doHostsPatch (const Sektion: TWorkSection; HostsFilename : String) : TSectionResult;

  var
  HostsLocation : String;
  expression, remaining : String;
   oldDisableWow64FsRedirectionStatus: pointer=nil;
  Wow64FsRedirectionDisabled, boolresult : boolean;


  procedure patchHosts (HostsLocation : String; var SectionResult : TSectionResult);

   var
   i: Integer=0;
   HostsImage : TuibPatchHostsFile;
   ///HostsFound : Boolean;
   Ident : String='';
   Hostname : String='';
   ipAdresse : String='';
   Alias : String='';
   ErrorInfo : String='';

  Begin
    HostsLocation := ExpandFileName(HostsLocation);
    ps := LogDatei.LogSIndentPlus (+2)+ 'FILE ' + HostsLocation ;
    LogDatei.DependentAdd (ps, LevelWarnings);

    ProcessMess;

    HostsImage := TuibPatchHostsFile.Create;

    if FileExists (HostsLocation)
    then HostsImage.LoadFromFile (HostsLocation)
    else
    Begin
      ps := LogDatei.LogSIndentPlus (+3) + 'Info: This file does not exist and will be created ';
      LogDatei.DependentAdd (ps, LevelInfo);
      LogDatei.NumberOfHints := Logdatei.NumberOfHints + 1;

      if CreateTextfile (HostsLocation, ErrorInfo)
      then
      Begin
       if ErrorInfo <> ''
       then
       Begin
         ps := LogDatei.LogSIndentPlus (+3) + 'Warning: ' + ErrorInfo;
         LogDatei.DependentAddWarning (ps, LevelWarnings);
       End;
      End
      else
      Begin
         ps := LogDatei.LogSIndentPlus (+3) + 'Error: ' + ErrorInfo;
         LogDatei.DependentAddError (ps, Baselevel);
         exit; (* ------------------------------  exit *)
       End;
    End;
    HostsImage.Text:= reencode(HostsImage.Text, 'system');
    LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;

    for i:=1 to Sektion.count
    do
    Begin
      Remaining := cutLeftBlanks(Sektion.strings [i-1]);

      if (Remaining = '') or (Remaining [1] = LineIsCommentChar)
         or (Remaining [1] = '#')
          (* Zeilen, die mit # beginnen, werden in einer HostsPatch-Sektion ebenfalls
             als Kommentar gewertet *)
      then
       (* continue *)
      else
      Begin
        GetWord (Remaining, Expression, Remaining, WordDelimiterSetHosts);

        Hostname := '';
        ipAdresse := '';
        Alias := '';
        Ident := '';

        if UpperCase (Expression) =  UpperCase ('SetAddr') then
        Begin
          GetWord (Remaining, Hostname, ipAdresse, WordDelimiterSetHosts);
          HostsImage.SetAddress (Hostname, ipAdresse);
        End
        else if UpperCase (Expression) =  UpperCase ('SetName') then
        Begin
          GetWord (Remaining, ipAdresse, Hostname, WordDelimiterSetHosts);
          HostsImage.SetName (ipAdresse, Hostname);
        End
        else if UpperCase (Expression) =  UpperCase ('SetAlias') then
        Begin
          GetWord (Remaining, Ident, Alias, WordDelimiterSetHosts);
          HostsImage.SetAlias (Ident, Alias);
        End
        else if UpperCase (Expression) =  UpperCase ('DelAlias') then
        Begin
          GetWord (Remaining, Ident, Alias, WordDelimiterSetHosts);
          HostsImage.DelAlias (Ident, Alias);
        End
        else if UpperCase (Expression) =  UpperCase ('DelHost') then
        Begin
          GetWord (Remaining, Ident, Remaining, WordDelimiterSetHosts);
          HostsImage.DelHost (Ident);
        End
        else if UpperCase (Expression) =  UpperCase ('SetComment') then
        Begin
          GetWord (Remaining, Ident, Remaining, WordDelimiterSetHosts);
          HostsImage.SetComment (Ident, Remaining);
        End

        else
          reportError (Sektion, i, Expression, ' Operation not defined');
      end;
    End;

    try
      HostsImage.SaveToFile (HostsLocation);
    except
      ps  := LogDatei.LogSIndent
             + 'Error: file ' + HostsLocation + ' could not be saved to disk';
      Logdatei.DependentAddError (ps, BaseLevel);
    end;
    HostsImage.free; HostsImage := nil;

    LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;
  End;

Begin
  Wow64FsRedirectionDisabled := false;
  result := tsrPositive;

  if not initSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings) then exit;

  if HostsFilename <> ''
  then
    patchHosts (HostsFilename, result)
  else
  Begin
    {$IFDEF WIN32}
    if Is64BitSystem then
    Begin
      boolresult := DSiDisableWow64FsRedirection(oldDisableWow64FsRedirectionStatus);
      Wow64FsRedirectionDisabled := true;
    End
    else Wow64FsRedirectionDisabled := false;
    {$ENDIF}
    HostsLocation := DefaultHosts;
    if FileExists (HostsLocation) then patchHosts (HostsLocation, result);
    {$IFDEF WIN32}
    if Wow64FsRedirectionDisabled then
    Begin
      boolresult := DSiRevertWow64FsRedirection(oldDisableWow64FsRedirectionStatus);
      Wow64FsRedirectionDisabled := false;
    End;
    {$ENDIF}

  End;

  finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                 DiffNumberOfErrors, DiffNumberOfWarnings);

  if ExitOnError and (DiffNumberOfErrors> 0)
  then result := tsrExitProcess;
end;


function TuibInstScript.doIdapiConfig (const Sektion : TWorkSection; IdapiParameter : String)
                                                                 : TSectionResult;

  begin
    // is not supported any more
    result :=  -1;
  end;


function tlcrToStr(x : TLDAPsearchCacheRequest) : String;
begin
  case x of
    tlcrNone    : result := '';
    tlcrCache   : result := 'Cache';
    tlcrCached  : result := 'Cached';
    tlcrClear   : result := 'Free';
  end;
end;

function tlorToStr(x : TLDAPsearchOutputRequest) : String;
begin
  case x of
    tlorNone        : result := '';
    tlorObjects     : result := 'Objects';
    tlorAttributes  : result := 'Attributes';
    tlorValues      : result := 'Values';
  end;
end;

function produceLDAPsearchParameters
    (Const LDAPparameter : String;
    var cacheRequest   : TLDAPsearchCacheRequest;
    var outputRequest  : TLDAPsearchOutputRequest;
    var errorinfo : String)
    : boolean;

Var
  remainingParameter : String='';
  checkParameter : String='';
  syntaxcheck : Boolean;

begin
  cacheRequest := tlcrNone;
  outputRequest := tlorNone;
  syntaxcheck := true;

  remainingParameter := LDAPParameter;
  while syntaxcheck and (length(remainingParameter) > 0)
  do
  begin
    getWord(remainingParameter, checkParameter, remainingParameter, worddelimiterWhiteSpace);

    if skip('/', checkParameter, checkParameter, errorinfo)
    then
    begin

      if lowercase(checkParameter) = lowercase(tlcrToStr(tlcrCache))
      then
        cacheRequest := tlcrCache
      else if lowercase(checkParameter) = lowercase(tlcrToStr(tlcrCached))
      then
        cacheRequest := tlcrCached
      else if lowercase(checkParameter) = lowercase(tlcrToStr(tlcrClear))
      then
        cacheRequest := tlcrClear

      else if lowercase(checkParameter) = lowercase(tlorToStr(tlorObjects))
      then
        outputRequest := tlorObjects
      else if lowercase(checkParameter) = lowercase(tlorToStr(tlorAttributes))
      then
        outputRequest := tlorAttributes
      else if lowercase(checkParameter) = lowercase(tlorToStr(tlorValues))
      then
        outputRequest := tlorValues

      else
      Begin
        syntaxcheck := false;
        errorinfo := 'no valid parameter';
      end;

    end
    else
      syntaxcheck := false;

  end;

  result := syntaxcheck;
end;


function TuibInstScript.doLDAPsearch
        (const Sektion : TWorkSection;
        cacheRequest   : TLDAPsearchCacheRequest;
        outputRequest  : TLDAPsearchOutputRequest;
        var output: TXStringList)
        : TSectionResult;

// uses ldapsend
Var
  targethost : String;
  targetport : String;
  ldapsearch_user: String;
  ldapsearch_credentials: String;
  ldapsearch_dn : String;
  ldapsearch_typesOnly : boolean;
  ldapsearch_filter : String;
  ldapsearch_attributes : TStringList;


  i : Integer;
  savelogsindentlevel : Integer;
  syntaxcheck : boolean;
  errorinfo : String;
  expression : String;
  remaining : String;
  itemS : String;

  errorOccurred : boolean;

  function analyzeSection : boolean;
  var
    ldapsearch_typesOnlyString : String;
    find : boolean;
    findInfo : String;
  begin
    syntaxCheck := true;

    targethost := '';
    targetport := '';
    ldapsearch_dn := '';
    ldapsearch_typesOnly := false;
    ldapsearch_typesOnlyString := 'false';
    ldapsearch_filter := '(objectclass=*)';
    ldapsearch_attributes := TStringList.Create;

    i := 1;

    while (i <= Sektion.count) and syntaxcheck
    do
    Begin
      Remaining := trim (Sektion.strings [i-1]);
      if (Remaining = '') or (Remaining [1] = LineIsCommentChar)
      then
        inc (i)
      else
      Begin //real line
        logdatei.DependentAdd('  analyze: ' + Remaining,  LevelComplete);
        GetWord (Remaining, Expression, Remaining, WordDelimiterSet0);

        if (length(expression) < 2) or (expression[length(expression)] <> ':')
        then
        begin
          syntaxcheck := false;
          errorInfo := 'keyname plus ":" expected"';
        end

        else
        begin
          expression := copy(expression, 0, length(expression) -1);
          if LowerCase (Expression) = 'targethost'
          then
          begin
            if (length (Remaining) = 0)
            then
            Begin
              syntaxCheck := false;
              errorinfo := 'expected targethost name';
            End
            else
            begin
              getWordOrStringExpression(remaining, targethost, remaining, errorinfo);
              if length(remaining) > 0
              then
                reportError(Sektion, i, Sektion.Strings[i-1], errorRemaining);

            end;
          End

          else if LowerCase (Expression) = 'targetport'
          then
          begin
            if (length (Remaining) = 0)
            then
            Begin
              //stay to default port
            End
            else
            begin
              getWordOrStringExpression(remaining, targetport, remaining, errorinfo);

              try
                strtoint(targetPort)
              except
                reportError(Sektion, i, Sektion.Strings[i-1], '"' + targetport + '" is no number');
                syntaxcheck := false;
              end;

              if length(remaining) > 0
              then
                reportError(Sektion, i, Sektion.Strings[i-1], errorRemaining);
            end;
          End
          
          else if LowerCase (Expression) = 'user'
          then
          begin
            if (length (Remaining) = 0)
            then
            Begin
              //anonymous logon
            End
            else
            begin
              getWordOrStringExpression(remaining, ldapsearch_user, remaining, errorinfo);

              if length(remaining) > 0
              then
                reportError(Sektion, i, Sektion.Strings[i-1], errorRemaining);
            end;
          End
          
          else if LowerCase (Expression) = 'password'
          then
          begin
            if (length (Remaining) = 0)
            then
            Begin
              //anonymous logon
            End
            else
            begin
              getWordOrStringExpression(remaining, ldapsearch_credentials, remaining, errorinfo);

              if length(remaining) > 0
              then
                reportError(Sektion, i, Sektion.Strings[i-1], errorRemaining);
            end;
          End


          else if LowerCase (Expression) = 'dn'
          then
          begin
            if (length (Remaining) = 0)
            then
            Begin
              //stay to default port
            End
            else
            begin
              getWordOrStringExpression(remaining, ldapsearch_dn, remaining, errorinfo);

              if length(remaining) > 0
              then
                reportError(Sektion, i, Sektion.Strings[i-1], errorRemaining);
            end;
          End

          else if LowerCase (Expression) = 'typesonly'
          then
          begin
            if (length (Remaining) = 0)
            then
            Begin
              //stay to default
            End
            else
            begin
              getWordOrStringExpression(remaining, ldapsearch_typesonlyString, remaining, errorinfo);
              if  lowercase(ldapsearch_typesonlyString) = 'false'
              then
                ldapsearch_typesOnly := false
              else if lowercase(ldapsearch_typesonlyString) = 'true'
              then
                ldapsearch_typesOnly := true
              else
              Begin
                syntaxcheck := false;
                errorinfo := 'only values "true" or "false" possible'
              end;

              if syntaxcheck and (length(remaining) > 0)
              then
                reportError(Sektion, i, Sektion.Strings[i-1], errorRemaining);

            end
          End

          else if LowerCase (Expression) = 'filter'
          then
          begin
            if (length (Remaining) = 0)
            then
            Begin
              //stay to default
            End
            else
            begin
              getWordOrStringExpression(remaining, ldapsearch_filter, remaining, errorinfo);

              if length(remaining) > 0
              then
                reportError(Sektion, i, Sektion.Strings[i-1], errorRemaining);

            end;
          End

          else if LowerCase (Expression) = 'attributes'
          then
          begin
            if (length (Remaining) = 0)
            then
            Begin
              //stay to default
            End
            else
            begin
              // construct string list!
              find := true;
              while find do
              begin
                getWord(Remaining, itemS, Remaining, [',']);
                if (length(itemS) > 0)
                then
                	ldapsearch_attributes.add(itemS);
                Skip(',', Remaining,  Remaining,  findInfo);
                find := length(Remaining) > 0;
                logdatei.DependentAdd('  attribute:'  + itemS +  ' remaining >' + Remaining +  '<',  LevelComplete);
              end;

            end;
          End

          else
            reportError(Sektion, i, Sektion.Strings[i-1], 'Unknown LDAP search specification');


        end;

        if syntaxcheck then inc(i);

      end; //real line

    end; //while

    if not syntaxcheck then
    begin
      reportError(Sektion, i, Sektion.Strings[i-1], errorinfo)
    end
    else
    begin
      logdatei.DependentAdd('LDAP search starting for:', LevelComplete);
      logdatei.DependentAdd('  targethost: ' + targethost, LevelComplete);
      logdatei.DependentAdd('  targetport: ' + targetport, LevelComplete);
      logdatei.DependentAdd('  dn: ' + ldapsearch_dn, LevelComplete);
      logdatei.DependentAdd('  typesOnly: ' + ldapsearch_typesOnlyString, LevelComplete);
      logdatei.DependentAdd('  filter: ' + ldapsearch_filter,  LevelComplete);
      logdatei.DependentAdd('  attribute:' + ldapsearch_attributes.text,  LevelComplete);
    end;

    result := syntaxcheck;

  end;

  function callLDAP : boolean;
  var
    ldap: TLDAPsend;
    goOn : boolean;
    l : Integer;
  begin
    ldap:= TLDAPsend.Create;

    goOn := true;
    if (ldapResult <> nil)
    then
    begin
      ldapResult.clear;
      ldapResult.free;
    end;
    ldapResult := TStringList.create;

    try

      try //for catching an exception
        ldap.TargetHost := targethost;
        if targetPort <> ''
        then
          ldap.TargetPort := targetPort;

         ldap.UserName := ldapsearch_user;
         ldap.Password :=  ldapsearch_credentials;

        if not ldap.Login
        then
        Begin
            goOn := false;
            logdatei.DependentAddError('Error in LDAP login: ' + ldap.ResultString, BaseLevel);
        End;

        if goOn and not ldap.Bind
        then
        Begin
            goOn := false;
            logdatei.DependentAddError('Error in LDAP login: ' + ldap.ResultString, BaseLevel);
        End;

        if goOn
        then
        Begin
          ldap.Search(ldapsearch_dn,ldapsearch_typesonly,ldapsearch_filter,ldapsearch_attributes);
          ldapResult.setText(PAnsiChar(LDAPResultdump(ldap.SearchResult)));

        (* // check result: *)
        logdatei.DependentAdd('LDAP search result: ', LevelComplete);
        logdatei.LogSIndentLevel := logDatei.logSIndentLevel + 4;
        for l := 0 to ldapResult.Count-1
        do
        Begin
          logdatei.DependentAdd(ldapResult.Strings[l], LevelComplete);
        End;
        logdatei.LogSIndentLevel := logDatei.logSIndentLevel - 4;
        logdatei.DependentAdd('', LevelComplete);
      End;


      ldap.Logout;

      except
        logdatei.DependentAddError('Error (LDAP): ' + ldap.ResultString, BaseLevel);
        goOn := false;
      end;

    finally

      ldap.Free;
    end;

    result := goOn;

  end; //callLDAP

  function buildOutput: boolean;

  var
    iLines : Integer=0;
    ///iObjects : Integer;
    ///iAttributes : Integer;

    found : boolean;

    errorOccurred : boolean;

    line : String='';
    n : Integer=0;
    rem : String='';
    err : String='';

  begin

    errorOccurred := false;

    if (outputRequest = tlorNone)
    then
    begin
      for iLines := 0 to ldapResult.count - 1
      do
        output.add(ldapResult.strings[iLines])
    end
    else
    begin

      iLines := 0;

      found := false;

      n := ldapresult.Count;
      while not found and (iLines < n)  do
      begin
        line := trim( ldapResult.strings[iLines] ) ;
        if pos('results:', lowercase(line)) > -1
        then found := true;
        inc(iLines);
      end;

      if not found then errorOccurred := true;

      while iLines < n do
      begin
        line := trim( ldapResult.strings[iLines] ) ;
        if (pos('result:', lowercase(line)) = 1) or (trim(line) = '')
        then
        begin
          //ignore
        end
        else
        begin
          rem := line;
          if skip('object:',line, rem, err)
          then
          begin
            if outputRequest = tlorObjects
            then
              output.add(rem);
          end

          else if skip('attribute:',line, rem, err)
          then
          begin
            if outputRequest = tlorAttributes
            then
              output.add(rem);
          end
          else
          begin
             if outputRequest = tlorValues
             then
                output.add(line);

          end;


        end;

        inc(iLines);

      end;

    end;

    result := errorOccurred;

  end;


begin
  result := tsrPositive;

  if Sektion.count = 0 then exit;

  LogDatei.LogSIndentLevel := Sektion.NestingLevel;
  savelogsindentlevel := LogDatei.LogSIndentLevel;

  OldNumberOfErrors := LogDatei.NumberOfErrors;
  OldNumberOfWarnings := LogDatei.NumberOfWarnings;

  ps := '';
  LogDatei.DependentAdd (ps, LevelWarnings);
  ps := 'Execution of ' + Sektion.Name;

  if  cacheRequest <> tlcrNone
  then
    ps := ps + '  (CacheOption: ' + tlcrToStr(cacheRequest) + ')';

  if  outputRequest <> tlorNone
  then
    ps := ps + '  (OutputOption: ' + tlorToStr(outputRequest) + ')';


  LogDatei.DependentAdd (ps, LevelWarnings);

  if pos (uppercase (PStatNames^ [tsLDAPsearch]), uppercase (Sektion.Name)) > 0 then
    //ps := (* 'Ausfuehrung von ' +  *) copy (Sektion.Name, length (PStatNames^ [tsLDAPsearch]) + 1, length (Sektion.Name));
    ps := Sektion.Name;

  {$IFDEF GUI}
  CentralForm.Label2.caption := ps;
  FBatchOberflaeche.setDetailLabel(ps);
  ProcessMess;
  {$ENDIF GUI}
  LogDatei.LogSIndentLevel := Sektion.NestingLevel + 1;
  //Sektion.eliminateLinesStartingWith (';', false);


  errorOccurred := false;
  syntaxCheck := true;

  output := TXStringList.create;


  if cacheRequest = tlcrClear
  then
  begin
    logdatei.DependentAdd('Clearing cached LDAP search result', LevelComplete);
    if (ldapResult <> nil)
    then
    begin
      ldapResult.clear;
      ldapResult.free;
      ldapResult := nil;
    end;

  end
  else if cacheRequest = tlcrCached
  then
  begin
    if (ldapResult = nil)
    then
    begin
      reportError(Sektion,0, '(parameter /cached)', 'There was probably no (successful) LDAP search');
      logDatei.DependentAddError('No cached LDAP search result found', baselevel);
      syntaxCheck := false;
      errorOccurred := true;
    end
  end
  else //tlcrNone, tlcrCache
  begin
    syntaxCheck := analyzeSection;
    if syntaxCheck
    then
      errorOccurred := not callLDAP;
      //testLDAP;
  end;

  if syntaxCheck and not errorOccurred and not (cacheRequest = tlcrClear)
  then
    buildOutput;

  if (cacheRequest = tlcrNone) and (ldapResult <> nil)
  then
  begin
    ldapResult.clear;
    ldapResult.free;
    ldapResult := nil;
  end;

  // if no error occurred we have a ldapResult stringlist
  // and may evaluate it

  finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                 DiffNumberOfErrors, DiffNumberOfWarnings);

  LogDatei.LogSIndentLevel := savelogsindentlevel;

  if ExitOnError and (DiffNumberOfErrors > 0)
  then result := tsrExitProcess;

end;

{$IFDEF WINDOWS}
function TuibInstScript.doRegistryHackInfSource (const Sektion: TWorkSection; Const RegParameter : String; const flag_force64 : boolean)
                                                               : TSectionResult;
var
  Regist : TuibRegistry;
  i, Startline_of_Command : Integer;

  r : String;
  LineWasComplete : Boolean;
  error : String;
  syntaxCheck : Boolean;

  function InterpretLine (var r  : String) : Boolean;
  var
    key0 : String='';
    key : String='';
    name : String='';
    value : String='';
    regTStr : String='';
    regTInt : LongInt;
    regType :  TuibRegDataType;

  begin
    result := false;
    syntaxCheck := true;

    GetWord (r, key0, r, [',']);
    if not Skip (',"', r, r, error) then Begin Syntaxcheck := false; exit End;
    GetWord (r, key, r, ['"']);
    if not Regist.openkey (key0, key)
    then
    Begin
     error := 'Registry key ' + key0 + '\' + key + ' could not be opened';
     exit;
    End;

    if not Skip ('","', r, r, error) then Begin Syntaxcheck := false; exit End;
    GetWord (r, name, r, ['"']);
    if not Skip ('",', r, r, error) then Begin Syntaxcheck := false; exit End;
    GetWord (r, regTStr, r, [',']);
    if not Skip (',', r, r, error) then Begin Syntaxcheck := false; exit End;

    try
      regTInt :=  StrToInt64 (regTStr);
    except
      reportError (Sektion, i, Sektion.strings [i-1], regTStr + ' is not a number');
      Begin Syntaxcheck := false; exit End;
    end;

    value := '';

    if regTInt = 0 then
    Begin
      regtype := trdString;
      if not Skip ('"', r, r, error) then Begin Syntaxcheck := false; exit End;
      GetWord (r, value, r, ['"']);
    End
    else if regTInt = 65537 then
    Begin
      regtype := trdInteger;
      value := r;
    End
    else if regTInt = 131072
    then
    Begin
      regtype := trdExpandString;
      if not Skip ('"', r, r, error) then Begin Syntaxcheck := false; exit End;
      GetWord (r, value, r, ['"']);
      (* Beispiel: 131072,"C:\Programme\wiz\wiz.exe %1" *)
    End
    else if regTInt = 196609 then
    Begin
      regtype := trdBinary;
      value := r;
    End

    else
    Begin
      Syntaxcheck := false;
      Error := regTStr + ' kein erkannter Registrytyp';
      exit;
    End;

    Regist.writeEntry (name, regtype, value);
    Regist.closeKey;

    result := true;
  end;

begin
  result := tsrPositive;

  if not initSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings) then exit;
  LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;

  if flag_force64 Then
    Regist := TuibRegistry.create(true)
  else
    Regist := TuibRegistry.create;

  i := 1;
  Startline_of_Command := 1;
  LineWasComplete := true;

  while i <= Sektion.count
  do
  Begin
    if LineWasComplete
    then
    Begin
      r := cutLeftBlanks(Sektion.strings [i-1]);
      Startline_of_Command := i;
    End
    else
      r := r + cutLeftBlanks (Sektion.strings [i-1]);

    if (length (r) > 1) and (r [length (r)] = '\')
    then
    Begin
      system.delete (r, length (r), 1);
      LineWasComplete := false;
    End
    else
      LineWasComplete := true;

    if (r = '') or (r [1] = LineIsCommentChar)
    then
     (* continue *)
    else
    Begin
      if LineWasComplete
      then
        if not InterpretLine (r)
        then
          if SyntaxCheck = false then
           reportError (Sektion, Startline_of_Command, Sektion.strings [i-1], error);
    End;

    inc (i);
  End;

  Regist.free; Regist := nil;

  finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                 DiffNumberOfErrors, DiffNumberOfWarnings);


  LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;

  if ExitOnError and (DiffNumberOfErrors> 0)
  then result := tsrExitProcess;
end;

function TuibInstScript.doRegistryHackRegeditFormat
                                       (const Sektion: TWorkSection;
                                        Const RegParameter : String;
                                        const flag_force64 : boolean)
                                                               : TSectionResult;
var
  Regist : TuibRegistry;
  keyOpenCommandExists : Boolean;
  keyOpened : Boolean;
  regtype : TuibRegDataType;
  ///oldregtype : TuibRegDataType;
  ///Separator : Char;
  ErrorInfo : String='';
  SyntaxCheck : Boolean;
  Expression : String='';
  (* wenn die globale Variable Expression hier nicht lokal neu angelegt wird,
     so verliert der Parameter Sectionname, der ein Zeiger auf die globale Variable Expression ist,
     zusammen mit dieser seinen Wert *)
    r : String='';
  i : integer=0;
  k : Integer=0;
  StartIndentLevel : Integer;

  registrykeys : TXStringList;
  entries : TXStringList;

  basekey : String='';
  sectionname : String='';
  key : String='';
  key0 : String='';
  key_completepath : String='';
  startlineno : Integer=0;

  field : String='';
  typeinfo : String='';
  value : String='';
  ///test : Integer;
  outkey: HKEY;

  function GetTypedValue_RegEditSyntax
    (s, regtypeinfo : String; var regtype : TuibRegDataType; var value, r, ErrorInfo : String) : Boolean;

   var
     ///PartValue,Info : String;
     ///Continue : Boolean;

     binValue : String='';
     lpdata : Pointer=nil;
     cbdata : DWord=0;

     j : Integer=0;
     startvalue : String='';

  Begin
    result := true;
    value := '';

    if Skip (':', s, r, ErrorInfo)
    then
    Begin
      if (upperCase (regtypeinfo) = 'REG_SZ') or (upperCase (regtypeinfo) = uppercase ('hex(0)'))
       // hex(0) stands for REG_NONE 'no defined value type'
      then regtype := trdString
      else
      if upperCase (regtypeinfo) = 'REG_EXPAND_SZ'
      then regtype := trdExpandString
      else
      //if upperCase (regtypeinfo) = 'REG_MULTI_SZ'
      //then regtype := trdMultiString
      //else
      if     (upperCase (regtypeinfo) = uppercase ('hex'))
          or (upperCase (regtypeinfo) = uppercase ('hex(7)'))
      then regtype := trdBinary
      else
      if uppercase (regtypeinfo) =  uppercase ('dword')
      then regtype := trdInteger
      else
      Begin
        result := false;
        ErrorInfo := regtypeinfo + ' is a not supported type of a registry entry';
        exit;
      End
    End
    else
    Begin
      if regtypeinfo = ''
      then
      Begin
        ErrorInfo := ''; (* zuruecksetzen, da noch Hoffnung auf Korrektheit *)
        regtype := trdString;
      End
      else
      begin
        result := false;
        exit;
      end;
    End;


    result := false;
    case regtype of
      trdString :
      begin

          if skip ('"', r, r, errorInfo)
          then
          Begin

            value := '';
            startvalue := r;
            j := 1;
            while j < length (startvalue)
            do
            Begin
             if (startvalue[j] = '\')  and (j < length(startvalue))
             then
               // backquoted char
               inc (j);
             value := value + startvalue[j];
             inc (j);

            end;
            r := '';

            if startvalue[j] = '"'
            then
              result := true
            else
              errorInfo := '""" expected';

          end;
      end;
      trdExpandString :
          if GetString (r, value, r, errorinfo, true) then result := true;
      trdMultiString :
          if GetString (r, value, r, errorinfo, true)
          then
          Begin
             result := true;
             value := value + MultiszVisualDelimiter + MultiszVisualDelimiter;
             value := StringReplace (value, MultiszVisualDelimiter, #10);
          End;
      trdInteger:
          try
            r := '$'+r;
            StrToInt64 (r);
            value := r;
            r := '';
            result := true;
          except
            on EConvertError do
               ErrorInfo := r + ' is no valid number';
            on E: Exception do
               ErrorInfo := E.Message;
          end;
      trdBinary :
          Begin
             binValue := StringReplace(r, ',', ' ');

             SetLength (binValue, length (r) + 1);
             if StrToBinary (PChar (binValue), lpdata, cbdata)
             then
             Begin
               result := true;
               Value := r;
               r := '';
             End
             else
               ErrorInfo :=  '"' + r + '" is not a binary or hex value ';
          End;
    end;

  End;


begin
  try
    basekey := RegParameter;
    result := tsrPositive;

    if not initSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings) then exit;
    StartIndentLevel := LogDatei.LogSIndentLevel;


    if flag_force64 Then
      Regist := TuibRegistry.create(true)
    else
      Regist := TuibRegistry.create;
    keyOpened := false;
    keyOpenCommandExists := false;



    // Sektion has ini file format, therefore we may do

    registrykeys := TXStringlist.create;
    Sektion.GetSectionTitles(registrykeys);

    for k := 0 to registrykeys.Count - 1
    do
    Begin
      sectionname := registrykeys.strings[k];
      sectionname := copy (sectionname, 2, length (sectionname) -2);
      key := sectionname;

      LogDatei.LogSIndentLevel  := startindentlevel + 1;

      LogDatei.DependentAdd('key ' + key, levelinfo);

      key_completepath := key;
      LogDatei.DependentAdd('Key is: '+key, LLdebug);
      GetWord (key, key0, key, ['\']);
      LogDatei.DependentAdd('Key0 is: '+key0, LLdebug);
      if Is64BitSystem and ('software' = lowerCase(key0)) then
      begin
        LogDatei.DependentAdd('key starting with software on 64 bit. Key is: '+key, LLdebug);
        if not flag_force64 then
        begin
          key := key0 + '\wow6432node' + key;
          LogDatei.DependentAdd('key starting with software on 64 bit has to be redirected. So we work with: '+key, LLdebug);
        end
        else
        begin
          key := key_completepath;
          LogDatei.DependentAdd('key starting with software on 64 bit. Redirection is disabled. So we work with: '+key, LLdebug);
        end
      end
      else
      if (flag_all_ntuser or flag_ntuser or runLoginScripts) and (('HKEY_CURRENT_USER' = UpperCase(key0)) or ('HKCU' = UpperCase(key0))) then
      begin
        // remove HKCU from the beginning
        key := key;
        LogDatei.log ('Running loginscripts: ignoring key0 : '+key0 + ', using only key : '+key, LLdebug2);
      end
      else  key := key_completepath;
      GetWord (key, key0, key, ['\']);
      if GetHKEY(key0, outkey) then
      begin
         LogDatei.log ('key0 : '+key0+' is a valid base key and we will use it',LLDebug2);
         key := key_completepath;
      end
      else
      begin
        LogDatei.DependentAdd('Key0 is: '+key0+ ' Key is: '+key, LLdebug2);
        LogDatei.log ('key0 : '+key0+' is not a valid base key and we will praefix it with: '+basekey,LLDebug2);
        // insert RegParameter before key
        if basekey <> '' then
        Begin
          if basekey [length (basekey)] = '\' then basekey := copy(basekey,1,length(basekey)-1);
          key_completepath := basekey;
          LogDatei.DependentAdd('key_completepath1 : '+key_completepath, LLdebug3);
          if (trim(key0) <> '') then
          begin
            if key0[1] = '\' then key0 := copy(key0,2,length(key0));
            if key0 [length (key0)] = '\' then key0 := copy(key0,1,length(key0)-1);
            key_completepath := key_completepath + '\' + key0;
            LogDatei.DependentAdd('key_completepath2 : '+key_completepath, LLdebug3);
          end;
          if (trim(key) <> '') then
          begin
            if key[1] = '\' then key := copy(key,2,length(key));
            key_completepath := key_completepath + '\' + key;
            LogDatei.DependentAdd('key_completepath3 : '+key_completepath, LLdebug3);
          end;
        End;
      end;

      // extract HKEY
      GetWord (key_completepath, key0, key, ['\']);
      system.delete(key,1,1);
      LogDatei.DependentAdd('We will open Key : '+key_completepath, LLdebug2);



      LogDatei.LogSIndentLevel  := startindentlevel + 2;
      Regist.BaseIndentLevel := startindentlevel + 2;

      // close key before opening the next -> regunload will fail if keys are open
      if keyOpened then keyOpened := not Regist.CloseKey;
      keyOpened := Regist.OpenKey (key0, key);


      entries := TXStringList.Create;

      sektion.GetSectionLines (sectionname, entries, startlineno, false, false, true);

      i := 0;
      while i < entries.count do
      begin

        r := cutLeftBlanks(entries.strings[i]);
        while (r[length(r)] = '\') and (i < entries.count - 1)
        do // join lines
        begin
           inc (i);
           r := copy (r, 1, length(r) - 1) + cutLeftBlanks (entries.strings[i]);
        end;

        LogDatei.DependentAdd(r, baselevel);

        if (r = '') or (r [1] = LineIsCommentChar)
        then
         (* continue *)
        else
        Begin
          syntaxcheck := true;

          if skip ('@', r, r, ErrorInfo)
          //in Regedit-Syntax, a '@' stands for the default variable ("") of the key
          then
          begin
            field := '';
          end

           // the following is the set command in the registry section according to the winst syntax
          else if Skip ('"', r, r, ErrorInfo)
          then
          Begin
            GetWord (r, field, r, ['"']);
            if not Skip ('"', r, r, ErrorInfo)
            then syntaxcheck := false;
          end

          else
            syntaxcheck := false;

          if syntaxcheck
          then
          Begin
            syntaxcheck := Skip ('=', r, r, ErrorInfo);
            if syntaxcheck
            then
            Begin
              GetWord (r, typeinfo, r, [':', '"']);

              syntaxcheck := GetTypedValue_RegEditSyntax (r, typeinfo, regtype, value, r, ErrorInfo);
              if syntaxcheck and (r <> '')
              then begin SyntaxCheck := false; ErrorInfo := ErrorRemaining end;
            end;

          End;


          if SyntaxCheck
          then
            Regist.WriteEntry (field, regtype, value)
          else
             reportError (Sektion, i, entries.strings [i], ErrorInfo);

          inc (i);
        end;
      end;

    End;


    Regist.free; Regist := nil;

    finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                   DiffNumberOfErrors, DiffNumberOfWarnings);

    LogDatei.LogSIndentLevel := StartIndentLevel;
    //LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;

    if ExitOnError and (DiffNumberOfErrors> 0)
    then result := tsrExitProcess;
  except
    on e: Exception do
    begin
      LogDatei.DependentAdd('Error in doRegistryHackRegeditFormat: '+ e.message,LLError);
    end;
  end;
end;


function TuibInstScript.doRegistryHack (const Sektion: TWorkSection; Const RegParameter : String; const flag_force64 : boolean)
                 : TSectionResult;
var
  Regist : TuibRegistry;
  keyOpenCommandExists : Boolean;
  keyOpened : Boolean;
  basekey : String='';
  key0 : String='';
  key : String='';
  key_completepath : String='';
  templatekey : String='';
  field : String='';
  value : String='';
  oldvalue : String='';
  typeinfo : String='';
  path : String='';
  textfile : TStringList;
  filename : String='';
  regtype, oldregtype : TuibRegDataType;
  Separator : Char;
  ErrorInfo : String='';
  citmark : Char;
  SyntaxCheck : Boolean;
  Expression : String='';
  (* wenn die globale Variable Expression hier nicht lokal neu angelegt wird,
     so verliert der Parameter Sectionname, der ein Zeiger auf die globale Variable Expression ist,
     zusammen mit dieser seinen Wert *)
  r : String='';
  i : Integer=0;
  varno : Integer=0;
  varlist : TStringList;

  StartIndentLevel : Integer=0;

  subkeys : TXStringList;
  regpath : String='';
  j : Integer;
  commandline : String='';
  report : String='';
  output: TXStringList;
  outputlines : integer=0;
  outkey: HKEY;



  function GetTypedValue
    (s, regtypeinfo : String; var regtype : TuibRegDataType; var value, r, ErrorInfo : String) : Boolean;

   var
     ///PartValue, Info : String;
     ///Continue : Boolean;

     binValue : String='';
     lpdata : Pointer=nil;
     cbdata : DWord=0;


  Begin
    result := true;
    value := '';

    if Skip (':', s, r, ErrorInfo)
    then
    Begin
      if upperCase (regtypeinfo) = 'REG_SZ'
      then regtype := trdString
      else if upperCase (regtypeinfo) = 'REG_EXPAND_SZ'
      then regtype := trdExpandString
      else if upperCase (regtypeinfo) = 'REG_MULTI_SZ'
      then regtype := trdMultiString
      else if upperCase (regtypeinfo) = uppercase ('REG_Binary')
      then regtype := trdBinary
      else if uppercase (regtypeinfo) =  uppercase ('REG_DWord')
      then regtype := trdInteger
      //else if uppercase (regtypeinfo) =  uppercase ('REG_NONE')
      //then regtype := trdUnknown
      else
      Begin
        result := false;
        ErrorInfo := regtypeinfo + ' is a unknown or not implemented registry type';
        exit;
      End
    End
    else
    Begin
      if regtypeinfo = ''
      then
      Begin
        ErrorInfo := ''; (* zuruecksetzen, da noch Hoffnung auf Korrektheit *)
        regtype := trdDefaultString;
      End
      else
      begin
        result := false;
        exit;
      end;
    End;


    result := false;
    case regtype of
      trdDefaultString  :
          if GetString (r, value, r, errorinfo, true) then result := true;
      trdString :
          if GetString (r, value, r, errorinfo, true) then result := true;
      trdExpandString :
          if GetString (r, value, r, errorinfo, true) then result := true;
      trdMultiString :
          if GetString (r, value, r, errorinfo, true)
          then
          Begin
             result := true;
             value := value + MultiszVisualDelimiter + MultiszVisualDelimiter;
             value := StringReplace (value, MultiszVisualDelimiter, #10);
          End;
      trdInteger:
          try
            StrToInt64 (r);
            Value := r;
            r := '';
            result := true;
          except
            on EConvertError do
               ErrorInfo := r + ' is no valid number';
            on E: Exception do
               ErrorInfo := E.Message;
          end;
      trdBinary :
          Begin
             binValue := r;
             SetLength (binValue, length (r));
             if StrToBinary (PChar (binValue), lpdata, cbdata)
             then
             Begin
               result := true;
               Value := r;
               r := '';
             End
             else
               ErrorInfo :=  '"' + r + '" is no valid binary or hex value';
          End;
      //trdUnknown :
      //    begin
      //      result := true;
      //    end;

    end;

  End;

begin
  basekey := RegParameter;
  result := tsrPositive;

  if not initSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings) then exit;
  StartIndentLevel := LogDatei.LogSIndentLevel;
  LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;
  if flag_force64 Then
    Regist := TuibRegistry.create(true)
  else
    Regist := TuibRegistry.create;
  keyOpened := false;
  keyOpenCommandExists := false;

  Regist.BaseIndentLevel := LogDatei.LogSIndentLevel;

  for i:=1 to Sektion.count
  do
  Begin
    r := cutLeftBlanks(Sektion.strings [i-1]);
    if (r = '') or (r [1] = LineIsCommentChar)
    then
     // continue
    else
    Begin
      GetWord (r, Expression, r, WordDelimiterSet1);

      if LowerCase (Expression) = LowerCase ('OpenKey')
      then
      Begin
        if keyOpenCommandExists (* i.e., existed already *)
        then
           //LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1
        else
           keyOpenCommandExists := true;

        SyntaxCheck := false;
        if Skip ('[', r, r, ErrorInfo)
        then
        Begin
          GetWord (r, key, r, [']']);
          if Skip (']', r, r, ErrorInfo)
          then
          Begin
           if r = '' then SyntaxCheck := true else ErrorInfo := ErrorRemaining;

            key_completepath := key;
            LogDatei.DependentAdd('Key is: '+key, LLdebug);
            GetWord (key, key0, key, ['\']);
            LogDatei.DependentAdd('Key0 is: '+key0, LLdebug);
            if Is64BitSystem and ('software' = lowerCase(key0)) then
            begin
              LogDatei.DependentAdd('key starting with software on 64 bit. Key is: '+key, LLdebug);
              if not flag_force64 then
              begin
                key := key0 + '\wow6432node' + key;
                LogDatei.DependentAdd('key starting with software on 64 bit has to be redirected. So we work with: '+key, LLdebug);
              end
              else
              begin
                key := key_completepath;
                LogDatei.DependentAdd('key starting with software on 64 bit. Redirection is disabled. So we work with: '+key, LLdebug);
              end
            end
            else
            if (flag_all_ntuser or flag_ntuser or runLoginScripts) and (('HKEY_CURRENT_USER' = UpperCase(key0)) or ('HKCU' = UpperCase(key0))) then
            begin
              // remove HKCU from the beginning
              key := key;
              LogDatei.log ('Running loginscripts: ignoring key0 : '+key0 + ', using only key : '+key, LLdebug2);
            end
            else  key := key_completepath;
            GetWord (key, key0, key, ['\']);
            if GetHKEY(key0, outkey) then
            begin
               LogDatei.log ('key0 : '+key0+' is a valid base key and we will use it',LLDebug2);
               key := key_completepath;
            end
            else
            begin
              LogDatei.DependentAdd('Key0 is: '+key0+ ' Key is: '+key, LLdebug2);
              LogDatei.log ('key0 : '+key0+' is not a valid base key and we will praefix it with: '+basekey,LLDebug2);
              // insert RegParameter before key
              if basekey <> '' then
              Begin
                if basekey [length (basekey)] = '\' then basekey := copy(basekey,1,length(basekey)-1);
                key_completepath := basekey;
                LogDatei.DependentAdd('key_completepath1 : '+key_completepath, LLdebug3);
                if (trim(key0) <> '') then
                begin
                  if key0[1] = '\' then key0 := copy(key0,2,length(key0));
                  if key0 [length (key0)] = '\' then key0 := copy(key0,1,length(key0)-1);
                  key_completepath := key_completepath + '\' + key0;
                  LogDatei.DependentAdd('key_completepath2 : '+key_completepath, LLdebug3);
                end;
                if (trim(key) <> '') then
                begin
                  if key[1] = '\' then key := copy(key,2,length(key));
                  key_completepath := key_completepath + '\' + key;
                  LogDatei.DependentAdd('key_completepath3 : '+key_completepath, LLdebug3);
                end;
              End;
            end;

            // extract HKEY
            GetWord (key_completepath, key0, key, ['\']);
            system.delete(key,1,1);
            LogDatei.DependentAdd('We will open Key : '+key_completepath, LLdebug2);
          end;


        End;

        if SyntaxCheck
        then
        Begin
          if keyOpened then keyOpened := not Regist.CloseKey;
          Regist.BaseIndentLevel := StartIndentLevel + 1;
          keyOpened := Regist.OpenKey (key0, key);
          //LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;
        End
        else
          reportError (Sektion, i, Sektion.strings [i-1], ErrorInfo);

      End

      else if LowerCase (Expression) = LowerCase ('DeleteKey')
      then
      Begin
        SyntaxCheck := false;
        SyntaxCheck := true;
        if Skip ('[', r, r, ErrorInfo)
        then
        Begin
          GetWord (r, key, r, [']']);
          if Skip (']', r, r, ErrorInfo)
          then
          Begin
            if r = '' then SyntaxCheck := true else ErrorInfo := ErrorRemaining;
          End;

          key_completepath := key;
          // extract HKEY
          GetWord (key_completepath, key0, key, ['\']);
          system.delete(key,1,1);

          if (flag_all_ntuser or flag_ntuser or runLoginScripts) and (('HKEY_CURRENT_USER' = UpperCase(key0)) or ('HKCU' = UpperCase(key0))) then
          begin
            // remove HKCU from the beginning
            key := key;
            LogDatei.log ('Running loginscripts: ignoring key0 : '+key0 + ', using only key : '+key, LLdebug2);
          end
          else  key := key_completepath;
          GetWord (key, key0, key, ['\']);
          if GetHKEY(key0, outkey) then
          begin
             LogDatei.log ('key0 : '+key0+' is a valid base key and we will use it',LLDebug2);
             key := key_completepath;
          end
          else
          begin
            LogDatei.DependentAdd('Key0 is: '+key0+ ' Key is: '+key, LLdebug2);
            LogDatei.log ('key0 : '+key0+' is not a valid base key and we will praefix it with: '+basekey,LLDebug2);
            // insert RegParameter before key
            if basekey <> '' then
            Begin
              if basekey [length (basekey)] = '\' then basekey := copy(basekey,1,length(basekey)-1);
              key_completepath := basekey;
              LogDatei.DependentAdd('key_completepath1 : '+key_completepath, LLdebug3);
              if (trim(key0) <> '') then
              begin
                if key0[1] = '\' then key0 := copy(key0,2,length(key0));
                if key0 [length (key0)] = '\' then key0 := copy(key0,1,length(key0)-1);
                key_completepath := key_completepath + '\' + key0;
                LogDatei.DependentAdd('key_completepath2 : '+key_completepath, LLdebug3);
              end;
              if (trim(key) <> '') then
              begin
                if key[1] = '\' then key := copy(key,2,length(key));
                key_completepath := key_completepath + '\' + key;
                LogDatei.DependentAdd('key_completepath3 : '+key_completepath, LLdebug3);
              end;
            End;
          end;

          // extract HKEY
          GetWord (key_completepath, key0, key, ['\']);
          system.delete(key,1,1);
          LogDatei.DependentAdd('We will open Key : '+key_completepath, LLdebug2);
        end;

        if Is64BitSystem and (GetNTVersionMajor < 6) and regist.myforce64 then
        begin
          // Workaround for RegDeleteKey 64 Bit problem
         //errorcode := RegDeleteKeyEx(mykey, PChar(keytoopen), KeyOpenMode,0);
          output := TXStringList.create;
          commandline := 'cmd64.exe /c "reg delete ""'+key_completepath+'"" /f"';
          LogDatei.DependentAdd ('Executing ' + commandline, LLinfo);
          if not RunCommandAndCaptureOut(commandline,true,output, report, SW_SHOWMINIMIZED, FLastExitCodeOfExe) then
          Begin
            ps := 'Error: ' + Report;
            LogDatei.log(ps, LLcritical);
            FExtremeErrorLevel := LevelFatal;
            scriptstopped := true;
          End
          else
          Begin
            LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 6;
            LogDatei.DependentAdd ('', LevelInfo);
            LogDatei.DependentAdd ('output:', LevelInfo);
            LogDatei.DependentAdd ('--------------', LevelInfo);
            for outputlines := 0 to output.count-1 do
            begin
              LogDatei.DependentAdd (output.strings[outputlines], LevelInfo);
            end;
            LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 6;
            LogDatei.DependentAdd ('', LevelInfo);
            output.Free;
          end
        end
        else // workaround
        begin
          if SyntaxCheck then
          Begin
            if keyOpened then keyOpened := not Regist.CloseKey;
            subkeys := TXStringList.create;
            stringsplit ( key_completepath, '\', subkeys);
            if subkeys.count <= 1
            then
            Begin
              SyntaxCheck := false;
              ErrorInfo := 'No deleting on root level of registry'
            end
          End;

          if Syntaxcheck
          then
          Begin
              regpath := subkeys[1];
              for j := 2 to subkeys.count - 1
              do regpath := regpath + '\' + subkeys[j];
              Regist.BaseIndentLevel := StartIndentLevel + 1;
              Regist.DeleteKey (subkeys[0], regpath);
(*
              if (basekey = '') or (basekey = 'HKEY_USERS\' + usercontextSID+'\')
              then
              Begin
                  Regist.DeleteKey (subkeys[0], regpath);
              End
              else
              Begin
                 Regist.DeleteKey (subkeys[0], regpath); //regunloadkey does not work in this case
                 //Syntaxcheck := false;
                 //ErrorInfo := 'deletkey with /AllNtUserdat is not allowed (Windows API Bug)';
                 //Logdatei.DependentAddError('deletkey with /AllNtUserdat is not allowed (Windows API Bug)', LLError);
              End;
*)
          End;
        end; // workaround


        if not syntaxcheck
        then
          reportError (Sektion, i, Sektion.strings [i-1], ErrorInfo);

      End

      else
      if not keyOpenCommandExists
      then
        reportError (Sektion, i, Sektion.strings [i-1], 'OpenKey expected')
      else
      Begin
        SyntaxCheck := false;
        if LowerCase (Expression) = 'set'
        then
        Begin
          CitMark := '#';
          if   (Skip ('"', r, r, ErrorInfo))
          then
            CitMark := '"'
          else if   (Skip ('''', r, r, ErrorInfo))
          then
            CitMark := ''''
          else
            ErrorInfo := 'Expected "' + 'or ''';

          if CitMark <> '#'
          (* syntax o.k.*)
          then
          Begin
            GetWord (r, field, r, [citMark]);
            if Skip (CitMark, r, r, ErrorInfo)

            then if Skip ('=', r, r, ErrorInfo)
            then
            Begin
              if (length(r) > 0) and (r[1] in ['"',''''])
              then
               typeinfo := ''
              else
               GetWord (r, typeinfo, r, [':']);
              if GetTypedValue (r, typeinfo, regtype, value, r, ErrorInfo)
              then
                if r = '' then SyntaxCheck := true else ErrorInfo := ErrorRemaining;
            End;
          End;
          if SyntaxCheck
          then
            Regist.WriteEntry (field, regtype, value)
          else
            reportError (Sektion, i, Sektion.strings [i-1], ErrorInfo);
        End

        else if LowerCase (Expression) = 'add'
        then
        Begin
          SyntaxCheck := false;

          if Skip ('"', r, r, ErrorInfo)
          then
          Begin
            GetWord (r, field, r, ['"']);
            if Skip ('"', r, r, ErrorInfo)
            then if Skip ('=', r, r, ErrorInfo)
            then
            Begin
              GetWord (r, typeinfo, r, [':', '"']);
              if GetTypedValue (r, typeinfo, regtype, value, r, ErrorInfo)
              then
                if r = '' then SyntaxCheck := true else ErrorInfo := ErrorRemaining;
            End;
          End;
          if SyntaxCheck
          then
          Begin
            if Regist.ReadEntry (field, oldRegType, oldValue)
            then
            Begin
              LogDatei.DependentAdd ('Info: Variable ' + field + ' exists, '
                         + ' no overwrite. (The value is "' + oldValue + '")', LevelInfo );
              LogDatei.NumberOfHints := LogDatei.NumberOfHints + 1;
            End
            else
              Regist.WriteEntry (field, regtype, value)
          End
          else
            reportError (Sektion, i, Sektion.strings [i-1], ErrorInfo);
        End

        else if LowerCase (Expression) = 'supp'
        then
        Begin
          SyntaxCheck := false;
          if Skip ('"', r, r, ErrorInfo)
          then
          Begin
            GetWord (r, field, r, ['"']);
            if Skip ('"', r, r, ErrorInfo)
            then
            Begin
              if (length (r) = 0)
              then ErrorInfo := 'Separator expected'
              else
              Begin
                if r[1] = '"'
                then
                  Separator := #0
                else
                Begin
                  Separator := r[1];
                  Skip (Separator, r, r, ErrorInfo);
                End;
                if Skip ('"', r, r, ErrorInfo)
                then
                Begin
                  GetWord (r, value, r, ['"']);
                  if Skip ('"', r, r, ErrorInfo)
                  then
                    SyntaxCheck := true;
                End;
              End;
            End;
          End;
          if SyntaxCheck
          then
            Regist.SupplementItems (Separator, field, value)
          else
            reportError (Sektion, i, Sektion.strings [i-1], ErrorInfo);
        End

        else if LowerCase (Expression) = LowerCase ('GetMultiSZFromFile')
        then
        Begin
          Syntaxcheck := false;
          if GetString (trim(r), field, r, ErrorInfo, false)
             and
             GetString (trim(r), filename, r, ErrorInfo, false)
          then
            if r = '' then syntaxCheck := true else ErrorInfo := ErrorRemaining;

          if SyntaxCheck
          then
          Begin
            LogDatei.DependentAdd ('Get value of variable "' + field + '" from file "' + filename + '"',
                                    LevelComplete);
            TextFile := TStringList.create;
            try
               filename := ExpandFileName(filename);
               TextFile.LoadFromFile (filename);
               TextFile.Text:= reencode(TextFile.Text, 'system');
            except
               on e: exception do
               Begin
                  LogDatei.DependentAddError ('Error: ' + e.message, LLError);
               End;
            End;
            value := TextFile.Text;
            value := StringReplace (value, #13#10, #10);
            Regist.WriteEntry (field, trdMultiString, value);
            TextFile.free;
          End
          else
            reportError (Sektion, i, Sektion.strings [i-1], ErrorInfo);
        End


        else if LowerCase (Expression) = LowerCase ('SaveValueToFile')
          // undocumented
        then
        Begin
          Syntaxcheck := false;
          if GetString (trim(r), field, r, ErrorInfo, false)
             and
             GetString (trim(r), filename, r, ErrorInfo, false)
          then
            if r = '' then syntaxCheck := true else ErrorInfo := ErrorRemaining;


          if SyntaxCheck
          then
          Begin
            LogDatei.DependentAdd ('Save value of variable "' + field + '" to file "' + filename + '"',
                                    LevelComplete);
            TextFile := TStringList.create;
            TextFile.Text := Regist.ReadString (field);

            try
               TextFile.SaveToFile (filename);
            except
               on e: exception do
               Begin
                  LogDatei.DependentAddError ('Error: ' + e.message, BaseLevel);
               End;
            End;
            Textfile.free;
          End
          else
            reportError (Sektion, i, Sektion.strings [i-1], ErrorInfo);
        End


        else if LowerCase (Expression) = 'flushkey'
        then
        Begin
           Regist.FlushKey
        End

        else if LowerCase (Expression) = LowerCase ('ReconstructFrom')
        then
        Begin
          SyntaxCheck := false;
          if Skip ('"', r, r, ErrorInfo)
          then
          Begin
            GetWord (r, path, r, ['"']);
            if Skip ('"', r, r, ErrorInfo)
            then
            Begin
              if r = ''
              then SyntaxCheck := true
              else ErrorInfo := 'not interpreted characters after "';
              if SyntaxCheck then Regist.RestoreFromFile (path)
              else reportError (Sektion, i, Sektion.strings [i-1], ErrorInfo);
            End;
          End;
        End

        else if LowerCase (Expression) = LowerCase ('CopySecurityFrom')
        // experimentell
        then
        Begin
          SyntaxCheck := false;
          if Skip ('[', r, r, ErrorInfo)
          then
          Begin
             GetWord (r, TemplateKey, r, [']']);
             if Skip (']', r, r, ErrorInfo)
             then
             Begin
               if r = ''
               then SyntaxCheck := true
               else ErrorInfo := 'not interpreted characters after ]';

             (* fuege RegParameter vor key ein *)
                TemplateKey := basekey + TemplateKey;

             (* hole HKEY aus key heraus *)
               GetWord (TemplateKey, key0, TemplateKey, ['\']);
               System.Delete (TemplateKey, 1,1);
             end;

             if SyntaxCheck
             then Regist.SetSecurity (TemplateKey, key)
             else reportError (Sektion, i, Sektion.strings [i-1], ErrorInfo);
          End;
        End

        else if LowerCase (Expression) = LowerCase ('DeleteVar')
        then
        Begin
           SyntaxCheck := false;
           if Skip ('"', r, r, ErrorInfo)
           then
           Begin
              GetWord (r, field, r, ['"']);
              if Skip ('"', r, r, ErrorInfo)
              then
                if r = ''
                then syntaxCheck :=true
                else ErrorInfo := ErrorRemaining;
           End;

           if SyntaxCheck
           then Regist.DeleteEntry (Field)
           else reportError (Sektion, i, Sektion.strings [i-1], ErrorInfo);
        End

        else if LowerCase (Expression) = LowerCase ('DeleteAllVars')
        then
        Begin

           syntaxcheck := false;

           if r <> ''
           then ErrorInfo := ErrorRemaining

           else
           Begin
             syntaxcheck := true;
             varlist := Regist.GetAllVars;
             for varno := 0 to varlist.count - 1
             do
              Regist.DeleteEntry (varlist.Strings[varno])
           end;
        End

        else
        reportError (Sektion, i, Expression, ' Operation nicht definiert');
      end;
    End;

  End;

  {
  if keyOpenCommandExists (* i.e., existed already *)
  then
    LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;
  }

  if keyOpened then keyOpened := not Regist.CloseKey;

  Regist.free; Regist := nil;

  finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                 DiffNumberOfErrors, DiffNumberOfWarnings);

  LogDatei.LogSIndentLevel := StartIndentLevel;
  //LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;

  if ExitOnError and (DiffNumberOfErrors> 0)
  then result := tsrExitProcess;

end;


function TuibInstScript.doRegistryAllNTUserDats (const Sektion: TWorkSection;
         rfSelected: TRegistryFormat; const flag_force64 : boolean): TSectionResult;

 var
   //SearchPath : String='';
   //SearchRec  : TSearchRec;
   //findresult : Integer=0;

   profilename, profilepath : string;
   ProfileList : TStringList;
   hkulist  : TStringList;
   i : integer;
   pc : integer;
   domain : string = '';
   UserPath : String='';
   aktsidStr : String = '';

   Errorcode  : Integer=0;
   Info : String='';

   StartWithErrorNumbers : integer=0;
   StartWithWarningsNumber: Integer=0;
{$IFDEF WIN32}

 function LoadNTUserDat (const path : String) : Boolean;
  var
   Errorcode                                     : Integer;
 begin
   SetProcessPrivilege ('SeSecurityPrivilege');
   SetProcessPrivilege ('SeRestorePrivilege');
   SetProcessPrivilege ('SeBackupPrivilege');

   {load the selected ntuser.dat in HKEY_USERS, subkey TempUserRegKey}

   Errorcode:= RegLoadKey (HKEY_USERS, PChar (TempUserRegKey), PChar (path));
   if Errorcode = Error_success
   then
   Begin
     LogDatei.DependentAdd ('"' + path + '" loaded.', LevelComplete);
     result := true;
   End
   else
   Begin
        (* check if NTUser.dat is in use, since the specific user is logged in *)
     LogDatei.DependentAddWarning ('Warning: NTUser.dat could not be loaded from path "' + path + '". '
        + 'Code ' + IntToStr(Errorcode) + ': ' +  RemoveLineBreaks(SysErrorMessage(Errorcode)), LLWarning);
     result := false;
   End;
 end;

 procedure workOnNtUserDat;
 begin
     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;


     case rfSelected of
       trfRegedit: doRegistryHackRegeditFormat (Sektion, 'HKEY_USERS\' + TempUserRegKey, flag_force64);
       trfWinst  : doRegistryHack (Sektion, 'HKEY_USERS\' + TempUserRegKey, flag_force64);
     end;

     LogDatei.DependentAdd ('', LevelDebug);
     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;

     ErrorCode := RegFlushKey(HKEY_Users);

     if Errorcode = Error_success
     then
       LogDatei.DependentAdd ('Flushed', LevelDebug)
     else
     Begin
       LogDatei.DependentAddWarning ('Warning: Could not be flushed. Code '
                              + IntToStr(Errorcode) +': ' + RemoveLineBreaks(SysErrorMessage(Errorcode)), LevelWarnings);
     End;

     Errorcode := RegUnloadKey (HKEY_Users, PChar(TempUserRegKey));
     if Errorcode = Error_success
     then
       LogDatei.DependentAdd ('Unloaded', LevelDebug)
     else
     Begin
       LogDatei.DependentAddWarning ('Warning: Could not be unloaded. Code '
                              + IntToStr(Errorcode) +': ' + RemoveLineBreaks(SysErrorMessage(Errorcode)), LevelWarnings);
     End;
 end;

 procedure workOnHkuserSid (const name : String);
 var
  sidStr : String='';
 begin
  LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;

  //sidStr := GetLocalUserSidStr(GetUserNameEx_);
  //LogDatei.DependentAdd('sidStr :'+sidStr,LLDebug);
  sidStr := GetLocalUserSidStr(name);
  LogDatei.DependentAdd('sidStr :'+sidStr,LLDebug2);
  sidStr := copy(sidStr,2,length(sidStr)-2);
  LogDatei.DependentAdd('sidStr :'+sidStr,LLDebug);


   case rfSelected of
     trfRegedit: doRegistryHackRegeditFormat (Sektion, 'HKEY_USERS\' + sidStr, flag_force64);
     trfWinst  : doRegistryHack (Sektion, 'HKEY_USERS\' + sidStr, flag_force64);
   end;

   LogDatei.DependentAdd ('', LLDebug);
   LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;

   ErrorCode := RegFlushKey(HKEY_Users);

   if Errorcode = Error_success
   then
     LogDatei.DependentAdd ('Flushed', LevelDebug)
   else
   Begin
     LogDatei.DependentAddWarning ('Warning: Could not be flushed. Code '
                            + IntToStr(Errorcode) +': ' + RemoveLineBreaks(SysErrorMessage(Errorcode)), LLWarning);
   End;
 end;

begin
   result := tsrPositive;

   if not initSection (Sektion, StartWithErrorNumbers, StartWithWarningsNumber) then exit;
   LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;

   // mount the NTUser.dat in the users profile path , patch them and write them back


   (*
   SearchPath  := GetProfilesPath; // GetWinDirectory + 'Profiles';
   findresult := findfirst (SearchPath + '\*.*',
                 faDirectory or faAnyFile, SearchRec);

   while findresult = 0
   do
   Begin
     if (SearchRec.Attr and faDirectory = faDirectory) and
         (SearchRec.Name <> '.') and
         (SearchRec.Name <> '..')
     then
     Begin
     *)
   ProfileList := getProfilesDirList;
   for pc:= 0 to ProfileList.Count -1 do
   begin
     profilepath := ProfileList.Strings[pc];
     profilename := ExtractFileName(profilepath);

     LogDatei.DependentAdd ('', LLNotice);
     LogDatei.DependentAdd ('Branch: ' + profilename, LLNotice);
     UserPath := profilepath + '\NTUser.dat';
     if FileExists (UserPath)
     then
     Begin
       if not FileGetWriteAccess (UserPath, Info)
       then
       Begin
         LogDatei.DependentAddError ('Error: ' + Info, LLError);
       End
       else
       Begin
         if Info <> ''
         then
         Begin
           LogDatei.DependentAddWarning ('Warning: ' + Info, LLWarning);
         End;
          if LoadNTUserdat (UserPath) then
          begin
              workOnNtUserDat;
          end
          else
          begin
            if (GetUserNameEx_ <> '') then
            begin
              hkulist := Tstringlist.Create;
              hkulist.AddStrings(GetRegistryKeyList('HKU\',false));
              for i := 0 to hkulist.Count-1 do
                LogDatei.log('found in hku  '+ hkulist.Strings[i],LLDebug2);
              hkulist.Free;
              aktsidStr := GetDomainUserSidS('',GetUserNameEx_,domain);
              aktsidStr := copy(aktsidStr,2,length(aktsidStr)-2);
              LogDatei.log('sid is: '+aktsidStr,LLDebug2);
              LogDatei.log('index is: '+inttostr(GetRegistryKeyList('HKU\',false).IndexOf(aktsidStr)),LLDebug2);
              if (profilename = GetUserNameEx_)
                 or (profilepath = getProfileImagePathfromSid(GetLocalUserSidStr(GetUserNameEx_)))
                 or (GetRegistryKeyList('HKU\',false).IndexOf(aktsidStr) > -1)
                 then
              begin
                LogDatei.DependentAdd('The Branch for :'+profilename+' seems to be the logged in user,',LLDebug);
                LogDatei.DependentAdd('so let us try to patch it via HKUsers\SID',LLDebug);
                workOnHkuserSid (GetUserNameEx_);
              end;
            end
            else
            begin
              // at XP we have problems to get the username while pcpatch is logged in
              if GetSystemOSVersionInfoEx('major_version') = '5' then
              begin
                LogDatei.DependentAdd('The Branch for :'+profilename+' may be the logged in user,',LLDebug);
                LogDatei.DependentAdd('so let us try to patch it via HKUsers\SID',LLDebug);
                workOnHkuserSid (profilename);
              end;
            end;
          end;
       End;
     End;
   End;

   (*
     findresult := findnext (SearchRec);
   End;

   sysutils.findclose (SearchRec);
   *)


   // Patch HKEY_Current_User

   LogDatei.DependentAdd ('', LevelWarnings);
   LogDatei.DependentAdd ('Make it for user .DEFAULT', LevelWarnings);
   LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;
   case rfSelected of
     trfRegedit: doRegistryHackRegeditFormat (Sektion, 'HKEY_USERS\.DEFAULT', flag_force64);
     trfWinst  : doRegistryHack (Sektion, 'HKEY_USERS\.DEFAULT', flag_force64);
   end;

   // do not to try the temporary pcpatch account or SYSTEM - sense less and may fail
   if not ((GetUserName_ = 'pcpatch') or (GetUserName_ = 'SYSTEM')) then
   begin
     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;
     LogDatei.DependentAdd ('', LevelWarnings);
     LogDatei.DependentAdd ('And finally: The current user: '+GetUserName_+' : '+GetLocalUserSidStr(GetUserName_), LLNotice);
     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;

     case rfSelected of
       trfRegedit: doRegistryHackRegeditFormat (Sektion, 'HKEY_CURRENT_USER', flag_force64);
       trfWinst  : doRegistryHack (Sektion, 'HKEY_CURRENT_USER', flag_force64);
     end;
   end;

   LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;

   LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;

   finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                 DiffNumberOfErrors, DiffNumberOfWarnings);

   if ExitOnError and (DiffNumberOfErrors > 0)
   then result := tsrExitProcess;
end;
{$ELSE WIN32}
begin
  // not implemented
  result := tsrExitProcess;
end;

{$ENDIF WIN32}

function TuibInstScript.doRegistryNTUserDat (const Sektion: TWorkSection;
         rfSelected: TRegistryFormat; const flag_force64 : boolean; const UserPath : string): TSectionResult;

 var
   //SearchPath : String='';
   //SearchRec  : TSearchRec;
   //findresult : Integer=0;

   //profilename, profilepath : string;
   //ProfileList : TStringList;
   //pc : integer;

   //UserPath : String='';

   Errorcode  : Integer=0;
   Info : String='';

   StartWithErrorNumbers : integer=0;
   StartWithWarningsNumber: Integer=0;

 function LoadNTUserDat (const path : String) : Boolean;
  var
   Errorcode                                     : Integer;
 begin
   SetProcessPrivilege ('SeSecurityPrivilege');
   SetProcessPrivilege ('SeRestorePrivilege');
   SetProcessPrivilege ('SeBackupPrivilege');

   {load the selected ntuser.dat in HKEY_USERS, subkey TempUserRegKey}

   Errorcode:= RegLoadKey (HKEY_USERS, PChar (TempUserRegKey), PChar (path));
   if Errorcode = Error_success
   then
   Begin
     LogDatei.DependentAdd ('"' + path + '" loaded.', LevelComplete);
     result := true;
   End
   else
   Begin
        (* check if NTUser.dat is in use, since the specific user is logged in *)
     LogDatei.DependentAddWarning ('Warning: NTUser.dat could not be loaded from path "' + path + '". '
        + 'Code ' + IntToStr(Errorcode) + ': ' +  RemoveLineBreaks(SysErrorMessage(Errorcode)), LLWarning);
     result := false;
   End;
 end;

 procedure workOnNtUserDat;
 begin
     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;


     case rfSelected of
       trfRegedit: doRegistryHackRegeditFormat (Sektion, 'HKEY_USERS\' + TempUserRegKey, flag_force64);
       trfWinst  : doRegistryHack (Sektion, 'HKEY_USERS\' + TempUserRegKey, flag_force64);
     end;

     LogDatei.DependentAdd ('', LevelDebug);
     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;

     ErrorCode := RegFlushKey(HKEY_Users);

     if Errorcode = Error_success
     then
       LogDatei.DependentAdd ('Flushed', LevelDebug)
     else
     Begin
       LogDatei.DependentAddWarning ('Warning: Could not be flushed. Code '
                              + IntToStr(Errorcode) +': ' + RemoveLineBreaks(SysErrorMessage(Errorcode)), LevelWarnings);
     End;

     Errorcode := RegUnloadKey (HKEY_Users, PChar(TempUserRegKey));
     if Errorcode = Error_success
     then
       LogDatei.DependentAdd ('Unloaded', LevelDebug)
     else
     Begin
       LogDatei.DependentAddWarning ('Warning: Could not be unloaded. Code '
                              + IntToStr(Errorcode) +': ' + RemoveLineBreaks(SysErrorMessage(Errorcode)), LevelWarnings);
     End;
 end;


begin
   result := tsrPositive;

   if not initSection (Sektion, StartWithErrorNumbers, StartWithWarningsNumber) then exit;
   LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;

   (*
   ProfileList := getProfilesDirList;
   for pc:= 0 to ProfileList.Count -1 do
   begin
     profilepath := ProfileList.Strings[pc];
     profilename := ExtractFileName(profilepath);

     LogDatei.DependentAdd ('', LLNotice);
     LogDatei.DependentAdd ('Branch: ' + profilename, LLNotice);
     UserPath := profilepath + '\NTUser.dat';
     *)
     if FileExists (UserPath)
     then
     Begin
       if not FileGetWriteAccess (UserPath, Info)
       then
       Begin
         LogDatei.DependentAddError ('Error: ' + Info, LLError);
       End
       else
       Begin
         if Info <> ''
         then
         Begin
           LogDatei.DependentAddWarning ('Warning: ' + Info, LLWarning);
         End;
          if LoadNTUserdat (UserPath) then
          begin
              workOnNtUserDat;
          end
          else
            LogDatei.log('Error: could not patch ntuserdat: '+UserPath,LLError);
          (*
          begin
            if (GetUserNameEx_ <> '') then
            begin
              if (profilename = GetUserNameEx_)
                 or (profilepath = getProfileImagePathfromSid(GetLocalUserSidStr(GetUserNameEx_)))
                 then
              begin
                LogDatei.DependentAdd('The Branch for :'+profilename+' seems to be the logged in user,',LLDebug);
                LogDatei.DependentAdd('so let us try to patch it via HKUsers\SID',LLDebug);
                workOnHkuserSid (profilename);
              end;
            end
            else
            begin
              // at XP we have problems to get the username while pcpatch is logged in
              if GetSystemOSVersionInfoEx('major_version') = '5' then
              begin
                LogDatei.DependentAdd('The Branch for :'+profilename+' may be the logged in user,',LLDebug);
                LogDatei.DependentAdd('so let us try to patch it via HKUsers\SID',LLDebug);
                workOnHkuserSid (profilename);
              end;
            end;
          end;
          *)
       End;
     End;
   //End;
   LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;

   LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;

   finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                 DiffNumberOfErrors, DiffNumberOfWarnings);

   if ExitOnError and (DiffNumberOfErrors > 0)
   then result := tsrExitProcess;
end;
{$ENDIF WINDOWS}


function TuibInstScript.doOpsiServiceCall
 (const Sektion: TWorkSection; Const parameter : String;
           var output: TXStringList)
                                                    : TSectionResult;

  Type
    TServiceChoice = (tscGlobal, tscReuse, tscLogin, tscInteractiveLogin, tscOpsiclientd);

  Var
   startSIndentLevel : Integer=0;
   serviceChoice : TServicechoice;
   errorOccured : Boolean;
   syntaxcheck : Boolean;
   errorInfo : String='';
   i : integer=0;
   paramstartI : Integer;
   j : Integer=0;

   methodname : String='';
   paramList : TStringList;
   parameters : Array of String;

   omc: TOpsiMethodCall;
   //local_opsidata : TOpsiDataJSONService;
   serviceURL : String='';
   username : String='';
   password : String='';
   sessionid : String='';
   r : String='';
   expression : String='';
   param : String='';
   inParams, paramsFound, paramsValueListFound : Boolean;
   stopIt : boolean;
   testresult : String='';
   {$IFDEF GUI}
   passwordDialog : TDialogServicePassword;
   {$ENDIF GUI}
   opsiServiceVersion : String='';
   myconf : TIniFile;
   opsiclientd_conf : String='';
   tmplist : Tstringlist;

   procedure getNextValidLine (var line : String; var lineno : Integer; const lines : TStrings);
   begin
    line := trim(lines [lineno - 1]);
    while (lineno <= lines.count) and (line = '') or (line [1] = LineIsCommentChar)
    do
    begin
      inc (lineno);
      if lineno <= lines.count
      then
        line := trim(lines [lineno - 1]);
    end;
   end;


begin
 try
    // initializing
    tmplist := Tstringlist.create;
    result := tsrPositive;
    startSIndentLevel :=  LogDatei.LogSIndentLevel;
    if not initSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings) then exit;
    LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;
    try
      //convert String to catch not allowed chars
      r := trim(Utf8ToAnsi(AnsiToUtf8(parameter)));
    except
      on ex: Exception
      do
      begin
        LogDatei.DependentAddError ('Exception in doOpsiServiceCall: convert parameter' + ex.message ,LLError);
      end;
    end;
    syntaxcheck := true;


    serviceChoice := tscGlobal;

    if local_opsidata <> nil
    then serviceChoice := tscReuse;

    if r <> ''
    then
    Begin
      serviceChoice := tscLogin;
      while r <> ''
      do
      Begin
        if skip ('/opsiclientd', r, r, errorInfo)
        then
           serviceChoice := tscOpsiclientd // we call the local opsiclientd

        else if skip ('/preloginservice', r, r, errorInfo)
        then
           serviceChoice := tscGlobal // we return to the default service from the installation server

        else if skip ('/interactive', r, r, errorInfo)
        then
           serviceChoice := tscInteractiveLogin

        else if skip ('/serviceurl', r, r, errorInfo)
           or skip ('/opsiservice', r, r, errorInfo)
           or skip ('/s', r, r, errorInfo)
        then
          EvaluateString(r, r, serviceurl, errorInfo)

        else if skip ('/username', r, r, errorInfo)
           or skip ('/user', r, r, errorInfo)
           or skip ('/u', r, r, errorInfo)
        then
          EvaluateString(r, r, username, errorInfo)

        else if skip ('/password', r, r, errorInfo)
           or skip ('/pass', r, r, errorInfo)
           or skip ('/p', r, r, errorInfo)
        then
          EvaluateString(r, r, password, errorInfo)

        else
        Begin
          r := '';
          errorInfo := 'Not valid parameter for section ' + Sektion.Name;
          syntaxcheck := false;
        End;
      end;

    end;

    if (serviceChoice in [tscGlobal, tscReuse, tscOpsiclientd])
      and
      ((username <> '') or (password <> '') or (serviceurl<>''))
    then
    Begin
      syntaxcheck := false;
      errorInfo := 'Connection parameters must not be specified if existing connection shall be used.'
    end;
    if (serviceChoice in [tscLogin, tscInteractiveLogin]) and (local_opsidata <> nil) then
      Logdatei.DependentAdd('Warning: Existing service connection will be reopend. This may cause critical errors. Do not do this, if you are not really shure what you doing.', LLwarning );

    // lets do something

    i := 1;
    if syntaxcheck
    then
    Begin
      errorOccured := false;
      methodname := '';
      paramList := TStringList.create;
      inParams := false;
      paramsFound := false;
      paramsValueListFound := false;

    end;


    while (i <= Sektion.count) and syntaxcheck
    do
    Begin
        getNextValidLine (r, i, Sektion);

      if i <= Sektion.count
      then
      Begin
        SyntaxCheck := false;
        GetWord (r, Expression, r, [':']);

        if Skip (':', r, r, errorInfo)
        then
        Begin
          if LowerCase (Expression) = LowerCase ('"method"')
          then
          Begin
            if GetString (r, methodname, r, errorInfo, false)
            then
              syntaxcheck := true;

          end

          else if LowerCase (Expression) = LowerCase ('"params"')
          then
          Begin
             syntaxcheck := true;
             paramsFound := true;

             if r = ''
             then
               getNextValidLine (r, i, Sektion);

             if (i <= Sektion.count) and skip ('[', r, r, errorInfo)
             then
             Begin
               inParams := true;
               paramsValueListFound := true;
               paramStartI := i;
               if r = ']'
               then  // empty param list
               Begin
                 inParams := false;
               end
               else if r <> ''
               then
               Begin
                 syntaxcheck := false;
                 errorInfo := 'Parameters must be on their own lines';
               end
               else
               Begin
                 inc (i);
               End;


               while
                 syntaxcheck and (i <= Sektion.count) and inParams
               do
               Begin
                  getNextValidLine(r, i, Sektion);
                  if i <= Sektion.count
                  then
                  Begin
                    if r = ']'
                    then inParams := false
                    else
                    Begin
                      if length(r) > 0
                      then
                      Begin
                        if r[length(r)] = ','
                        then r := trim(copy (r, 1, length(r) -1));
                        if length(r) > 0
                        then
                        Begin

                          if GetString (r, param, r, errorInfo, true)
                          then
                          begin
                            LogDatei.DependentAdd ('Parsing: getparam: ' + param ,LLdebug2);
                            paramList.Add(param);
                          end
                          else
                            syntaxcheck := false;
                        end;
                      end;
                      inc(i);
                    End;
                  End

               end;
             End;

             if syntaxcheck and (i > Sektion.count) and inParams
             then
             Begin
               SyntaxCheck := false;
               errorInfo := 'ParamList starting on line ' + inttoStr(paramStartI) + ' not closed '
                 + ' (must be a pure "]" on a line)'
             End;

          End

          else
          Begin
             SyntaxCheck := false;
             ErrorInfo := Expression + ' is not a valid parameter ';
          End
        End


      end;


      inc(i);

    End; // loop through lines


    if syntaxCheck
    then
    Begin
      if (methodname = '')
      then
      Begin
        syntaxCheck := false;
        errorInfo := errorInfo + ' Method name missing';
      End;

      if paramsFound
      then
      Begin
        if not paramsValueListFound
        then
        Begin
        errorInfo := errorInfo + ' Params missing';
        syntaxCheck := false;
        End
      end
      else
      Begin
        errorInfo := errorInfo + ' Params missing';
        syntaxCheck := false;
      End;
    end;


    if syntaxCheck then
    Begin
      LogDatei.log('   "method": "' + methodname + '"', LevelComplete);
      //LogDatei.DependentAdd('   "params" : "' + jsonParams, LevelComplete);

      testresult := 'service not initialized';
      case serviceChoice of
        tscGlobal:
          Begin

            if opsidata = nil
            then
            Begin
              errorOccured := true;
            End
            else
             try
              if opsidata.getOpsiServiceVersion = '4' then
                local_opsidata := TOpsi4Data(opsidata);
               LogDatei.log('Calling opsi service at ' + local_opsidata.serviceUrl, LevelComplete);
             except
               errorOccured := true;
               testresult := 'not in service mode';
             end;

          end;

        tscReuse:
          begin
            if (local_opsidata = nil) or  not(local_opsidata is TOpsi4Data)
            then
            Begin
              errorOccured := true;
              testresult := 'not connected to service';
            End
            else
            Begin
              LogDatei.DependentAdd('Calling opsi service at ' + local_opsidata.serviceUrl, LevelComplete);
            End
          end;

        tscLogin:
          begin
            try
              opsiServiceVersion := getOpsiServiceVersion(serviceurl, username, password, sessionid);
              if opsiServiceVersion = '4' then
              begin
                local_opsidata := TOpsi4Data.Create;
                local_opsidata.initOpsiConf(serviceurl, username, password, sessionid);
                //Topsi4data(local_opsidata).initOpsiConf(serviceurl, username, password);
                //OpsiData.setOptions (opsiclientd_serviceoptions);
                omc := TOpsiMethodCall.create ('backend_info',[]);
                //omc := TOpsiMethodCall.create ('authenticated',[]);
                testresult := local_opsidata.CheckAndRetrieve (omc, errorOccured);
                omc.free;
              end
              else if opsiServiceVersion = '' then LogDatei.DependentAdd ('opsi service version could not retrieved, perhaps no connection', LLwarning)
              else LogDatei.log ('Internal Error: Unkown Opsi Service Version:>'+opsiServiceVersion+'<', LLerror);
            except
              on e: exception do
              Begin
                LogDatei.log('Exception in doOpsiServicecall: tscLogin: ' + e.message, LLError);
                errorOccured := true;
                testresult := 'not connected to service';
              End;
            end;
          end;

        tscInteractiveLogin:
          Begin
            {$IFDEF GUI}
            stopIt := false;
            passwordDialog := TDialogServicePassword.create(nil);


            while not stopIt
            do
            Begin
              passwordDialog.Visible := false;
              passwordDialog.EditServiceURL.Text := serviceurl;
              passwordDialog.EditUsername.Text := username;
              passwordDialog.EditPassword.Text := '';

              if passwordDialog.showModal = mrOK
              then
              Begin
                serviceUrl := passwordDialog.EditServiceURL.Text;
                username := passwordDialog.EditUsername.Text;
                password := passwordDialog.EditPassword.Text;
                LogDatei.DependentAdd ('serviceUrl: '+serviceUrl, LLconfidential);
                LogDatei.DependentAdd ('username: '+username, LLconfidential);
                LogDatei.DependentAdd ('password: '+password, LLconfidential);
                opsiServiceVersion := getOpsiServiceVersion(serviceurl, username, password,sessionid);
                if opsiServiceVersion = '4' then
                begin
                  local_opsidata := TOpsi4Data.Create;
                  local_opsidata.initOpsiConf(serviceurl, username, password, sessionid);
                  //Topsi4data(local_opsidata).initOpsiConf(serviceurl, username, password);
                  //OpsiData.setOptions (opsiclientd_serviceoptions);
                  omc := TOpsiMethodCall.create ('backend_info',[]);
                  //omc := TOpsiMethodCall.create ('authenticated',[]);
                  testresult := local_opsidata.CheckAndRetrieve (omc, errorOccured);
                  omc.free;
                end
                else errorOccured := true;
                //LogDatei.DependentAdd ('Internal Error: Unkown Opsi Service Version:>'+opsiServiceVersion+'<', LLerror);

                stopIt := not errorOccured;
              End

              else
              Begin
                stopIt := true;
                errorOccured := true;
                testresult := 'Cancelled by user';
              end;

            end;

            passwordDialog.Free;

            {$ENDIF GUI}
          end;

        tscOpsiclientd:
           begin
            serviceurl := 'https://localhost:4441/opsiclientd';
            {$IFDEF WINDOWS}
            opsiclientd_conf := getSpecialFolder(CSIDL_PROGRAM_FILES)
                                +'\opsi.org\opsi-client-agent\opsiclientd\opsiclientd.conf';
            {$ENDIF WINDOWS}
            {$IFDEF LINUX}
            opsiclientd_conf := '/etc/opsi/opsiclientd.conf';
            {$ENDIF LINUX}
            if FileExists(opsiclientd_conf) then
            begin
              myconf := TInifile.Create(opsiclientd_conf);
              password := myconf.ReadString('global','opsi_host_key','');
              username := myconf.ReadString('global','host_id','');
              myconf.Free;
            end;
            if password = '' then
            begin
              stopIt := true;
              errorOccured := true;
              testresult := 'Can not get opsi_host_key';
            end
            else
            begin
              local_opsidata := TOpsi4Data.Create;
              local_opsidata.initOpsiConf(serviceurl, username, password);
              omc := TOpsiMethodCall.create ('backend_info',[]);
              testresult := local_opsidata.CheckAndRetrieve (omc, errorOccured);
              omc.free;
            end;
          end;

      end;

      if errorOccured
        then
        Begin
          local_opsidata := nil;
          LogDatei.DependentAddError('Error: ' + testresult, LLError);
        End;

      if local_opsidata = nil
        then
        Begin
          errorOccured := true;
          LogDatei.DependentAddError('Error: no connection to service', BaseLevel);
        End;

    end;

    if not errorOccured and syntaxcheck
      then
      Begin
        try
          setlength(parameters, paramList.count);
          for j := 0 to paramList.count - 1 do
          begin
            parameters[j] := paramlist.Strings[j]
          end;

          omc := TOpsiMethodCall.create (methodname, parameters);
          testresult := '';

          if copy(methodname, length(methodname) - length('_hash') + 1, length(methodname))
             = '_hash'
          then
          Begin
            if output = nil then output := TXStringList.create;
              tmplist := local_opsidata.checkAndRetrieveMap(omc, errorOccured);
              if tmplist <> nil then output.Assign(tmplist);
              //output.Text := tmplist.Text;
             if (not errorOccured) and (output <> nil) then
             begin
               try
                      if output.count > 0 then
                      testresult :=    output.strings[0];

                  for j:= 0 to output.count - 1
                   do
                     testresult := testresult + ', ' + output.strings[j]
                except
                LogDatei.DependentAddError('Error: exeption after checkAndRetrieveMap in reading the stringlist' + testresult, LLError);
               end
             end
             else if output = nil then output := TXStringList.create;
          end
          else if copy(methodname, length(methodname) - length('_list') + 1, length(methodname))
             = '_list'
          then
          Begin
            if output = nil then output := TXStringList.create;
             tmplist := local_opsidata.checkAndRetrieveStringList(omc, errorOccured);
             if tmplist <> nil then output.Assign(tmplist);
             //output.Text := tmplist.Text;
             if (not errorOccured) and (output <> nil) then
             begin
                try
                  if output.count > 0 then
                   testresult :=    output.strings[0];

                   for j:= 1 to output.count - 1
                   do
                     testresult := testresult + ', ' + output.strings[j]
               except
                LogDatei.log('Error: exeption after checkAndRetrieveStringList in reading the stringlist' + testresult, LLError);
               end
             end
             else if output = nil then output := TXStringList.create;
          end
          else

          Begin
             testresult := local_opsidata.CheckAndRetrieveString (omc, errorOccured);
             output := TXStringList.create;
             output.add (testresult);
          End;

          omc.free;

          if errorOccured
          then
          begin
            LogDatei.DependentAddError('Error: ' + testresult, LLError);
          end
          else
          begin
            LogDatei.DependentAdd('JSON result: '+ testresult, LLinfo);
            //Logdatei.DependentAdd('Setup script name: '+opsidata.getProductScriptPath(tacSetup), LLessential);
          end;
        except
          on e: exception do
          Begin
            LogDatei.log('Exception in doOpsiServiceCall: do the call: ' + e.message, LLError);
          End;
        end;
      end;

    // finishing our section
    finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                   DiffNumberOfErrors, DiffNumberOfWarnings);

    LogDatei.LogSIndentLevel := startSIndentLevel;

    if ExitOnError and (DiffNumberOfErrors > 0)
    then result := tsrExitProcess;

    if not SyntaxCheck then
    Begin
      if i >= Sektion.count
      then
        reportError (Sektion, Sektion.count, Sektion.strings [Sektion.count - 1], ErrorInfo)
      else
         reportError (Sektion, i, Sektion.strings [i-1], ErrorInfo);
    End
  except
    on ex: Exception
    do
    begin
      LogDatei.DependentAddError ('Exception in doOpsiServiceCall: general' + ex.message ,LLError);
    end;
  end;

end;


//#############################################################################

function TuibInstScript.doOpsiServiceHashList
 (const Sektion: TWorkSection; Const parameter : String;
           var output: TXStringList)
                                                    : TSectionResult;

  Type
    TServiceChoice = (tscGlobal, tscReuse, tscLogin, tscInteractiveLogin);

  Var
   startSIndentLevel : Integer=0;
   serviceChoice : TServicechoice;
   errorOccured : Boolean;
   syntaxcheck : Boolean;
   errorInfo : String='';
   i : integer=0;
   paramstartI : Integer=0;
   j : Integer=0;
   methodname : String='';
   paramList : TStringList;
   parameters : Array of String;

   omc: TOpsiMethodCall;
   //local_opsidata : TOpsiDataJSONService;
   serviceURL : String='';
   username : String='';
   password : String='';
   sessionid : String='';
   r : String='';
   expression : String='';
   param : String='';
   inParams, paramsFound, paramsValueListFound : Boolean;
   stopIt : boolean;
   testresult : String='';
   {$IFDEF GUI}
   passwordDialog : TDialogServicePassword;
   {$ENDIF GUI}
  listname : String='';
  list : TStringList;
  varindex : integer=0;
  opsiServiceVersion : String='';

   procedure getNextValidLine (var line : String; var lineno : Integer; const lines : TStrings);
   begin
    line := trim(lines [lineno - 1]);
    while (lineno <= lines.count) and (line = '') or (line [1] = LineIsCommentChar)
    do
    begin
      inc (lineno);
      if lineno <= lines.count
      then
        line := trim(lines [lineno - 1]);
    end;
   end;


begin
  // initializing
  result := tsrPositive;
  sessionid := '';
  startSIndentLevel :=  LogDatei.LogSIndentLevel;
  if not initSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings) then exit;
  LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;
  try
    //convert String to catch not allowed chars
    r := trim(Utf8ToAnsi(AnsiToUtf8(parameter)));
  except
    on ex: Exception
    do
    begin
      LogDatei.DependentAddError ('Exception in doOpsiServiceCall: ' + ex.message ,LLError);
    end;
  end;
  syntaxcheck := true;


  serviceChoice := tscGlobal;

  if local_opsidata <> nil
  then serviceChoice := tscReuse;

  if r <> ''
  then
  Begin
    serviceChoice := tscLogin;
    while r <> ''
    do
    Begin
      if skip ('/preloginservice', r, r, errorInfo)
      then
         serviceChoice := tscGlobal // we return to the default service from the installation server

      else if skip ('/interactive', r, r, errorInfo)
      then
         serviceChoice := tscInteractiveLogin

      else if skip ('/serviceurl', r, r, errorInfo)
         or skip ('/opsiservice', r, r, errorInfo)
         or skip ('/s', r, r, errorInfo)
      then
        EvaluateString(r, r, serviceurl, errorInfo)

      else if skip ('/username', r, r, errorInfo)
         or skip ('/user', r, r, errorInfo)
         or skip ('/u', r, r, errorInfo)
      then
        EvaluateString(r, r, username, errorInfo)

      else if skip ('/password', r, r, errorInfo)
         or skip ('/pass', r, r, errorInfo)
         or skip ('/p', r, r, errorInfo)
      then
        EvaluateString(r, r, password, errorInfo)

      else
      Begin
        r := '';
        errorInfo := 'Not valid parameter for section ' + Sektion.Name;
        syntaxcheck := false;
      End;
    end;

  end;

  if (serviceChoice in [tscGlobal, tscReuse])
    and
    ((username <> '') or (password <> '') or (serviceurl<>''))
  then
  Begin
    syntaxcheck := false;
    errorInfo := 'Connection parameters must not be specified if existing connection shall be used.'
  end;

  // lets do something

  i := 1;
  if syntaxcheck
  then
  Begin
    errorOccured := false;
    methodname := '';
    paramList := TStringList.create;
    inParams := false;
    paramsFound := false;
    paramsValueListFound := false;
  end;


  while (i <= Sektion.count) and syntaxcheck
  do
  Begin
      getNextValidLine (r, i, Sektion);
    if i <= Sektion.count
    then
    Begin
      SyntaxCheck := false;
      GetWord (r, Expression, r, [':']);

      if Skip (':', r, r, errorInfo)
      then
      Begin
        if LowerCase (Expression) = LowerCase ('"method"')
        then
        Begin
          if GetString (r, methodname, r, errorInfo, false)
          then
            syntaxcheck := true;
        end

        else if LowerCase (Expression) = LowerCase ('"HashList"')
          then
          Begin
            if GetString (r, listname, r, errorInfo, false)
            then
            begin
              syntaxcheck := true;
              list := TXStringList.create;
              VarIndex := listOfStringLists.IndexOf (LowerCase (listname));
              if VarIndex >= 0 then
              begin
                list.Assign(TStringList(contentOfStringLists[VarIndex]));
                syntaxCheck := true;
              end
            end
          end

        else if LowerCase (Expression) = LowerCase ('"params"')
        then
        Begin
           syntaxcheck := true;
           paramsFound := true;

           if r = ''
           then
             getNextValidLine (r, i, Sektion);

           if (i <= Sektion.count) and skip ('[', r, r, errorInfo)
           then
           Begin
             inParams := true;
             paramsValueListFound := true;
             paramStartI := i;
             if r = ']'
             then  // empty param list
             Begin
               inParams := false;
             end
             else if r <> ''
             then
             Begin
               syntaxcheck := false;
               errorInfo := 'Parameters must be on their own lines';
             end
             else
             Begin
               inc (i);
             End;


             while
               syntaxcheck and (i <= Sektion.count) and inParams
             do
             Begin
                getNextValidLine(r, i, Sektion);
                if i <= Sektion.count
                then
                Begin
                  if r = ']'
                  then inParams := false
                  else
                  Begin
                    if length(r) > 0
                    then
                    Begin
                      if r[length(r)] = ','
                      then r := trim(copy (r, 1, length(r) -1));
                      if length(r) > 0
                      then
                      Begin

                        if GetString (r, param, r, errorInfo, true)
                        then
                        begin
                          LogDatei.DependentAdd ('Parsing: getparam: ' + param ,LLdebug2);
                          paramList.Add(param);
                        end
                        else
                          syntaxcheck := false;
                      end;
                    end;
                    inc(i);
                  End;
                End

             end;
           End;

           if syntaxcheck and (i > Sektion.count) and inParams
           then
           Begin
             SyntaxCheck := false;
             errorInfo := 'ParamList starting on line ' + inttoStr(paramStartI) + ' not closed '
               + ' (must be a pure "]" on a line)'
           End;

        End

        else
        Begin
           SyntaxCheck := false;
           ErrorInfo := Expression + ' is not a valid parameter ';
        End
      End

    end;
    inc(i);
  End; // loop through lines


  if syntaxCheck
  then
  Begin
    if (methodname = '')
    then
    Begin
      syntaxCheck := false;
      errorInfo := errorInfo + ' Method name missing';
    End;

    if paramsFound
    then
    Begin
      if not paramsValueListFound
      then
      Begin
      errorInfo := errorInfo + ' Params missing';
      syntaxCheck := false;
      End
    end
    else
    Begin
      errorInfo := errorInfo + ' Params missing';
      syntaxCheck := false;
    End;
  end;


  if syntaxCheck then
  Begin
    LogDatei.DependentAdd('   "method": "' + methodname + '"', LevelComplete);
    //LogDatei.DependentAdd('   "params" : "' + jsonParams, LevelComplete);

    testresult := 'service not initialized';
    case serviceChoice of
      tscGlobal:
        Begin

          if opsidata = nil
          then
          Begin
            errorOccured := true;
          End
          else
           try
              if opsidata.getOpsiServiceVersion = '4' then
              local_opsidata := opsidata;
             LogDatei.DependentAdd('Calling opsi service on existing connection at ' + local_opsidata.serviceUrl, LevelComplete);
           except
             errorOccured := true;
             testresult := 'not in service mode';
           end;

        end;

      tscReuse:
        begin
          if (local_opsidata = nil) or  not(local_opsidata is TOpsi4Data)
          then
          Begin
            errorOccured := true;
            testresult := 'not connected to service';
          End
          else
          Begin
            LogDatei.DependentAdd('Calling opsi service on existing connection at ' + local_opsidata.serviceUrl, LevelComplete);
          End
        end;

      tscLogin:
        begin
          opsiServiceVersion := getOpsiServiceVersion(serviceurl, username, password, sessionid);
          if opsiServiceVersion = '4' then
          begin
            Local_opsidata := TOpsi4Data.Create;
            local_opsidata.initOpsiConf(serviceurl, username, password, sessionid);
            //Topsi4data(local_opsidata).initOpsiConf(serviceurl, username, password);
            //OpsiData.setOptions (opsiclientd_serviceoptions);
            omc := TOpsiMethodCall.create ('backend_info',[]);
            //omc := TOpsiMethodCall.create ('authenticated',[]);
            testresult := local_opsidata.CheckAndRetrieve (omc, errorOccured);
            omc.free;
          end
          else LogDatei.DependentAdd ('Internal Error: Unkown Opsi Service Version:>'+opsiServiceVersion+'<', LLerror);
        end;

      tscInteractiveLogin:
        Begin
          {$IFDEF GUI}
          stopIt := false;
          passwordDialog := TDialogServicePassword.create(nil);


          while not stopIt
          do
          Begin
            passwordDialog.Visible := false;
            passwordDialog.EditServiceURL.Text := serviceurl;
            passwordDialog.EditUsername.Text := username;
            passwordDialog.EditPassword.Text := '';

            if passwordDialog.showModal = mrOK
            then
            Begin
              serviceUrl := passwordDialog.EditServiceURL.Text;
              username := passwordDialog.EditUsername.Text;
              password := passwordDialog.EditPassword.Text;
              opsiServiceVersion := getOpsiServiceVersion(serviceurl, username, password, sessionid);
              if opsiServiceVersion = '4' then
              begin
                local_opsidata := TOpsi4Data.Create;
                local_opsidata.initOpsiConf(serviceurl, username, password, sessionid);
                //Topsi4data(local_opsidata).initOpsiConf(serviceurl, username, password, sessionid);
                //OpsiData.setOptions (opsiclientd_serviceoptions);
                omc := TOpsiMethodCall.create ('backend_info',[]);
                //omc := TOpsiMethodCall.create ('authenticated',[]);
                testresult := local_opsidata.CheckAndRetrieve (omc, errorOccured);
                omc.free;
              end
              else LogDatei.DependentAdd ('Internal Error: Unkown Opsi Service Version:>'+opsiServiceVersion+'<', LLerror);

              stopIt := not errorOccured;
            End

            else
            Begin
              stopIt := true;
              errorOccured := true;
              testresult := 'Cancelled by user';
            end;

          end;

          passwordDialog.Free;

          {$ENDIF GUI}
        end;
    end;

    if errorOccured
      then
      Begin
        local_opsidata := nil;
        LogDatei.DependentAddError('Error: ' + testresult, BaseLevel);
      End;

    if local_opsidata = nil
      then
      Begin
        errorOccured := true;
        LogDatei.DependentAddError('Error: no connection to service', BaseLevel);
      End;

  end;

  if not errorOccured and syntaxcheck
    then
    Begin
      setlength(parameters, paramList.count);
      for j := 0 to paramList.count - 1 do
      begin
        parameters[j] := paramlist.Strings[j]
      end;

      omc := TOpsiMethodCall.create (methodname, list, parameters);
      testresult := '';

      TStringList(output) := local_opsidata.checkAndRetrieveHashList(omc, errorOccured);
      if output.count > 0 then
        testresult :=    output.strings[0];

      for j:= 0 to output.count - 1
      do
        testresult := testresult + ', ' + output.strings[j];

      omc.free;
      //Logdatei.DependentAdd('Setup script name: '+opsidata.getProductScriptPath(tacSetup), LLessential);

      if errorOccured
      then
      begin
        LogDatei.DependentAddError('Error: ' + testresult, BaseLevel);
      end
      else
      begin
        LogDatei.DependentAdd('JSON result: '+ testresult, LLinfo);
      end;
    end;

  // finishing our section
  finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                 DiffNumberOfErrors, DiffNumberOfWarnings);

  LogDatei.LogSIndentLevel := startSIndentLevel;

  if ExitOnError and (DiffNumberOfErrors > 0)
  then result := tsrExitProcess;

  if not SyntaxCheck then
  Begin
    if i >= Sektion.count
    then
      reportError (Sektion, Sektion.count, Sektion.strings [Sektion.count - 1], ErrorInfo)
    else
       reportError (Sektion, i, Sektion.strings [i-1], ErrorInfo);
  End
end;
//#############################################################################

function TuibInstScript.doXMLPatch (const Sektion: TWorkSection; Const XMLFilename : String;
                var output: TXStringList) : TSectionResult;
{$IFDEF WINDOWS}
begin
  //DataModuleLogServer.IdTCPServer1.Active:=true;
  result := executeWith (Sektion,  '"'+ ExtractFileDir(paramstr(0))+PathDelim+'opsiwinstxmlplugin.exe" --xmlfile="'+trim(XMLFilename)+'" --scriptfile=' , true, output);
  LogDatei.includelogtail(StandardLogPath+'opsiwinstxmlplugin.log',1000,'auto');
  DeleteFile(StandardLogPath+'opsiwinstxmlplugin.log');
    //DataModuleLogServer.IdTCPServer1.Active:=false;
end;

{$ELSE WINDOWS}
begin
  LogDatei.DependentAdd('Not implemented for Linux', LLError);
end;

{$ENDIF WINDOWS}




function TuibInstScript.doFileActions (const Sektion: TWorkSection; CopyParameter : String) : TSectionResult;
 var
  Source : String='';
  Target : String='';
  SourceDirectory : String='';
  targetDirectory : String='';
  startDirectory : String='';
  presetDirectory : String='';
  cpSpecify : TcpSpecify;
  NoCounted : Integer=0;
  recursive, ignoreReadOnly : Boolean;
  finished : Boolean;
  daysback : Integer=0;
  SyntaxCheck : Boolean;
  RebootWanted : Boolean=false;

  errorinfo : String='';
  expression : String='';
  remaining : String='';

  findresultcode : Integer=0;
  searchresult : TSearchRec;
  ch : Char;
  oldDisableWow64FsRedirectionStatus: pointer=nil;
  Wow64FsRedirectionDisabled : boolean;
  boolresult : boolean;
  ProfileList : TStringList;
  pc : integer;
  //OldWinapiErrorMode: Cardinal;

  Install : TuibFileInstall;

  procedure fileActionsMain (const Section : TXStringList; const presetDir : String);
  var
    i : integer=0;
    j: Integer=0;
    workingSection : TXStringList;
    ///info : string;
    remaining_with_leading_blanks : String='';
    search4file : boolean;
    mode : string;


  begin
    targetDirectory := presetDir;
    targetDirectory := ExpandFileName(targetDirectory);

    workingSection := TXStringList.Create;
    workingSection.Assign(Section);
    workingSection.GlobalReplace(1, '%userprofiledir%', copy (presetDir, 1, length(presetDir) - 1), false);
    workingSection.GlobalReplace(1, '%currentprofiledir%', copy (presetDir, 1, length(presetDir) - 1), false);
    ApplyTextConstants (TXStringList (workingSection), false);
    ApplyTextVariables (TXStringList (workingSection), false);

    for i:= 1 to Sektion.count
    do
    Begin
      Remaining := cutLeftBlanks(workingSection.strings [i-1]);
      logdatei.DependentAdd(Remaining, LevelDebug);
      SyntaxCheck := true;

      if (Remaining = '') or (Remaining [1] = LineIsCommentChar)
      then
       // continue
      else
      Begin
        GetWord (Remaining, Expression, Remaining, WordDelimiterSet0);

        if UpperCase (Expression) = 'SOURCEPATH'
        then
        begin
          if (length (Remaining) = 0) or (Remaining [1] <> '=')
          then
            reportError (Sektion, i, Sektion.strings [i-1], '=  expected')
          else
          Begin
            Remaining := copy (Remaining, 2, length (Remaining) - 1);
            Remaining := cutLeftBlanks (Remaining);

            if not GetString (Remaining, SourceDirectory, Remaining, errorinfo, false)
            then
              GetWord (Remaining, SourceDirectory, Remaining, WordDelimiterSet2);

            if length (Remaining) > 0
            then
              reportError (Sektion, i, Sektion.Strings [i-1], 'end of line expected');

            if     (length (SourceDirectory) > 0)
               and (SourceDirectory [length(SourceDirectory)] <> PathDelim)
            then  SourceDirectory := SourceDirectory + PathDelim;

          End;


        end

        else if UpperCase (Expression) = 'CHECKTARGETPATH'
        then
        begin
          if (length (Remaining) = 0) or (Remaining [1] <> '=')
          then
            reportError (Sektion, i, Sektion.strings [i-1], '=  expected')
          else
          Begin
            Remaining := copy (Remaining, 2, length (Remaining) - 1);
            Remaining := cutLeftBlanks (Remaining);

            if not GetString (Remaining, TargetDirectory, Remaining, errorinfo, false)
            then
              GetWord (Remaining, TargetDirectory, Remaining, WordDelimiterSet2);

            if length (Remaining) > 0
            then
              reportError (Sektion, i, Sektion.strings [i-1], 'end of line expected')
            else
              Install.MakePath (TargetDirectory);

            if     (length (TargetDirectory) > 0)
             and (TargetDirectory [length(TargetDirectory)] <> PathDelim)
            then  TargetDirectory := TargetDirectory + PathDelim;
          End;
        end

        else if UpperCase (Expression) = 'COPY'
        then
        begin
          if not GetString (Remaining, Expression, Remaining, errorinfo, false)
          then
            GetWord (Remaining, Expression, Remaining, WordDelimiterSet0);

          cpSpecify := 0;

            // which copy options

          if Expression [1] = '-'
          then
          Begin
            Expression := copy (Expression, 2, length (Expression) - 1);
            for j:= 1 to length (Expression) do
            Begin
              if Expression[j] = 's'
              then
                cpSpecify := cpSpecify or cpRecursive
              else if Expression[j] = 'e'
              then
                cpSpecify := cpSpecify or cpCreateEmptySubdirectories
              else if Expression[j] = 'v' then
              begin
                {$IFDEF WINDOWS}
                cpSpecify := cpSpecify or cpVersionControl;
                LogDatei.log('The copy -v Option is deprecated. Use -V',LLWarning);
                {$ELSE}
                LogDatei.log('The copy -v Option is Windows only',LLWarning);
                {$ENDIF WINDOWS}
              end
              else if Expression[j] = 'V' then
              begin
                {$IFDEF WINDOWS}
                cpSpecify := cpSpecify or cpVersionControlRestricted;
                {$ELSE}
                LogDatei.log('The copy -V Option is Windows only',LLWarning);
                {$ENDIF WINDOWS}
              end
              else if Expression[j] = 'd' then
              begin
                {$IFDEF WINDOWS}
                cpSpecify := cpSpecify or cpDateControl;
                {$ELSE}
                LogDatei.log('The copy -d Option is Windows only',LLWarning);
                {$ENDIF WINDOWS}
              end
              else if Expression[j] = 'u' then
              begin
                {$IFDEF WINDOWS}
                cpSpecify := cpSpecify or cpUpdate;
                {$ELSE}
                LogDatei.log('The copy -u Option is Windows only',LLWarning);
                {$ENDIF WINDOWS}
              end
              else if Expression[j] = 'w'
              then
                cpSpecify := cpSpecify or cpDontForceOverwrite
              else if Expression[j] = 'n'
              then
                cpSpecify := cpSpecify or cpNoOverwrite
              else if Expression[j] = 'x'  then
              begin
                {$IFDEF WINDOWS}
                cpSpecify := cpSpecify or cpExtract;
                {$ELSE}
                LogDatei.log('The copy -x Option is Windows only',LLWarning);
                {$ENDIF WINDOWS}
              end
              else if Expression[j] = 'r' then
              begin
                {$IFDEF WINDOWS}
                cpSpecify := cpSpecify or cpLeaveReadonly;
                {$ELSE}
                LogDatei.log('The copy -r Option is Windows only',LLWarning);
                {$ENDIF WINDOWS}
              end
              else if Expression[j] = 'c' then
              begin
                {$IFDEF WINDOWS}
                cpSpecify := cpSpecify or cpNoExtraReboot;
                {$ELSE}
                LogDatei.log('The copy -c Option is Windows only',LLWarning);
                {$ENDIF WINDOWS}
              end
              else
              Begin
                SyntaxCheck := false;
                reportError (Sektion, i, Sektion.strings [i-1],
                             Expression[j] + ' is not a valid copy option');
              End;
            End;

            if (cpSpecify and cpRecursive) = cpRecursive
            then
              cpSpecify := cpSpecify or cpCreateEmptySubdirectories;
             // creat also empty directories

           if not GetString (Remaining, Expression, Remaining, errorinfo, false)
           then
              GetWord (Remaining, Expression, Remaining, WordDelimiterSet0);

          End;

          if isAbsoluteFileName (Expression)
          then
            Source := Expression
          else
            Source := SourceDirectory + Expression;
          source := ExpandFileName(source);

          LogDatei.log('source: '+source+' - target: '+target,LLDebug2);
          if not GetString (Remaining, Target, Remaining, errorinfo, false)
          then Target := Remaining;
          LogDatei.log('source: '+source+' - target: '+target,LLDebug2);
          target := trim(target);
          Target := opsiUnquoteStr(target,'"');
          Target := opsiUnquoteStr(target,'''');
          LogDatei.log('source: '+source+' - target: '+target,LLDebug2);
          if not isAbsoluteFileName (Target)
          then
          Begin
            Target := TargetDirectory + Remaining;
          End;
          LogDatei.log('source: '+source+' - target: '+target,LLDebug2);
          target := trim(target);
          LogDatei.log('source: '+source+' - target: '+target,LLDebug2);
          target := ExpandFileName(target);
          LogDatei.log('source: '+source+' - target: '+target,LLDebug2);
          if Target = ''
          then
          Begin
            SyntaxCheck := false;
            reportError (Sektion, i, Sektion.strings [i-1], 'No target directory defined');
          End;

          if SyntaxCheck
          then
          Begin
            if Install.MakePath (Target)
            then
            Begin
              Target := ExpandFileName (Target);
              Install.AllCopy  (Source, Target, cpSpecify, tccmCounting, NoCounted, RebootWanted);
              Install.AllCopy  (Source, Target, cpSpecify, tccmCounted,  NoCounted, RebootWanted);
            End;
            if RebootWanted and not( cpSpecify and cpNoExtraReboot = cpNoExtraReboot) then
            Begin
              PerformExitWindows := txrReboot; // txrRegisterForReboot; bis Version 3.03
              LogDatei.DependentAdd ('', LLnotice);
              LogDatei.DependentAdd ('ExitWindows set to Reboot', LLnotice);
            End;
          End;

        end

        else if (UpperCase (Expression) = 'DELETE') or (UpperCase (Expression) = 'DEL')
        then
        begin
          search4file := true;
          if UpperCase (Expression) = 'DEL' then search4file := false;
          if not GetString (Remaining, Expression, Remaining, errorinfo, false)
          then
          Begin
             // instead of using (as up to version 4.1)
             // GetWord (Remaining, Expression, Remaining, WordDelimiterWhiteSpace);
             // we want to be exact with the number of blanks
             DivideAtFirst (' ', remaining, expression, remaining_with_leading_blanks);
             remaining := cutLeftBlanks(remaining_with_leading_blanks);
          End;

          recursive := false;
          ignoreReadOnly := false;
          daysback := 0;
          while (length(Expression) > 0) and (Expression [1] = '-')
          do
          Begin
            Expression := lowerCase (copy (Expression, 2, length (Expression) - 1));
            j := 1;
            while j <= length (Expression)
            do
            Begin
              if Expression[j] = 's'
              then
                recursive := true
              else if Expression [j] = 'f'
              then
                ignoreReadOnly := true
              else if Expression [j] = 'd'
              then
              Begin
                 finished := false;
                 while (j+1 <= length (Expression)) and not finished
                 do
                 Begin
                    ch := Expression [j+1];
                    if (ord ('0') <= ord (ch)) and (ord (ch) <= ord('9'))
                    then
                    Begin
                      inc (j);
                      daysback := daysback * 10 + ord (Expression[j]) -ord ('0');
                    End
                    else
                      finished := true;
                 End;
                 //default
                 if daysback = 0 then daysback := 1;
              End
              else
              Begin
                SyntaxCheck := false;
                reportError (Sektion, i, Sektion.strings [i-1], Expression[j] + ' is no copy option');
              End;
              inc (j);
            End;

            if not GetString (Remaining, Expression, Remaining, errorinfo, false)
            then
            Begin
             DivideAtFirst (' ', remaining, expression, remaining_with_leading_blanks);
             remaining := cutLeftBlanks(remaining_with_leading_blanks);
             //GetWord (Remaining, Expression, Remaining, WordDelimiterWhiteSpace);
            End;

          End;

          if Remaining <> ''
          then
            Expression := trim(Expression + ' ' + Remaining_with_leading_blanks);
            // if file names have e.g. blanks in it, don't let them be split
            // (with the consequence of deleting files that have the first part as name)

          if isAbsoluteFileName (Expression)
          then
            Source := Expression
          else
            Source := SourceDirectory + Expression;
          source := ExpandFileName(source);

          if SyntaxCheck
          then
          begin
           LogDatei.DependentAdd ('we try to delete: '+source, LLDebug2);
           Install.AllDelete (Source, recursive, ignoreReadOnly, daysback,search4file);
          end;
        end

        {$IFDEF LINUX}
        else if (UpperCase (Expression) = 'CHMOD')
        then
        begin
          if not GetString (Remaining, Expression, Remaining, errorinfo, false)
          then
          Begin
             // instead of using (as up to version 4.1)
             // GetWord (Remaining, Expression, Remaining, WordDelimiterWhiteSpace);
             // we want to be exact with the number of blanks
             DivideAtFirst (' ', remaining, expression, remaining_with_leading_blanks);
             remaining := cutLeftBlanks(remaining_with_leading_blanks);
          End;

          mode := expression;

            if not GetString (Remaining, Expression, Remaining, errorinfo, false)
            then
            Begin
             DivideAtFirst (' ', remaining, expression, remaining_with_leading_blanks);
             remaining := cutLeftBlanks(remaining_with_leading_blanks);
             //GetWord (Remaining, Expression, Remaining, WordDelimiterWhiteSpace);
            End;

          if Remaining <> ''
          then
            Expression := trim(Expression + ' ' + Remaining_with_leading_blanks);
            // if file names have e.g. blanks in it, don't let them be split
            // (with the consequence of deleting files that have the first part as name)

          if isAbsoluteFileName (Expression)
          then
            Source := Expression
          else
            Source := SourceDirectory + Expression;
          source := ExpandFileName(source);

          if SyntaxCheck
          then
          begin
           LogDatei.DependentAdd ('we try to chmod: '+source, LLDebug2);
           Install.chmod(mode,Source);
          end;
        end
        {$ENDIF LINUX}

        {$IFDEF WINDOWS}
        else if UpperCase (Expression) = 'ZIP'
        then
        begin
          if not GetString (Remaining, Expression, Remaining, errorinfo, false)
          then
              GetWord (Remaining, Expression, Remaining, WordDelimiterSet0);

          recursive := false;
          if Expression [1] = '-'
          then
          Begin
            Expression := copy (Expression, 2, length (Expression) - 1);
            for j:= 1 to length (Expression) do
            Begin
              if Expression[j] = 's'
              then
                recursive := true
              else
              Begin
                SyntaxCheck := false;
                reportError (Sektion, i, Sektion.strings [i-1], Expression[j] + ' is not a valid zip option');
              End;
            End;

            if not GetString (Remaining, Expression, Remaining, errorinfo, false)
            then
              GetWord (Remaining, Expression, Remaining, WordDelimiterSet0);
          End;

          if isAbsoluteFileName (Expression)
          then
            Target := Expression
          else
            Target := TargetDirectory + Expression;

          if isAbsoluteFileName (Remaining)
          then
            Source := Remaining
          else
            Source := SourceDirectory + Remaining;

          if SyntaxCheck
          then
          Begin
            Install.MakePath (Target);
            Install.AllCompress (Source, Target, recursive, true);
          End;
        End
        {$ENDIF WINDOWS}
        else
          reportError (Sektion, i, Expression, 'is not a valid command');
      end;
    end;

    workingSection.Free;

  end;

begin
  Wow64FsRedirectionDisabled := false;
  result := tsrPositive;

  if not initSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings) then exit;
  LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;

  Install := TuibFileInstall.create;

  {$IFDEF WIN32}
  // disable  critical-error-handler message box. (Drive not ready)
  //OldWinapiErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
   if (0 < pos(lowercase (Parameter_64Bit), lowercase (CopyParameter)))
     or (0 < pos(lowercase (Parameter_SysNative), lowercase (CopyParameter))) then
   Begin
     boolresult := DSiDisableWow64FsRedirection(oldDisableWow64FsRedirectionStatus);
     Wow64FsRedirectionDisabled := true;
   End
   else Wow64FsRedirectionDisabled := false;
   {$ENDIF WIN32}

  if (0 < pos(lowercase (Parameter_AllNTUserProfiles),lowercase (CopyParameter)))
    or flag_all_ntuser
  then
  Begin
    flag_all_ntuser := false;
    ProfileList := getProfilesDirList;
    for pc:= 0 to ProfileList.Count -1 do
    begin
      presetdirectory := ProfileList.Strings[pc]+PathDelim;
      logdatei.DependentAdd(' Make it for user directory: '+presetdirectory, LLNotice);
      fileActionsMain (Sektion, presetDirectory);
    end;
  End
  else if 0 < pos(lowercase(Parameter_AllNTUserSendTo), lowercase (CopyParameter))
  then
  Begin
    flag_all_ntuser := false;
    ProfileList := getProfilesDirList;
    for pc:= 0 to ProfileList.Count -1 do
    begin
      presetdirectory := ProfileList.Strings[pc] + '\SendTo\';
      fileActionsMain (Sektion, presetDirectory);
    end;
  End
  else
  Begin
    // no special preset directory
    SourceDirectory := '';
    PresetDirectory := '';
    if runLoginScripts then
       PresetDirectory := GetUserProfilePath + PathDelim;
    fileActionsMain (Sektion, presetdirectory);
    {$IFDEF WIN32}
    //setErrorMode(OldWinapiErrorMode);
    if Wow64FsRedirectionDisabled then
    Begin
      boolresult := DSiRevertWow64FsRedirection(oldDisableWow64FsRedirectionStatus);
      Wow64FsRedirectionDisabled := false;
    End;
    {$ENDIF WIN32}
  End;


  Install.free; Install := nil;

  finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                 DiffNumberOfErrors, DiffNumberOfWarnings);


  if ExitOnError and (DiffNumberOfErrors > 0)
  then result := tsrExitProcess;


  LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;

end;

{$IFDEF WIN32}
function TuibInstScript.doLinkFolderActions (const Sektion: TWorkSection; common : boolean)
                                                                 : TSectionResult;
 var
   ShellLinks : TuibShellLinks;
   stack : TStringList;
   startindentlevel : Integer;
   expression : String='';
   ///remaining : String;

 procedure linkActionsMain ();
  Var
   i : Integer=0;
   SyntaxCheck : boolean;
   Remaining : String='';
   errorInfo : String='';

   csidl : Integer=0;
   csidl_set : Boolean;
   folder_opened : Boolean;

   basefolder : String='';
   subfoldername : String='';
   deletefoldername : String='';
   s : String='';

   in_link_features : Boolean;
   regular_end : boolean;
   link_name : String='';
   link_target : String='';
   link_paramstr : String='';
   link_working_dir : String='';
   link_icon_file : String='';
   link_icon_index: Integer=0;

 begin

    i := 1;
    if Sektion.count = 0 then exit;

    stack := TStringList.create;

    csidl := 0;
    csidl_set := false;
    folder_opened := false;
    subfoldername := '';

    while i <= Sektion.count
    do
    Begin
      Remaining := trim (Sektion.strings [i-1]);
      if (Remaining = '') or (Remaining [1] = LineIsCommentChar)
      then
        inc (i)
      else
      Begin
        GetWord (Remaining, Expression, Remaining, WordDelimiterSet0);

        if LowerCase (Expression) = 'set_basefolder'
        then
        begin

          syntaxcheck := true;
          if (length (Remaining) = 0)
          then
          Begin
            syntaxCheck := false;
            reportError (Sektion, i, Sektion.strings [i-1], 'folder name  expected');
          End
          else
          Begin
            if not GetString (Remaining, basefolder, Remaining, errorinfo, false)
            then
            Begin
              basefolder := Remaining;
              Remaining := '';
            End;

            if length (Remaining) > 0
            then
            Begin
              reportError (Sektion, i, Sektion.Strings [i-1], 'end of line expected');
            End;

            if producecsidlfromName (basefolder, csidl, errorinfo)
              then
              Begin
                csidl_set := true;
                LogDatei.DependentAdd ('Base folder is '
                + ShellLinks.Tell_Systemfolder(csidl) , levelComplete);
              End
              else
              Begin
                LogDatei.DependentAddError ('Error: ' + errorinfo, baselevel);
              End;

          End;
        End

        {
        else if LowerCase (Expression) = 'push_location'
        then
        begin
           if length (Remaining) > 0
           then
              reportError (Sektion, i, Sektion.Strings [i-1], 'end of line expected');
           stack.Insert(0, startdirectory);

           LogDatei.DependentAdd ('Folder ' + Startdirectory + ' put on stack', levelcomplete);
        End

        else if LowerCase (Expression) = 'pop_location'
        then
        begin
           if length (Remaining) > 0
           then
              reportError (Sektion, i, Sektion.Strings [i-1], 'end of line expected');

           if stack.count > 0
           then
           Begin
             startdirectory := stack.Strings[0];
             LogDatei.DependentAdd ('New base folder is ' + Startdirectory, levelComplete);
             stack.Delete (0);
           End
           else
           Begin
             LogDatei.DependentAdd ('No folder left on stack', levelInfo);
           End

        End
        }

        else if LowerCase (Expression) = 'set_subfolder'
        then
        begin
          if not getString (Remaining, subfoldername, Remaining, errorinfo, false)
          then
          Begin
             subfoldername  := Remaining;
             Remaining := '';
          End;

          if length (Remaining) > 0
           then
           Begin
              reportError (Sektion, i, Sektion.Strings [i-1], 'end of line expected');
           End;

          if csidl_set then
             Begin
                {LogDatei.DependentAdd ('Subfolder is '  + subfoldername + ' in '
                   +  shellLinks.tell_systemfolder(csidl), levelComplete);
                }
                ShellLinks.OpenShellFolderPath (csidl, subfoldername);
                folder_opened := true;
             End
             else
               LogDatei.DependentAddWarning ('No base folder set, therefore subfolder not set',
                 levelWarnings);

          //startdirectory := startdirectory + '\' + subfoldername;
          //LogDatei.DependentAdd ('New base folder is ' + Startdirectory, levelComplete);

        End

        else if LowerCase (Expression) = 'delete_subfolder'
        then
        begin

          if not getString (Remaining, deletefoldername, Remaining, errorinfo, false)
          then
          Begin
             deletefoldername  := Remaining;
             Remaining := '';
          End;

          if length (Remaining) > 0
          then
          Begin
              reportError (Sektion, i, Sektion.Strings [i-1], 'end of line expected');
              syntaxCheck := false;
          End;

          if csidl_set
          then
          Begin
             LogDatei.LogSIndentLevel := startindentlevel;
             ShellLinks.DeleteShellFolder (csidl, deletefoldername);
             //csidl_set := false;
          End
          else
            LogDatei.DependentAddWarning ('No base folder set, therefore no deletion of subfolder', levelWarnings);

        End

        else if LowerCase (Expression) = 'delete_element'
        then
        begin
          syntaxcheck := true;
          if not getString (Remaining, s, Remaining, errorinfo, false)
          then
          Begin
             s  := Remaining;
             Remaining := '';
          End;

          if length (Remaining) > 0
          then
          begin
              reportError (Sektion, i, Sektion.Strings [i-1], 'end of line expected');
              syntaxcheck := false;
          end;

          if folder_opened
          then
          Begin
             if syntaxcheck
             then
               ShellLinks.DeleteShellLink (s);

          End
          else
            LogDatei.DependentAddWarning ('No folder selected, therefore no deletion of "' + s + '"', levelWarnings);

        End

        else if LowerCase (Expression) = 'set_link'
        then
        begin
          syntaxcheck := true;

          if length (Remaining) > 0
          then
          Begin
              reportError (Sektion, i, Sektion.Strings [i-1], 'end of line expected');
              syntaxCheck := false;
          End;
          inc (i);
          in_link_features := true;
          regular_end := false;
          link_name := '';
          link_target := '';
          link_paramstr := '';
          link_working_dir := '';
          link_icon_file := '';
          link_icon_index := 0;

          while (i <= Sektion.count) and in_link_features do
          Begin
            Remaining :=  trim (Sektion.strings [i-1]);
            if (Remaining = '') or (Remaining [1] = LineIsCommentChar)
            then
              inc (i)
            else
            Begin
              GetWord (Remaining, Expression, Remaining, [':']);
              Skip (':', Remaining, Remaining, errorInfo);

              if LowerCase (Expression) = 'name'
              then
              Begin
                if not getString (Remaining, link_name, Remaining, errorinfo, false)
                then
                Begin
                   link_name  := Remaining;
                   Remaining := '';
                End;
              End

              else if LowerCase (Expression) = 'target'
              then
              Begin
                if not getString (Remaining, link_target, Remaining, errorinfo, true)
                then
                Begin
                 link_target  := Remaining;
                 Remaining := '';
                End;
              End

              else if LowerCase (Expression) = 'parameters'
              then
              Begin
                if not getString (Remaining, link_paramstr, Remaining, errorinfo, true)
                then
                Begin
                 link_paramstr  := Remaining;
                 Remaining := '';
                End;
              End

              else if LowerCase (Expression) = 'working_dir'
              then
              Begin
                if not getString (Remaining, link_working_dir, Remaining, errorinfo, false)
                then
                Begin
                 link_working_dir  := Remaining;
                 Remaining := '';
                End;
              End


              else if LowerCase (Expression) = 'working_directory'
              then
              Begin
                if not getString (Remaining, link_working_dir, Remaining, errorinfo, false)
                then
                Begin
                 link_working_dir  := Remaining;
                 Remaining := '';
                End;
              End

              else if LowerCase (Expression) = 'icon_file'
              then
              Begin
                if not getString (Remaining, link_icon_file, Remaining, errorinfo, false)
                then
                Begin
                 link_icon_file  := Remaining;
                 Remaining := '';
                End;
              End


              else if LowerCase (Expression) = 'icon_index'
              then
              Begin
                if not getString (Remaining, s, Remaining, errorinfo, false)
                then
                  s := Remaining;

                if s = ''
                then
                  link_icon_index := 0
                else
                 try
                   link_icon_index  := strtoint (s);
                   Remaining := s;
                 except

                   reportError (Sektion, i, Sektion.Strings [i-1],
                     '"' + s + '" could not converted to an integer.');
                 end;

              End

              else if LowerCase (Expression) = 'end_link'
              then
              Begin in_link_features := false; regular_end := true End

              else
              Begin
                reportError (Sektion, i, Sektion.Strings [i-1], 'unknown Option');
                syntaxCheck := false;
              End;


              if in_link_features then inc (i);
            end;
          End;



          if not regular_end
          then
          Begin
            reportError (Sektion, i, Sektion.Strings[i-1], 'end_link missing');
            syntaxCheck := false;
          End;

          //InstallItem (Const CommandLine, ItemName, Workdir, IconPath, IconIndex : String);


          if csidl_set
          then
          begin
            if syntaxCheck
            then
            Begin

              if not folder_opened
              then
              Begin
                if ShellLinks.OpenShellFolderPath (csidl, subfoldername)
                then folder_opened := true
              End;

              ShellLinks.MakeShellLink(link_name,  link_target, link_paramstr,
                      link_working_dir, link_icon_file,
                      link_icon_index);

            End
          end

        End

        else
          reportError (Sektion, i, Expression, 'is not a defined command');

        inc (i);
      End;

    end;
 end;


begin
  result := tsrPositive;

  if not initSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings) then exit;

  LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;
  startindentlevel := LogDatei.LogSIndentLevel;

  begin  // eigentliche Verarbeitung

    //Install := TuibFileInstall.create;
    if runLoginScripts then
    begin
      if Impersonate2User(usercontextDomain, usercontextUser) then
      begin
        try
          ShellLinks := TuibShellLinks.create;
          linkActionsMain;
          ShellLinks.free;
        finally
          RevertToSelf;
        end;
      end
      else
        LogDatei.DependentAddError('Error: could not impersonate for user:' +usercontextDomain+'\'+ usercontextUser, LLError);
    end
    else
    begin
      ShellLinks := TuibShellLinks.create;
      linkActionsMain;
      ShellLinks.free;
    end;

  end;  // eigentliche Verarbeitung

  finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                 DiffNumberOfErrors, DiffNumberOfWarnings);

  if ExitOnError and (DiffNumberOfErrors > 0)
  then result := tsrExitProcess;

  LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;
end;
{$ENDIF WIN32}

function TuibInstScript.doDDEwithProgman (const Sektion: TWorkSection; DDEParameter : String;
                           SaveddeWithProgman : Boolean)
                           : TSectionResult;
// not implemented

begin
// not implemented
end;

function TuibInstScript.execWinBatch (const Sektion: TWorkSection; WinBatchParameter : String;
                                     WaitConditions : TSetWaitConditions;
                                     ident : String;
                                     WaitSecs : Word;
                                     runAs : TRunAs;
                                     flag_force64:boolean)
                     : TSectionResult;

Var
 i : Integer=0;
 commandline : String='';
 report : String='';
 waitForReturn : Boolean;
 StartIndentLevel : Integer=0;
 targetfilename : String='';
 ///exefilename : string;
 retrycount : integer=0;
 waitsecsAsTimeout : boolean = false;
 oldDisableWow64FsRedirectionStatus: pointer=nil;
 Wow64FsRedirectionDisabled, boolresult: boolean;

begin
  try
    result := tsrPositive;
    retrycount := 0;

    if not initSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings) then exit;



    StartIndentLevel := LogDatei.LogSIndentLevel;
    LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;
    {$IFDEF WIN32}
    Wow64FsRedirectionDisabled := false;
    if flag_force64 then
    Begin
      boolresult := DSiDisableWow64FsRedirection(oldDisableWow64FsRedirectionStatus);
      Wow64FsRedirectionDisabled := true;
    End
    else Wow64FsRedirectionDisabled := false;
    {$ENDIF WIN32}
    {$IFDEF GUI}
    if AutoActivityDisplay then FBatchOberflaeche.showAcitvityBar(true);
    {$ENDIF GUI}


    for i:= 1 to Sektion.count
    do
    Begin
      if (Sektion.strings[i-1] = '') or (Sektion.strings[i-1] [1] = LineIsCommentChar)
      then
         // continue
      else
      Begin

        {GetWordOrStringExpression (Sektion.strings[i-1], Expression, Remaining, report);}

        CommandLine := trim(Sektion.strings[i-1]);
        If 1 = pos('"',CommandLine) then
        begin
          //we have a heading '"'
          // we assume, that all until the next '"' is the target file
          targetfilename := copy(CommandLine,2,posex('"',CommandLine,2)-2);
        end
        else
        begin
          //we have no heading '"'
          // we assume, that all until the next ' ' is the target file
          targetfilename := leftstr(CommandLine,pos(' ',CommandLine));
        end;
        // targetfile has no path separators we assume it is a command in the path
        // so we dont try to find it
        if (0 = pos(PathDelim,targetfilename)) and (0 = pos(PathDelim,targetfilename)) then retrycount := 99;
        // if there was no second '"' or ' ' we use the command line
        if targetfilename = '' then targetfilename := CommandLine;

        while (not FileExists(targetfilename)) and (retrycount < 10) do
        begin
          LogDatei.DependentAdd('Warning: file not found :'+targetfilename+' -retrying', LLwarning);
          FileGetAttr(targetfilename);
          ProcessMess;
          sleep(200);
          FileGetAttr(targetfilename);
          ProcessMess;
          sleep(200);
          inc(retrycount);
        end;
        if retrycount = 10 then
          LogDatei.DependentAdd('Warning: file not found :'+targetfilename+' - giving up', LLwarning);

        LogDatei.DependentAdd ('Call "' + CommandLine + '"', LevelComplete);

        if ttpWaitTimeout in WaitConditions then waitsecsAsTimeout := true;
        if WaitSecs > 0
        then
          if waitsecsAsTimeout then
            LogDatei.DependentAdd ('   Timeout ' + IntToStr (WaitSecs) + ' seconds ', LevelComplete)
          else
            LogDatei.DependentAdd ('   Waiting ' + IntToStr (WaitSecs) + ' seconds ', LevelComplete);



        if ttpWaitForWindowVanished in WaitConditions
        then
        Begin
          LogDatei.DependentAdd ('   Waiting until window "' + ident + '" has vanished' , LevelComplete);
          if not StartProcess (Commandline, sw_show, true, true, false, false, waitsecsAsTimeout, runAs, ident, WaitSecs, Report, FLastExitCodeOfExe)

          then
          Begin
            ps := 'Error: ' + Report;
            LogDatei.DependentAddError (ps, BaseLevel);
          End
          else
            LogDatei.DependentAdd (Report, LevelComplete);
        End
        else if ttpWaitForWindowAppearing in WaitConditions
        then
        Begin
          LogDatei.DependentAdd ('   Waiting until window "' + ident + '" is coming up' , LevelComplete);

          if not StartProcess (Commandline, sw_show, true, false, true, false, waitsecsAsTimeout, runAs, ident, WaitSecs, Report, FLastExitCodeOfExe)
          then
          Begin
            ps := 'Error: ' + Report;
            LogDatei.DependentAddError (ps, BaseLevel);
          End
          else
            LogDatei.DependentAdd (Report, LevelComplete);
        End
        else if ttpWaitForProcessEnding in WaitConditions
        then
        Begin
          LogDatei.DependentAdd ('   Waiting until process "' + ident + '" started and has ended' , LevelComplete);

          if not StartProcess (Commandline, sw_show, true, false, false, true, waitsecsAsTimeout, runAs, ident, WaitSecs, Report, FLastExitCodeOfExe)
          then
          Begin
            ps := 'Error: ' + Report;
            LogDatei.DependentAddError (ps, BaseLevel);
          End
          else
            LogDatei.DependentAdd (Report, LevelComplete);
        End
        else
        Begin

          if ttpWaitOnTerminate in WaitConditions
          then
          Begin
            WaitForReturn := true;
            LogDatei.DependentAdd ('   Waiting until the called process is finished', LevelComplete);
          End

          else
            WaitForReturn := false;

            (*     0 : Showcmd:=SW_HIDE;
                     1 : Showcmd:=SW_MINIMIZE;
                     2 : Showcmd:=SW_RESTORE;
                     3 : Showcmd:=SW_SHOW;
                     4 : Showcmd:=SW_SHOWMAXIMIZED;
                     5 : Showcmd:=SW_SHOWMINIMIZED;
                     6 : Showcmd:=SW_SHOWMINNOACTIVE;
                     7 : Showcmd:=SW_SHOWNA;
                     8 : Showcmd:=SW_SHOWNOACTIVATE;
                     9 : Showcmd:=SW_SHOWNORMAL;
                end; *)


          if not StartProcess (Commandline, sw_show, WaitForReturn, false, false, false, waitsecsAsTimeout, runAs, '', WaitSecs, Report, FLastExitCodeOfExe)
          then
          Begin
              ps := 'Error: ' + Report;
              LogDatei.log(ps, LLError);
          End
          else
              LogDatei.log (Report, LLInfo);
        End;
      End;
    end;
    {$IFDEF WIN32}
    if Wow64FsRedirectionDisabled then
    Begin
      boolresult := DSiRevertWow64FsRedirection(oldDisableWow64FsRedirectionStatus);
      Wow64FsRedirectionDisabled := false;
    End;
    {$ENDIF WIN32}
    finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                   DiffNumberOfErrors, DiffNumberOfWarnings);

    LogDatei.LogSIndentLevel := StartIndentLevel;
    if ExitOnError and (DiffNumberOfErrors > 0)
    then result := tsrExitProcess;

  finally
    {$IFDEF GUI}
    FBatchOberflaeche.showAcitvityBar(false);
    {$ENDIF GUI}
  end;
end;

function TuibInstScript.execShellCall (command : String; archparam:string): TStringlist;
Var
 commandline : String='';
 runas : TRunAs;
 force64: boolean;
 oldDisableWow64FsRedirectionStatus: pointer=nil;
 output: TXStringList;
 dummybool : boolean;
 filename : String='';
 parameters : String='';
 report : String='';
 errorinfo : String='';
 i : integer=0;
begin
  Result := TStringList.Create;
  output := TXStringList.Create;
  runAs := traInvoker;
  OldNumberOfErrors := LogDatei.NumberOfErrors;
  OldNumberOfWarnings := LogDatei.NumberOfWarnings;
  force64 := false;

  If (lowercase(archparam) = '64') and Is64BitSystem then
     force64 := true;

  If (lowercase(archparam) = 'sysnative') and Is64BitSystem then
       force64 := true;

  If (lowercase(archparam) = '32') then
       force64 := false;

  {$IFDEF WIN32}
  if force64 then
  begin
    if not FileExists(GetWinDirectory+'\cmd64.exe') then
    begin
      Logdatei.DependentAdd(GetWinDirectory+'\cmd64.exe not found - try to get it', LLDebug2);
      try
        if DSiDisableWow64FsRedirection(oldDisableWow64FsRedirectionStatus) then
        begin
          LogDatei.DependentAdd('DisableWow64FsRedirection succeeded', LLinfo);
          if FileExists(GetWinSystemDirectory+'\cmd.exe') then
          begin
           if fileutil.CopyFile(GetWinSystemDirectory+'\cmd.exe',GetWinDirectory+'\cmd64.exe') then
             LogDatei.DependentAdd('cmd64.exe created in '+GetWinDirectory, LLinfo)
           else
             LogDatei.DependentAddError('could not get cmd64.exe', LLError);
          end
          else
            LogDatei.DependentAddError('could see: '+GetWinSystemDirectory+'\cmd.exe', LLError);
          dummybool := DSiRevertWow64FsRedirection(oldDisableWow64FsRedirectionStatus);
          LogDatei.DependentAdd('RevertWow64FsRedirection succeeded', LLinfo);
        end
        else
        begin
          LogDatei.DependentAddError('Error: DisableWow64FsRedirection failed', LLError);
        end;
      except
        on ex: Exception
        do
        Begin
          LogDatei.DependentAddError ('Error: ' + ex.message, LLError);
        End;
      end;
    end;
    if not FileExists(GetWinDirectory+'\cmd64.exe') then
      LogDatei.DependentAddError('no cmd64.exe - will use cmd.exe instead', LLError);
  end;
  {$ENDIF WIN32}

  if GetUibOsType (errorinfo) = tovLinux then
  begin
    FileName := '/bin/bash';
    Parameters := Parameters+' -c "' + command + '"';
  end
  else
  begin
   {$IFDEF WINDOWS}
     If force64 and FileExists(GetWinDirectory+'\cmd64.exe') then
       FileName := '"'+GetWinDirectory+'\cmd64.exe"'
     else
       FileName := '"cmd.exe"';
     Parameters := ' /C "' + command + '" ';
   {$ENDIF WINDOWS}
  end;

  commandline := FileName + ' ' +trim(Parameters);

  LogDatei.DependentAdd ('Executing ' + commandline, LLNotice);
  if not RunCommandAndCaptureOut
     (commandline,
      true,
      output, report, SW_Minimize, FLastExitCodeOfExe)
  then
  Begin
    ps := 'Error: ' + Report;
    LogDatei.log(ps, LLcritical);
    FExtremeErrorLevel := LevelFatal;
    scriptstopped := true;
  End
  else
  begin
    LogDatei.DependentAdd ('output:', LLDebug2);
    LogDatei.DependentAdd ('--------------', LLDebug2);
    for i := 0 to output.count-1 do
    begin
     LogDatei.DependentAdd (output.strings[i], LLDebug2);
    end;
    LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 6;
    LogDatei.DependentAdd ('', LLDebug2);
    result.Text := output.text;
  end;
 output.Free;
end;


function TuibInstScript.execDOSBatch (
      const Sektion: TWorkSection; BatchParameter : String;
      ShowCmd : Integer; catchOut: Boolean;
      WaitConditions : TSetWaitConditions;
      var output: TXStringList)                       : TSectionResult;


Var
 SaveStayOnTop : Boolean;
 commandline : String='';
 filename : String='';
 parameters : String='';
 report : String='';
 errorinfo : String='';
 i : integer=0;
 force64, dummybool : boolean;
 winstparam : String='';
 oldDisableWow64FsRedirectionStatus: pointer=nil;
 tempfilename : String='';
 runas : TRunAs;
 showoutput : boolean = false;

begin
 try
    {$IFDEF GUI}
    SaveStayOnTop := BatchScreenOnTop;
    if BatchScreenOnTop then FBatchOberflaeche.ForceStayOnTop (false);
    if AutoActivityDisplay then FBatchOberflaeche.showAcitvityBar(true);
    FBatchOberflaeche.TimerProcessMess.Enabled:= true;
    {$ENDIF GUI}

    result := tsrPositive;

    if Sektion.count = 0 then exit;

    LogDatei.LogSIndentLevel := Sektion.NestingLevel;
    OldNumberOfErrors := LogDatei.NumberOfErrors;
    OldNumberOfWarnings := LogDatei.NumberOfWarnings;


    ps := '';
    LogDatei.log (ps, LLNotice);
    ps := Sektion.Name;
    LogDatei.log (ps, LLNotice);

    (*
    if pos (uppercase (PStatNames^ [tsDOSInAnIcon]), uppercase (Sektion.Name)) > 0 then
       ps := Sektion.Name;
    if pos (uppercase (PStatNames^ [tsDOSBatchFile]), uppercase (Sektion.Name)) > 0 then
       ps := Sektion.Name;
    if pos (uppercase (PStatNames^ [tsShellInAnIcon]), uppercase (Sektion.Name)) > 0 then
       ps := Sektion.Name;
    if pos (uppercase (PStatNames^ [tsShellBatchFile]), uppercase (Sektion.Name)) > 0 then
       ps := Sektion.Name;
     *)

    {$IFDEF GUI}
    CentralForm.Label2.caption := ps;
    FBatchOberflaeche.setDetailLabel(ps);
    ProcessMess;
    {$ENDIF GUI}

    LogDatei.LogSIndentLevel := Sektion.NestingLevel + 1;

    Sektion.eliminateLinesStartingWith (';', false);

    //Sektion.SaveToFile (TempPath + TempBatchdatei);
    //inc(TempBatchDatei_UniqueCount);
    //tempfilename := TempPath + TempBatchfilename + inttoStr(TempBatchDatei_UniqueCount) + '.bat';
    tempfilename := winstGetTempFileName;
    //Sektion.SaveToFile (tempfilename);
    if not Sektion.FuncSaveToFile (tempfilename) then
    begin
      LogDatei.DependentAddError ('Error: Sektion could not be saved - so we switch to failed', LLcritical);
      FExtremeErrorLevel:=LevelFatal;
    end
    else
    begin
    {$IFDEF LINUX}
    fpchmod(tempfilename, &700);
    {$ENDIF LINUX}
    if pos('winst ', lowercase(BatchParameter)) > 0 then
    begin
      winstparam := trim(copy(BatchParameter,pos('winst ', lowercase(BatchParameter))+5,length(BatchParameter)));
      BatchParameter := trim(copy(BatchParameter,0,pos('winst ', lowercase(BatchParameter))-1));
    end;
    force64 := false;
    runAs := traInvoker;

    If (pos(lowercase('/64bit'),lowercase(winstparam)) > 0 ) and Is64BitSystem then
       force64 := true;

    If (pos(lowercase('/sysnative'),lowercase(winstparam)) > 0 ) and Is64BitSystem then
         force64 := true;

    If (pos(lowercase('/32bit'),lowercase(winstparam)) > 0 ) then
         force64 := false;

    If (pos(lowercase('/showoutput'),lowercase(winstparam)) > 0 ) then
         showoutput := true;

    If (pos(lowercase(ParameterRunAsLoggedOnUser),lowercase(winstparam)) > 0 ) then
    Begin
      if runLoginScripts then
        runAs := traLoggedOnUser
      else
        LogDatei.DependentAdd('Warning: Not in UserLoginScript mode: /RunAsLoggedinUser ignored', LLWarning);
    End;

    {$IFDEF WIN32}
    if force64 then
    begin
      if not FileExists(GetWinDirectory+'\cmd64.exe') then
      begin
        Logdatei.DependentAdd(GetWinDirectory+'\cmd64.exe not found - try to get it', LLDebug2);
        try
          if DSiDisableWow64FsRedirection(oldDisableWow64FsRedirectionStatus) then
          begin
            LogDatei.DependentAdd('DisableWow64FsRedirection succeeded', LLinfo);
            if FileExists(GetWinSystemDirectory+'\cmd.exe') then
            begin
             if fileutil.CopyFile(GetWinSystemDirectory+'\cmd.exe',GetWinDirectory+'\cmd64.exe') then
               LogDatei.DependentAdd('cmd64.exe created in '+GetWinDirectory, LLinfo)
             else
               LogDatei.DependentAddError('could not get cmd64.exe', LLError);
            end
            else
              LogDatei.DependentAddError('could see: '+GetWinSystemDirectory+'\cmd.exe', LLError);
            dummybool := DSiRevertWow64FsRedirection(oldDisableWow64FsRedirectionStatus);
            LogDatei.DependentAdd('RevertWow64FsRedirection succeeded', LLinfo);
          end
          else
          begin
            LogDatei.DependentAddError('Error: DisableWow64FsRedirection failed', LLError);
          end;
        except
          on ex: Exception
          do
          Begin
            LogDatei.DependentAddError ('Error: ' + ex.message, LLError);
          End;
        end;
      end;
      if not FileExists(GetWinDirectory+'\cmd64.exe') then
        LogDatei.DependentAddError('no cmd64.exe - will use cmd.exe instead', LLError);
    end;
    {$ENDIF WIN32}

      if GetUibOsType (errorinfo) = tovLinux then
      begin
       {$IFDEF GUI}
       if ShowCmd = SW_Minimize then
       begin
        FileName := '/bin/bash';
        Parameters := Parameters+' -c ' + tempfilename + ' ' + BatchParameter;
       end
       else
       begin
       FileName := '/usr/bin/xterm';
       Parameters := Parameters+' -e script /tmp/opsi-script-out.txt -c "/bin/bash -c ' + tempfilename
                     + ' ' + BatchParameter + '"';
       end
       {$ELSE GUI}
        FileName := '/bin/bash';
        Parameters := Parameters+' -c ' + tempfilename + ' ' + BatchParameter;
       {$ENDIF GUI}
      end
      else
      begin
       {$IFDEF WINDOWS}
       if GetUibOsType (errorinfo) = tovWinNT
       then
       Begin
         If force64 and FileExists(GetWinDirectory+'\cmd64.exe') then
           FileName := '"'+GetWinDirectory+'\cmd64.exe"'
         else
           FileName := '"cmd.exe"';
         Parameters := ' /C "' + tempfilename + '" ' + BatchParameter;
       End
       else  // win16
       Begin
         FileName := 'command.com';
         Parameters := ' /E:' + SpaceForEnvVarAsString +
                              ' /C ' + tempfilename + ' ' + BatchParameter;
       End;
       {$ENDIF WINDOWS}
      end;

     commandline := FileName + ' ' +trim(Parameters);

     begin
      output := TXStringlist.create;
      LogDatei.log ('Executing ' + commandline, LLInfo);
      if not RunCommandAndCaptureOut
         (commandline,
          catchout,
          output, report, showcmd, FLastExitCodeOfExe,showoutput)
      then
      Begin
        ps := 'Error: ' + Report;
        LogDatei.log(ps, LLcritical);
        FExtremeErrorLevel := LevelFatal;
        scriptstopped := true;
      End
          //
      else if catchout or (filename = '/usr/bin/xterm') then
      Begin
        if filename = '/usr/bin/xterm' then
        begin
          output.LoadFromFile('/tmp/opsi-script-out.txt');
          sysutils.DeleteFile('/tmp/opsi-script-out.txt');
        end;
        //xoutput.AddStrings(output);
        LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 6;
        LogDatei.DependentAdd ('', LevelInfo);
        LogDatei.DependentAdd ('output:', LevelInfo);
        LogDatei.DependentAdd ('--------------', LevelInfo);
        for i := 0 to output.count-1 do
        begin
         LogDatei.DependentAdd (output.strings[i], LevelInfo);
        end;
        LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 6;
        LogDatei.DependentAdd ('', LevelInfo);
      End
     End;
    end;


    finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                   DiffNumberOfErrors, DiffNumberOfWarnings);

    if ExitOnError and (DiffNumberOfErrors > 0)
    then result := tsrExitProcess;
    {$IFDEF GUI}
    if SaveStayOnTop then FBatchOberflaeche.ForceStayOnTop (true);
    {$ENDIF GUI}
    deleteTempBatFiles(tempfilename);
  finally
    {$IFDEF GUI}
    FBatchOberflaeche.showAcitvityBar(false);
    {$ENDIF GUI}
  end;
end;


function TuibInstScript.execPython (
      const Sektion: TWorkSection; PythonParameter : String;
      catchOut : Boolean; WaitConditions : TSetWaitConditions;
      var output: TXStringList)                       : TSectionResult;


Var
 ///commandline, filename, parameters,
 report : String='';
 ///errorinfo: String;
 i : integer=0;
 showcmd : Integer=0;
 outlines : TXStringList;
 pythonVersionInfo : TXStringList;
 versionTestResult : String='';
 savelogsindentlevel : Integer=0;
 fatalError : Boolean;
 tempfilename : String='';


 function pythonCall (const parameters : String; var outlines : TXStringList; showcmd : Integer) : Boolean;

 begin
    result := true;
    LogDatei.DependentAdd ('python ' + parameters, levelcomplete);

    if not RunCommandAndCaptureOut
       ('python ' + parameters,
        true,
        outlines, report, showcmd, FLastExitCodeOfExe)
    then
    Begin
      ps := 'Error: ' + Report;
      LogDatei.log(ps, LLcritical);
      FExtremeErrorLevel := LevelFatal;
      scriptstopped := true;
    End;
 end;

begin

  result := tsrPositive;
  showcmd := SW_SHOWMINIMIZED; // SW_SHOWNORMAL;
  fatalError := false;

  if Sektion.count = 0 then exit;

  LogDatei.LogSIndentLevel := Sektion.NestingLevel;
  savelogsindentlevel := LogDatei.LogSIndentLevel;

  OldNumberOfErrors := LogDatei.NumberOfErrors;
  OldNumberOfWarnings := LogDatei.NumberOfWarnings;

  ps := '';
  LogDatei.DependentAdd (ps, LevelWarnings);
  ps := 'Execution of ' + Sektion.Name;
  LogDatei.DependentAdd (ps, LevelWarnings);

  if pos (uppercase (PStatNames^ [tsExecutePython]), uppercase (Sektion.Name)) > 0 then
     ps := Sektion.Name;
    //ps := (* 'Ausfuehrung von ' +  *) copy (Sektion.Name, length (PStatNames^ [tsExecutePython]) + 1, length (Sektion.Name));

  {$IFDEF GUI}
  CentralForm.Label2.caption := ps;
  FBatchOberflaeche.setDetailLabel(ps);
  ProcessMess;
  {$ENDIF GUI}

  LogDatei.LogSIndentLevel := Sektion.NestingLevel + 1;

  Sektion.eliminateLinesStartingWith (';', false);

  outlines := TXStringList.create;

  if pythonCall ('--version', outlines, showcmd)
  then
  Begin
    LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 6;
    if outlines.count > 0
    then
      versionTestResult := outlines.Strings[0];

    for i := 0 to outlines.count-1 do
    begin
     LogDatei.DependentAdd ('::: ' + outlines.strings[i], LevelComplete);
    end;

    LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 6;
    LogDatei.DependentAdd ('', LevelComplete);
  End;

  outlines.Clear;


  pythonVersionInfo := TXStringList.Create;
  stringsplitByWhiteSpace (versionTestResult, pythonVersionInfo);

  if (pythonVersionInfo.Count = 0)
    or (lowerCase (pythonVersionInfo.Strings[0]) <> 'python')
  then
  Begin
   LogDatei.DependentAddError ('Error: python command not found', BaseLevel);
   fatalError := true;
  end;

  if not fatalError then
  begin
   //Sektion.SaveToFile (TempPath + TempBatchdatei);
     //inc(TempBatchDatei_UniqueCount);
     //tempfilename := TempPath + TempBatchfilename + inttoStr(TempBatchDatei_UniqueCount) + '.bat';
     //Sektion.SaveToFile (tempfilename);
     tempfilename := winstGetTempFileName;
     if not Sektion.FuncSaveToFile (tempfilename) then
     begin
       LogDatei.DependentAddError ('Error: Sektion could not be saved - so we switch to failed', LLcritical);
       FExtremeErrorLevel:=LevelFatal;
     end
     else
     begin
       output := TXStringList.create;
       if pythonCall (tempfilename +
        (* '--winstvars ' + [loglevel:loglevel, url:serviceurl, user, client, password] *) ' '
         + pythonparameter, output, showcmd)
       then
       Begin
          LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 6;
          LogDatei.DependentAdd ('', LevelInfo);
          LogDatei.DependentAdd ('output:', LevelInfo);
          LogDatei.DependentAdd ('--------------', LevelInfo);

          for i := 0 to output.count-1 do
          begin
           LogDatei.DependentAdd (output.strings[i], LevelInfo);
          end;

          LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 6;
          LogDatei.DependentAdd ('', LevelInfo);
        End;
     end;

  end;

  finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                 DiffNumberOfErrors, DiffNumberOfWarnings);


  LogDatei.LogSIndentLevel := savelogsindentlevel;

  if ExitOnError and (DiffNumberOfErrors > 0)
  then result := tsrExitProcess;
  deleteTempBatFiles(tempfilename);
end;


function TuibInstScript.produceExecLine(const s : String;
                        var programfilename, programparas, passparas, winstoption: String;
                        var InfoSyntaxError : String): boolean;

 var
    parts : TXStringList;
    remaining : String='';
    r : String='';
    part : String='';
    partA : String='';
    partB : String='';
    continue : Boolean;

begin

  result := false;
  programfilename := '';
  programparas := '';
  passparas := '';
  winstoption := '';

  remaining := s;
  parts := TXStringList.create;

  //determine part1 until PASS
  continue := true;
  partA := '';

  while (remaining <> '') and continue
  do
  Begin
    GetWord(remaining, part, remaining, WordDelimiterWhiteSpace);
    if (lowercase(part) = lowercase(passSplitter)) or (lowercase(part) = lowercase(optionsSplitter))
    then
      continue := false
    else
      partA:= partA + ' ' + part;
  end;

  parts.add(trim(partA));


  //determine parts[1] until WINST
  continue := true;
  partB := '';

  if lowercase(part) <> lowercase(optionsSplitter)
  then
    while (remaining <> '') and continue
    do
    Begin
      GetWord(remaining, part, remaining, WordDelimiterWhiteSpace);
      if lowercase(part) = lowercase(optionsSplitter)
      then
        continue := false
      else
        partB := partB + ' ' + part;
    end;

  parts.add(trim(partB));

  parts.add(trim(remaining));

  if (parts[2]<> '')
  then
  Begin
    if not GetString(parts[2], remaining, r, InfoSyntaxError, true)
    then
      remaining := parts[2];

    continue := true;

    while (remaining <> '') and continue
    do
    Begin
      if
      not Skip(ParameterDontWait, remaining, remaining, InfoSyntaxError)
      and
      not Skip(ParameterEscapeStrings, remaining, remaining, InfoSyntaxError)
      and
      not Skip(Parameter_64Bit, remaining, remaining, InfoSyntaxError)
      and
      not Skip(Parameter_32Bit, remaining, remaining, InfoSyntaxError)
      and
      not Skip(Parameter_SysNative, remaining, remaining, InfoSyntaxError)
      then continue := false;
    end;


    if (remaining <> '') and not continue
    then
    Begin
      InfoSyntaxError := 'winst option not recognized';
      exit;
    End;

  end;

  if parts[0] = ''
  then
  Begin
    InfoSyntaxError := 'Program file name missing';
    exit;
  end;

  result := true;

  if not GetString(parts[0], programFileName, remaining, infosyntaxError, true)
  then GetWord(parts[0], programFileName, remaining, WordDelimiterWhiteSpace);

  if not EvaluateString(remaining, remaining, programParas, infoSyntaxError)
  then
    programParas := remaining;

  if not EvaluateString(parts[1], remaining, passParas, infoSyntaxError)
  then
      passParas := parts[1];

  winstOption := parts[2];

  parts.free;
end;

function TuibInstScript.executeWith (
      const Sektion: TWorkSection; ExecParameter : String;
      catchOut : Boolean;
      var output: TXStringList)                       : TSectionResult;


Var
 commandline : String='';
 programfilename : String='';
 programparas : String='';
 passparas : String='';
 winstoption : String='';
 report : String='';
 threaded : boolean;
 errorinfo : String='';
 i : integer=0;
 showcmd : Integer=0;
 waitSecs : Integer=0;
 tempfilename : String='';
 savelogsindentlevel : Integer=0;
 runAs : TRunAs;
 useext : string;
 force64 : boolean;
 oldDisableWow64FsRedirectionStatus: pointer=nil;
 Wow64FsRedirectionDisabled, boolresult: boolean;


begin
  (*
  if  GetNTVersionMajor < 6 then
    runAs := traInvoker
  else
    runAs := traInvoker;
  *)
  runAs := traInvoker;
  result := tsrPositive;
  showcmd := SW_SHOWMINIMIZED; // SW_SHOWNORMAL;
  waitSecs := 0;

  if Sektion.count = 0 then exit;

  LogDatei.LogSIndentLevel := Sektion.NestingLevel;
  savelogsindentlevel := LogDatei.LogSIndentLevel;

  OldNumberOfErrors := LogDatei.NumberOfErrors;
  OldNumberOfWarnings := LogDatei.NumberOfWarnings;

  ps := '';
  LogDatei.DependentAdd (ps, LevelWarnings);
  ps := 'Execution of ' + Sektion.Name;
  LogDatei.DependentAdd (ps, LevelWarnings);

  if pos (uppercase (PStatNames^ [tsExecuteWith]), uppercase (Sektion.Name)) > 0 then
     ps := Sektion.Name;
    //ps := (* 'Ausfuehrung von ' +  *) copy (Sektion.Name, length (PStatNames^ [tsExecuteWith]) + 1, length (Sektion.Name));

  {$IFDEF GUI}
  CentralForm.Label2.caption := ps;
  FBatchOberflaeche.setDetailLabel(ps);
  ProcessMess;
  {$ENDIF GUI}

  LogDatei.LogSIndentLevel := Sektion.NestingLevel + 1;

  Sektion.eliminateLinesStartingWith (';', false);

  output := TXStringList.create;

  //inc(TempBatchDatei_UniqueCount);
  //tempfilename := TempPath + TempBatchfilename + inttoStr(TempBatchDatei_UniqueCount) + '.bat';
  //Sektion.SaveToFile (tempfilename);

  // syntax should been checked
  if not produceExecLine(
    ExecParameter,
    programfilename, programparas, passparas, winstoption,
    errorInfo)
  then
  begin
    LogDatei.DependentAddError ('Error: Illegal Parameter Syntax  - so we switch to failed', LLcritical);
    FExtremeErrorLevel:=LevelFatal;
    exit;
  end;

  useext := '.cmd';
  if pos('powershell.exe',LowerCase(programfilename)) > 0  then useext := '.ps1';
  if LowerCase(programfilename) = 'powershell' then useext := '.ps1';
  tempfilename := winstGetTempFileNameWithExt(useext);

  if not Sektion.FuncSaveToFile (tempfilename) then
  begin
    LogDatei.DependentAddError ('Error: Sektion could not be saved - so we switch to failed', LLcritical);
    FExtremeErrorLevel:=LevelFatal;
  end
  else
  begin
    {$IFDEF LINUX}
    fpchmod(tempfilename, &700);
    {$ENDIF LINUX}
    // if parameters end with '=' we concat tempfile without space
    if copy(programparas,length(programparas),1) = '=' then
        commandline :=
           '"' + programfilename +  '" ' + programparas
        + '"' + tempfilename + '"  '
        + passparas
    else
      commandline :=
           '"' + programfilename +  '" ' + programparas
        + ' "' + tempfilename + '"  '
        + passparas;

    force64 := false;
    If (pos (lowercase('/64bit'), lowercase (winstoption)) > 0) and Is64BitSystem then
       force64 := true;

    If (pos (lowercase('/sysnative'), lowercase (winstoption)) > 0) and Is64BitSystem then
       force64 := true;

    If (pos (lowercase('/32bit'), lowercase (winstoption)) > 0) then
       force64 := false;

    {$IFDEF WIN32}
    Wow64FsRedirectionDisabled := false;
    if force64 then
    Begin
      boolresult := DSiDisableWow64FsRedirection(oldDisableWow64FsRedirectionStatus);
      Wow64FsRedirectionDisabled := true;
    End
    else Wow64FsRedirectionDisabled := false;
    {$ENDIF WIN32}


    threaded :=
      (pos (lowercase(ParameterDontWait), lowercase (winstoption)) > 0);

    if threaded
    then
    begin
      if not StartProcess (Commandline, SW_SHOWMINIMIZED, false, false, false, false, runas, '', WaitSecs, Report, FLastExitCodeOfExe)
      then
      Begin
          ps := 'Error: ' + Report;
          LogDatei.log(ps, LLcritical);
          FExtremeErrorLevel := LevelFatal;
      End
      else
          LogDatei.DependentAdd (Report, LevelComplete);
    end
    else
    begin
      LogDatei.DependentAdd ('Executing ' + commandline, LLInfo);
      if not RunCommandAndCaptureOut
         (commandline,
          true,
          output, report, showcmd, FLastExitCodeOfExe)
      then
      Begin
        ps := 'Error: ' + Report;
        LogDatei.log(ps, LLcritical);
        FExtremeErrorLevel := LevelFatal;
        scriptstopped := true;
      End
      else
      Begin
        LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 6;
        LogDatei.DependentAdd ('', LevelInfo);
        LogDatei.DependentAdd ('output:', LevelInfo);
        LogDatei.DependentAdd ('--------------', LevelInfo);

        for i := 0 to output.count-1 do
        begin
         LogDatei.DependentAdd (output.strings[i], LevelInfo);
        end;

        LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 6;
        LogDatei.DependentAdd ('', LevelInfo);
      End;
    end;

    {$IFDEF WIN32}
    if Wow64FsRedirectionDisabled then
    Begin
      boolresult := DSiRevertWow64FsRedirection(oldDisableWow64FsRedirectionStatus);
      Wow64FsRedirectionDisabled := false;
    End;
    {$ENDIF WIN32}
  end;
  finishSection (Sektion, OldNumberOfErrors, OldNumberOfWarnings,
                 DiffNumberOfErrors, DiffNumberOfWarnings);


  LogDatei.LogSIndentLevel := savelogsindentlevel;

  if ExitOnError and (DiffNumberOfErrors > 0)
  then result := tsrExitProcess;
  if not threaded then deleteTempBatFiles(tempfilename);
end;


function TuibInstScript.produceStringList
   (const section: TuibIniScript;
   const s0 : String;
   var Remaining: String;
   var list : TXStringList;
   var InfoSyntaxError : String ) : Boolean;

var
  VarIndex : integer=0;
  i: Integer=0;
  k: Integer=0;
  startlineofsection : Integer=0;
  syntaxCheck : boolean;
  localsyntaxcheck : boolean;
  goOn : boolean;
  a2_to_default : boolean;
  s : String='';
  r : String='';
  s1 : String='';
  s2 : String='';
  s3 : String='';
  r1 : String='';
  ///sx,
  tmpstr : String='';
  a1 : integer=0;
  a2 : Integer=0;
  list1 : TXStringList;
  list2 : TXStringList;
  inifile: TuibIniScript;
  localSection : TWorkSection;
  secSpec : TSectionSpecifier;
  localKindOfStatement  : TStatement;
  logstring : String='';
  savelogsindentlevel : Integer=0;
  {$IFDEF WINDOWS}
  versionInfo : TVersionInfo; //from versionInfoX
  {$ENDIF WINDOWS}
  // is needed with $OBJECTCHECKS ON
  dummyActionresult : TSectionResult=0;

begin

 syntaxcheck := false;

 savelogsindentlevel := LogDatei.LogSIndentLevel;

 if Skip ('(', s0, s1, InfoSyntaxError)
 then
 begin
    if produceStringList (section, s1, r, list, InfoSyntaxError) //Recursion
    and Skip (')', r,r, InfoSyntaxError)
       then
       Begin
         syntaxCheck := true;
       End
 end

 else
 Begin
   GetWord (s0, s, r, WordDelimiterSet1);  // getting word s
   list := TXStringList.create; //list to return

   logstring := s;
   // clone of an existing list?
   VarIndex := listOfStringLists.IndexOf (LowerCase (s));
   if VarIndex >= 0 then
   begin
      list.Assign(TStringList(contentOfStringLists[VarIndex]));
      syntaxCheck := true;
   end

   // Funktion?

    else if LowerCase (s) = LowerCase ('shellcall')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
     if EvaluateString (r, r, s1, InfoSyntaxError)
     then
       if Skip (')', r,r, InfoSyntaxError)
       then
       Begin
         syntaxCheck := true;
         try
           //LogDatei.DependentAdd ('Executing0 ' + s1, LLNotice);
           list.Text := execShellCall(s1, 'sysnative').Text;
         except
           on e: exception do
           begin
             LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
             LogDatei.DependentAddError('Error executing :'+s1+' : '+ e.message,
               LLError);
             FNumberOfErrors := FNumberOfErrors + 1;
             LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 2;
           end
         end;
       End
   end


   else if LowerCase (s) = LowerCase ('LoadTextFile')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
     if EvaluateString (r, r, s1, InfoSyntaxError)
     then
     Begin
       try
         s1 := ExpandFileName(s1);
         list.loadfromfile (s1);
         list.Text:= reencode(list.Text, 'system');
       except
         on e: exception do
         begin
           LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
           LogDatei.DependentAddError('Error on loading file: ' + e.message,
             BaseLevel);
           FNumberOfErrors := FNumberOfErrors + 1;
           LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 2;
         end
       end;
       if Skip (')', r,r, InfoSyntaxError)
       then
       Begin
         syntaxCheck := true;
       End
     End
   end

   else if LowerCase (s) = LowerCase ('LoadUnicodeTextFile')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
     if EvaluateString (r, r, s1, InfoSyntaxError)
     then
     Begin
       try
         s1 := ExpandFileName(s1);
         TStringList(list).Assign(stringListLoadUtf8FromFile(s1));
         //wsloadfromfile (s1, TStringList (list));
       except
         on e: exception do
         begin
           LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
           LogDatei.DependentAddError('Error on loading file: ' + e.message,
             LLError);
           FNumberOfErrors := FNumberOfErrors + 1;
           LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 2;
         end
       end;
       if Skip (')', r,r, InfoSyntaxError)
       then
       Begin
         syntaxCheck := true;
       End
     End
   end

   else if LowerCase (s) = LowerCase ('GetSectionNames')
   then
   begin
      if Skip ('(', r, r, InfoSyntaxError)
      and EvaluateString (r, r, s1, InfoSyntaxError)
      and Skip (')', r,r, InfoSyntaxError)
      then
      Begin
        syntaxCheck := true;
        inifile := TuibIniScript.create;
        try
          s1 := ExpandFileName(s1);
          inifile.loadfromfile (s1);
          inifile.Text:= reencode(inifile.Text, 'system');
        except
           on e: exception do
           begin
             LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
             LogDatei.DependentAddError('Error on loading file: ' + e.message,
               BaseLevel);
             FNumberOfErrors := FNumberOfErrors + 1;
             LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 2;
           end
        end;

        inifile.GetSectionNames(list);
        inifile.free;
      end
   end


   else if LowerCase (s) = LowerCase ('retrieveSection')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
     if EvaluateString (r, r, s1, InfoSyntaxError)
     then
     Begin

       //list.assign(TXStringList(self));  // the complete script

       (*(Tuibiniscript(self)).*)
       GetSectionLines (s1, list, startlineofsection, true, true, true);

       if Skip (')', r,r, InfoSyntaxError)
       then
       Begin
         syntaxCheck := true;
       End
     End
   end

   else if LowerCase (s) = LowerCase ('getOutstreamFromSection')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
     if EvaluateString (r, r, s1, InfoSyntaxError)
     then
     Begin
       savelogsindentlevel := LogDatei.LogSIndentLevel;
       localSection := TWorkSection.create(LogDatei.LogSIndentLevel  + 1);
       GetWord (s1, s2, r1, WordDelimiterSet1);
       localSection.Name := s2;

       localKindOfStatement := findKindOfStatement (s2, SecSpec, s1);

       if
         not
         (
         localKindOfStatement
         in
         [tsDOSBatchFile, tsDOSInAnIcon,
         tsShellBatchFile, tsShellInAnIcon,
         tsExecutePython, tsExecuteWith, tsExecuteWith_escapingStrings]
         )
       then
         InfoSyntaxError := 'not implemented for this kind of section'
       else
       Begin
         if not (section.GetSectionLines (s2, TXStringList(localSection), startlineofsection, true, true, false)
           or GetSectionLines (s2, TXStringList(localSection), startlineofsection, true, true, false))
         then
             InfoSyntaxError := 'Section "' + s2 + '" not found'
         else
         Begin
           if localKindOfStatement in [tsExecutePython, tsExecuteWith_escapingStrings]
           then
           Begin
            ApplyTextConstants (TXStringList (localSection), true);
            ApplyTextVariables (TXStringList (localSection), true);
           End
           else
           Begin
            ApplyTextConstants (TXStringList (localSection), false);
            ApplyTextVariables (TXStringList (localSection), false);
           End;

           case localKindOfStatement of

            tsExecutePython :
                  execPython(localSection, r1,
                      true {catchout},
                      [ttpWaitOnTerminate], list);

            tsExecuteWith_escapingStrings, tsExecuteWith:
                  executeWith(localSection, r1,
                      true {catchout}, list);

            tsDOSBatchFile, tsDOSInAnIcon, tsShellBatchFile, tsShellInAnIcon:
                  execDOSBatch (localSection, r1,
                      SW_Minimize, true {catchout},
                      [ttpWaitOnTerminate], list);

           end;

           if Skip (')', r,r, InfoSyntaxError)
           then
           Begin
             syntaxCheck := true;
           End
         End;

       End;

       if localSection <> nil then localSection.Free;

       LogDatei.LogSIndentLevel := saveLogSIndentLevel;
     End
   end

   else if LowerCase (s) = LowerCase ('getReturnlistFromSection')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
     if EvaluateString (r, r, s1, InfoSyntaxError)
     then
     Begin
       savelogsindentlevel := LogDatei.LogSIndentLevel;
       localSection := TWorkSection.create(LogDatei.LogSIndentLevel  + 1);
       GetWord (s1, s2, r1, WordDelimiterSet1);
       localKindOfStatement := findKindOfStatement (s2, SecSpec, s1);
       if
         not (localKindOfStatement in
         [tsXMLPatch, tsOpsiServiceCall, tsLDAPsearch, tsOpsiServiceHashList]
         )
       then
         InfoSyntaxError := 'not implemented for this kind of section'
       else
       Begin
         if not (section.GetSectionLines (s2, TXStringList(localSection), startlineofsection, true, true, true)
           or GetSectionLines (s2, TXStringList(localSection), startlineofsection, true, true, true))
         then
           InfoSyntaxError := 'Section "' + s2 + '" not found'
         else
         Begin
           localsyntaxcheck := true;
           localSection.Name := s2;
           ApplyTextVariables (TXStringList (localSection), false);
           ApplyTextConstants (TXStringList (localSection), false);

           case localKindOfStatement of
             tsXMLPatch : dummyActionresult := doxmlpatch (localSection, r1, list);
             tsOpsiServiceCall : dummyActionresult := doOpsiServiceCall (localSection, r1, list);
             tsOpsiServiceHashList : dummyActionresult := doOpsiServiceHashList (localSection, r1, list);
             tsLDAPsearch :
               begin
                  if produceLDAPsearchParameters(r1, cacheRequest, outputRequest, InfoSyntaxError)
                  then
                    dummyActionresult := doLDAPSearch (localSection, cacheRequest, outputRequest, list)
                  else
                    localsyntaxcheck := false;
               end;
           end;
           localSection.Free;

           if localsyntaxcheck and (Skip (')', r,r, InfoSyntaxError))
           then
           Begin
             syntaxCheck := true;
           End
         End;
       End;
       LogDatei.LogSIndentLevel := saveLogSIndentLevel;
     End
   end


   else if LowerCase (s) = LowerCase ('editStringList')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
     if EvaluateString (r, r, s1, InfoSyntaxError)
     then
     Begin
       if Skip (')', r,r, InfoSyntaxError)
         then
         Begin
           syntaxCheck := true;
         End
     End
   end

   else if LowerCase (s) = LowerCase ('splitStringOnWhiteSpace')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
     if EvaluateString (r, r, s1, InfoSyntaxError)
     then
             if Skip (')', r,r, InfoSyntaxError)
             then
             Begin
               syntaxCheck := true;

               stringsplitByWhiteSpace (s1, list);
             End
   End


   else if LowerCase (s) = LowerCase ('splitString')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
     if EvaluateString (r, r, s1, InfoSyntaxError)
     then
       if Skip (',', r,r, InfoSyntaxError)
       then
        if EvaluateString (r, r, s2, InfoSyntaxError)
        then
             if Skip (')', r,r, InfoSyntaxError)
             then
             Begin
               syntaxCheck := true;

               stringsplit (s1, s2, list);
             End
   End

   else if LowerCase (s) = LowerCase ('GetProductPropertyList')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
     if EvaluateString (r, r, s1, InfoSyntaxError)
     then
       if Skip (',', r,r, InfoSyntaxError)
       then
        if EvaluateString (r, r, s2, InfoSyntaxError)
        then
             if Skip (')', r,r, InfoSyntaxError)
             then
             Begin
               syntaxCheck := true;
               if opsidata <> nil then
               begin
                 list.AddStrings(opsidata.getProductPropertyList(s1,s2));
               end
               else list.Add(s2);
             End
   End


   else if LowerCase (s) = LowerCase ('getlistcontaining')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
    Begin
       list1 := TXStringList.create;
      if produceStringList (section,r, r, list1, InfoSyntaxError) //Recursion
        and skip (',', r, r, InfoSyntaxError)
      then
      Begin
        if EvaluateString (r, r, s1, InfoSyntaxError)
        and
          skip (')', r, r, InfoSyntaxError)
        then
        Begin
          syntaxcheck := true;
           list.clear;
           for i := 0 to list1.count - 1
           do
           try
            if AnsiContainsText(list1[i], s1) then
              list.add (list1[i]);
           except
             on e: exception do
             begin
               LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
               LogDatei.DependentAddError('Error on producing sublist: ' + e.message,
                 LLerror);
               FNumberOfErrors := FNumberOfErrors + 1;
               LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 2;
             end
           end;
           list1.Free;
           list1 := nil;
         End
       End
    End
   End


   else if LowerCase (s) = LowerCase ('reencodestrlist')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
    Begin
      list1 := TXStringList.create;
      if produceStringList (section,r, r, list1, InfoSyntaxError) //Recursion
      then
       if Skip (',', r,r, InfoSyntaxError)
         then
          if EvaluateString (r,r, s1, InfoSyntaxError)
          then
            if Skip (',', r,r, InfoSyntaxError)
            then
             if EvaluateString (r,r, s2, InfoSyntaxError)
             then
              if Skip (')', r,r, InfoSyntaxError)
              then
              Begin
                syntaxCheck := true;
                 list.clear;
                 try
                    list.Text:= reencode(list1.Text,s1,s2);
                 except
                   on e: exception do
                   begin
                     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
                     LogDatei.DependentAddError('Error on producing sublist: ' + e.message,
                       LLerror);
                     FNumberOfErrors := FNumberOfErrors + 1;
                     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 2;
                     list1.Free;
                     list1 := nil;
                   end
                 end;
               End;
      list1.Free;
      list1 := nil;
    End
   End


   else if LowerCase (s) = LowerCase ('addtolist')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
    Begin
       list1 := TXStringList.create;
      if produceStringList (section,r, r, list1, InfoSyntaxError) //Recursion
        and skip (',', r, r, InfoSyntaxError)
      then
      Begin
        if EvaluateString (r, r, s1, InfoSyntaxError)
        and
          skip (')', r, r, InfoSyntaxError)
        then
        Begin
          syntaxcheck := true;
           list.clear;
           //list.AddStrings(list1.lines);
           try
            //for i := 0 to list1.count - 1
              //do list.add (list1[i]);
              list.AddStrings(list1);
            list.Add(s1);
           except
             on e: exception do
             begin
               LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
               LogDatei.DependentAddError('Error on producing sublist: ' + e.message,
                 LLerror);
               FNumberOfErrors := FNumberOfErrors + 1;
               LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 2;
             end
           end;
           list1.Free;
           list1 := nil;
         End
       End
    End
   End

   else if LowerCase (s) = LowerCase ('addlisttolist')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
    Begin
       list1 := TXStringList.create;
      if produceStringList (section,r, r, list1, InfoSyntaxError) //Recursion
        and skip (',', r, r, InfoSyntaxError)
      then
      Begin
        list2 := TXStringList.create;
        if produceStringList (section,r, r, list2, InfoSyntaxError) //Recursion
          and skip (')', r, r, InfoSyntaxError)
        then
        Begin
          syntaxcheck := true;
          list.clear;
          try
            list.AddStrings(list1);
            list.AddStrings(list2);
          except
            on e: exception do
            begin
              LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
              LogDatei.DependentAddError('Error on producing sublist: ' + e.message,
                LLerror);
              FNumberOfErrors := FNumberOfErrors + 1;
              LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 2;
            end
          end;
          list1.Free;
          list1 := nil;
          list2.Free;
          list2 := nil;
         End
       End
    End
   End

   else if LowerCase (s) = LowerCase ('getListContainingList')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
    Begin
       list1 := TXStringList.create;
      if produceStringList (section,r, r, list1, InfoSyntaxError) //Recursion
        and skip (',', r, r, InfoSyntaxError)
      then
      Begin
        list2 := TXStringList.create;
        if produceStringList (section,r, r, list2, InfoSyntaxError) //Recursion
          and skip (')', r, r, InfoSyntaxError)
        then
        Begin
          syntaxcheck := true;
          list.clear;
          try
           for i := 0 to list1.count - 1 do
             for k := 0 to list2.count - 1 do
               if list1.Strings[i] = list2.Strings[k] then
                list.Add(list1.Strings[i]);
          except
            on e: exception do
            begin
              LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
              LogDatei.DependentAddError('Error on producing sublist: ' + e.message,
                LLerror);
              FNumberOfErrors := FNumberOfErrors + 1;
              LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 2;
            end
          end;
          list1.Free;
          list1 := nil;
          list2.Free;
          list2 := nil;
         End
       End
    End
   End



   else if LowerCase (s) = LowerCase ('getsublist')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
    Begin
       syntaxcheck := true;
       // syntax: "{d}:[-]{d}, listvalue , that is any number of digits followed by a ':'
       // followed by again any number of digits, followed by a comma, then the listvalue
       // if the first series of digits is empty, the start index is zero
       // if the second series of digits is empty, the last index is count - 1

       try
         GetWord (r, s1, r, [':']);
         if length (s1) = 0
         then
           a1 := 0
         else
           a1 := strtoint(trim(s1));

         syntaxCheck := Skip(':', r, r, InfoSyntaxError);
         GetWord (r, s1, r, [',']);

         a2_to_default := false;
         if length (s1) = 0
         then
         begin
           a2 := 0;
           a2_to_default := true;
         end
         else
           a2 := strtoint(trim(s1));

         syntaxCheck := Skip(',', r, r, InfoSyntaxError);

       except
         syntaxcheck := false;
         InfoSyntaxError := ' No valid sublist selection ';
       end;

       if syntaxCheck then
       Begin
         list1 := TXStringList.create;

         if not produceStringList (section,r, r, list1, InfoSyntaxError) //Recursion
         or not Skip (')', r,r, InfoSyntaxError)
         then
            syntaxCheck := false
         else
         Begin
           list.clear;

           if a2_to_default
           then a2 := list1.count - 1;
           adjustBounds (a1, a2, list1);

           for i := a1 to a2
           do
           try
             list.add (list1[i]);
           except
             on e: exception do
             begin
               LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
               LogDatei.DependentAddWarning('Error on producing sublist: ' + e.message,
                 BaseLevel);
               FNumberOfWarnings := FNumberOfWarnings + 1;
               LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 2;
             end
           end;


           list1.Free;
           list1 := nil;
         End
       End
    End
   End

   else if LowerCase (s) = LowerCase ('createStringList')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
    Begin
      if length (r) = 0
      then
        InfoSyntaxError := ' ")" missing '
      else
      Begin
        goOn := true;
        syntaxCheck := true;
      End;

      while syntaxCheck and goon
      do
      Begin
          evaluateString (r, r, s1, InfoSyntaxError);
          if length(s1) > 0
          then
            list.add (s1);

          if length(r) = 0
          then
          Begin
            syntaxCheck := false;
            InfoSyntaxError := ' expression not terminated ';
          End
          else
          Begin
           if r[1] = ','
           then
             Skip (',', r, r, InfoSyntaxError) //here is no syntax error possible
           else if r[1] = ')'
           then
           Begin
             goOn := false;
             Skip (')', r, r, InfoSyntaxError) //consume the ')'
           End
           else
           Begin
             syntaxCheck := false;
             InfoSyntaxError := ' "," or ")" expected ';
           End;
          End;
      End
    end
   end

   else if LowerCase (s) = LowerCase ('reverse')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
    begin
      list1 := TXStringList.create;
      if produceStringList (section,r, r, list1, InfoSyntaxError) //Recursion
      then
      Begin
        list.clear;
        for i := list1.count downto 1
        do
          list.add (list1[i-1]);
        if Skip (')', r, r, InfoSyntaxError)
        then
          syntaxCheck := true;
      End;
      list1.free;
    end;
   end

   else if LowerCase (s) = LowerCase ('emptyList')
   then
   begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
    begin
      // we do not need it - but for syntax check reasons it has to be done
      list1 := TXStringList.create;
      if produceStringList (section,r, r, list1, InfoSyntaxError) //Recursion
      then
      Begin
        list.clear;
        if Skip (')', r, r, InfoSyntaxError) then
          syntaxCheck := true;
      end;
      list1.free;
    end;
   end

   else if LowerCase(s) = LowerCase ('getProductMap')
   then
   Begin
     //if (r = '') or (r=')') then
     Begin
      syntaxcheck := true;
      if not (opsidata = nil) then
      begin
        list.add ('id='+Topsi4data(opsidata).getActualProductId);
        list.add ('name='+Topsi4data(opsidata).getActualProductName);
        list.add ('description='+Topsi4data(opsidata).getActualProductDescription);
        list.add ('advice='+Topsi4data(opsidata).getActualProductAdvice);
        list.add ('productversion='+Topsi4data(opsidata).getActualProductProductVersion);
        list.add ('packageversion='+Topsi4data(opsidata).getActualProductPackageVersion);
        list.add ('priority='+Topsi4data(opsidata).getActualProductPriority);
        list.add ('installationstate='+Topsi4data(opsidata).getActualProductInstallationState);
        list.add ('lastactionrequest='+Topsi4data(opsidata).getActualProductLastActionRequest);
        list.add ('lastactionresult='+Topsi4data(opsidata).getActualProductProductLastActionReport);
        list.add ('installedversion='+Topsi4data(opsidata).getActualProductInstalledVersion);
        list.add ('installedpackage='+Topsi4data(opsidata).getActualProductInstalledPackage);
        list.add ('installedmodificationtime='+Topsi4data(opsidata).getActualProductInstalledModificationTime);
        list.add ('actionrequest='+ Topsi4data(opsidata).getActualProductActionRequest);
       end;
     end;
   end

   {$IFDEF WIN32}
   else if LowerCase(s) = LowerCase ('getIpMacMap')
   //does not work (do 15.6.2012)
   then
   Begin
     Begin
      syntaxcheck := true;
      list.AddStrings(getIpMacHash);
     end;
   end
   {$ENDIF WIN32}

   else if LowerCase(s) = LowerCase ('getLocaleInfo')
   then
   Begin
     //if (r = '') or (r=')') then
     Begin
      syntaxcheck := true;
      {$IFDEF WINDOWS}
      list.add (copy (GetSystemDefaultLocale(LOCALE_SABBREVLANGNAME), 1, 2));
      list.add (GetSystemDefaultLocale(LOCALE_SABBREVLANGNAME));
      list.add (GetSystemDefaultLocale(LOCALE_SENGLANGUAGE));
      list.add (GetSystemDefaultLocale(LOCALE_SENGCOUNTRY));
      list.add (GetSystemDefaultLocale(LOCALE_ILANGUAGE));
      list.add (GetSystemDefaultLocale(LOCALE_SNATIVELANGNAME));
      list.add (GetSystemDefaultLocale(LOCALE_IDEFAULTLANGUAGE));
      //list.add (GetSystemDefaultLocale(LOCALE_NOUSEROVERRIDE));
      {$ENDIF WINDOWS}
     end;
   end

   else if LowerCase(s) = LowerCase ('getLocaleInfoMap')
   then
   Begin
     //if (r = '') or (r=')') then
     Begin
      syntaxcheck := true;
      {$IFDEF WINDOWS}
      list.add ('language_id_2chars=' + copy (GetSystemDefaultLocale(LOCALE_SABBREVLANGNAME), 1, 2));
      list.add ('language_id=' + GetSystemDefaultLocale(LOCALE_SABBREVLANGNAME));
      list.add ('localized_name_of_language=' + GetSystemDefaultLocale(LOCALE_SLANGUAGE));
      list.add ('English_name_of_language=' + GetSystemDefaultLocale(LOCALE_SENGLANGUAGE));
      list.add ('abbreviated_language_name=' + GetSystemDefaultLocale(LOCALE_SABBREVLANGNAME));
      list.add ('native_name_of_language=' + GetSystemDefaultLocale(LOCALE_SNATIVELANGNAME));

      list.add ('country_code=' + GetSystemDefaultLocale(LOCALE_ICOUNTRY));
      list.add ('localized_name_of_country=' + GetSystemDefaultLocale(LOCALE_SCOUNTRY));
      list.add ('English_name_of_country=' + GetSystemDefaultLocale(LOCALE_SENGCOUNTRY));
      list.add ('abbreviated_country_name=' + GetSystemDefaultLocale(LOCALE_SABBREVCTRYNAME));
      list.add ('native_name_of_country=' + GetSystemDefaultLocale(LOCALE_SNATIVECTRYNAME));
      list.add ('default_language_id=' + GetSystemDefaultLocale(LOCALE_IDEFAULTLANGUAGE));
      list.add ('default_language_id_decimal=' + IntToStr(StrToInt('$'+GetSystemDefaultLocale(LOCALE_IDEFAULTLANGUAGE))));
      list.add ('default_country_code=' + GetSystemDefaultLocale(LOCALE_IDEFAULTCOUNTRY));
      list.add ('default_oem_code_page=' + GetSystemDefaultLocale(LOCALE_IDEFAULTCODEPAGE));
      list.add ('default_ansi_code_page=' + GetSystemDefaultLocale(LOCALE_IDEFAULTANSICODEPAGE));
      tmpstr := GetRegistrystringvalue('HKEY_LOCAL_MACHINE\System\CurrentControlset\Control\Nls\Language','InstallLanguage',false);
      list.add ('system_default_language_id=' + tmpstr);
      //list.add ('system_default_UI_language=' + GetSystemDefaultUILanguage );
      list.add ('system_default_posix=' +  StringReplace(getlangcodeByHexvalueStr('0x'+tmpstr),'-','_'));
      list.add ('system_default_lang_region=' + getlangcodeByHexvalueStr('0x'+tmpstr));
      {$ENDIF WINDOWS}
     end;
   end

  {$IFDEF WINDOWS}
  else if LowerCase(s) = LowerCase ('getMSVersionMap')
   then
   Begin
     //if (r = '') or (r=')') then
     Begin
      syntaxcheck := true;
      list.add ('major_version=' + GetSystemOSVersionInfoEx('major_version'));
      list.add ('minor_version=' + GetSystemOSVersionInfoEx('minor_version'));
      list.add ('build_number=' + GetSystemOSVersionInfoEx('build_number'));
      list.add ('platform_id=' + GetSystemOSVersionInfoEx('platform_id'));
      list.add ('csd_version=' + GetSystemOSVersionInfoEx('csd_version'));
      list.add ('service_pack_major=' + GetSystemOSVersionInfoEx('service_pack_major'));
      list.add ('service_pack_minor=' + GetSystemOSVersionInfoEx('service_pack_minor'));
      list.add ('suite_mask=' + GetSystemOSVersionInfoEx('suite_mask'));
      list.add ('product_type_nr=' + GetSystemOSVersionInfoEx('product_type_nr'));
      list.add ('2003r2=' + GetSystemOSVersionInfoEx('2003r2'));
     end;
   end
   {$ENDIF WINDOWS}

   {$IFDEF LINUX}
   else if LowerCase(s) = LowerCase ('getLinuxVersionMap')
    then
    Begin
      Begin
       syntaxcheck := true;
       list.AddStrings(getLinuxVersionMap);
      end;
    end
    {$ENDIF LINUX}



   else if LowerCase(s) = LowerCase ('getFileInfoMap')
   then
   Begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
      if EvaluateString (r, r, s1, InfoSyntaxError)
      then
      Begin
        if not fileExists (s1) then
        begin
          LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
          LogDatei.DependentAdd('File "' + s1 + '" does not exist', LLWarning);
          FNumberOfWarnings := FNumberOfWarnings + 1;
          LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 2;
        end
        else
        Begin
         {$IFDEF WINDOWS}
          versionInfo := TVersionInfo.create (s1);

          for i := 0 to versionInfo.TranslationCount-1 do
          Begin
            list.add('Language name ' + IntToStr(i) + '=' + versionInfo.LanguageNames[i]);
            list.add('Language ID ' + IntToStr(i) + '=' + IntToStr(versionInfo.LanguageID[i]));
          End;

          list.add('file version=' + IntToStr(versionInfo.FileVersion));
          list.add('file version with dots=' + versionInfo.GetFileVersionWithDots);
          list.add('product version=' + IntToStr(versionInfo.ProductVersion));


          for i := Low(versionInfoX.PredefinedStrings) to High(versionInfoX.PredefinedStrings) do
          list.add (versionInfoX.PredefinedStrings[i] + '=' + versionInfo.getString(PredefinedStrings[i]) );


          versionInfo.free;
         {$ENDIF WINDOWS}
        end;
        if Skip (')', r,r, InfoSyntaxError)
        then
        Begin
          syntaxCheck := true;
        End
      End;
   end

   else if LowerCase(s) = LowerCase ('getRegistryKeyList32')
   then
   Begin
    {$IFDEF WINDOWS}
    if Skip ('(', r, r, InfoSyntaxError) then
      if EvaluateString (r, r, s1, InfoSyntaxError) then
      Begin
        //for i :=
        list.AddStrings(GetRegistryKeyList(s1,false));
        if Skip (')', r,r, InfoSyntaxError)  then
        Begin
          syntaxCheck := true;
        End
      End;
    {$ELSE WINDOWS}
    SyntaxCheck := false;
    InfoSyntaxError := 'Only implemented for Windows';
    LogDatei.DependentAdd(s +' is only implemented for Windows',LLError);
    {$ENDIF WINDOWS}
   end

   else if (LowerCase(s) = LowerCase ('getRegistryKeyList64'))
        or (LowerCase(s) = LowerCase ('getRegistryKeyListSysnative'))
   then
   Begin
    {$IFDEF WINDOWS}
    if Skip ('(', r, r, InfoSyntaxError) then
      if EvaluateString (r, r, s1, InfoSyntaxError) then
      Begin
        //for i :=
        list.AddStrings(GetRegistryKeyList(s1,true));
        if Skip (')', r,r, InfoSyntaxError)  then
        Begin
          syntaxCheck := true;
        End
      End;
    {$ELSE WINDOWS}
    SyntaxCheck := false;
    InfoSyntaxError := 'Only implemented for Windows';
    LogDatei.DependentAdd(s +' is only implemented for Windows',LLError);
    {$ENDIF WINDOWS}
   end

   else if LowerCase(s) = LowerCase ('getRegistryVarList32')
   then
   Begin
    {$IFDEF WINDOWS}
    if Skip ('(', r, r, InfoSyntaxError) then
      if EvaluateString (r, r, s1, InfoSyntaxError) then
      Begin
        //for i :=
        list.AddStrings(GetRegistryVarList(s1,false));
        if Skip (')', r,r, InfoSyntaxError)  then
        Begin
          syntaxCheck := true;
        End
      End;
    {$ELSE WINDOWS}
    SyntaxCheck := false;
    InfoSyntaxError := 'Only implemented for Windows';
    LogDatei.DependentAdd(s +' is only implemented for Windows',LLError);
    {$ENDIF WINDOWS}
   end

   else if (LowerCase(s) = LowerCase ('getRegistryVarList64'))
        or (LowerCase(s) = LowerCase ('getRegistryVarListSysnative'))
   then
   Begin
    {$IFDEF WINDOWS}
    if Skip ('(', r, r, InfoSyntaxError) then
      if EvaluateString (r, r, s1, InfoSyntaxError) then
      Begin
        //for i :=
        list.AddStrings(GetRegistryVarList(s1,true));
        if Skip (')', r,r, InfoSyntaxError)  then
        Begin
          syntaxCheck := true;
        End
      End;
    {$ELSE WINDOWS}
    SyntaxCheck := false;
    InfoSyntaxError := 'Only implemented for Windows';
    LogDatei.DependentAdd(s +' is only implemented for Windows',LLError);
    {$ENDIF WINDOWS}
   end

   else if LowerCase(s) = LowerCase ('getRegistryVarMap32')
   then
   Begin
    {$IFDEF WINDOWS}
    if Skip ('(', r, r, InfoSyntaxError) then
      if EvaluateString (r, r, s1, InfoSyntaxError) then
      Begin
        //for i :=
        list.AddStrings(GetRegistryVarMap(s1,false));
        if Skip (')', r,r, InfoSyntaxError)  then
        Begin
          syntaxCheck := true;
        End
      End;
    {$ELSE WINDOWS}
    SyntaxCheck := false;
    InfoSyntaxError := 'Only implemented for Windows';
    LogDatei.DependentAdd(s +' is only implemented for Windows',LLError);
    {$ENDIF WINDOWS}
   end

   else if (LowerCase(s) = LowerCase ('getRegistryVarMap64'))
        or (LowerCase(s) = LowerCase ('getRegistryVarMapSysnative'))
   then
   Begin
    {$IFDEF WINDOWS}
    if Skip ('(', r, r, InfoSyntaxError) then
      if EvaluateString (r, r, s1, InfoSyntaxError) then
      Begin
        //for i :=
        list.AddStrings(GetRegistryVarMap(s1,true));
        if Skip (')', r,r, InfoSyntaxError)  then
        Begin
          syntaxCheck := true;
        End
      End;
    {$ELSE WINDOWS}
    SyntaxCheck := false;
    InfoSyntaxError := 'Only implemented for Windows';
    LogDatei.DependentAdd(s +' is only implemented for Windows',LLError);
    {$ENDIF WINDOWS}
   end


else if LowerCase (s) = LowerCase ('getSlowInfoMap')
  // reads slowinfocache
  // productkey is the key below ARPCache
  //hash key may be: hasname, installsize, lastused, usagefrequency, binaryname
   then
   begin
    {$IFDEF WINDOWS}
    if Skip ('(', r, r, InfoSyntaxError)
    then
     if EvaluateString (r, r, s1, InfoSyntaxError)
     then
       if Skip (',', r,r, InfoSyntaxError)
       then
        if EvaluateString (r, r, s2, InfoSyntaxError)
        then
            if Skip (')', r,r, InfoSyntaxError)
            then
            Begin
              syntaxCheck := true;
              tmpstr := GetSlowInfoCache(s1, 'hasname', s2);
              if tmpstr <> '' then list.add('hasname=' + tmpstr);
              tmpstr := GetSlowInfoCache(s1, 'installsize', s2);
              if tmpstr <> '' then list.add('installsize=' + tmpstr);
              tmpstr := GetSlowInfoCache(s1, 'lastused', s2);
              if tmpstr <> '' then list.add('lastused=' + tmpstr);
              tmpstr := GetSlowInfoCache(s1, 'usagefrequency', s2);
              if tmpstr <> '' then list.add('usagefrequency=' + tmpstr);
              tmpstr := GetSlowInfoCache(s1, 'binaryname', s2);
              if tmpstr <> '' then list.add('binaryname=' + tmpstr);
              //list.add('installsize=' + GetSlowInfoCache(s1, 'installsize', s2));
              //list.add('lastused=' + GetSlowInfoCache(s1, 'lastused', s2));
              //list.add('usagefrequency=' + GetSlowInfoCache(s1, 'usagefrequency', s2));
              //list.add('binaryname=' + GetSlowInfoCache(s1, 'binaryname', s2));
            End
    {$ELSE WINDOWS}
    SyntaxCheck := false;
    InfoSyntaxError := 'Only implemented for Windows';
    LogDatei.DependentAdd(s +' is only implemented for Windows',LLError);
    {$ENDIF WINDOWS}
   End

else if LowerCase (s) = LowerCase ('getSwauditInfoList')
  // reads slowinfocache
  // productkey is the key below ARPCache
  //hash key may be: hasname, installsize, lastused, usagefrequency, binaryname
   then
   begin
    {$IFDEF WINDOWS}
    if Skip ('(', r, r, InfoSyntaxError)
    then
     if EvaluateString (r, r, s1, InfoSyntaxError)
     then
       if Skip (',', r,r, InfoSyntaxError)
       then
        if EvaluateString (r, r, s2, InfoSyntaxError)
        then
          if Skip (',', r,r, InfoSyntaxError)
          then
            if EvaluateString (r, r, s3, InfoSyntaxError)
            then
              if Skip (')', r,r, InfoSyntaxError)
              then
              Begin
                syntaxCheck := true;
                list1 := TXStringList.Create;
                getSwauditInfoList(s1,s2,s3,list1);
                list.AddStrings(list1);
                list1.Free;
              End
    {$ELSE WINDOWS}
    SyntaxCheck := false;
    InfoSyntaxError := 'Only implemented for Windows';
    LogDatei.DependentAdd(s +' is only implemented for Windows',LLError);
    {$ENDIF WINDOWS}
   End


   else if LowerCase(s) = LowerCase ('getProcesslist')
   then
   Begin
   //   if r = '' then
        Begin
        syntaxcheck := true;
        list.AddStrings(getProcessList);
       end;
    end

   else if LowerCase(s) = LowerCase ('getProfilesDirList')
   then
   Begin
   //   if r = '' then
        Begin
        syntaxcheck := true;
        list.AddStrings(getProfilesDirList);
       end;
    end

   else if LowerCase(s) = LowerCase ('getHWBiosInfoMap')
   then
   Begin
   //   if r = '' then
        Begin
        syntaxcheck := true;
        list.AddStrings(getHwBiosShortlist);
       end;
    end

   else
    InfoSyntaxError := s0 + ' no valid expression for a string list';



   if syntaxcheck
   then
   Begin
     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
     LogDatei.DependentAdd ('retrieving strings from ' + logstring + ' [switch to loglevel ' + inttostr(LevelDebug) + ' for debugging]',
     LevelComplete);
     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
     LogDatei.DependentAddStringList(list, LevelDebug);
     LogDatei.DependentAdd('', LevelDebug);
     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 4;
   end;

 End;

 if syntaxcheck
 then
   Remaining := r
 else
   Remaining := s0;

 result := syntaxCheck;

end;

// string functions
function TuibInstScript.EvaluateString
   (const s0 : String;
   var Remaining: String;
   var StringResult : String;
   var InfoSyntaxError : String ) : Boolean;


var
 VarIndex : Integer=0;
 a1 : Integer=0;
 syntaxCheck : boolean;
 s : String='';
 sx : String='';
 r : String='';
 s1 : String='';
 s2 : String='';
 r1 : String='';
 s3 : String='';
 s4 : String='';
 n1 : integer=0;
 n2 : Integer=0;
 listindex : Integer=0;
 randomInt : Integer=0;
 errorinfo : String='';
 intresult : Integer=0;
 list1 : TXStringlist;
 HostsImage : TuibPatchHostsFile;
 HostsLocation : String='';
 i : Integer=0;
 ///m, n, rest : Integer;
 itemlist : TXStringList;
 {$IFDEF WINDOWS}
   Regist : TuibRegistry;
   RegType : TuibRegDataType;
 {$ENDIF WINDOWS}
   majorver : TuibNTVersion;
   minorver : DWORD=0;
   ///programfilesdir, diffx86 : String;
   key0 : String='';
   key : String='';
   valuename : String='';
   StartIndentLevel : Integer=0;
   errorOccured : Boolean;
   continue : Boolean;
   j : Integer=0;
   parameters : Array of String;
   omc : TOpsiMethodCall;
 IniFile : TIniFile;
 //tempchar : char;
 //tempansistr : ansistring;
 //tempansistrp : Pansichar;



begin

 syntaxCheck := false;
 InfoSyntaxError := '';
 StringResult := '';

 StartIndentLevel := LogDatei.LogSIndentLevel;

 (* string variable? *)
 GetWord (s0, s, r, WordDelimiterSet3);
 VarIndex := VarList.IndexOf (LowerCase (s));
 if VarIndex >= 0 then
 begin
   if ValuesList.count - 1 < VarIndex
   then
   Begin
    InfoSyntaxError := 'kein Stringwert auf Variable';
   End
   else
   Begin
     StringResult := ValuesList [VarIndex];
     syntaxCheck := true;
   End
 end

 (* string constant?  *)
 else if (length (s0) > 0) and (s0[1] = '"') then
 Begin
   r := copy (s0, 2, length (s0)-1);
   GetWord (r, StringResult, r, ['"']);
   if skip ('"', r, r, InfoSyntaxError)
   then syntaxCheck := true;

 End

 (* string constant delimited by "'" ?  *)
 else if (length (s0) > 0) and (s0[1] = '''') then
 Begin
   r := copy (s0, 2, length (s0)-1);
   GetWord (r, StringResult, r, ['''']);
   if skip ('''', r, r, InfoSyntaxError)
   then syntaxCheck := true;
 End

 (* checking our pseudo function name for retrieving a string avoiding any escape problems of citations marks *)
 else if LowerCase (s) = LowerCase ('EscapeString') then
 Begin
   if Skip (':', r, s1, InfoSyntaxError)
   then
   Begin
     StringResult := s1;
     r := '';
     syntaxCheck := true;
   End
 End

  (* string functions ? *)

 else if (LowerCase (s) = LowerCase ('LogLevel')) or ( LowerCase (s) = LowerCase('getLogLevel') ) then
 Begin
    StringResult := IntToStr (Logdatei.LogLevel) ;
    syntaxCheck := true;
 End

 else if (LowerCase (s) = LowerCase('getLastExitCode') ) then
 Begin
    StringResult := IntToStr (FLastExitCodeOfExe) ;
    syntaxCheck := true;
 End

 else if (LowerCase (s) = LowerCase('getDiffTimeSec') ) then
 Begin
    StringResult := IntToStr (SecondsBetween(markedTime,Time)) ;
    syntaxCheck := true;
 End


 else if LowerCase (s) = LowerCase ('EnvVar') then
 Begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
     StringResult := ValueOfEnvVar (s1);
     syntaxCheck := true;
   End
 End

 else if LowerCase(s) = LowerCase ('GetOS')
 then
 Begin
    syntaxCheck := true;
    OldNumberOfErrors := LogDatei.NumberOfErrors;
    case GetuibOsType (ErrorInfo) of
     tovNotKnown :
       Begin
         LogDatei.dependentAddError (ErrorInfo, BaseLevel);
         StringResult := 'OS not identified';
       End;
     tovWin16 : StringResult := 'Windows_16';
     tovWin95 : StringResult := 'Windows_95';
     tovWinNT : StringResult := 'Windows_NT';
     tovLinux : StringResult := 'Linux';
    end;

    DiffNumberOfErrors := LogDatei.NumberOfErrors - OldNumberOfErrors;
    FNumberOfErrors := NumberOfErrors + DiffNumberOfErrors;

 End

 else if LowerCase(s) = LowerCase ('GetNTVersion')
 then
 Begin
   {$IFDEF WINDOWS}
    syntaxCheck := true;


    OldNumberOfErrors := LogDatei.NumberOfErrors;

    if GetUibOsType (errorinfo) <> tovWinNT
    then
      StringResult := 'No OS of type Windows NT'
    else
    Begin
      OldNumberOfErrors := LogDatei.NumberOfErrors;
      case GetuibNTversion (ErrorInfo) of
       tntverNONE:
         Begin
           LogDatei.dependentAddError (ErrorInfo, BaseLevel);
           StringResult := ErrorInfo;
         End;
       tntverNT3 : StringResult := 'NT3';
       tntverNT4 : StringResult := 'NT4';
       tntverWIN2K :
         Begin
          minorver := GetNTVersionMinor;
          if minorver = 0
          then StringResult := 'Win2k'
          else if minorver = 1
          then StringResult := 'WinXP'
          else StringResult := 'Win NT 5.' + inttostr(minorver);
         End;
       tntverWINVISTA :
          Begin
              StringResult := 'Windows Vista'
          end;
       tntverWINLATER: StringResult := 'Win NT ' + inttostr(GetNtVersionMajor) + '.' + inttostr(minorver);
      end;
      DiffNumberOfErrors := LogDatei.NumberOfErrors - OldNumberOfErrors;
      FNumberOfErrors := NumberOfErrors + DiffNumberOfErrors;
    End
    {$ELSE}
    StringResult := 'No Windows';
    {$ENDIF WINDOWS}
 End

 else if LowerCase(s) = LowerCase('GetLinuxDistroType')
 then
 Begin
    syntaxcheck := true;
    StringResult := 'no_linux';
    {$IFDEF LINUX}
    StringResult := getLinuxDistroType;
    {$ENDIF LINUX}
 End

 else if LowerCase(s) = LowerCase('GetSystemtype')
 then
 Begin
    syntaxcheck := true;
    if Is64BitSystem
      then
        StringResult := '64 Bit System'
      else
        StringResult := 'x86 System';
 End

 else if LowerCase(s) = LowerCase('GetUsercontext')
 then
 Begin
    syntaxcheck := true;
    StringResult := usercontext;
 End

 else if LowerCase(s) = LowerCase('GetLoggedInUser')
 then
 Begin
    syntaxcheck := true;
    StringResult := getLoggedInUser;
 End

 else if LowerCase(s) = LowerCase('readVersionFromProfile')
 then
 Begin
    syntaxcheck := true;
    StringResult := readVersionFromProfile;
 End


 else if LowerCase(s) = LowerCase('GetScriptMode')
 then
 Begin
    syntaxcheck := true;
    case  scriptMode of
      tsmMachine: StringResult := 'Machine';
      tsmLogin: StringResult := 'Login';
    end;
 End


 else if LowerCase(s) = LowerCase ('GetMSVersionInfo')
 then
 Begin
    syntaxCheck := true;

    OldNumberOfErrors := LogDatei.NumberOfErrors;

    if GetUibOsType (errorinfo) <> tovWinNT
    then
      StringResult := 'Not an OS of type Windows NT'
    else
    Begin
      {$IFDEF WINDOWS}
      OldNumberOfErrors := LogDatei.NumberOfErrors;

      majorVer := GetuibNTversion (ErrorInfo);
      if majorVer = tntverNONE
      then
      Begin
        LogDatei.dependentAddError (ErrorInfo, BaseLevel);
        StringResult := ErrorInfo;
      End
      else
      Begin
        StringResult := intToStr (GetNTVersionMajor) + '.' + intToStr(GetNTVersionMinor);
      end;

      DiffNumberOfErrors := LogDatei.NumberOfErrors - OldNumberOfErrors;
      FNumberOfErrors := NumberOfErrors + DiffNumberOfErrors;
      {$ENDIF WINDOWS}
    End
 End

 else if LowerCase (s) = LowerCase ('IniVar')  then
 Begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
     StringResult := ProductvarsForPC.Values [s1];
     syntaxCheck := true;
   End
 End

 else if LowerCase (s) = LowerCase ('GetProductProperty')  then
 Begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip(',', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s2, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   begin
     syntaxCheck := true;
     //writeln('GetProductProperty');
     (*
     // test:
     list1 := TXStringList.create;
     list1.Add('a=wert1');
     list1.add('b=wert2');
     *)

     //if list1.indexOfName(s1) = -1
     if ProductvarsForPC.indexOfName(s1) = -1
     then
       StringResult := s2
     else
       //StringResult := list1.Values[s1];
       StringResult := ProductvarsForPC.Values [s1];
   End
 End

 else if LowerCase (s) = LowerCase ('GetHostsName') then
 Begin
   if Skip ('(', r, r, InfoSyntaxError)
   then
   if Skip ('"', r, r, InfoSyntaxError)
   then
   Begin
     GetWord (r, s1, r, ['"']);

     if Skip ('"', r, r, InfoSyntaxError) then
     if Skip (')', r, r, InfoSyntaxError) then
     Begin
       syntaxCheck := true;
       //StringResult := GetHostByName(s1);

       HostsImage := TuibPatchHostsFile.Create;
       Logdatei.LogLevel := LogLevel;
       Logdatei.LogSIndentLevel := 0;

       OldNumberOfErrors := LogDatei.NumberOfErrors;
       OldNumberOfWarnings := LogDatei.NumberOfWarnings;

       HostsLocation := DefaultHosts;

       if not FileExists (HostsLocation)
       then
       begin
         LogDatei.dependentAddError ('Error: Hosts ' + HostsLocation + ' not found', BaseLevel);
       end
       else
       begin
         HostsImage.LoadFromFile (HostsLocation);
         HostsImage.GetHostname (s1, StringResult)
       end;
       HostsImage.free; HostsImage := nil;

       DiffNumberOfErrors := LogDatei.NumberOfErrors - OldNumberOfErrors;
       DiffNumberOfWarnings := LogDatei.NumberOfWarnings - OldNumberOfWarnings;
       FNumberOfErrors := NumberOfErrors + DiffNumberOfErrors;
       FNumberOfWarnings := NumberOfWarnings + DiffNumberOfWarnings;

     end;

   End;

 End

 else if LowerCase (s) =  LowerCase ('GetHostsAddr') then
 Begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
     syntaxCheck := true;

     HostsImage := TuibPatchHostsFile.Create;
     Logdatei.LogLevel := LogLevel;
     Logdatei.LogSIndentLevel := 0;

     OldNumberOfErrors := LogDatei.NumberOfErrors;
     OldNumberOfWarnings := LogDatei.NumberOfWarnings;

     HostsLocation := DefaultHosts;

     if not FileExists (HostsLocation)
     then
     begin
       Logdatei.dependentAdd('Hosts ' + HostsLocation + ' not found', LLerror);
     end
     else
     begin
       HostsImage.LoadFromFile (HostsLocation);
       HostsImage.GetAddress (s1, StringResult)
     end;
     HostsImage.free; HostsImage := nil;

     DiffNumberOfErrors := LogDatei.NumberOfErrors - OldNumberOfErrors;
     DiffNumberOfWarnings := LogDatei.NumberOfWarnings - OldNumberOfWarnings;
     FNumberOfErrors := NumberOfErrors + DiffNumberOfErrors;
     FNumberOfWarnings := NumberOfWarnings + DiffNumberOfWarnings;
   End;
 End

 {$IFDEF WIN32}
 else if LowerCase (s) = LowerCase ('GetMyIpByTarget') then
 Begin
   if Skip ('(', r, r, InfoSyntaxError)
    then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
     syntaxCheck := true;
     if isip(s1) then
       StringResult := getMyIpByTarget(s1)
     else
     begin
       StringResult :=  '';
       Logdatei.dependentAdd('Error: '+s1+' is not a valid IP Address', LLerror);
     end;
   End;
 End
 {$ENDIF WIN32}


 else if LowerCase (s) = LowerCase ('GetIpByName') then
 Begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
     syntaxCheck := true;
     if GetIPFromHost(s1,s2,s3) then StringResult := s2
     else
     begin
       {$IFDEF LINUX}
       StringResult :=  getCommandResult('resolveip -s '+s1);
       {$ENDIF LINUX}
       {$IFDEF WINDOWS}
       StringResult :=  '';
       Logdatei.dependentAdd('Error: '+s3, LLerror);
       {$ENDIF WINDOWS}
     end;
   End;
 End



 else if LowerCase (s) =  LowerCase ('GetIni') then
 Begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip ('[', r, r, InfoSyntaxError)
   then
   Begin
     s1 := ExpandFileName(s1);
     Inifile := TInifile.Create (s1);
     GetWord (r, s1, r, WordDelimiterSet0);
     if Skip (']', r, r, InfoSyntaxError)
     then
     Begin
       GetWord (r, sx, r, WordDelimiterSet1);
       if Skip (')', r, r, InfoSyntaxError)
       then
       Begin
         StringResult := Inifile.ReadString (s1, sx, '' (* 'ERROR' *));
         syntaxCheck := true;
       end;
     end;
     Inifile.free; Inifile := nil;
   End;
 End

 else if LowerCase (s) =  LowerCase ('GetValueFromInifile') then
 Begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (',', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s2, InfoSyntaxError)
   then if Skip (',', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s3, InfoSyntaxError)
   then if Skip (',', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s4, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
     syntaxCheck := true;
     try
       s1 := ExpandFileName(s1);
       Inifile := TInifile.Create (s1);

       LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
       LogDatei.DependentAdd
       ('    reading the value to the key "' +  s3 + '" in section "' +  s2 + '"  from inifile  "' + s1 + '", default value  "' + s4 +'"',
       LevelComplete);
       StringResult := Inifile.ReadString( s2, s3, s4);
       LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 2;

       Inifile.free; Inifile := nil;
     except
       on e: Exception
          do
          Begin
              LogDatei.DependentAdd ('Error in creating inifile "' + s1 + '", message: "' + e.Message + '"', LevelWarnings);
              StringResult := s4;
          End;
     end;

   End;
 End


 else if LowerCase (s) = LowerCase ('Lower') then
 begin
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (')', r,r, InfoSyntaxError)
     then
     Begin
         syntaxCheck := true;
         StringResult := lowercase(s1);
     End;
 end

 else if LowerCase (s) = LowerCase ('Upper') then
 begin
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (')', r,r, InfoSyntaxError)
     then
     Begin
         syntaxCheck := true;
         StringResult := uppercase(s1);
     End;
 end

 else if LowerCase (s) = LowerCase ('Trim') then
 begin
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (')', r,r, InfoSyntaxError)
     then
     Begin
         syntaxCheck := true;
         StringResult := trim(s1);
     End;
 end

  else if LowerCase (s) = LowerCase ('calculate') then
 begin
  syntaxCheck := false;
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (')', r,r, InfoSyntaxError)
     then
     Begin
         syntaxCheck := true;
         if not opsicalc(s1,StringResult) then
         begin
           LogDatei.DependentAdd ('Error in calculate : could not calculate : ' + s1 + ' ; '+StringResult, LLError);
           StringResult := '';
         end;
     End;
  if  not syntaxCheck then
  begin
   LogDatei.DependentAdd ('Error in calculate : could not calculate : ' + s1 + ' ; '+InfoSyntaxError, LLError);
  end;
 end


 else if LowerCase (s) = LowerCase ('strLength') then
 begin
  syntaxCheck := false;
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (')', r,r, InfoSyntaxError)
     then
     Begin
         syntaxCheck := true;
         StringResult := IntToStr(length(s1));
     End;
  if  not syntaxCheck then
  begin
   LogDatei.DependentAdd ('Error in strLength : could not get length of : ' + s1 + ' ; '+InfoSyntaxError, LLError);
  end;
 end

 else if LowerCase (s) = LowerCase ('strLoadTextFile')
 then
 begin
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
   Begin
     try
       list1 := TXStringList.create;
       s1 := ExpandFileName(s1);
       list1.loadfromfile (s1);
       StringResult:= reencode(list1.Text, 'system');
       list1.Free;
     except
       on e: exception do
       begin
         LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
         LogDatei.DependentAddError('Error on loading file: ' + e.message,
           BaseLevel);
         FNumberOfErrors := FNumberOfErrors + 1;
         LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 2;
       end
     end;
     if Skip (')', r,r, InfoSyntaxError)
     then
     Begin
       syntaxCheck := true;
     End
   End
 end

 else if LowerCase (s) = LowerCase ('strPos') then
 begin
  syntaxCheck := false;
  if Skip ('(', r, r, InfoSyntaxError)
     and EvaluateString(r,r,s1, InfoSyntaxError)
     and Skip(',', r, r, InfoSyntaxError)
     and EvaluateString(r,r,s2, InfoSyntaxError)
     and Skip (')', r, r, InfoSyntaxError)
  then
    Begin
      syntaxCheck := true;
      StringResult := IntToStr(pos(s2,s1));
    End;
  if  not syntaxCheck then
  begin
   LogDatei.DependentAdd ('Error in strPos : could not get pos of : ' + s2 + 'in : '+s1+' ; '+InfoSyntaxError, LLError);
  end;
 end

 else if LowerCase (s) = LowerCase ('strPart') then
 begin
  syntaxCheck := false;
  if Skip ('(', r, r, InfoSyntaxError)
     and EvaluateString(r,r,s1, InfoSyntaxError)
     and Skip(',', r, r, InfoSyntaxError)
     and EvaluateString(r,r,s2, InfoSyntaxError)
     and Skip(',', r, r, InfoSyntaxError)
     and EvaluateString(r,r,s3, InfoSyntaxError)
     and Skip (')', r, r, InfoSyntaxError)
  then
    Begin
      syntaxCheck := true;
      try
        n1 := StrToInt(LowerCase(trim(s2)));
        try
          n2 := StrToInt(LowerCase(trim(s3)));
          StringResult := copy(s1,n1,n2);
          LogDatei.DependentAdd('strPart from: ' + s1 + ' start: '+inttostr(n1)+' number: '+inttostr(n2)+' gives: >'+stringresult+'<', LLDebug2);
        except
          LogDatei.DependentAddError('Error: ' + s2 + ' has no Integer format', LLerror)
        end;
      except
        LogDatei.DependentAddError('Error: ' + s3 + ' has no Integer format', LLerror)
      end;
    End;
   if  not syntaxCheck then
  begin
   LogDatei.DependentAdd ('Error in strPart : could not get part of : ' + s1 + ' ; '+InfoSyntaxError, LLError);
  end;
 end

 else if LowerCase (s) = LowerCase ('randomIntStr') then
 begin
  syntaxCheck := false;
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (')', r,r, InfoSyntaxError)
     then
     Begin
         syntaxCheck := true;
         //LogDatei.DependentAdd ('incStr for : ' + s1 , LLDebug2);
         try
           intresult := StrToInt(s1);
           //LogDatei.DependentAdd ('incStr for : ' + IntToStr(intresult) , LLDebug2);
           //Randomize;
           StringResult := IntToStr(random(intresult));
           //LogDatei.DependentAdd ('incStr for : ' + IntToStr(intresult) , LLDebug2);
           //StringResult := IntToStr(intresult);
         except
           on E:Exception do
           LogDatei.DependentAdd ('Error in randomIntStr : perhaps could not convert to int : ' + s1 + ' Error : '+E.Message, LLError);
         end;
     End;
  if  not syntaxCheck then
  begin
   LogDatei.DependentAdd ('Error in randomIntStr : could not make random for : ' + s1 + ' ; '+InfoSyntaxError, LLError);
  end;
 end
(*
 else if LowerCase (s) = LowerCase ('decStr') then
 begin
  syntaxCheck := false;
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (')', r,r, InfoSyntaxError)
     then
     Begin
         syntaxCheck := true;
         LogDatei.DependentAdd ('decStr for : ' + s1 , LLDebug2);
         try
           intresult := StrToInt(s1);
           dec(intresult);
           StringResult := IntToStr(intresult);
         except
           on E:Exception do
           LogDatei.DependentAdd ('Error in decStr : could not dec : ' + s1 + ' Error : '+E.Message, LLError);
         end;
     End;
  if  not syntaxCheck then
  begin
   LogDatei.DependentAdd ('Error in decStr : could not get dec : ' + s1 + ' ; '+InfoSyntaxError, LLError);
  end;
 end
*)

 else if LowerCase (s) = LowerCase ('LangCodeByHex') then
 begin
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (')', r,r, InfoSyntaxError)
     then
     Begin
      syntaxCheck := true;
      s1 := LowerCase(trim(s1));
      if pos('$',s1) = 1 then
        s1 := copy(s1,2,length(s1));
      if pos('0x',s1) = 1 then
        s1 := copy(s1,3,length(s1));
      try
        StringResult := getlangcodeByHexvalueStr('0x'+s1);
      except
        LogDatei.DependentAddError('Error: ' + s1 + ' has no Integer format', BaseLevel)
      end;
     End;
 end


 else if LowerCase (s) = LowerCase ('HexStrToDecStr') then
 begin
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (')', r,r, InfoSyntaxError)
     then
     Begin
      syntaxCheck := true;
      s1 := LowerCase(trim(s1));
      if pos('$',s1) = 1 then
        s1 := copy(s1,2,length(s1));
      if pos('0x',s1) = 1 then
        s1 := copy(s1,3,length(s1));
      try
        StringResult := IntToStr(StrToInt('$'+s1));
      except
        LogDatei.DependentAddError('Error: ' + s1 + ' has no Integer format', BaseLevel)
      end;
     End;
 end

 else if LowerCase (s) = LowerCase ('DecStrToHexStr') then
 begin
  if Skip ('(', r, r, InfoSyntaxError)
     and EvaluateString(r,r,s1, InfoSyntaxError)
     and Skip(',', r, r, InfoSyntaxError)
     and EvaluateString(r,r,s2, InfoSyntaxError)
     and Skip (')', r, r, InfoSyntaxError)
  then
    Begin
      syntaxCheck := true;
      s1 := LowerCase(trim(s1));
      try
        n2 := StrToInt(LowerCase(trim(s2)));
        try
          n1 := StrToInt(s1);
          StringResult := IntToHex(n1,n2);
        except
          LogDatei.DependentAddError('Error: ' + s1 + ' has no Integer format', LLerror)
        end;
      except
        LogDatei.DependentAddError('Error: ' + s2 + ' has no Integer format', LLerror)
      end;
    End;
 end

 else if LowerCase (s) = LowerCase ('base64EncodeStr') then
 begin
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (')', r,r, InfoSyntaxError)
     then
     Begin
      syntaxCheck := true;
      StringResult := B64Encode(s1);
    End;
 end

 else if LowerCase (s) = LowerCase ('base64DecodeStr') then
 begin
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (')', r,r, InfoSyntaxError)
     then
     Begin
      syntaxCheck := true;
      StringResult := B64Decode(s1);
    End;
 end

 else if LowerCase (s) = LowerCase ('Convert2JsonStr') then
 begin
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (')', r,r, InfoSyntaxError)
     then
     Begin
      syntaxCheck := true;
      str2jsonstr(s1, s2);
      if s2 = 'ok' then
        StringResult := s1
      else
      begin
        StringResult := '';
        LogDatei.DependentAddError('Error: ' + s2, LLerror);
      end

    End;
 end


 else if LowerCase (s) = LowerCase ('RandomStr') then
 begin
   StringResult := randomstr(true);
   syntaxCheck := true;
 end

 else if LowerCase (s) = LowerCase ('createNewOpsiHostKey') then
 begin
   StringResult := createNewOpsiHostKey;
   syntaxCheck := true;
 end


 (* comparison expressions *)
 else if LowerCase (s) = LowerCase ('CompareStrings') then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
     and EvaluateString(r,r,s1, InfoSyntaxError)
     and Skip(',', r, r, InfoSyntaxError)
     and EvaluateString(r,r,s2, InfoSyntaxError)
     and Skip (')', r, r, InfoSyntaxError)
   then
   begin
    syntaxCheck := true;
    StringResult := inttostr (getCompareSignStrings(s1, s2));
   end;
 end

 else if LowerCase (s) = LowerCase ('CompareNumbers') then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
     and EvaluateString(r,r,s1, InfoSyntaxError)
     and Skip(',', r, r, InfoSyntaxError)
     and EvaluateString(r,r,s2, InfoSyntaxError)
     and Skip (')', r, r, InfoSyntaxError)
   then
   begin
    syntaxCheck := true;
    OldNumberOfErrors := LogDatei.NumberOfErrors;

    try
      n1 := StrToInt(s1);
      try
        n2 := StrToInt(s2);
        StringResult := inttostr (getCompareSign(n1, n2));
      except
        LogDatei.DependentAddError('Error: ' + s2 + ' has no Integer format', BaseLevel);
      end;
    except
      LogDatei.DependentAddError('Error: ' + s1 + ' has no Integer format', BaseLevel)
    end;

    DiffNumberOfErrors := LogDatei.NumberOfErrors - OldNumberOfErrors;
    FNumberOfErrors := NumberOfErrors + DiffNumberOfErrors;
   end;
 end

 else if LowerCase (s) = LowerCase ('CompareDotSeparatedNumbers') then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
     and EvaluateString(r,r,s1, InfoSyntaxError)
     and Skip(',', r, r, InfoSyntaxError)
     and EvaluateString(r,r,s2, InfoSyntaxError)
     and Skip (')', r, r, InfoSyntaxError)
   then
   begin
    syntaxCheck := true;
    OldNumberOfErrors := LogDatei.NumberOfErrors;

    if getDecimalCompareSign(s1, s2, intresult, errorinfo, false)
    then
      StringResult := inttostr (intresult)
    else
      LogDatei.DependentAddError('Error: ' + errorinfo, BaseLevel);

    DiffNumberOfErrors := LogDatei.NumberOfErrors - OldNumberOfErrors;
    FNumberOfErrors := NumberOfErrors + DiffNumberOfErrors;
   end;
 end

 else if LowerCase (s) = LowerCase ('CompareDotSeparatedStrings') then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
     and EvaluateString(r,r,s1, InfoSyntaxError)
     and Skip(',', r, r, InfoSyntaxError)
     and EvaluateString(r,r,s2, InfoSyntaxError)
     and Skip (')', r, r, InfoSyntaxError)
   then
   begin
    syntaxCheck := true;

    OldNumberOfErrors := LogDatei.NumberOfErrors;

    if getDecimalCompareSign(s1, s2, intresult, errorinfo, true)
    then
      StringResult := inttostr (intresult)
    else
      LogDatei.DependentAddError('Error: ' + errorinfo, BaseLevel);

    DiffNumberOfErrors := LogDatei.NumberOfErrors - OldNumberOfErrors;
    FNumberOfErrors := NumberOfErrors + DiffNumberOfErrors;
   end;
 end


 else if LowerCase (s) = LowerCase ('ParamStr') then
 begin
   StringResult := ExtraParameter;
   syntaxCheck := true;
 end

 else if LowerCase (s) = LowerCase ('SubstringBefore')
 then
 begin
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (',', r,r, InfoSyntaxError)
     then
      if EvaluateString (r,r, s2, InfoSyntaxError)
      then
       if Skip (')', r,r, InfoSyntaxError)
       then
       Begin
         syntaxCheck := true;

         StringResult := '';
         if  (length (s1) >= length (s2))
            and (copy (s1, length(s1) - length(s2) + 1, length (s2)) = s2)

         then
           StringResult := copy (s1, 1, length(s1) - length(s2))
       End
 End


 else if LowerCase (s) = LowerCase ('unquote')
 then
 begin
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (',', r,r, InfoSyntaxError)
     then
      if EvaluateString (r,r, s2, InfoSyntaxError)
      then
       if Skip (')', r,r, InfoSyntaxError)
       then
       Begin
         syntaxCheck := true;
         StringResult := opsiUnquotestr(s1,s2);
         (*
         if  (length(s1) >= 1) and (length(s2) >= 1) then
         begin
          tempchar := trim(s2)[1];
          tempansistr := s1;
          tempansistrp := pansichar(tempansistr);
           StringResult := AnsiExtractQuotedStr(tempansistrp,tempchar);
           // s1 was not quoted then give back s1
           if StringResult = '' then  StringResult := s1;
           // s1 was not quoted by s2 then give back s1
           // and (ansipos('NULL',s1)=0)
           if (StringResult = NULL_STRING_VALUE)  then  StringResult := s1;
         end;
         *)
       End
 End



 else if LowerCase (s) = LowerCase ('stringreplace')
 then
 begin
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (',', r,r, InfoSyntaxError)
     then
      if EvaluateString (r,r, s2, InfoSyntaxError)
      then
        if Skip (',', r,r, InfoSyntaxError)
        then
         if EvaluateString (r,r, s3, InfoSyntaxError)
         then
          if Skip (')', r,r, InfoSyntaxError)
          then
          Begin
            syntaxCheck := true;
            StringResult := StringReplace1(s1,s2,s3);
            if (StringResult = NULL_STRING_VALUE)  then  StringResult := s1;
          End
 End

 else if LowerCase (s) = LowerCase ('reencodestr')
 then
 begin
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (',', r,r, InfoSyntaxError)
     then
      if EvaluateString (r,r, s2, InfoSyntaxError)
      then
        if Skip (',', r,r, InfoSyntaxError)
        then
         if EvaluateString (r,r, s3, InfoSyntaxError)
         then
          if Skip (')', r,r, InfoSyntaxError)
          then
          Begin
            syntaxCheck := true;
            StringResult := reencode(s1,s2,s3);
          End
 End

 else if LowerCase (s) = LowerCase ('StringSplit')
   // deprecated, please replace by splitting the string by splitstring and
   // returning a specific part by takestring
 then
 begin
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (',', r,r, InfoSyntaxError)
     then
      if EvaluateString (r, r, s2, InfoSyntaxError)
      then
       if Skip (',', r,r, InfoSyntaxError)
       then
        if EvaluateString (r, r, sx, InfoSyntaxError)
        then
           if Skip (')', r,r, InfoSyntaxError)
           then
           Begin
             syntaxCheck := true;

             itemlist.free;
             itemlist := TXStringList.create;
             stringsplit (s1, s2, itemlist);

             try
                ListIndex := strtoint (sx);
             except
                syntaxCheck := false;
                InfoSyntaxError := sx + ' keine ganze Zahl';
                ListIndex := 0;
             end;

             if ListIndex >= itemList.count
             then
             Begin
                StringResult := '';
                OldNumberOfWarnings := LogDatei.NumberOfWarnings;
                LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;
                LogDatei.DependentAddWarning  ('Warning: String "' + s1 + '" using delimiter "'
                                              + s2 + '" was not splitted in ('
                                              + inttostr (ListIndex) + ' + 1)  parts', LevelWarnings);
                DiffNumberOfWarnings := LogDatei.NumberOfWarnings - OldNumberOfWarnings;
                FNumberOfWarnings := NumberOfWarnings + DiffNumberOfWarnings;
                LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;
            End
             else
                StringResult := itemlist[ListIndex];
           End
 End


 else if LowerCase (s) = LowerCase ('takeString')
 then
 begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
    Begin
       syntaxcheck := true;
       stringresult := '';
       try
         GetWord (r, s1, r, [',']);

         a1 := strtoint(s1);

         syntaxCheck := Skip(',', r, r, InfoSyntaxError);
       except
          try
            sx := s1;
            if EvaluateString (s1, s1, s2, InfoSyntaxError) then
            begin
              a1 := strtoint(s2);
              syntaxCheck := Skip(',', r, r, InfoSyntaxError);
            end
            else  a1 := strtoint(sx);
          except
            syntaxcheck := false;
            InfoSyntaxError := ' No valid index for list ';
          end;
       end;

       if syntaxCheck then
       Begin
         list1 := TXStringList.create;
         r1 := r;
         if not produceStringList (script,r, r, list1, InfoSyntaxError)
         or not Skip (')', r,r, InfoSyntaxError)
         then
            syntaxCheck := false
         else
         Begin
           if list1.count = 0 then // list is empty
           begin
             Logdatei.log('Stringlist '+ r1 + ' is empty in takeString function ! Use count() before takestring() to avoid this problem.',LLWarning);
             if FatalOnRuntimeError then
             begin
               Logdatei.log('Set to FatalError because FatalOnRuntimeError is set',LLCritical);
               FExtremeErrorLevel := LevelFatal;
               LogDatei.ActionProgress:='Runtime Error';
             end;
           end
           else
           begin
             if (a1 < 0)
             then
                a1 := list1.count + a1; //we count downward

             if (a1 < 0) or (a1 > list1.count - 1)
             then
             begin
               Logdatei.log ('Stringlist list ' + r1 + ' has '+ intToStr(list1.count) +' elements. And the effective list index ' + inttostr (a1)
                          + ' is out of bounds in takeString function ! Use count() before takestring() to avoid this problem.',LLError);
               if FatalOnRuntimeError then
               begin
                 Logdatei.log('Set to FatalError because FatalOnRuntimeError is set',LLCritical);
                 FExtremeErrorLevel := LevelFatal;
                 LogDatei.ActionProgress:='Runtime Error';
               end;
             end
             else
               stringresult := list1[a1];
           end;
         End;

         list1.Free;
         list1 := nil;
       End
    End
 End

 else if LowerCase (s) = LowerCase ('count')
 then
 begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
    Begin
       syntaxcheck := true;
       stringresult := '';
       list1 := TXStringList.create;

       if not produceStringList (script, r, r, list1, InfoSyntaxError)
         or not Skip (')', r,r, InfoSyntaxError)
       then
            syntaxCheck := false
       else
       Begin
         stringresult := intToStr(list1.count);
         list1.Free;
         list1 := nil;
       End
    End
 End

 else if LowerCase (s) = LowerCase ('getValue')
 then
 begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
    Begin
       syntaxcheck := true;
       stringresult := '';

       if not evaluateString (r, r, s1, InfoSyntaxError)
       or
       not Skip (',', r,r, InfoSyntaxError)
       then syntaxCheck := false;

       if syntaxCheck then
       Begin
         list1 := TXStringList.create;

         if not produceStringList (script, r, r, list1, InfoSyntaxError)
         or not Skip (')', r,r, InfoSyntaxError)
         then
            syntaxCheck := false
         else
         Begin
             stringresult := list1.getStringValue(s1);//list1.values[s1];
             // if key does not exist we get NULL_STRING_VALUE
             (*
             if stringresult = NULL_STRING_VALUE then
             begin
               // let us retry with trimed keys
               for i := 0 to list1.Count -1 do
               begin
                 if list1.Names[i] <> '' then
                   if lowerCase(trim(list1.Names[i])) = lowerCase(trim(s1)) then
                     stringresult := list1.getStringValue(list1.Names[i]);
               end;
             end;
             *)
         End;

         list1.Free;
         list1 := nil;
       End
    End
 End

 else if LowerCase (s) = LowerCase ('getValueBySeparator')
 then
 begin
   syntaxCheck := false;
   stringresult := '';
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (',', r,r, InfoSyntaxError)
     then
      if EvaluateString (r, r, s2, InfoSyntaxError)
      then
       if Skip (',', r,r, InfoSyntaxError)
       then
         syntaxCheck := true;


       if syntaxCheck then
       Begin
         list1 := TXStringList.create;

         if not produceStringList (script, r, r, list1, InfoSyntaxError)
         or not Skip (')', r,r, InfoSyntaxError)
         then
            syntaxCheck := false
         else
         Begin
           // use the first char of the second argument as separator char
           list1.NameValueSeparator := trim(s2)[1];
           stringresult := list1.getStringValue(s1);//list1.values[s1];
           // if key does not exist we get NULL_STRING_VALUE
           (*
           if stringresult = NULL_STRING_VALUE then
             begin
               // let us retry with trimed keys
               for i := 0 to list1.Count -1 do
               begin
                 if list1.Names[i] <> '' then
                   if lowerCase(trim(list1.Names[i])) = lowerCase(trim(s1)) then
                     stringresult := list1.getStringValue(list1.Names[i]);
               end;
             end;
           *)
         End;

         list1.Free;
         list1 := nil;
       End
 End

 else if LowerCase (s) = LowerCase ('getValueFromFile')
 then
 begin
    if Skip ('(', r, r, InfoSyntaxError)
    then
    Begin
       syntaxcheck := true;
       stringresult := '';

       if not evaluateString (r, r, s1, InfoSyntaxError)
       or
       not Skip (',', r,r, InfoSyntaxError)
       then syntaxCheck := false;

       if syntaxCheck then
       Begin
         list1 := TXStringList.create;
         if EvaluateString (r, r, s3, InfoSyntaxError)
         then
         Begin
           try
             s3 := ExpandFileName(s3);
             list1.loadfromfile (s3);
             list1.Text:= reencode(list1.Text, 'system');
           except
             on e: exception do
             begin
               LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
               LogDatei.log('Error on loading file: ' + e.message, LLError);
               LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 2;
             end
           end;
           if not Skip (')', r,r, InfoSyntaxError)
           then
              syntaxCheck := false
           else
           Begin
             syntaxCheck := true;
             stringresult := list1.getStringValue(s1);//list1.values[s1];
             // if key does not exist we get NULL_STRING_VALUE
             (*
             if stringresult = NULL_STRING_VALUE then
             begin
               // let us retry with trimed keys
               for i := 0 to list1.Count -1 do
               begin
                 if list1.Names[i] <> '' then
                   if lowerCase(trim(list1.Names[i])) = lowerCase(trim(s1)) then
                     stringresult := list1.getStringValue(list1.Names[i]);
               end;
             end;
             *)
           End;
         end;
         list1.Free;
         list1 := nil;
       End
    End
 End


 else if LowerCase (s) = LowerCase ('getValueFromFileBySeparator')
 then
 begin
   syntaxCheck := false;
   stringresult := '';
  if Skip ('(', r, r, InfoSyntaxError)
  then
   if EvaluateString (r, r, s1, InfoSyntaxError)
   then
     if Skip (',', r,r, InfoSyntaxError)
     then
      if EvaluateString (r, r, s2, InfoSyntaxError)
      then
       if Skip (',', r,r, InfoSyntaxError)
       then
         syntaxCheck := true;


       if syntaxCheck then
       Begin
         list1 := TXStringList.create;
         if EvaluateString (r, r, s3, InfoSyntaxError)
         then
         Begin
           try
             s3 := ExpandFileName(s3);
             list1.loadfromfile (s3);
             list1.Text:= reencode(list1.Text, 'system');
           except
             on e: exception do
             begin
               LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
               LogDatei.log('Error on loading file: ' + e.message, LLError);
               LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 2;
             end
           end;
           if not Skip (')', r,r, InfoSyntaxError)
           then
              syntaxCheck := false
           else
           Begin
             syntaxCheck := true;
             // use the first char of the second argument as separator char
             list1.NameValueSeparator := trim(s2)[1];
             stringresult := list1.getStringValue(s1);//list1.values[s1];
             // if key does not exist we get NULL_STRING_VALUE
             (*
             if stringresult = NULL_STRING_VALUE then
             begin
               // let us retry with trimed keys
               for i := 0 to list1.Count -1 do
               begin
                 if list1.Names[i] <> '' then
                   if lowerCase(trim(list1.Names[i])) = lowerCase(trim(s1)) then
                     stringresult := list1.getStringValue(list1.Names[i]);
               end;
             end;
             *)
           End;
         end;
         list1.Free;
         list1 := nil;
       End
 End

  else if LowerCase (s) = LowerCase ('takeFirstStringContaining')
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then
   Begin

     list1 := TXStringList.create;

     if produceStringList (script, r, r, list1, InfoSyntaxError)
        and skip (',', r, r, InfoSyntaxError)
     then
     Begin
       if EvaluateString (r, r, s1, InfoSyntaxError)
       and
       skip (')', r, r, InfoSyntaxError)
       then
       Begin
         SyntaxCheck := true;
         stringResult := '';
         i := 0;
         while (stringResult = '') and (i < list1.Count) do
         begin
           if AnsiContainsText(list1[i], s1) then
            stringResult := list1[i]
           else
             inc(i);
         end;
       End
     End
   End;
 End

 else if LowerCase (s) = LowerCase ('composeString')
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then
   Begin

     list1 := TXStringList.create;

     if produceStringList (script, r, r, list1, InfoSyntaxError)
        and skip (',', r, r, InfoSyntaxError)
     then
     Begin
       if EvaluateString (r, r, s1, InfoSyntaxError)
       and
       skip (')', r, r, InfoSyntaxError)
       then
       Begin
         SyntaxCheck := true;
         stringResult := '';
         for i := 0 to list1.Count - 2
         do
           stringResult := stringResult + list1.strings[i] + s1;

         stringResult := stringResult + list1[list1.count-1];
       End
     End
   End;
 End

 else if LowerCase (s) = LowerCase ('ExtractFilePath')
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then
    if EvaluateString (r, r, s1, InfoSyntaxError)
    then
      if Skip (')', r, r, InfoSyntaxError)
      then
      Begin
        try
         StringResult := ExtractFilePath (s1);
         syntaxCheck := true;
        except
          InfoSyntaxError := '"' + s1 + '" is not a valid file path';
        end;
      End
 end

  else if LowerCase (s) = LowerCase ('RegString')
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
     StringResult := CEscaping (s1);
     syntaxCheck := true;
   End
 end

 {$IFDEF WINDOWS}
 {$IFDEF WIN32}
 else if LowerCase (s) = LowerCase ('SidToName')
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then
    if EvaluateString (r, r, s1, InfoSyntaxError)
    then
      if Skip (')', r, r, InfoSyntaxError)
      then
      Begin
        try
         StringResult := StrSIDToName (s1);
         syntaxCheck := true;
        except
          InfoSyntaxError := '"' + s1 + '" is not a valid sid string';
        end;
      End
 end

 else if LowerCase (s) = LowerCase ('NameToSID')
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then
    if EvaluateString (r, r, s1, InfoSyntaxError)
    then
      if Skip (')', r, r, InfoSyntaxError)
      then
      Begin
        try
         StringResult := GetLocalUserSidStr(s1);
         syntaxCheck := true;
        except
          InfoSyntaxError := '"' + s1 + '" is not a valid sid string';
        end;
      End
 end
{$ENDIF WIN32}


 else if (LowerCase (s) = LowerCase ('GetRegistryStringValue'))
        or (LowerCase (s) = LowerCase ('GetRegistryStringValue32'))
  then
  begin
    if Skip ('(', r, r, InfoSyntaxError)
    then if EvaluateString (r, r, s1, InfoSyntaxError)
    then if Skip (')', r, r, InfoSyntaxError)
    then if Skip ('[', s1, r1, InfoSyntaxError)
    then
    Begin
      GetWord (r1, key, r1, [']']);
      GetWord (key, key0, key, ['\']);
      System.delete (key, 1, 1);

      if Skip (']', r1, r1, InfoSyntaxError)
      then
      Begin
        SyntaxCheck := true;
        ValueName := CutRightBlanks (r1);

        StringResult := '';
        LogDatei.DependentAdd ('key0 = '+key0, LLdebug2);
        if runLoginScripts and (('HKEY_CURRENT_USER' = UpperCase(key0)) or ('HKCU' = UpperCase(key0))) then
        begin
          // remove HKCU from the beginning
          // switch to HKEY_USERS
          key0 := 'HKEY_USERS';
          key := usercontextSID+'\'+key;
          LogDatei.DependentAdd ('Running loginscripts: key0 is now: '+key0 + ', key is now: '+key, LLdebug);
        end;

          Regist := Tuibregistry.Create;
          //StartIndentLevel := LogDatei.LogSIndentLevel;
          LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;
          if Regist.OpenExistingKey (key0, key)
          then
          Begin
            try
               StringResult := Regist.ReadString (ValueName);
            except
               try
                  Regist.ReadEntry (Valuename, RegType, StringResult);
                  { in ReadString abgehandelt:
                  if RegType = trdmultistring
                  then
                    StringResult := StringReplace (StringResult, #13#10, MultiszVisualDelimiter);
                  }
               except
               end;
            end;
            Regist.CloseKey;
          End;
          //LogDatei.LogSIndentLevel := StartIndentLevel;
          Regist.free; Regist := nil;
        End
    End;
  end

  else if (LowerCase (s) = LowerCase ('GetRegistryStringValue64'))
        or (LowerCase (s) = LowerCase ('GetRegistryStringValueSysNative'))
  then
  begin
    if Skip ('(', r, r, InfoSyntaxError)
    then if EvaluateString (r, r, s1, InfoSyntaxError)
    then if Skip (')', r, r, InfoSyntaxError)
    then if Skip ('[', s1, r1, InfoSyntaxError)
    then
    Begin
      GetWord (r1, key, r1, [']']);
      GetWord (key, key0, key, ['\']);
      System.delete (key, 1, 1);

      if Skip (']', r1, r1, InfoSyntaxError)
      then
      Begin
        SyntaxCheck := true;
        ValueName := CutRightBlanks (r1);

        StringResult := '';
        if (GetNTVersionMajor = 5) and (GetNTVersionMinor = 0) then
        begin
          // we are on win 2000 which can't handle redirections flags
          Regist := Tuibregistry.Create;
        end
        else // we are on xp or higher
        begin
          Regist := Tuibregistry.Create(true);
        end;
        LogDatei.DependentAdd ('key0 = '+key0, LLdebug2);
        if runLoginScripts and (('HKEY_CURRENT_USER' = UpperCase(key0)) or ('HKCU' = UpperCase(key0))) then
        begin
          // remove HKCU from the beginning
          // switch to HKEY_USERS
          key0 := 'HKEY_USERS';
          key := usercontextSID+'\'+key;
          LogDatei.DependentAdd ('Running loginscripts: key0 is now: '+key0 + ', key is now: '+key, LLdebug);
        end;

        //StartIndentLevel := LogDatei.LogSIndentLevel;
        LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;
        if Regist.OpenExistingKey (key0, key)
        then
        Begin
          try
             StringResult := Regist.ReadString (ValueName);
          except
             try
                Regist.ReadEntry (Valuename, RegType, StringResult);
                { in ReadString abgehandelt:
                if RegType = trdmultistring
                then
                  StringResult := StringReplace (StringResult, #13#10, MultiszVisualDelimiter);
                }
             except
             end;
          end;
          Regist.CloseKey;
        End;
        //LogDatei.LogSIndentLevel := StartIndentLevel;
        Regist.free; Regist := nil;
      End
    End;
  end

  {$IFDEF WIN32}
  else if LowerCase(s) = LowerCase('GetUserSID')
  then
  begin
    if Skip('(', r, r, InfoSyntaxError)
    then if EvaluateString(r, r, s1, InfoSyntaxError)
    then if Skip(')', r, r, InfoSyntaxError)
    then
    Begin
      if r <> ''
      then InfoSyntaxError := ErrorRemaining
      else
      Begin
        SyntaxCheck := true;
        itemlist := TXStringlist.create;
        stringsplit(s1, '\', itemlist);
        if itemlist.count > 1
        then
        Begin
          s2 := itemlist.Strings[0];
          s3 := itemlist.strings[itemlist.count - 1]
        end
        else
        Begin
          s2 := '';
          s3 := s1;
        End;
        logdatei.DependentAdd('search user: ' + s3 + ' in domain: ' + s2 , LevelComplete);
        s4 := ''; //founddomain
        StringResult := GetDomainUserSidS(s2, s3, s4);

        logdatei.DependentAdd('found in domain ' + s4 + ', SID: ' + StringResult, LevelComplete);

        if length(StringResult) > 1
        then
        Begin
          Skip('[', StringResult, StringResult, InfoSyntaxError);
          if StringResult[length(StringResult)] = ']'
          then StringResult := copy(StringResult, 1, length(StringResult) - 1);
        End;

        if StringResult = ''
        then
        Begin
          OldNumberOfErrors := LogDatei.NumberOfErrors;
          LogDatei.DependentAddError  ('Error: SID not found for "' + s1 + '"', BaseLevel);
          DiffNumberOfErrors := LogDatei.NumberOfErrors - OldNumberOfErrors;
          FNumberOfErrors := NumberOfErrors + DiffNumberOfErrors;
        End
      end
    End
  End
  {$ENDIF WIN32}
  {$ELSE WINDOWS}
  else if LowerCase (s) = LowerCase ('SidToName')
  then
  begin
    SyntaxCheck := false;
    InfoSyntaxError := 'Not implemented for Linux';
    StringResult := 'Error';
    LogDatei.DependentAdd('SyntaxError: SidToName not implemented for Linux',LLError );
  end

  else if LowerCase (s) = LowerCase ('NameToSID')
  then
  begin
    SyntaxCheck := false;
    InfoSyntaxError := 'Not implemented for Linux';
    StringResult := 'Error';
    LogDatei.DependentAdd('SyntaxError: NameToSID not implemented for Linux',LLError );
  end



  else if (LowerCase (s) = LowerCase ('GetRegistryStringValue'))
        or (LowerCase (s) = LowerCase ('GetRegistryStringValue32'))
        or (LowerCase (s) = LowerCase ('GetRegistryStringValue64'))
        or (LowerCase (s) = LowerCase ('GetRegistryStringValueSysNative'))
  then
  begin
    SyntaxCheck := false;
    InfoSyntaxError := 'Not implemented for Linux';
    StringResult := 'Error';
    LogDatei.DependentAdd('SyntaxError: GetRegistryStringValue not implemented for Linux',LLError );
  end


  else if LowerCase(s) = LowerCase('GetUserSID')
  then
  begin
    SyntaxCheck := false;
    InfoSyntaxError := 'Not implemented for Linux';
    StringResult := 'Error';
    LogDatei.DependentAdd('SyntaxError: GetUserSID not implemented for Linux',LLError );
  End
  {$ENDIF WINDOWS}

  else if LowerCase(s) = LowerCase('getLastServiceErrorClass')
  then
  begin
    SyntaxCheck := true;
    testresult := '';
    errorOccured := false;
    if opsidata = nil
    then
    Begin
      errorOccured := true;
      testresult := '!!! no opsidata !!!';
    End
    else
      try
        local_opsidata := opsidata;

        //LogDatei.DependentAdd('Calling opsi service at ' + local_opsidata.serviceUrl, LevelComplete);
      except
        errorOccured := true;
        testresult := '!!! not in service mode !!!';
      end;


      if errorOccured
      then
        stringresult := testresult
      else
      begin
        if local_opsidata.ServiceLastErrorInfo.indexOfName('class') < 0
        then
          stringresult := 'None' //'!!! error key "class" not found !!!'
        else
          stringresult := local_opsidata.ServiceLastErrorInfo.values['class'];
      end
  end


  else if LowerCase(s) = LowerCase('getLastServiceErrorMessage')
  then
  begin
    testresult := '';
    SyntaxCheck := true;
    errorOccured := false;
    if opsidata = nil
    then
    Begin
      errorOccured := true;
      testresult := '!!! no opsidata !!!';
    End
    else
      try
        local_opsidata := opsidata;

        //LogDatei.DependentAdd('Calling opsi service at ' + local_opsidata.serviceUrl, LevelComplete);
      except
        errorOccured := true;
        testresult := '!!! not in service mode !!!';
      end;

     if errorOccured
     then
      stringresult := testresult
     else
     begin
      if local_opsidata.ServiceLastErrorInfo.indexOfName('message') < 0
      then
        stringresult := 'None' //'!!! error key "message" not found !!!'
      else
        stringresult := local_opsidata.ServiceLastErrorInfo.values['message'];
     end;
  end

  else if LowerCase(s) = LowerCase('demandLicenseKey')
  then
   begin
      errorOccured := false;
      syntaxCheck := true;
      testresult := '';

      r := trim(r);
      setLength(parameters, 4);

      parameters[0] := osconf.computername;
      parameters[1] := '';
      parameters[2] := '';
      parameters[3] := '';

      syntaxcheck := skip ('(', r, r, InfoSyntaxError);

      j := 1;
      continue := true;

      while syntaxCheck and continue do
      Begin
        if skip (')', r, r, InfoSyntaxError)
          and (r = '')
        then
          continue :=  false
        else
        Begin
          if j > 3 then syntaxcheck := false
          else
          begin
            if j > 1
            then
               syntaxcheck := skip (',', r, r, InfoSyntaxError);

             if syntaxCheck
             then
               syntaxCheck := EvaluateString(r, r, parameters[j], InfoSyntaxError);
          end
        end;
        inc(j);
      end;

      if syntaxcheck
      then
      begin
        testresult := 'service request possible';
        if opsidata = nil
        then
        Begin
          errorOccured := true;
          testresult := '!!! no opsidata !!!';
        End
        else
         try
            local_opsidata := opsidata;

           LogDatei.DependentAdd('Calling opsi service at ' + local_opsidata.serviceUrl, LevelComplete);
         except
           errorOccured := true;
           testresult := '!!! not in service mode !!!';
         end;

         if not errorOccured
         then
         Begin
            omc := TOpsiMethodCall.create ('getAndAssignSoftwareLicenseKey', parameters);

            testresult := local_opsidata.CheckAndRetrieveString (omc, errorOccured);
         end
      end;

      if errorOccured
      then
      Begin
          OldNumberOfErrors := LogDatei.NumberOfErrors;
          LogDatei.DependentAddError  ('Error: Got no license key: ' + testresult, BaseLevel);
          DiffNumberOfErrors := LogDatei.NumberOfErrors - OldNumberOfErrors;
          FNumberOfErrors := NumberOfErrors + DiffNumberOfErrors;
          stringresult := '';
      end
      else
        stringresult := testresult;
   end


  else if LowerCase(s) = LowerCase('freeLicense')
  then
   begin
      errorOccured := false;
      syntaxCheck := true;
      testresult := '';

      r := trim(r);
      setLength(parameters, 5);

      parameters[0] := osconf.computername;
      parameters[1] := '';
      parameters[2] := '';
      parameters[3] := '';
      parameters[4] := '';

      syntaxcheck := skip ('(', r, r, InfoSyntaxError);

      j := 2;
      continue := true;

      while syntaxCheck and continue do
      Begin
        if skip (')', r, r, InfoSyntaxError)
          and (r = '')
        then
          continue :=  false
        else
        Begin
          if j > 4 then syntaxcheck := false
          else
          begin
            if j > 2
            then
               syntaxcheck := skip (',', r, r, InfoSyntaxError);

             if syntaxCheck
             then
               syntaxCheck := EvaluateString(r, r, parameters[j], InfoSyntaxError);
          end
        end;
        inc(j);
      end;

      if syntaxcheck
      then
      begin
        testresult := 'service request possible';
        if opsidata = nil
        then
        Begin
          errorOccured := true;
          testresult := '!!! no opsidata !!!';
        End
        else
         try
            local_opsidata := opsidata;

           LogDatei.DependentAdd('Calling opsi service at ' + local_opsidata.serviceUrl, LevelComplete);
         except
           errorOccured := true;
           testresult := '!!! not in service mode !!!';
         end;

         if not errorOccured
         then
         Begin
            omc := TOpsiMethodCall.create ('deleteSoftwareLicenseUsage', parameters);
            testresult := local_opsidata.CheckAndRetrieveString (omc, errorOccured);
         end
      end;

      if errorOccured
      then
      Begin
          OldNumberOfErrors := LogDatei.NumberOfErrors;
          LogDatei.DependentAddError  ('Error: Could not delete software license usage ' + testresult, BaseLevel);
          DiffNumberOfErrors := LogDatei.NumberOfErrors - OldNumberOfErrors;
          FNumberOfErrors := NumberOfErrors + DiffNumberOfErrors;
          stringresult := '';
      end
      else
        stringresult := '';
   end

 else
    InfoSyntaxError := s0 + ' illegal String expression';


 (* Addition weiterer Teilstrings mit + *)
 if syntaxCheck and skip ('+', r, r, sx)
 then
 Begin
    syntaxCheck := EvaluateString (r, r, s1, InfoSyntaxError);
    StringResult := StringResult + s1;
 End;

 if syntaxcheck
 then
    Remaining := r;

 result := syntaxCheck;

       (*  if Script.ExitOnError then
        Begin
          tsr := tsrExitProcess;
          .DependentAdd (StopInfo, BaseLevel);
        End; *)

  LogDatei.LogSIndentLevel := StartIndentLevel;

End;


procedure TuibInstScript.GetWordOrStringExpression (const s: String;
                           var resultString, Remaining, errorinfo : String);
 { nur fuer AktionenSektion-Syntax 0 }
 var s0 : String='';

begin
  Resultstring := '';
  s0 := s;
  setLength (s0, length (s)); //should create a new instance, but does not always work
  if not EvaluateString (s0, Remaining, resultString, errorInfo)
  then
    GetWord (s0, resultString, Remaining, WordDelimiterWhiteSpace);
end;



function TuibInstScript.doXMLAddNamespace(filename:string;
  const elementname:string;
  const namespace:string):boolean;

 var list:TStringList;
  s1,s2,s3,s4:string;
  i,p1,p2:integer;
  bChanged:Boolean;
  ///done : Boolean;
 begin
  Result:=false;
  bChanged:=False;
  list:=TStringList.Create;
  try
    filename := ExpandFileName(filename);
    list.LoadFromFile(filename);
    list.Text:= reencode(list.Text, 'system');
    for i:=0 to list.Count-1 do
    begin
      p1:=pos('<'+elementname,list[i]);
      if p1>0 then
      begin //Element gefunden
        s1:=copy(list[i],1,p1-1); //String vor '<element'
        s2:=copy(list[i],p1,Length(list[i])); //String ab '<element'
        p2:=pos('>',s2);
        s3:=copy(s2,1,p2); //String von '<element' bis '>'
        s4:=copy(s2,p2+1,Length(list[i])); //Alles hinter '>'

        p2:=pos(namespace,s3);
        if p2=0 then //sonst schon vorhanden
        begin
          s3:=copy(s3,1,Length(s3)-1); //'>' abschneiden
          s3:=s3+' '+namespace+'>'; //und wieder anfï¿½gen

          list[i]:=s1+s3+s4;
          bChanged:=True;
          Result:=True;
          break; //wir suchen nur nach dem ersten Vorkommen
        end;
      end;
    end;
    if bChanged then
    list.SaveToFile(filename);

  finally
    list.Free;
  end;

 end;

 function TuibInstScript.doXMLRemoveNamespace(filename:string;
  const elementname:string;
  const namespace:string):boolean;
  var
    list:TStringList;
    s1,s2,s3,s4:string;
    i,p1,p2:integer;
    bChanged:Boolean;
  begin
    Result:=false;
    bChanged:=False;
    list:=TStringList.Create;
    try
      filename := ExpandFileName(filename);
      list.LoadFromFile(filename);
      list.Text:= reencode(list.Text, 'system');
      for i:=0 to list.Count-1 do
      begin
        p1:=pos('<'+elementname,list[i]);
        if p1>0 then
        begin //Element gefunden
          s1:=copy(list[i],1,p1-1); //String vor '<element'
          s2:=copy(list[i],p1,Length(list[i])); //String ab '<element'
          p2:=pos('>',s2);
          s3:=copy(s2,1,p2); //String von '<element' bis '>'
          s4:=copy(s2,p2+1,Length(list[i])); //Alles hinter '>'

          p2:=pos(namespace,s3);
          if p2>0 then //sonst nicht vorhanden
          begin
            System.delete(s3,p2,Length(namespace));
          if s3[p2-1]=' ' then //wir haben bei Add ein Leerzeichen hinzugefï¿½gt
          System.delete(s3,p2-1,1);

          list[i]:=s1+s3+s4;
          bChanged:=True;
          Result:=True;
          break; //wir suchen nur nach dem ersten Vorkommen
        end;
      end;
    end;
    if bChanged then
    list.SaveToFile(filename);
  finally
    list.Free;
  end;
 end;



function TuibInstScript.EvaluateBoolean
     (Input : String;
     var Remaining : String;
     var BooleanResult : Boolean;
     NestingLevel : Integer;
     var InfoSyntaxError : String) : Boolean;
var
  sx : String='';
  r : String='';
  s1 : String='';
  s2 : String='';
  s3 : String='';
  syntaxcheck : Boolean;
  FileRecord : TSearchRec;
  RunTimeInfo : String='';
  BooleanResult0 : Boolean;
  Textfile : TPatchList;
  freebytes : Int64=0;
  requiredbytes : Int64=0;
  einheit  :  Int64=0;
  j : integer=0;
  drivenumber : integer=0;
  errnumber : Integer=0;
  relationSymbol : String='';
  intresult : integer=0;
  n1 : integer=0;
  n2 : integer=0;
  comparesign : Integer=0;
  erroroccured : boolean;
  oldDisableWow64FsRedirectionStatus: pointer=nil;
  dummybool : boolean;
  OldWinapiErrorMode: Cardinal;
  list1 : TXStringList;




begin
 syntaxCheck := false;
 InfoSyntaxError := '';
 RunTimeInfo := '';
 BooleanResult := false;

 // geklammerter Boolescher Ausdruck
 if Skip ('(', Input, r, sx)
 then
 begin
   if EvaluateBoolean (r, r, BooleanResult, NestingLevel+1, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
      syntaxCheck := true;
 end

 // Boolean function
 else if Skip ('not', Input, r, sx)
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateBoolean (r, r, BooleanResult, NestingLevel+1, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
      BooleanResult := not BooleanResult;
      syntaxCheck := true;
   End;
 end

 {$IFDEF WIN32}
 else if Skip ('FileExists64', Input, r, sx)
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
      LogDatei.DependentAdd ('  Starting query if file exist (64 Bit mode)...', LevelComplete);
      // BooleanResult := CheckFileExists (s1, RunTimeInfo)  or IsDirectory (s1);

      s2 := s1;
      if (length(s1) > 0) and (s1[length(s1)] = PATHSEPARATOR)
        then s2 := copy(s1,1,length(s1)-1);
      try
        if DSiDisableWow64FsRedirection(oldDisableWow64FsRedirectionStatus) then
        begin
          LogDatei.DependentAdd('DisableWow64FsRedirection succeeded', LLinfo);
          //BooleanResult := GetFileInfo (s2, FileRecord, RunTimeInfo);
          // disable  critical-error-handler message box. (Drive not ready)
          OldWinapiErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
          try
            try
              BooleanResult := FileExists(s2) or DirectoryExists(s2);
            except
              BooleanResult := false;
            end;
          finally
            setErrorMode(OldWinapiErrorMode);
          end;
          dummybool := DSiRevertWow64FsRedirection(oldDisableWow64FsRedirectionStatus);
          LogDatei.DependentAdd('RevertWow64FsRedirection succeeded', LLinfo);
        end
        else
        begin
          LogDatei.DependentAddError('Error: DisableWow64FsRedirection failed', LLError);
          BooleanResult := false;
        end;
      except
        on ex: Exception
        do
        Begin
          LogDatei.DependentAddError ('Error: ' + ex.message, LLError);
        End;
      end;
      if not BooleanResult then
      Begin
        RunTimeInfo := '  "' + s1 + '": ' + RunTimeInfo;
        LogDatei.DependentAdd (RunTimeInfo, LLwarning);
      End;
      syntaxCheck := true;
   End;
 end

  else if Skip ('FileExistsSysNative', Input, r, sx)
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
      if Is64BitSystem then
        LogDatei.DependentAdd ('  Starting query if file exist (SysNative 64 Bit mode)...', LevelComplete)
      else
        LogDatei.DependentAdd ('  Starting query if file exist (SysNative 32 Bit mode)...', LevelComplete);
      (* BooleanResult := CheckFileExists (s1, RunTimeInfo)
                       or IsDirectory (s1); *)

      s2 := s1;
      if (length(s1) > 0) and (s1[length(s1)] = PATHSEPARATOR)
        then s2 := copy(s1,1,length(s1)-1);
      if Is64BitSystem then
      begin
        try
          if DSiDisableWow64FsRedirection(oldDisableWow64FsRedirectionStatus) then
          begin
            LogDatei.DependentAdd('DisableWow64FsRedirection succeeded', LLinfo);
            //BooleanResult := GetFileInfo (s2, FileRecord, RunTimeInfo);
            // disable  critical-error-handler message box. (Drive not ready)
            OldWinapiErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
            try
              try
                BooleanResult := FileExists(s2) or DirectoryExists(s2);
              except
                BooleanResult := false;
              end;
            finally
              setErrorMode(OldWinapiErrorMode);
            end;
            dummybool := DSiRevertWow64FsRedirection(oldDisableWow64FsRedirectionStatus);
            LogDatei.DependentAdd('RevertWow64FsRedirection succeeded', LLinfo);
          end
          else
          begin
            LogDatei.DependentAddError('Error: DisableWow64FsRedirection failed', LLError);
            BooleanResult := false;
          end;
        except
          on ex: Exception
          do
          Begin
            LogDatei.DependentAddError ('Error: ' + ex.message, LLError);
          End;
        end
      end
      else
      begin
        //BooleanResult := GetFileInfo (s2, FileRecord, RunTimeInfo);
       BooleanResult := FileExists(s2) or DirectoryExists(s2);
      end;
      if not BooleanResult then
      Begin
        RunTimeInfo := '  "' + s1 + '": ' + RunTimeInfo;
        LogDatei.DependentAdd (RunTimeInfo, LLwarning);
      End;
      syntaxCheck := true;
   End;
 end

  else if Skip ('FileExists32', Input, r, sx)
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
      LogDatei.DependentAdd ('  Starting query if file exist ...', LevelComplete);
      s2 := s1;
      if (length(s1) > 0) and (s1[length(s1)] = PATHSEPARATOR)
       then s2 := copy(s1,1,length(s1)-1);
      //BooleanResult := GetFileInfo (s2, FileRecord, RunTimeInfo);
      // disable  critical-error-handler message box. (Drive not ready)
      OldWinapiErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
      try
        try
          BooleanResult := FileExists(s2) or DirectoryExists(s2);
        except
          BooleanResult := false;
        end;
      finally
        setErrorMode(OldWinapiErrorMode);
      end;
      if not BooleanResult then
      Begin
        RunTimeInfo := '  "' + s1 + '": ' + RunTimeInfo;
        LogDatei.DependentAdd (RunTimeInfo, LevelWarnings);
      End;
      syntaxCheck := true;
   End;
 end
 {$ENDIF WIN32}

 else if Skip ('FileExists', Input, r, sx)
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
     s1 := ExpandFileName(s1);
      LogDatei.DependentAdd ('  Starting query if file exist ...', LevelComplete);
      s2 := s1;
      if (length(s1) > 0) and (s1[length(s1)] = PATHSEPARATOR)
       then s2 := copy(s1,1,length(s1)-1);
      {$IFDEF WINDOWS}
      // disable  critical-error-handler message box. (Drive not ready)
      OldWinapiErrorMode := SetErrorMode(SEM_FAILCRITICALERRORS);
      try
        try
          BooleanResult := FileExists(s2) or DirectoryExists(s2);
        except
          BooleanResult := false;
        end;
      finally
        setErrorMode(OldWinapiErrorMode);
      end;
      {$ELSE WINDOWS}
      //BooleanResult := GetFileInfo (s2, FileRecord, RunTimeInfo);
      BooleanResult := FileExists(s2) or DirectoryExists(s2);
      {$ENDIF WINDOWS}
      if not BooleanResult then
      Begin
        RunTimeInfo := '  "' + s1 + '": ' + RunTimeInfo;
        LogDatei.DependentAdd (RunTimeInfo, LevelWarnings);
      End;
      syntaxCheck := true;
   End;
 end


 {$IFDEF WINDOWS}
 (* XMLAddNamespace(Datei:string,ElementName:string,Namespace:string):Boolean
  True, wenn Namespace noch nicht da war und eingefï¿½gt werden muï¿½te *)
 else if Skip ('XMLAddNamespace', Input, r, sx)
 then
 begin
    if Skip ('(', r, r, InfoSyntaxError)
    then if EvaluateString (r, r, s1, InfoSyntaxError)
    then if Skip (',', r, r, InfoSyntaxError)
    then if EvaluateString (r, r, s2, InfoSyntaxError)
    then if Skip (',', r, r, InfoSyntaxError)
    then if EvaluateString (r, r, s3, InfoSyntaxError)
    then if Skip (')', r, r, InfoSyntaxError)
    then
    Begin
      syntaxCheck := true;
      LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;

      LogDatei.DependentAdd (' Adding NameSpace (if not existing) "' + s3 + '" for element "' + s2 + '" in file "' + s1 + '"', LevelComplete);

      BooleanResult:=false;
      try
        BooleanResult:=doXMLAddNamespace(s1,s2,s3);
      except
        on ex: Exception
        do
        Begin
          LogDatei.DependentAddError ('Error: ' + ex.message, BaseLevel);
        End;
      end;

      LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;
    End;
 end

  (* XMLRemoveNamespace(Datei:string,ElementName:string,Namespace:string):Boolean
    True, wenn der Namespace entfernt werden konnte *)
 else if Skip ('XMLRemoveNamespace', Input, r, sx)
 then
 begin
    if Skip ('(', r, r, InfoSyntaxError)
    then if EvaluateString (r, r, s1, InfoSyntaxError)
    then if Skip (',', r, r, InfoSyntaxError)
    then if EvaluateString (r, r, s2, InfoSyntaxError)
    then if Skip (',', r, r, InfoSyntaxError)
    then if EvaluateString (r, r, s3, InfoSyntaxError)
    then if Skip (')', r, r, InfoSyntaxError)
    then
    Begin
      syntaxCheck := true;
      LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;
      LogDatei.DependentAdd
       (' Removing NameSpace "' + s3 + '" for element "' + s2 + '" in file "' + s1 + '"',
       LevelComplete);

      BooleanResult:=false;
      try
        BooleanResult:=doXMLRemoveNamespace(s1,s2,s3);
      except
        on ex: Exception
        do
        Begin
          LogDatei.DependentAddError ('Error: ' + ex.message, BaseLevel);
        End;
      end;
      LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;
    End;
 end
 {$ENDIF WINDOWS}

 else if Skip ('LineBeginning_ExistsIn', Input, r, sx)
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (',', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s2, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
     syntaxCheck := true;
     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;
     LogDatei.DependentAdd ('Searching "' + s1 + '" in File "' + s2 + '"', LevelComplete);
     try
       Textfile := TPatchList.Create;
       Textfile.clear;
       Textfile.ItemPointer := -1;
       s2 := ExpandFileName(s2);
       Textfile.LoadFromFile (s2);
       Textfile.Text:= reencode(Textfile.Text, 'system');
       BooleanResult := ( Textfile.FindFirstItemStartingWith(s1, false, -1) >= 0 )
     except
       on ex: Exception
       do
       Begin
         LogDatei.DependentAddError ('Error: ' + ex.message, BaseLevel);
       End;
     end;

     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;
   End
 End

 else if Skip ('LineExistsIn', Input, r, sx)
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (',', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s2, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
     syntaxCheck := true;

     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;
     LogDatei.DependentAdd ('Searching "' + s1 + '" in File "' + s2 + '"', LevelComplete);
     try
       Textfile := TPatchList.Create;
       Textfile.clear;
       Textfile.ItemPointer := -1;
       s2 := ExpandFileName(s2);
       Textfile.LoadFromFile (s2);
       Textfile.Text:= reencode(Textfile.Text, 'system');

       BooleanResult := (Textfile.FindFirstItem(s1, false, -1, BooleanResult0) >= 0 )
     except
       on ex: Exception
       do
       Begin
         LogDatei.DependentAddError ('Error: ' + ex.message, BaseLevel);
       End;
     end;

     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;
   End
 End

  else if Skip ('LineContaining_ExistsIn', Input, r, sx)
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (',', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s2, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
     syntaxCheck := true;

     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;
     LogDatei.DependentAdd ('Searching "' + s1 + '" in File "' + s2 + '"', LevelComplete);
     try
       Textfile := TPatchList.Create;
       Textfile.clear;
       Textfile.ItemPointer := -1;
       s2 := ExpandFileName(s2);
       Textfile.LoadFromFile (s2);
       Textfile.Text:= reencode(Textfile.Text, 'system');

       BooleanResult := (Textfile.FindFirstItemWith(s1, false, -1) >= 0 )
     except
       on ex: Exception
       do
       Begin
         LogDatei.DependentAddError ('Error: ' + ex.message, BaseLevel);
       End;
     end;

     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;
   End
 End

 else if Skip ('contains', Input, r, sx)
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (',', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s2, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
     syntaxCheck := true;
     BooleanResult := strContains(s1,s2);
   end;
 End

 else if Skip ('sendlog', Input, r, sx)
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (',', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s2, InfoSyntaxError)
   then if Skip (',', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s3, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
     syntaxCheck := true;
     if local_opsidata <> nil then
     begin
     local_opsidata.setActualClient(s1);
     if 'true' = LowerCase(s3) then
       BooleanResult := local_opsidata.sendLog(s2,true)
     else
       BooleanResult := local_opsidata.sendlog(s2,false);
     end
     else
     begin
       LogDatei.log('Service not initialized',LLError);
     end;
   end;
 End

 else if Skip ('savetextfile', Input, r, sx)
 then
 begin
   try
     BooleanResult := false;
     list1 := TXStringList.create;
     if Skip ('(', r, r, InfoSyntaxError)
     then if produceStringList (script, r, r, list1, InfoSyntaxError)
     then if Skip (',', r, r, InfoSyntaxError)
     then if EvaluateString (r, r, s1, InfoSyntaxError)
     then if Skip (')', r, r, InfoSyntaxError)
     then
     Begin
       syntaxCheck := true;
       try
          list1.SaveToFile(s1, 'system');
          BooleanResult := true;
       except
         logdatei.log('Error: Could not write list to filename: '+s1,LLError);
       end;
     end;
   finally
     list1.free;
     list1 := nil;
   end
 End



 else if Skip ('isNumber', Input, r, InfoSyntaxError)
 then
 begin
    if Skip ('(', r, r, InfoSyntaxError)
    then if EvaluateString (r, r, s1, InfoSyntaxError)
    then if Skip (')', r, r, InfoSyntaxError)
    then
    Begin
      syntaxCheck := true;
      try
        intresult := strToInt (s1);
        BooleanResult := true;
      except
        BooleanResult := false;
      end
    end;
 end

 {$IFDEF WINDOWS}
 else if Skip ('IsDriveReady', Input, r, InfoSyntaxError)
 then
 begin
    if Skip ('(', r, r, InfoSyntaxError)
    then if EvaluateString (r, r, s1, InfoSyntaxError)
    then if Skip (')', r, r, InfoSyntaxError)
    then
    Begin
      syntaxCheck := true;
      try
        BooleanResult := IsDriveReady (s1);
      except
        BooleanResult := false;
      end
    end;
 end
 {$ENDIF WINDOWS}

 else if (Skip ('ErrorsOccuredSinceMark ', Input, r, sx) or Skip ('ErrorsOccurredSinceMark ', Input, r, sx))
 then
 begin
   getword (r, relationSymbol, r, WordDelimiterWhiteSpace);
   try
     errNumber := strtoint (r);
     syntaxcheck := true;
     r := '';
   except
     InfoSyntaxError := r + ' is not a number'
   end;

   syntaxCheck :=
     syntaxcheck and
     hasRelation ( relationSymbol ,
                   getCompareSign (Logdatei.NumberOfErrors - Logdatei.ErrorNumberMarked, errNumber),
                   BooleanResult, InfoSyntaxError )
 End

 else if Skip ('opsiLicenseManagementEnabled', Input, r, InfoSyntaxError)
 then
 begin
    booleanResult := false;
    Syntaxcheck := true;
    errorOccured := false;
    if opsidata = nil
    then
    Begin
      errorOccured := true;
    End
    else
    begin
      try
        local_opsidata := opsidata;

        //LogDatei.DependentAdd('Calling opsi service at ' + local_opsidata.serviceUrl, LevelComplete);
      except
        errorOccured := true;
      end;
    end;

    if not errorOccured
    then
    begin
      booleanresult := local_opsidata.withLicenceManagement;
    end;
 end

 else if Skip ('runningAsAdmin', Input, r, InfoSyntaxError)
 then
 begin
    Syntaxcheck := true;
    errorOccured := false;
    booleanresult := runningasadmin;
 end

 else if Skip ('isLoginScript', Input, r, InfoSyntaxError)
 then
 begin
    Syntaxcheck := true;
    errorOccured := false;
    booleanresult := runloginscripts;
 end

 else if Skip ('runningOnUefi', Input, r, InfoSyntaxError)
 then
 begin
    Syntaxcheck := true;
    errorOccured := false;
    booleanresult := isUefi;
 end

 else if Skip ('scriptWasExecutedBefore', Input, r, InfoSyntaxError)
 then
 begin
    Syntaxcheck := true;
    errorOccured := false;
    booleanresult := scriptWasExecutedBefore;
 end



 else if Skip ('HasMinimumSpace', Input, r, sx)
 then
 begin
   if Skip ('(', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s1, InfoSyntaxError)
   then if Skip (',', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s2, InfoSyntaxError)
   then if Skip (')', r, r, InfoSyntaxError)
   then
   Begin
     syntaxCheck := true;

     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;

     einheit := 1;
     j := pos ('kb', lowercase(s2));
     if j > 0
     then
       einheit := 1000
     else
     Begin
        j := pos ('mb', lowercase(s2));
        if j > 0
        then
           einheit := 1000 * 1000
        else
        Begin
          j := pos ('gb', lowercase(s2));
          if j > 0
          then
             einheit := 1000 * 1000 * 1000;
        End
     End;


     if j = 0
     then
       try
         freebytes := strtoint64 (s2);
       except
         RunTimeInfo := '"' + s2 + '" is not a valid number"';
         syntaxCheck := false;
       end
     else
       try
         sx := cutRightBlanks(copy (s2, 1, j - 1));
         requiredbytes := strtoint64 (sx);
         requiredbytes := requiredbytes * einheit;
       except
         RunTimeInfo := '"' + s2 + '" is not a valid number"';
         syntaxCheck := false;
       end;

     if syntaxCheck
     then // parse s1 in order to get the drive char
     Begin
       if (length (s1) = 2) and (s1[2] = ':')
       then
         drivenumber := ord (uppercase(s1)[1]) - ord ('A') + 1
       else
       begin
         syntaxcheck := false;
         RunTimeInfo := '"' + s1 + '" is not a valid drive"';
       end;
     end;

     if syntaxCheck
     then
       freebytes := diskfree (drivenumber);

     if syntaxCheck and (freebytes = -1)
     then
     Begin
       syntaxCheck := false;
       RunTimeInfo := '"' + s1 + '" is not a valid drive"';
     End;

     if syntaxCheck
     then
     Begin
       BooleanResult := (freebytes >= requiredBytes);
       RunTimeInfo := 'Free on Disk ' + s1 + ': ' + formatInt (freebytes) + ' bytes';
       if BooleanResult
       then
         RunTimeInfo := RunTimeInfo + '  This is more '
       else
         RunTimeInfo := RunTimeInfo + '  This is less ';

       RunTimeInfo := RunTimeInfo + 'than the required amount of ' + formatInt (requiredbytes) + ' bytes';
     End;

     LogDatei.DependentAdd (RunTimeInfo, LevelComplete);

     LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;
   End
 End

 (* Boolescher Ausdruck  s1 = s2 *)
 else if EvaluateString (Input, r, s1, InfoSyntaxError)
 then
 Begin
   if skip('int', r, r, InfoSyntaxError)
   then
   Begin
     if getOrdersymbol (r, relationsymbol, r, InfoSyntaxError)
     then if EvaluateString (r, r, s2, InfoSyntaxError)
     then
     Begin
       syntaxCheck := true;
       OldNumberOfErrors := LogDatei.NumberOfErrors;

       try
          n1 := StrToInt(s1);
          try
            n2 := StrToInt(s2);
            comparesign := getCompareSign(n1, n2);
            syntaxCheck := hasRelation(
              relationsymbol,
              comparesign,
              BooleanResult, InfoSyntaxError);
          except
            LogDatei.DependentAddError('Error: ' + s2 + ' has no Integer format', BaseLevel);
          end;
       except
          LogDatei.DependentAddError('Error: ' + s1 + ' has no Integer format', BaseLevel)
       end;

       DiffNumberOfErrors := LogDatei.NumberOfErrors - OldNumberOfErrors;
       FNumberOfErrors := NumberOfErrors + DiffNumberOfErrors;

     End
   end
   else
   Begin
     if getOrdersymbol (r, relationsymbol, r, InfoSyntaxError)
     then if EvaluateString (r, r, s2, InfoSyntaxError)
     then
     Begin
       comparesign := getCompareSignStrings(s1, s2);
       syntaxCheck := hasRelation(
          relationsymbol,
          comparesign,
          BooleanResult, InfoSyntaxError);
       syntaxCheck := true;
     End
   End

   {
   if Skip ('=', r, r, InfoSyntaxError)
   then if EvaluateString (r, r, s2, InfoSyntaxError)
   then
   Begin
     BooleanResult := (AnsiUpperCase (s1) = AnsiUpperCase (s2));
     syntaxCheck := true;
   End
   }
 End

 else
   if InfoSyntaxError = '' then InfoSyntaxError := 'not a well formed boolean expression';


 (*  concatenate  AND / OR  *)
 if syntaxCheck then
 Begin
   if Skip ('and', r, r, sx)
   then
   Begin
     if EvaluateBoolean (r, r, BooleanResult0, NestingLevel+1, InfoSyntaxError)
     then
       BooleanResult := BooleanResult and BooleanResult0
     else
       syntaxCheck := false;
   End
   else
   if Skip ('or', r, r, sx)
   then
   Begin
     if EvaluateBoolean (r, r, BooleanResult0, NestingLevel+1, InfoSyntaxError)
     then
       BooleanResult := BooleanResult or BooleanResult0
     else
       syntaxCheck := false;
   End
 End;

 result := syntaxCheck;
 Remaining := r;

 RunTimeInfo := copy (Input, 1, length (Input) - length (Remaining));

 if result
 then
 Begin
   if BooleanResult
   then
     RunTimeInfo := RunTimeInfo + '   <<< result true'
   else
     RunTimeInfo := RunTimeInfo + '   <<< result false'
 End
 else
   RunTimeInfo := RunTimeInfo +   '    <<< syntax error, no result!! - set to false';

 LogDatei.DependentAdd (RunTimeInfo, LevelWarnings);


End;


function TuibInstScript.doSetVar (const section: TuibIniScript; const Expression : String;
                   var Remaining : String; var InfoSyntaxError : String) : Boolean;
 var
   VarName : String='';
   VarValue : String='';
   r : String='';
   VarIndex : Integer=0;
   list : TXStringList;

begin
  result := false;
  GetWord (Expression, VarName, r, WordDelimiterSet1);
  if VarName = ''
  then
     InfoSyntaxError := 'variable expected'
  else
  Begin
    VarIndex := listOfStringLists.IndexOf(LowerCase(VarName));
    if VarIndex >= 0 // we should get a StringList
    then
    Begin
      if    Skip ('=', r, r, InfoSyntaxError)
        and produceStringList (section, r, Remaining, list,  InfoSyntaxError)
      then
      try
        ContentOfStringLists.Items[VarIndex] := list;
        result := true;
      except
      end;

      {
      if result
      then
      begin
         LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
         LogDatei.DependentAdd ('lines retrieved:', LevelComplete);
         LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 2;
         LogDatei.DependentAddStringList(list, LevelComplete);
         LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 4;
      end
      }

    End
    else
    Begin // it must be a string value
      VarIndex := VarList.IndexOf (LowerCase (VarName));
      if VarIndex < 0
      then
        InfoSyntaxError := 'Variable unbekannt'
      else
      Begin
        if    Skip ('=', r, r, InfoSyntaxError)
          and EvaluateString (r, Remaining, VarValue, InfoSyntaxError)
        then
        Begin
          try
            ValuesList [VarIndex] := VarValue;
            result := true;
          except
          end;
        End
      End;

      if result
      then
      Begin
        LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;
        LogDatei.DependentAdd
        ('The value of the variable "'+Varname+'" is now: "' + VarValue + '"', LevelComplete);
        LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;
      End;
    End;
  End;
end;


{$IFDEF WINDOWS}
(* experimentell *)
function TuibInstScript.StartConnection (LocalName, NetResourceName: String; WaitTime : LongInt) : TSectionResult;
  Var
    NetResource : TNetResourceA;
    waitedTime : LongInt=0;
    showTime  : LongInt=0;
    waitTimeMilsec : LongInt=0;
    netresult : DWord=0;
    lastErrorCode : DWord=0;
    ErrorInfo : String='';
    ReportedUser : String='';



    function netErrorMessage (errorcode : Integer) : String;

    var
      pErrorBuff, pNameBuff : PChar;
      nErrorBuffSize : DWord=0;
      nNamebuffSize : DWord=0;
      Error : String='';
      Name : String='';

    begin

      case  errorcode of
       no_error                         : result := 'no_error';
       ERROR_ACCESS_DENIED          : result := 'Access to the network resource was denied.';
       ERROR_ALREADY_ASSIGNED           : result :=
          'The local device specified by lpLocalName is already connected to a network resource.';
       ERROR_BAD_DEV_TYPE               : result :=
          'The type of local device and the type of network resource do not match.';
       ERROR_BAD_DEVICE                 : result :=
          'The value specified by lpLocalName is invalid.';
       ERROR_BAD_NET_NAME               : result :=
          'The value specified by lpRemoteName is not acceptable to any network resource provider. ' +
          'The resource name is invalid, or the named resource cannot be located.';
       ERROR_BAD_PROFILE               : result :=
          'The user profile is in an incorrect format.';
       ERROR_BAD_PROVIDER               : result :=
          'The value specified by lpProvider does not match any provider.';
       ERROR_BUSY                       : result :=
          'The router or provider is busy, possibly initializing. The caller should retry.';
       ERROR_CANCELLED               : result :=
          'The attempt to make the connection was cancelled by the user through a dialog box from one ' +
          'of the network resource providers, or by a called resource.';
       ERROR_CANNOT_OPEN_PROFILE       : result :=
          'The system is unable to open the user profile to process persistent connections.';
       ERROR_DEVICE_ALREADY_REMEMBERED  : result :=
          'An entry for the device specified in lpLocalName is already in the user profile.';
       ERROR_EXTENDED_ERROR       :
          Begin
            GetMem (pErrorBuff, 300);
            GetMem (pNameBuff, 300);
            WNetGetLastError (DWord (errorcode), pErrorBuff, nErrorBuffSize, pNameBuff, nNameBuffSize);
            Error := pErrorBuff;
            result := Error;
            FreeMem (pErrorBuff);
            FreeMem (pNameBuff);
          End;
       ERROR_INVALID_PASSWORD      : result := 'The specified password is invalid.';
       ERROR_NO_NET_OR_BAD_PATH      : result :=
       'A network component has not started, or the specified name could not be handled.';
       ERROR_NO_NETWORK              : result := 'There is no network present.';
       else
        result := ''
      end;
    end;



begin
  result := tsrPositive;

  NetResource.dwType := RESOURCETYPE_DISK;
  NetResource.lpRemoteName :=  PAnsiChar (NetResourceName);
  NetResource.lpLocalName  :=  PAnsiChar (LocalName) ;
  NetResource.lpProvider := '';

  LogDatei.DependentAdd ('Add Connection '  (* + 'User ' + Username *) +  ' to ' + NetResourceName, levelInfo);
  LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;

  netresult := wNetAddConnection2 (NetResource, nil (* PAnsiChar (Password) *), nil (* PAnsiChar (Username) *), 0);
  lastErrorCode := 0;

  if (netresult = no_error)
  then
  Begin
    GetNetUser ('', ReportedUser, ErrorInfo);
    ReportedUser := 'User ' + ReportedUser;
    LogDatei.DependentAdd ('Sec 0 ' + ReportedUser + ' Connected ' + ErrorInfo, levelInfo)
  End
  else
  Begin
    lastErrorCode := GetLastError;
    GetNetUser ('', ReportedUser, ErrorInfo);
    LogDatei.DependentAdd ( 'User ' + ReportedUser + ' '  + ErrorInfo, levelinfo);
    LogDatei.DependentAdd ('Sec 0  Connect error '
                            + IntToStr (lastErrorCode) + ': "'
                            + RemoveLineBreaks(SysErrorMessage(lastErrorCode)) + '"', levelinfo);
    CentralForm.TimerWaitSet (100);
    // alle Zehntelsec Timer-Ereignis anschauen
  End;
  WaitedTime := 1000;
  ShowTime := 1000;
  WaitTimeMilsec := WaitTime * 1000;
  while (netresult <> no_error) and (WaitedTime < WaitTimeMilSec)
  do
  Begin
    ProcessMess;
    if CentralForm.TimerWaitReady (10)
    then
    (* nach 10 Zehntelsec erneuten Versuch unternehmen *)
    Begin
      netresult := wNetAddConnection2 (NetResource, nil (* PAnsiChar (Password)*), nil (* PAnsiChar (Username)*), 0);
      if netresult = no_error
      then
          LogDatei.DependentAdd ('Sec ' + IntToStr (WaitedTime DIV 1000) + '  Connected', levelInfo)
      else
      Begin
        if (lastErrorCode <> GetLastError) or (ShowTime > 2000)
        then
        Begin
          lastErrorCode := GetLastError;
          ShowTime := 1000;
          LogDatei.DependentAdd ('Sec ' + IntToStr (WaitedTime DIV 1000) + '  Connect error '
                   + IntToStr (lastErrorCode) + ': "'
                   + RemoveLineBreaks(SysErrorMessage (lastErrorCode))  + ' '
                   + netErrorMessage (lastErrorCode) + '"', levelinfo);
        End
        else
          ShowTime := ShowTime + 1000;

        CentralForm.TimerWaitSet (100);
        WaitedTime := WaitedTime + 1000;
      End
    End;
  End;

  if WaitedTime >= WaitTimeMilSec
  then
  Begin
    LogDatei.DependentAdd ('tried for ' + IntToStr (WaitedTime DIV 1000) + ' sec', levelinfo);
    LogDatei.DependentAddError ('Error: No Connect to ' + NetResourceName, baselevel);

    DiffNumberOfErrors := 1;
  End
  else
   DiffNumberOfErrors := 0;

  LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;

  if ExitOnError and (DiffNumberOfErrors > 0)
  then result := tsrExitProcess;
End;
{$ENDIF WINDOWS}


procedure TuibInstScript.ApplyTextConstants (var Sektion : TXStringList; CStringEscaping : Boolean);
 var
  i: Integer;
begin
 for i := 1 to ConstList.Count
 do
   if CStringEscaping
   then
    Sektion.GlobalReplace (1, Constlist.Strings [i-1], CEscaping (ConstValuesList.Strings [i-1]), false)
   else
    Sektion.GlobalReplace (1, Constlist.Strings [i-1], ConstValuesList.Strings [i-1], false)
end;


procedure TuibInstScript.ApplyTextVariables (var Sektion : TXStringList; CStringEscaping : Boolean);
 var
  i: Integer;
begin
 for i := 1 to VarList.Count
 do
 Begin
   if CStringEscaping
   then
      Sektion.GlobalReplace (1, Varlist.Strings [i-1], CEscaping (ValuesList.Strings [i-1]), false)
   else
      Sektion.GlobalReplace (1, Varlist.Strings [i-1], ValuesList.Strings [i-1], false)
 end;
end;

function TuibInstScript.doAktionen (const Sektion: TWorkSection; const CallingSektion: TWorkSection)
                       : TSectionResult;
 var
  i : integer=0;
  StartlineOfSection: Integer=0;
  Parameter : String='';
  Filename : String='';
  SectionSpecifier : TSectionSpecifier;
  posSlash : integer=0;
  imageNo : Integer=0;
  ArbeitsSektion : TWorkSection;
  WaitConditions : TSetWaitConditions;
  expr : String='';
  ident : String='';
  WaitSecs : Word=0;
  numberString : String='';
  ActionResult : TSectionResult=0;
  ActLevel : integer=0;
  NestLevel : Integer=0;
  StatKind : TStatement;
  expression : String='';
  remaining : String='';
  registryformat : TRegistryFormat;
  reg_specified_basekey : String='';
  flag_force64 : boolean;
  BooleanResult : Boolean;
  Info : String='';
  ErrorInfo : String='';
  InfoSyntaxError : String='';
  SyntaxCheck : Boolean;
  sign : Integer=0;
  evaluated : Boolean;
  FName : String='';
  Labeltext : String='';
  localname : String='';
  remotename : String='';
  username : String='';
  password : String='';
  trytime : String='';
  timeout : Integer=0;
  s1 : String='';
  Fehlertext : String='';
  output : TXStringlist;
  inputlist : TXStringList;
  inputname : String='';
  looplist : TXStringList;
  loopvar : String='';
  loopvalue : String='';
  loopindex : Integer=0;
  inloop : Boolean;
  continue : Boolean;
  stayOnStatement : String='';
  Startindentlevel : Integer=0;
  goon : boolean;
  sleepsecs : Integer=0;
  diffTime : TDateTime;
  Encoding2use,usedEncoding : String;
  ntuserpath : String = '';

  //outlist : TXStringList;
  //versionI  : TVersionInfo; //from versioninfoX

  j : Integer=0;
  includelogLinecount : integer=0;
  //includelogStrList : TStringList;
  logtailLinecount : integer=0;
  logtailLinecountstr : String='';
  logtailEncodingstr : String='system';
  includeLogLineStart : integer=0;
  aktline : integer=0;
  call : String='';
  p1 : String='';
  p2 : String='';
  p3 : String='';
  p4 : String='';
  seconds : String='';
  runAs : TRunAs;
     linecount ,k, constcounter : integer;
    incfilename, fullincfilename, incline, myline,replacedline : string;
    //remaining, errorinfo, expr , numberString : string;
    incfile : TextFile;
    inclist : TStringlist;
    found   : boolean;
    //, doincludes, evaluated : boolean;

begin
  try
    result := tsrPositive;
    ActionResult := tsrPositive;

    NestLevel := Sektion.NestingLevel;
    ActLevel := NestLevel;
    conditions [ActLevel] := true;

    StartIndentLevel := LogDatei.LogSIndentLevel;
    //LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;

    //FBatchOberflaeche.setPicture (3, '', '');

    ArbeitsSektion := TWorkSection.create (NestLevel);
    output := TXStringList.Create;
    {$IFDEF GUI}
    FBatchOberflaeche.setWindowState(batchWindowMode);
    {$ENDIF GUI}

    i := 1;
    continue := true;

    looplist := TXStringList.create;
    inloop := false;

    while (i <= Sektion.count) and continue
    and (actionresult > tsrFatalError)
    and (FExtremeErrorLevel > levelfatal)
    and not scriptstopped
    do
    begin
     //writeln(actionresult);
      Remaining := trim (Sektion.strings [i-1]);
      //writeln(remaining);
      //readln;

      repeat // looping if inLoop, otherwise going through the statements just once

        if inLoop
        then
        Begin
          Remaining := stayOnStatement; //looping on this statement
          loopvalue := looplist[0];
          Remaining := StringReplace(Remaining, loopvar, loopvalue);
          looplist.delete (0);
        End;

        if (Remaining = '') or (Remaining [1] = LineIsCommentChar)
        then
           (* continue *)
        else if Remaining [1] = '[' then
           // subsection beginning
        begin
           continue := false;
           LogDatei.DependentAdd ('Section ending since next line is starting with "["', LevelComplete);
        end
        else
        Begin
        call := remaining;
          GetWord (Remaining, Expression, Remaining, WordDelimiterSet0);
          StatKind := FindKindOfStatement (Expression, SectionSpecifier, call);
          ArbeitsSektion.Name := Expression;
          ArbeitsSektion.SectionKind := StatKind;

          // treat statements for if-else first

          if StatKind = tsCondOpen
          then
          Begin
            //if FExtremeErrorLevel > levelfatal then
            begin
              inc (NestLevel);
              ThenBranch [NestLevel] := true;

              doLogEntries (PStatNames^ [tsCondOpen], LLinfo);
              if NestLevel > High (TConditions)
              then
              Begin
                reportError (Sektion, i, '', 'Too many nested conditions');
                exit;
              End;

              LogDatei.LogSIndentLevel := NestLevel;

              if (NestLevel = ActLevel + 1) and Conditions [ActLevel] then
              begin
                // eine neue aktive Ebene wird erzeugt, falls
                // die if-Anweisung auf einer aktiven Ebene UND im positiven Zweig steht

                Expression := Remaining;
                if EvaluateBoolean (Expression, Remaining, BooleanResult,
                                    NestLevel, InfoSyntaxError)
                then
                begin
                   inc (ActLevel);
                   Conditions [NestLevel] := BooleanResult;
                end
                else
                  reportError (Sektion, i, Expression, InfoSyntaxError);
                if Remaining <> ''
                then reportError (Sektion, i, Remaining, 'erroneous characters ');
              end;

              LogDatei.LogSIndentLevel := NestLevel - 1;
              doLogEntries (PStatNames^ [tsCondThen], LLInfo);
              LogDatei.LogSIndentLevel := NestLevel;
            end;
          End

          else if StatKind = tsCondElse then
          Begin
            //if FExtremeErrorLevel > levelfatal then
            begin
              if NestLevel <= Sektion.NestingLevel
              then
                reportError (Sektion, i, '',PStatNames^ [tsCondElse] + '  without  ' + PStatNames^ [tsCondOpen])
              else
              Begin
                if not ThenBranch [NestLevel]
                then
                  reportError (Sektion, i, '', 'double ' + PStatNames^ [tsCondElse])
                else
                Begin
                  ThenBranch [NestLevel] := false;

                      // innerhalb einer aktiven Ebene Wechsel zwischen positivem/negativen Zweig
                  LogDatei.LogSIndentLevel := NestLevel - 1;
                  doLogEntries (PStatNames^ [tsCondElse], LLinfo);
                  LogDatei.LogSIndentLevel := NestLevel;

                  if NestLevel = ActLevel then Conditions [ActLevel] := not Conditions [ActLevel];
                End;
              End;
            end;
          End

          else if StatKind = tsCondClose then
          begin
           // if FExtremeErrorLevel > levelfatal then
            begin
              //Herabstufen einer formalen Ebene, innerhalb einer aktiven Ebene Beenden von dieser

              if NestLevel = ActLevel then dec (ActLevel);
              dec (NestLevel);

              LogDatei.LogSIndentLevel := NestLevel ;
              doLogEntries (PStatNames^ [tsCondClose] , LLinfo);


              if NestLevel < Sektion.NestingLevel
              then
                reportError (Sektion, i, '', PStatNames^ [tsCondClose] + '  ohne  ' + PStatNames^ [tsCondOpen]);
            end;
          End

          else
             // Ausfuehrung alles folgenden nur falls in einem aktuellen true-Zweig
          if (NestLevel = ActLevel) and conditions [ActLevel]
             // sowie falls weitere Bearbeitung gewuenscht
              and (ActionResult > 0)
          then
          Begin
            case SectionSpecifier of
             tsecIncluded:
              Begin

                ArbeitsSektion.clear;

                // look if we are in a subprogram
                // that may have its own sections in it
                (*
                if Sektion.SectionKind = tsActions
                then
                Begin

                  CallingSektion.GetSectionLines (Expression, TXStringList (ArbeitsSektion),
                                           StartlineOfSection, true, true, false);
                End;
                *)

                if ArbeitsSektion.count = 0
                then
                begin
                  // normal case
                  Logdatei.log('Looking for section: '+ Expression +' in standard section.',LLDebug3);
                  GetSectionLines (Expression, TXStringList (ArbeitsSektion),
                                    StartlineOfSection, true, true, false);
                end;

                if ArbeitsSektion.count = 0
                then
                begin
                  // subsub case
                  Logdatei.log('Looking for section: '+ Expression +' in calling section.',LLDebug3);
                  CallingSektion.GetSectionLines (Expression, TXStringList (ArbeitsSektion),
                                    StartlineOfSection, true, true, false);
                end;

                if ArbeitsSektion.count = 0
                then
                begin
                  // subsub case
                  Logdatei.log('Looking for section: '+ Expression +' in global section.',LLDebug3);
                  Sektion.GetSectionLines (Expression, TXStringList (ArbeitsSektion),
                                    StartlineOfSection, true, true, false);
                end;


                if inLoop then ArbeitsSektion.GlobalReplace(1, loopvar, loopvalue, false);

                if ArbeitsSektion.count = 0
                then
                Begin
                  LogDatei. log('Warning: The section "' + expression + '" (called in line ' +
                    inttostr(i) +
                    ' of the calling section) does not exist or is empty', LLWarning);
                  FNumberOfWarnings := FNumberOfWarnings + 1;
                End

                else
                   ArbeitsSektion.StartLineNo := StartlineOfSection;
              End;

             tsecExpected:
              Begin
                ArbeitsSektion.clear;

                inputlist := TXStringList.create;
                inputname := Remaining;

                if produceStringList (sektion ,Remaining, Remaining, inputlist, InfoSyntaxError)
                then // do we get the section as a string list? then ready.
                begin
                  Arbeitssektion.Assign(inputlist);
                  if Arbeitssektion.Count > 0 then
                  begin
                   ArbeitsSektion.Name := ArbeitsSektion.Name +  ' {' + inputname + '} ';
                   ArbeitsSektion.StartLineNo := 1;
                  end
                end

                 // Otherwise, we should have a file name and try to get our command lines from it
                else if EvaluateString (Remaining, Remaining, FName, InfoSyntaxError)
                then
                Begin
                  ArbeitsSektion.Name := ArbeitsSektion.Name + ' "' + FName + '"';
                  Expression := Expression + ' ["' + FName + '"]';
                  Fname := ExpandFileName(Fname);
                  if CheckFileExists (Fname, ErrorInfo)
                  then
                  Begin
                    try
                      LoadValidLinesFromFile (FName, ArbeitsSektion);

                      ArbeitsSektion.StartLineNo := 1;
                    except
                      Logdatei.DependentAddError ('File "' + Fname + '" cannot be read', BaseLevel);
                    end;
                  End
                  else
                   Begin
                    Logdatei.DependentAddError ('Error: File "' + Fname + '" not found', BaseLevel);
                  End;
                End
                else
                  reportError (Sektion, i, Expression + '^' + Remaining, InfoSyntaxError);

              End
            End;


            // treating first the special cases of sub sections and loops
            if StatKind in [tsActions,tsProfileActions]
            then
            Begin
              if StatKind = tsProfileActions then
                runProfileActions := true;
              LogDatei.DependentAdd ('', LevelInfo);
              LogDatei.DependentAdd ('~~~~~~~ Start Sub ~~~~~~~  ' + ArbeitsSektion.Name, LevelInfo);
              ArbeitsSektion.NestingLevel := NestLevel; // ArbeitsSektion.NestingLevel + 1;
              ApplyTextConstants (TXStringList (ArbeitsSektion), false);

              ActionResult := doAktionen (ArbeitsSektion, Sektion);
              LogDatei.DependentAdd ('', LevelInfo);
              LogDatei.DependentAdd ('~~~~~~~ End Sub   ~~~~~~~  ' + ArbeitsSektion.Name, LevelInfo);
              LogDatei.DependentAdd ('', LevelInfo);
              runProfileActions := false;
            End

            else if StatKind = tsLoopStringList
            // we have to fetch the ArbeitsSektion after checking the loop syntax
            then
            Begin
              if inloop
              then
              begin
                syntaxCheck := false;
                InfoSyntaxError := 'loop in loop not yet implemented';
              End
              else
              begin
                // syntax: for varname in list
                syntaxCheck := false;
                GetWord (Remaining, loopvar, Remaining, WordDelimiterWhiteSpace);
                if     ( VarList.IndexOf (LowerCase (loopvar)) >= 0 )
                    or  ( listOfStringLists.IndexOf (LowerCase (loopvar)) >= 0 )
                then
                   InfoSyntaxError := 'Existing variable must not be used als loop variable'
                else
                Begin
                  VarList.add (loopvar);
                  ValuesList.add ('');

                  if Skip ('in', Remaining, Remaining, InfoSyntaxError)
                      and produceStringList (sektion, Remaining, Remaining, looplist, InfoSyntaxError)
                      and Skip ('do', Remaining, Remaining, InfoSyntaxError)
                  then
                  begin
                    if looplist.count = 0 then
                    begin
                       LogDatei.log('Warning: list to loop through is empty - no loop ...', LLWarning);
                       // clearing the loop variable from the list of variables, first the value
                       ValuesList.Delete( varlist.indexOf (loopvar));
                       varlist.Delete( varlist.indexOf (loopvar) );
                       syntaxCheck := true;
                    end
                    else
                    begin
                      syntaxCheck := true;
                      inloop := true;
                      //GetWord (Remaining, Expression, Remaining, WordDelimiterSet1);
                      LogDatei.DependentAdd ('', LevelInfo);

                      s1 := '';
                      for loopindex := 0 to looplist.count - 2 do
                      Begin s1 := s1 + '''' + looplist[loopindex] + ''', '; End;
                      if looplist.count > 0
                      then
                        s1 := s1 + '''' + looplist[looplist.count - 1]+ '''';

                      LogDatei.DependentAdd ('~~~~~~ Looping through:  ' + s1, LevelInfo);
                      LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel + 1;

                      stayOnStatement := remaining;
                    end;
                   end;
                 End;
               end;

               if not syntaxCheck then reportError (Sektion, i, Expression, InfoSyntaxError);

            End

            else //
            Begin
              if StatKind in [tsFileActions]
              then
              Begin
                // do ApplyTextConstants later while working
              End
              else
              Begin
                if StatKind in [tsExecutePython, tsExecuteWith_escapingStrings]
                then
                Begin
                  ApplyTextConstants (TXStringList (ArbeitsSektion), true);
                  ApplyTextVariables (TXStringList (ArbeitsSektion), true);
                End
                else
                Begin
                  ApplyTextConstants (TXStringList (ArbeitsSektion), false);
                  ApplyTextVariables (TXStringList (ArbeitsSektion), false);
                End;
              End;


              if inloop then ArbeitsSektion.GlobalReplace(1, loopvar, loopvalue, false);

              case StatKind of
                tsMessage:
                  if skip ('=', remaining, remaining, InfoSyntaxError)
                  then
                    ActionResult := doInfo (Remaining)
                  else if EvaluateString (Remaining, Remaining, Parameter, InfoSyntaxError)
                  then
                  begin
                    ActionResult := doInfo (Parameter);
                    LogDatei.DependentAdd('message '+Parameter, LLnotice)
                  end
                  else
                    ActionResult
                    := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);

                tsMessageFile:
                  if EvaluateString (Remaining, Remaining, FName, InfoSyntaxError)
                  then
                  Begin
                    {$IFDEF GUI}
                    CreateSystemInfo;
                    SystemInfo.Memo1.Lines.clear;
                    try
                      Fname := ExpandFileName(Fname);
                      SystemInfo.Memo1.Lines.LoadFromFile (FName);
                      //SystemInfo.Memo1.Lines.Text := reencode(SystemInfo.Memo1.Lines.Text, 'system');
                      Logdatei.DependentAdd ('', LevelComplete);
                      Logdatei.DependentAdd ('ShowMessagefile "' + Fname + '"', LevelComplete);
                      SystemInfo.Showmodal;
                    except
                        on E: exception do
                        Begin
                          Logdatei.DependentAdd ('ShowMessagefile "' + Fname + '"', LLwarning);
                          Logdatei.DependentAdd ('  File does not exist or cannot be accessed, system message: "' + E.Message +'"',
                                                 LLwarning);
                        End
                    end;

                    SystemInfo.free; SystemInfo := nil;
                    FBatchOberflaeche.BringToFront;
                    {$ENDIF GUI}

                  End
                  else
                    ActionResult
                    := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);


                  tsIncludeInsert:
                    begin
                      syntaxCheck := EvaluateString (Remaining, Remaining, FName, InfoSyntaxError);
                      if syntaxCheck then
                      Begin
                        try
                          incfilename := FName;
                          LogDatei.DependentAdd('Found Include statement for: '+incfilename,LLDebug);
                          found := false;
                          if FileExistsUTF8(incfilename) then
                          begin
                            fullincfilename := incfilename;
                            found := true;
                          end;
                          if FileExistsUTF8(ExtractFileDir(Paramstr(0))+PathDelim+'lib'+PathDelim+incfilename) then
                          begin
                            fullincfilename := ExtractFileDir(Paramstr(0))+PathDelim+'lib'+PathDelim+incfilename;
                            found := true;
                          end;
                          if FileExistsUTF8(ExtractFileDir(FFilename)+PathDelim+incfilename) then
                          begin
                            fullincfilename := ExtractFileDir(FFilename)+PathDelim+incfilename;
                            found := true;
                          end;
                          if found then
                          begin
                            inclist := TStringList.Create;
                            inclist.LoadFromFile(fullincfilename);
                            Encoding2use := searchencoding(inclist.Text);
                            //Encoding2use := inclist.Values['encoding'];
                            inclist.Free;
                            if Encoding2use = '' then Encoding2use := 'system';
                            LogDatei.DependentAdd('Will Include : '+incfilename+' with encoding: '+Encoding2use,LLDebug2);
                            assignfile(incfile,fullincfilename);
                            reset(incfile);
                            //script.Strings[i] := '';
                            k := 0;
                            while not eof(incfile) do
                            begin
                              inc(k);
                              readln(incfile, incline);
                              //LogDatei.DependentAdd('Will Include line (raw): '+incline,LLDebug3);
                              incline := reencode(incline, Encoding2use,usedEncoding);
                              //LogDatei.DependentAdd('Will Include line (reencoded): '+incline,LLDebug3);
                              for constcounter := 1 to ConstList.Count   do
                                if Sektion.replaceInLine(incline, Constlist.Strings [constcounter-1], ConstValuesList.Strings [constcounter-1], false,replacedline)
                                then incline := replacedline;
                              LogDatei.DependentAdd('Will Include line (constants replaced): '+incline,LLDebug3);
                              Sektion.Insert(i-1+k,incline);
                              LogDatei.DependentAdd('Line included at pos: '+inttostr(i-1+k)+' to Sektion with '+inttostr(Sektion.Count)+' lines.',LLDebug3);
                              //LogDatei.DependentAdd('Will Include add at pos '+inttostr(Sektion.StartLineNo + i-1+k)+'to FLinesOriginList with count: '+inttostr(script.FLinesOriginList.Count),LLDebug3);
                              script.FLinesOriginList.Insert(Sektion.StartLineNo + i-1+k,incfilename+ ' Line: '+inttostr(k));
                              LogDatei.DependentAdd('Include added to FLinesOriginList.',LLDebug3);
                            end;
                            closeFile(incfile);
                            linecount := Count;
                            LogDatei.DependentAdd('Included (insert) file: '+fullincfilename+' with encoding: '+usedEncoding,LLInfo);
                          end
                          else
                          begin
                            LogDatei.DependentAdd('Error: Could not find include file :'+incfilename,LLCritical);
                            FExtremeErrorLevel:= levelFatal;
                          end;
                         except
                              on E: exception do
                             Begin
                                Logdatei.DependentAdd ('Include_Insert "' + Fname + '"', LLCritical);
                                Logdatei.DependentAdd (' Failed to include (insert) file, system message: "' + E.Message +'"',
                                                       LLCritical);
                                FExtremeErrorLevel:= levelFatal;
                              End
                          end;
                      End
                      else
                        ActionResult
                        := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);
                    end;

                  tsIncludeAppend:
                    begin
                      syntaxCheck := EvaluateString (Remaining, Remaining, FName, InfoSyntaxError);
                      if syntaxCheck then
                      Begin
                        try
                          incfilename := FName;
                          LogDatei.DependentAdd('Found Include statement for: '+incfilename,LLDebug);
                          found := false;
                          if FileExistsUTF8(incfilename) then
                          begin
                            fullincfilename := incfilename;
                            found := true;
                          end;
                          if FileExistsUTF8(ExtractFileDir(Paramstr(0))+PathDelim+'lib'+PathDelim+incfilename) then
                          begin
                            fullincfilename := ExtractFileDir(Paramstr(0))+PathDelim+'lib'+PathDelim+incfilename;
                            found := true;
                          end;
                          if FileExistsUTF8(ExtractFileDir(FFilename)+PathDelim+incfilename) then
                          begin
                            fullincfilename := ExtractFileDir(FFilename)+PathDelim+incfilename;
                            found := true;
                          end;
                          if found then
                          begin
                            inclist := TStringList.Create;
                            inclist.LoadFromFile(fullincfilename);
                            Encoding2use := searchencoding(inclist.Text);
                            //Encoding2use := inclist.Values['encoding'];
                            inclist.Free;
                            if Encoding2use = '' then Encoding2use := 'system';
                            linecount := count;
                            assignfile(incfile,fullincfilename);
                            reset(incfile);
                            //script.Strings[i] := '';
                            k:=0;
                            while not eof(incfile) do
                            begin
                              inc(k);
                              readln(incfile, incline);
                              incline := reencode(incline, Encoding2use,usedEncoding);
                              for constcounter := 1 to ConstList.Count   do
                                if Sektion.replaceInLine(incline, Constlist.Strings [constcounter-1], ConstValuesList.Strings [constcounter-1], false,replacedline)
                                then incline := replacedline;
                              append(incline);
                              linecount := Count;
                              script.FLinesOriginList.Append(incfilename+ ' Line: '+inttostr(k));
                            end;
                            closeFile(incfile);
                            //linecount := Count;
                            LogDatei.DependentAdd('Included (append) file: '+fullincfilename+' with encoding: '+usedEncoding,LLInfo);
                          end
                          else
                          begin
                            LogDatei.DependentAdd('Error: Could not find include file :'+incfilename,LLCritical);
                            FExtremeErrorLevel:= levelFatal;
                          end;
                         except
                              on E: exception do
                             Begin
                                Logdatei.DependentAdd ('Include_Append "' + Fname + '"', LLCritical);
                                Logdatei.DependentAdd (' Failed to include (append) file, system message: "' + E.Message +'"',
                                                       LLCritical);
                                FExtremeErrorLevel:= levelFatal;
                              End
                          end;
                      End
                      else
                        ActionResult
                        := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);
                    end;


                  tsIncludeLog:
                    begin
                      logtailEncodingstr := 'system';
                      syntaxCheck := EvaluateString (Remaining, Remaining, FName, InfoSyntaxError);
                      if syntaxCheck and (Remaining <> '') then
                               syntaxCheck := EvaluateString (Remaining, Remaining, logtailLinecountstr, InfoSyntaxError);
                      if syntaxCheck and (Remaining <> '') then
                               syntaxCheck := EvaluateString (Remaining, Remaining, logtailEncodingstr, InfoSyntaxError);
                      if syntaxCheck then
                      Begin
                        try
                          logtailLinecount := StrToInt(logtailLinecountstr);
                          logdatei.includelogtail(fname,logtailLinecount,logtailEncodingstr);
                         except
                              on E: exception do
                             Begin
                                Logdatei.DependentAdd ('IncludeLogFile "' + Fname + '"', LLwarning);
                                Logdatei.DependentAdd (' Failed to include log file, system message: "' + E.Message +'"',
                                                       LLwarning);
                              End
                          end;
                      End
                      else
                        ActionResult
                        := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);
                    end;

                  tsShrinkFileToMB:
                    begin
                      syntaxCheck := EvaluateString (Remaining, Remaining, FName, InfoSyntaxError);
                      if syntaxCheck and (Remaining <> '') then
                               syntaxCheck := EvaluateString (Remaining, Remaining, logtailLinecountstr, InfoSyntaxError);
                      if syntaxCheck then
                      Begin
                        try
                          logtailLinecount := StrToInt(logtailLinecountstr);
                          shrinkFileToMB(fname,logtailLinecount);
                         except
                              on E: exception do
                             Begin
                                Logdatei.DependentAdd ('shrinkFileToMB "' + Fname + '"', LLwarning);
                                Logdatei.DependentAdd (' Failed to shrink file, system message: "' + E.Message +'"',
                                                       LLwarning);
                              End
                          end;
                      End
                      else
                        ActionResult
                        := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);
                    end;


                tsShowBitmap:
                   Begin
                     SyntaxCheck := true;

                     if PathDelim <> '/' then
                     begin
                       posSlash := pos ('/', Remaining);
                       if posSlash > 0
                       then
                       Begin
                          if    (length (Remaining) >= posSlash  + 1)
                            and (Remaining[posSlash + 1] in ['1'..'9'])
                          then
                          Begin
                            imageNo := ord (Remaining[posSlash + 1]) - ord('0');

                            if (imageNo > 4)
                            or  (length (Remaining) >= posSlash  + 2)
                             and (Remaining[posSlash + 2] in ['0'..'9'])
                            then
                            Begin
                              SyntaxCheck := false;
                              InfoSyntaxError := 'only supported 1 .. 4 ';
                            End;

                            system.delete (Remaining, posSlash, 2);
                          End
                          else
                          Begin
                            SyntaxCheck := false;
                            InfoSyntaxError := 'after "/", a number between 1 and 9 is expected';
                          End
                       End
                       else
                         {$IFDEF GUI}
                         imageNo := centralImageNo;
                         {$ENDIF GUI}
                     end
                     else
                         {$IFDEF GUI}
                         imageNo := centralImageNo;
                        {$ENDIF GUI}

                     if syntaxCheck
                     then
                     Begin
                       Remaining := cutLeftBlanks (Remaining);

                       Labeltext := '';
                       FName := '';

                       if Remaining = ''
                       then
                       Begin
                       (*
                        // set back to default
                         if imageNo <= wibtch.maxBitmaps
                         then
                         Begin
                           Labeltext := wibtch.labelTexts [imageNo];
                           FName := wibtch.bitmapFnames [imageNo];
                         End
                       *)
                       End

                       else
                       Begin
                          syntaxCheck := EvaluateString (Remaining, Remaining, FName, InfoSyntaxError);

                          if syntaxCheck and (Remaining <> '')
                          then
                             syntaxCheck := EvaluateString (Remaining, Remaining, Labeltext, InfoSyntaxError)
                       End;
                     End;

                     if syntaxCheck
                     then
                     begin
                       if FName <> '' then FName := ExpandFileName(FName);
                       {$IFDEF GUI}
                       FBatchOberflaeche.setPicture (FName, Labeltext);
                       {$ENDIF GUI}
                     end
                     else
                       ActionResult
                       := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);

                  end;

                tsChangeDirectory:
                  Begin
                    syntaxCheck := false;
                    if skip ('=', remaining, Parameter, InfoSyntaxError)
                    then syntaxCheck := true
                    else if EvaluateString (Remaining, Remaining, Parameter, InfoSyntaxError)
                    then syntaxCheck := true;

                    if syntaxCheck then
                    begin
                       Parameter := ExpandFileName(Parameter);
                       if DirectoryExists(Parameter) then
                         ChangeDirectory(parameter)
                       else
                         LogDatei.DependentAdd ('Error at ChangeDirectory: '+Parameter+ ' is not a directory', LLError);
                    end;
                  End;


                tsPause:
                   Begin
                    syntaxCheck := false;
                    if skip ('=', remaining, Parameter, InfoSyntaxError)
                    then syntaxCheck := true
                    else if EvaluateString (Remaining, Remaining, Parameter, InfoSyntaxError)
                    then syntaxCheck := true;

                    if syntaxCheck
                    then
                    Begin
                      {$IFDEF GUI}
                      if messagedlg (Parameter + LineEnding + 'Bereit zur Fortsetzung?', mtConfirmation, [mbYes], 0)
                       = mrNo
                      then
                        ActionResult := tsrExitProcess;
                      {$ENDIF GUI}
                    End
                    else
                      ActionResult
                      := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);
                  End;

                  tsSleep:
                   Begin
                    syntaxCheck := true;
                    processmess;

                    try
                      sleepSecs := StrToInt (remaining);

                    except
                      syntaxCheck := false;
                      InfoSyntaxError := remaining + ' -- expected an integer (number of secs) ';
                    end;

                    if syntaxCheck
                    then
                      Sleep(1000 * sleepSecs)
                    else
                      ActionResult
                      := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);

                    processmess;

                  End;

               tsStop:
                   Begin
                    syntaxCheck := false;
                    if skip ('=', remaining, Parameter, InfoSyntaxError)
                    then syntaxCheck := true
                    else if EvaluateString (Remaining, Remaining, Parameter, InfoSyntaxError)
                    then syntaxCheck := true;

                    if syntaxCheck
                    then
                    Begin
                      {$IFDEF GUI}
                      if messagedlg (Parameter + LineEnding + '... beenden?', mtConfirmation, [mbYes, mbNo], 0)
                       = mrYes
                      then
                        ActionResult := tsrExitProcess;
                      {$ELSE GUI}
                        ActionResult := tsrExitProcess;
                      {$ENDIF GUI}
                    End
                    else
                      ActionResult
                      := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);
                  End;


                tsComment:
                  Begin
                    syntaxCheck := false;
                    if skip ('=', remaining, Parameter, InfoSyntaxError)
                    then syntaxCheck := true
                    else if EvaluateString (Remaining, Remaining, Parameter, InfoSyntaxError)
                    then syntaxCheck := true;

                    if syntaxCheck
                    then
                       LogDatei.DependentAdd ('comment: ' + Parameter, LLnotice);
                  End;

                tsActionProgress:
                  Begin
                    syntaxCheck := false;
                    if skip ('=', remaining, Parameter, InfoSyntaxError)
                    then syntaxCheck := true
                    else if EvaluateString (Remaining, Remaining, Parameter, InfoSyntaxError)
                    then syntaxCheck := true;
                    if syntaxCheck
                    then
                       LogDatei.DependentAdd ('set ActionProgress to: ' + Parameter, LLnotice);
                       opsidata.setActionProgress(Parameter);
                  End;


                tsLogWarning:
                  Begin
                    syntaxCheck := false;
                    if skip ('=', remaining, Parameter, InfoSyntaxError)
                    then syntaxCheck := true
                    else if EvaluateString (Remaining, Remaining, Parameter, InfoSyntaxError)
                    then syntaxCheck := true
                    else InfoSyntaxError := 'Info string expected';

                    if syntaxCheck
                    then
                    Begin
                       LogDatei.DependentAddWarning ('Warning: ' + Parameter, LLwarning);
                       FNumberOfWarnings := FNumberOfWarnings + 1;
                    end
                    else
                     ActionResult
                      := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);

                  End;

                tsLogError:
                  Begin
                    syntaxCheck := false;
                    if skip ('=', remaining, Parameter, InfoSyntaxError)
                    then syntaxCheck := true
                    else if EvaluateString (Remaining, Remaining, Parameter, InfoSyntaxError)
                    then syntaxCheck := true
                    else InfoSyntaxError := 'Info string expected';

                    if syntaxCheck
                    then
                    Begin
                       LogDatei.DependentAddError ('Error: ' + Parameter, LLerror);
                       FNumberOfErrors := FNumberOfErrors + 1;
                    End
                    else
                     ActionResult
                      := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);
                  End;

                 tsSetSkinDir:
                   Begin
                    syntaxCheck := false;
                    if EvaluateString (Remaining, Remaining, Parameter, InfoSyntaxError)
                    then syntaxCheck := true
                    else InfoSyntaxError := 'Expected a string (directory path)';

                    if syntaxCheck
                    then
                    Begin
                      if Parameter <> '' then FName := ExpandFileName(Parameter);
                      {$IFDEF GUI}
                      FBatchOberflaeche.loadSkin(Parameter);
                      processMess;
                      {$ENDIF GUI}
                    End
                    else
                     ActionResult
                      := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);
                  End;


                 tsKillTask:
                   Begin
                     syntaxCheck := false;
                     if EvaluateString (Remaining, Remaining, Fname, InfoSyntaxError)
                     then
                     Begin
                       syntaxCheck := true;
                       {$IFNDEF WIN64}
                       if KillTask (Fname, Info)
                       then
                       Begin
                         LogDatei.Log (info, LLInfo);
                       End
                       else
                       Begin
                         LogDatei.log('"'+ Fname + '" could not be killed, ' + info, LLWarning );
                       End
                       {$ELSE WIN64}
                       LogDatei.Log ('Not implemnted on win64', LLWarning);
                       {$ENDIF WIN64}
                    End
                    else
                       ActionResult := reportError (Sektion, i, Expression, InfoSyntaxError);
                   End;

                {$IFDEF WIN32}
                tsBlockInput:
                  Begin
                    syntaxCheck := false;
                    if EvaluateString (Remaining, Remaining, Parameter, InfoSyntaxError) then
                    Begin
                      if UpperCase (Parameter) = UpperCase ('True')
                      then
                      Begin
                        syntaxCheck := true;
                        ActionResult := tsrPositive;
                        if winBlockInput(true) then LogDatei.DependentAdd ('Blocking Input', LLNotice)
                        else LogDatei.DependentAdd ('Failed Blocking Input ...', LLWarning);
                      End

                      else if UpperCase (Parameter) = UpperCase ('False')
                      then
                      Begin
                        syntaxCheck := true;
                        ActionResult := tsrPositive;
                        if winBlockInput(false) then LogDatei.DependentAdd ('Unblocking Input', LLNotice)
                        else LogDatei.DependentAdd ('Failed Unblocking Input ...', LLWarning);
                      End;
                    end;
                    if not syntaxCheck then
                    ActionResult
                        := reportError (Sektion, i, Sektion.strings [i-1], 'Expected a boolean string (true/false)');
                    if not (Remaining = '')  then  LogDatei.DependentAdd ('Error at Blockinput: trailing parameter: '+Parameter+ ' ignored', LLWarning);
                  End;


                tsLocalAdmin:
                  Begin
                    if UpperCase (Remaining) = UpperCase ('/Create1')
                    then
                    Begin
                      LogDatei.DependentAdd ('Creating temporary local admin ...', LLNotice);
                      ActionResult := tsrPositive;
                      if CreateTemporaryLocalAdmin(traAdmin) then
                      begin
                        LogDatei.DependentAdd ('Created temporary local admin ...', LLNotice);

                        FConstValuesList.Strings[FConstList.IndexOf('%AppDataDir%')] := GetAppDataPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentAppDataDir%')] := GetAppDataPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentStartmenuDir%')] := GetStartmenuPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentDesktopDir%')] := GetDesktopPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentStartupDir%')] := GetStartupPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentProgramsDir%')] := GetProgramsPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentSendToDir%')] := GetSendToPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentProfileDir%')] := getUserProfilePath;
                        FConstValuesList.Strings[FConstList.IndexOf('%AppDataDir%')] := GetAppDataPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%AppDataDir%')] := GetAppDataPath;

                        ApplyTextConstants (TXStringList (ArbeitsSektion), false);
                      end
                      else LogDatei.DependentAdd ('Failed creating temporary local admin ...', LLWarning);
                    End

                    else if UpperCase (Remaining) = UpperCase ('/Create2')
                    then
                    Begin
                      LogDatei.DependentAdd ('Creating temporary local admin ...', LLNotice);
                      ActionResult := tsrPositive;
                      if CreateTemporaryLocalAdmin(traAdminProfile) then
                      begin
                        LogDatei.DependentAdd ('Created temporary local admin ...', LLNotice);

                        FConstValuesList.Strings[FConstList.IndexOf('%AppDataDir%')] := GetAppDataPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentAppDataDir%')] := GetAppDataPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentStartmenuDir%')] := GetStartmenuPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentDesktopDir%')] := GetDesktopPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentStartupDir%')] := GetStartupPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentProgramsDir%')] := GetProgramsPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentSendToDir%')] := GetSendToPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentProfileDir%')] := getUserProfilePath;
                        FConstValuesList.Strings[FConstList.IndexOf('%AppDataDir%')] := GetAppDataPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%AppDataDir%')] := GetAppDataPath;

                        ApplyTextConstants (TXStringList (ArbeitsSektion), false);
                      end
                      else LogDatei.DependentAdd ('Failed creating temporary local admin ...', LLWarning);
                    End

                    else if UpperCase (Remaining) = UpperCase ('/Create3')
                    then
                    Begin
                      LogDatei.DependentAdd ('Creating temporary local admin ...', LLNotice);
                      ActionResult := tsrPositive;
                      if CreateTemporaryLocalAdmin(traAdminProfileImpersonate) then
                      begin
                        LogDatei.DependentAdd ('Created temporary local admin ...', LLNotice);

                        FConstValuesList.Strings[FConstList.IndexOf('%AppDataDir%')] := GetAppDataPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentAppDataDir%')] := GetAppDataPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentStartmenuDir%')] := GetStartmenuPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentDesktopDir%')] := GetDesktopPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentStartupDir%')] := GetStartupPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentProgramsDir%')] := GetProgramsPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentSendToDir%')] := GetSendToPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentProfileDir%')] := getUserProfilePath;
                        FConstValuesList.Strings[FConstList.IndexOf('%AppDataDir%')] := GetAppDataPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%AppDataDir%')] := GetAppDataPath;

                        ApplyTextConstants (TXStringList (ArbeitsSektion), false);
                      end
                      else LogDatei.DependentAdd ('Failed creating temporary local admin ...', LLWarning);
                    End

                    else if UpperCase (Remaining) = UpperCase ('/Create4')
                    then
                    Begin
                      LogDatei.DependentAdd ('Creating temporary local admin ...', LLNotice);
                      ActionResult := tsrPositive;
                      if CreateTemporaryLocalAdmin(traAdminProfileImpersonateExplorer) then
                      begin
                        LogDatei.DependentAdd ('Created temporary local admin ...', LLNotice);

                        FConstValuesList.Strings[FConstList.IndexOf('%AppDataDir%')] := GetAppDataPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentAppDataDir%')] := GetAppDataPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentStartmenuDir%')] := GetStartmenuPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentDesktopDir%')] := GetDesktopPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentStartupDir%')] := GetStartupPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentProgramsDir%')] := GetProgramsPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentSendToDir%')] := GetSendToPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%CurrentProfileDir%')] := getUserProfilePath;
                        FConstValuesList.Strings[FConstList.IndexOf('%AppDataDir%')] := GetAppDataPath;
                        FConstValuesList.Strings[FConstList.IndexOf('%AppDataDir%')] := GetAppDataPath;

                        ApplyTextConstants (TXStringList (ArbeitsSektion), false);
                      end
                      else LogDatei.DependentAdd ('Failed creating temporary local admin ...', LLWarning);
          End

          else if UpperCase (Remaining) = UpperCase ('/Delete')
          then
          Begin
            LogDatei.DependentAdd ('Deleting temporary local admin ...', LLNotice);
                      ActionResult := tsrPositive;
                      if opsiSetupAdmin_created then
                        if DeleteTemporaryLocalAdmin then
                        begin
                          LogDatei.DependentAdd ('Deleted temporary local admin ...', LLNotice);

                          FConstValuesList.Strings[FConstList.IndexOf('%AppDataDir%')] := GetAppDataPath;
                          FConstValuesList.Strings[FConstList.IndexOf('%CurrentAppDataDir%')] := GetAppDataPath;
                          FConstValuesList.Strings[FConstList.IndexOf('%CurrentStartmenuDir%')] := GetStartmenuPath;
                          FConstValuesList.Strings[FConstList.IndexOf('%CurrentDesktopDir%')] := GetDesktopPath;
                          FConstValuesList.Strings[FConstList.IndexOf('%CurrentStartupDir%')] := GetStartupPath;
                          FConstValuesList.Strings[FConstList.IndexOf('%CurrentProgramsDir%')] := GetProgramsPath;
                          FConstValuesList.Strings[FConstList.IndexOf('%CurrentSendToDir%')] := GetSendToPath;
                          FConstValuesList.Strings[FConstList.IndexOf('%CurrentProfileDir%')] := getUserProfilePath;
                          FConstValuesList.Strings[FConstList.IndexOf('%AppDataDir%')] := GetAppDataPath;
                          FConstValuesList.Strings[FConstList.IndexOf('%AppDataDir%')] := GetAppDataPath;

                          ApplyTextConstants (TXStringList (ArbeitsSektion), false);
                        end
                        else LogDatei.DependentAdd ('Failed deleting temporary local admin ...', LLWarning);
                    End
                    else if Remaining = ''
                    then
                      ActionResult
                        := reportError (Sektion, i, Sektion.strings [i-1], 'Parameter needed')
                    else
                      ActionResult
                        := reportError (Sektion, i, Sektion.strings [i-1], 'not an allowed Parameter');
                  End;
                  {$ENDIF WIN32}


                tsExitWindows:
                  Begin
                    if UpperCase (Remaining) = UpperCase ('/ImmediateReboot')
                    then
                    Begin
                      PerformExitWindows := txrImmediateReboot;
                      ActionResult := tsrExitWindows;
                      scriptstopped := true;
                      LogDatei.DependentAdd ('ExitWindows set to Immediate Reboot', BaseLevel);
                    End
                    else if UpperCase (Remaining) = UpperCase ('/ImmediateLogout')
                    then
                    Begin
                      PerformExitWindows := txrImmediateLogout;
            LogDatei.DependentAdd ('', BaseLevel);
                      ActionResult := tsrExitWindows;
                      scriptstopped := true;
                      LogDatei.DependentAdd ('ExitWindows set to Immediate Logout', BaseLevel);
                    End
                    else if UpperCase (Remaining) = UpperCase ('/Reboot')
                    then
                    Begin
                      PerformExitWindows := txrReboot;
            LogDatei.DependentAdd ('', BaseLevel);
                      LogDatei.DependentAdd ('ExitWindows set to Reboot', BaseLevel);
                    End
                    else if UpperCase (Remaining) = UpperCase ('/RebootWanted')
                    then
                    Begin
                      if PerformExitWindows < txrRegisterForReboot
                      then
                      Begin
                        PerformExitWindows := txrRegisterForReboot;
              LogDatei.DependentAdd ('', BaseLevel);
                        LogDatei.DependentAdd ('ExitWindows set to RegisterReboot', BaseLevel);
                      End
                      else
                        LogDatei.DependentAdd ('ExitWindows already set to Reboot', BaseLevel);
                    End
                    else if UpperCase (Remaining) = UpperCase ('/LogoutWanted')
                    then
                    Begin
                      if PerformExitWindows < txrRegisterForLogout
                      then
                      Begin
                        PerformExitWindows := txrRegisterForLogout;
                        LogDatei.DependentAdd ('', BaseLevel);
                        LogDatei.DependentAdd ('ExitWindows set to RegisterForLogout', BaseLevel);
                      End
                      else
                        LogDatei.DependentAdd ('ExitWindows already set to (Register)Reboot', BaseLevel);
                    End

            else if UpperCase (Remaining) = UpperCase ('/ShutdownWanted')
                    then
                    Begin
                      PerformShutdown := tsrRegisterForShutdown;
                      LogDatei.DependentAdd ('', BaseLevel);
                      LogDatei.DependentAdd ('PerformShutdown set to RegisterForShutdown', BaseLevel);
                    End

                    else if Remaining = ''
                    then
                      ActionResult
                        := reportError (Sektion, i, Sektion.strings [i-1], 'Parameter needed')
                    else
                      ActionResult
                        := reportError (Sektion, i, Sektion.strings [i-1], 'not an allowed Parameter');
                  End;

                  tsAutoActivityDisplay:
                    if skip ('=', remaining, remaining, InfoSyntaxError)
                    then
                    Begin
                       if   UpperCase (Remaining) = 'TRUE' then
                       begin
                         LogDatei.DependentAdd ('AutoActivityDisplay was '+BoolToStr(AutoActivityDisplay,true)+' is set to true', LLNotice);
                         AutoActivityDisplay := true;
                       end
                       else
                       begin
                         LogDatei.DependentAdd ('AutoActivityDisplay was '+BoolToStr(AutoActivityDisplay,true)+' is set to false', LLNotice);
                         AutoActivityDisplay := false;
                       end;
                    End
                    else
                      ActionResult
                      := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);


              tsFatalOnSyntaxError:
                if skip ('=', remaining, remaining, InfoSyntaxError)
                then
                Begin
                   if   UpperCase (Remaining) = 'TRUE' then
                   begin
                     LogDatei.DependentAdd ('FatalOnSyntaxError was '+BoolToStr(FatalOnSyntaxError,true)+' is set to true', LLNotice);
                     FatalOnSyntaxError := true;
                   end
                   else
                   begin
                     LogDatei.DependentAdd ('FatalOnSyntaxError was '+BoolToStr(FatalOnSyntaxError,true)+' is set to false', LLNotice);
                     FatalOnSyntaxError := false;
                     if (FExtremeErrorLevel=LevelFatal) and (LogDatei.ActionProgress='Syntax Error') then
                       FExtremeErrorLevel := Level_not_initialized;
                   end;
                End
                else
                  ActionResult
                  := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);

              tsFatalOnRuntimeError:
                if skip ('=', remaining, remaining, InfoSyntaxError)
                then
                Begin
                   if   UpperCase (Remaining) = 'TRUE' then
                   begin
                     LogDatei.log('FatalOnRuntimeError was '+BoolToStr(FatalOnRuntimeError,true)+' is set to true', LLNotice);
                     FatalOnRuntimeError := true;
                   end
                   else
                   begin
                     LogDatei.log('FatalOnRuntimeError was '+BoolToStr(FatalOnRuntimeError,true)+' is set to false', LLNotice);
                     FatalOnRuntimeError := false;
                   end;
                End
                else
                  ActionResult
                  := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);

                tsSetExitOnError:
                  if skip ('=', remaining, remaining, InfoSyntaxError)
                  then
                  Begin
                     if   UpperCase (Remaining) = 'TRUE' then
                     begin
                      LogDatei.DependentAdd ('ExitOnError was '+BoolToStr(ExitOnError,true)+' is set to true', LLNotice);
                      ExitOnError := true;
                     end
                     else
                     begin
                       LogDatei.DependentAdd ('ExitOnError was '+BoolToStr(ExitOnError,true)+' is set to false', LLNotice);
                       ExitOnError := false;
                     end;
                  End
                  else
                    ActionResult
                    := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);

                tsSetFatalError:
                  if remaining = ''
                  then
                  Begin
                     FExtremeErrorLevel := LevelFatal;
                     LogDatei.DependentAdd('Error level set to fatal', LLnotice);
                     ActionResult := tsrFatalError;
                     scriptstopped := true;
                     NestLevel:= NestingLevel;
                     ActLevel:= NestLevel;
                  End
                  else
                  begin
                    EvaluateString (remaining, remaining, Parameter, infosyntaxerror);
                    if remaining = '' then
                    begin
                      FExtremeErrorLevel := LevelFatal;
                     LogDatei.DependentAdd('Error level set to fatal', LLnotice);
                      ActionResult := tsrFatalError;
                      LogDatei.ActionProgress:=Parameter;
                      scriptstopped := true;
                      //NestLevel:= NestingLevel;
                      //ActLevel:= NestLevel;
                    end
                    else
                        ActionResult
                        := reportError (Sektion, i, Sektion.strings [i-1], ' none or one parameter expected');
                  end;

                  tsSetSuccess:
                    if remaining = ''
                    then
                    Begin
                       LogDatei.DependentAdd('Set: Exit Script as successful', LLnotice);
                       ActionResult := tsrExitProcess;
                       scriptstopped := true;
                       //NestLevel:= NestingLevel;
                       //ActLevel:= NestLevel;
                    End
                    else
                    begin
                          ActionResult
                          := reportError (Sektion, i, Sektion.strings [i-1], ' no parameter expected');
                    end;

                  tsSetNoUpdate:
                    if remaining = ''
                    then
                    Begin
                       LogDatei.DependentAdd('Set: Do not run Update script', LLnotice);
                       runUpdate := false;
                    End
                    else
                    begin
                          ActionResult
                          := reportError (Sektion, i, Sektion.strings [i-1], ' no parameter expected');
                    end;

                tsSetSuspended:
                  if remaining = ''
                    then
                    Begin
                       LogDatei.DependentAdd('Set: Stop script and leave switches unchanged', LLnotice);
                       runUpdate := false;
                       script.suspended:= true;
                       scriptstopped := true;
                       ActionResult := tsrExitProcess;
                       //NestLevel:= NestingLevel;
                       //ActLevel:= NestLevel;
                    End
                    else
                    begin
                          ActionResult
                          := reportError (Sektion, i, Sektion.strings [i-1], ' no parameter expected');
                    end;

                tsSetMarkerErrorNumber:
                  if remaining = ''
                  then
                  Begin
                    LogDatei.ErrorNumberMarked := Logdatei.NumberOfErrors;
                    LogDatei.DependentAdd('Marked error number '
                        + inttostr(LogDatei.ErrorNumberMarked),
                        levelcomplete);
                  End
                  else
                    ActionResult
                    := reportError (Sektion, i, Sektion.strings [i-1], ' end of line expected');

                tsSaveVersionToProfile:
                  if remaining = ''
                  then
                  Begin
                    saveVersionToProfile;
                    LogDatei.DependentAdd('Saved productversion-packageversion to local profile',LLNotice);
                  End
                  else
                    ActionResult
                    := reportError (Sektion, i, Sektion.strings [i-1], ' end of line expected');


                tsSetReportMessages:
                  if skip ('=', remaining, remaining, InfoSyntaxError)
                  then
                  Begin
                     if    (UpperCase (Remaining) = 'OFF')
                        or (UpperCase (Remaining) = 'FALSE')
                     then
                     begin
                       LogDatei.DependentAdd ('ReportMessages was '+BoolToStr(ReportMessages,true)+' is set to true', LLNotice);
                       ReportMessages := false;
                     end
                     else
                     begin
                       LogDatei.DependentAdd ('ReportMessages was '+BoolToStr(ReportMessages,true)+' is set to false', LLNotice);
                       ReportMessages := true;
                     end;
                  End
                  else
                    ActionResult
                    := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);

                tsSetTimeMark:
                  Begin
                    markedTime :=  Time;

                    LogDatei.DependentAdd(FormatDateTime('hh:mm:ss:zzz', markedTime)
                    + '  ============  Time marked ', baselevel);
                  End;

                tsLogDiffTime:
                  Begin
                    diffTime := Time - markedTime;

                    LogDatei.DependentAdd(FormatDateTime('hh:mm:ss:zzz', diffTime)
                    + '  ============  Time passed since marked time  ', baselevel);
                  End;


                tsSetTraceMode:
                  if skip ('=', remaining, remaining, InfoSyntaxError)
                  then
                  Begin
                     if    (UpperCase (Remaining) = 'ON')
                        or (UpperCase (Remaining) = 'TRUE')
             then
                     Begin
                        TraceMode := true;
                        Logdatei.TraceMode := true;
                     end
                     else
                     begin
                        TraceMode := false;
                        Logdatei.TraceMode := false;
                     end
                  End
                  else
                    ActionResult
                    := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);

                tsSetOldLogLevel:
                  if skip ('=', remaining, remaining, InfoSyntaxError)
                  then
                  Begin
                    try
                      LogLevel := StrToInt (Remaining) + 4;
                      LogDatei.DependentAddWarning ('Warning: depricated: <LogLevel=> please use <setLogLevel=> ', LLwarning);
                      LogDatei.DependentAdd ('LogLevel was ' + inttoStr(LogDatei.LogLevel), LLessential);
                      LogDatei.LogLevel := Loglevel;
                      LogDatei.DependentAdd ('LogLevel set to ' + inttoStr(LogLevel), LLessential);
                    except
                      try
                        EvaluateString (remaining, remaining, Parameter, infosyntaxerror);
                        LogLevel := StrToInt (Parameter) + 4;
                        LogDatei.DependentAddWarning ('Warning: depricated: <LogLevel=> please use <setLogLevel=> ', LLwarning);
                        LogDatei.DependentAdd ('LogLevel was ' + inttoStr(LogDatei.LogLevel), LLessential);
                        LogDatei.LogLevel := Loglevel;
                        LogDatei.DependentAdd ('LogLevel set to ' + inttoStr(LogLevel), LLessential);
                      except
                        LogDatei.DependentAdd ('Integer conversion error, LogLevel could not be set, it is ' + inttoStr(LogLevel), Logdatei.loglevel);
                        LogLevel := LLinfo;
                      end;
                    end
                  End
                  else
                    ActionResult := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);


                tsSetLogLevel:
                  if skip ('=', remaining, remaining, InfoSyntaxError)
                  then
                  Begin
                    try
                      LogLevel := StrToInt (Remaining);
                      LogDatei.DependentAdd ('LogLevel was ' + inttoStr(LogDatei.LogLevel), LLinfo);
                      LogDatei.LogLevel := Loglevel;
                      LogDatei.DependentAdd ('LogLevel set to ' + inttoStr(LogLevel), LLinfo);
                    except
                      try
                        EvaluateString (remaining, remaining, Parameter, infosyntaxerror);
                        LogLevel := StrToInt (Parameter);
                        LogDatei.DependentAdd ('LogLevel was ' + inttoStr(LogDatei.LogLevel), LLinfo);
                        LogDatei.LogLevel := Loglevel;
                        LogDatei.DependentAdd ('LogLevel set to ' + inttoStr(LogLevel), LLinfo);
                      except
                        LogDatei.DependentAdd ('Integer conversion error, LogLevel could not be set, it is ' + inttoStr(LogLevel), Logdatei.loglevel);
                        LogLevel := LLinfo;
                      end;
                    end
                  End
                  else
                    ActionResult := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);

                tsSetConfidential:
                   Begin
                    syntaxCheck := false;
                    if EvaluateString (Remaining, Remaining, Parameter, InfoSyntaxError)
                    then syntaxCheck := true
                    else InfoSyntaxError := 'Expected a string (confidential)';

                    if syntaxCheck
                    then
                    Begin
                      LogDatei.AddToConfidentials(Parameter);
                    End
                    else
                     ActionResult
                      := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);
                  End;

                tsSetUsercontext:
                  if skip ('=', remaining, remaining, InfoSyntaxError)
                  then
                  Begin
                    EvaluateString (remaining, remaining, Parameter, infosyntaxerror);
                    LogDatei.DependentAdd ('Usercontext was ' + usercontext, LLessential);
                    usercontext := Parameter;
                    LogDatei.DependentAdd ('Usercontext set to ' + usercontext, LLessential);
                  End
                  else
                    ActionResult := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);


                tsSetOutputLevel:
                  if skip ('=', remaining, remaining, InfoSyntaxError)
                  then
                  Begin
                    try
                      OutputLevel := StrToInt (Remaining);
                      //LogDatei.DependentAdd ('OutputLevel was ' + inttoStr(LogDatei.LogLevel), LLessential);
                      {$IFDEF GUI}
                      FBatchOberflaeche.setOutputLevel(OutputLevel);
                      {$ENDIF GUI}
                      LogDatei.DependentAdd ('OutputLevel set to ' + inttoStr(OutputLevel), LLessential);
                    except
                      try
                        EvaluateString (remaining, remaining, Parameter, infosyntaxerror);
                        OutputLevel := StrToInt (Parameter);
                        //LogDatei.DependentAdd ('OutputLevel was ' + inttoStr(LogDatei.LogLevel), LLessential);
                        {$IFDEF GUI}
                        FBatchOberflaeche.setOutputLevel(OutputLevel);
                        {$ENDIF GUI}
                        LogDatei.DependentAdd ('OutputLevel set to ' + inttoStr(OutputLevel), LLessential);
                      except
                        LogDatei.DependentAdd ('Integer conversion error, OutputLevel could not be set, it is ' + inttoStr(LogLevel), Logdatei.loglevel);
                        {$IFDEF GUI}
                        FBatchOberflaeche.setOutputLevel(3);
                        {$ENDIF GUI}
                      end;
                    end
                  End
                  else
                    ActionResult := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);

                tsSetStayOnTop:
                   if skip ('=', remaining, remaining, InfoSyntaxError)
                   then
                   Begin
                     {$IFDEF GUI}
                      if    (UpperCase (Remaining) = 'ON')
                         or (UpperCase (Remaining) = 'TRUE')
                      then
                         FBatchOberflaeche.ForceStayOnTop (true)
                      else if
                            (UpperCase (Remaining) = 'OFF')
                         or (UpperCase (Remaining) = 'FALSE')
                      then
                         FBatchOberflaeche.ForceStayOnTop (false)
                      else
                        ActionResult := reportError (Sektion, i, Sektion.strings [i-1],
                                                     Remaining + ' is no valid value');
                     {$ENDIF GUI}
                   End
                   else
                     ActionResult
                     := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);

                tsIconizeWinst:
                   {$IFDEF GUI}
                   begin
                     SavedBatchWindowMode := BatchWindowMode;
                     BatchWindowMode := bwmIcon;
                     FBatchOberflaeche.setWindowState (BatchWindowMode);
                   end
                   {$ENDIF GUI}
                   ;


                tsNormalizeWinst:
                   {$IFDEF GUI}
                   begin
                     SavedBatchWindowMode := BatchWindowMode;
                     BatchWindowMode := bwmNormalWindow;
                     FBatchOberflaeche.setWindowState (bwmNormalWindow);
                   end
                   {$ENDIF GUI}
                   ;

                tsRestoreWinst:
                   {$IFDEF GUI}
                   begin
                     BatchWindowMode := SavedBatchWindowMode;
                     FBatchOberflaeche.setWindowState (BatchWindowMode);
                   end
                   {$ENDIF GUI}
                   ;

                tsEncoding:
                   ;

                tsWinstVersionRequired:
                   begin

                     GetWord (Remaining, expr, Remaining, WordDelimiterWhiteSpace);
                     GetWordOrStringExpression (Remaining, numberString, Remaining, InfoSyntaxError);
                     // expr should be a comparison sign

                     if
                      getDecimalCompareSign (osconf.WinstVersion, numberString, sign, InfoSyntaxError, false)
                     then
                     Begin

                       hasRelation (expr, sign, evaluated, InfoSyntaxError);

                       if evaluated then
                       Begin
                         LogDatei.DependentAdd
                          (osconf.selfProductName+' has version  ' + osconf.WinstVersion + ', required is : ' + expr + ' ' + numberString,
                           LLinfo);
                        LogDatei.WinstVersionRequired := numberString;
                       end
                       else
                       Begin

                         LogDatei.DependentAddError
                          ('Error: wrong opsi-winst version,  requested :     ' + expr + '  ' + numberString,
                           LLcritical);
                         FNumberOfErrors := FNumberOfErrors + 1;
                         FExtremeErrorLevel := LevelFatal;
                         LogDatei.DependentAdd('Error level set to fatal', LLcritical);
                         ActionResult := tsrFatalError;
                       End

                     End
                     else
                     Begin
                       ActionResult
                       := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);
                     end;
                   end;

                tsPatchAnyTextFile:
                  begin
                     flag_all_ntuser := false;
                     // if this is a 'ProfileActions' which is called as sub in Machine mode
                     // so run patches sections implicit as /Allntuserprofiles
                     if runProfileActions then flag_all_ntuser := true;
                     if Remaining = ''
                     then
                        ActionResult := reportError (Sektion, i, Sektion.strings [i-1], 'File parameter missing')
                     else
                     Begin
                       GetWordOrStringExpression (Remaining, Filename, Remaining, ErrorInfo);
                       if Remaining = '' then
                         ActionResult := doTextpatch (ArbeitsSektion, Filename,'')
                       else ActionResult := doTextpatch (ArbeitsSektion, Filename, Remaining);
                     End;
                  end;

                tsTests:
                ActionResult := doTests (ArbeitsSektion, Remaining);


                tsPatchIniFile:
                  begin
                    flag_all_ntuser := false;
                    // if this is a 'ProfileActions' which is called as sub in Machine mode
                    // so run patches sections implicit as /Allntuserprofiles
                    if runProfileActions then flag_all_ntuser := true;
                    if Remaining = ''
                    then
                      ActionResult := reportError (Sektion, i, Sektion.strings [i-1], 'File parameter missing')
                    else
                    Begin
                      GetWordOrStringExpression (Remaining, Filename, Remaining, ErrorInfo);
                      if Remaining = '' then
                          ActionResult := doInifilePatches (ArbeitsSektion, Filename,'')
                      else ActionResult := doInifilePatches (ArbeitsSektion, Filename, Remaining);
                    End;
                  end;

                tsHostsPatch:
                  Begin
                     GetWordOrStringExpression (Remaining, Filename, Remaining, ErrorInfo);
                     ActionResult := doHostsPatch (ArbeitsSektion, Filename);
                  End;



                tsRegistryHack:
                   begin
                     {$IFDEF WINDOWS}
                     syntaxcheck := true;

                     registryformat := trfWinst;
                     flag_all_ntuser := false;
                     flag_ntuser := false;
                     reg_specified_basekey := '';
                     flag_force64 := false;

                     // if this is a 'ProfileActions' which is called as sub in Machine mode
                     // so run registry sections implicit as /Allntuserdats
                     if runProfileActions then
                        flag_all_ntuser := true;

                     remaining := CutRightBlanks (Remaining);

                     if length (remaining) > 0 then goon := true;
                     while goon
                     do
                     begin

                        if skip(Parameter_AllNTUserDats, Remaining, Remaining, ErrorInfo)
                        then
                          flag_all_ntuser := true

                        else if skip(Parameter_RegistryNTUserDat, Remaining, Remaining, ErrorInfo)
                        then
                        begin
                          flag_ntuser := true;
                          if not EvaluateString (Remaining, Remaining, ntuserpath, ErrorInfo) then
                          begin
                           syntaxcheck := false;
                            //ActionResult := reportError (ErrorInfo);
                          end;
                        end
                        else if skip(Parameter_Registry64Bit, Remaining, Remaining, ErrorInfo)
                        then
                        begin
                          if (GetNTVersionMajor = 5) and (GetNTVersionMinor = 0) then
                          begin
                            // we are on win 2000 which can't handle redirections flags
                            flag_force64 := false;
                          end
                          else // we are on xp or higher
                          begin
                            flag_force64 := true;
                          end;
                        end


                        else if skip(Parameter_Registry32Bit, Remaining, Remaining, ErrorInfo)
                        then
                          flag_force64 := false

                        else if skip(Parameter_RegistrySysNative, Remaining, Remaining, ErrorInfo)
                        then
                        begin
                          if (GetNTVersionMajor = 5) and (GetNTVersionMinor = 0) then
                          begin
                            // we are on win 2000 which can't handle redirections flags
                            flag_force64 := false;
                          end
                          else // we are on xp or higher
                          begin
                            flag_force64 := true;
                          end;
                        end


                        else if skip (Parameter_RegistryUsercontext, Remaining, Remaining, ErrorInfo)
                        then
                          reg_specified_basekey := 'HKEY_USERS\' + usercontextSID

                        else if
                          skip (Parameter_RegistryBaseKey, Remaining, Remaining, ErrorInfo)
                          and skip ('=', Remaining, Remaining, ErrorInfo)
                          and GetString(Remaining, s1, Remaining, ErrorInfo, false)
                        then
                          reg_specified_basekey := s1

                        else if skip (Parameter_SysDiffAddReg, Remaining, Remaining, ErrorInfo)
                        then
                          registryformat := trfSysdiff

                        else if skip (Parameter_RegeditFormat, Remaining, Remaining, ErrorInfo)
                        then
                          registryformat := trfRegedit

                        else
                        Begin
                          goon := false;
                          if length (remaining) > 0
                          then
                          begin
                            syntaxcheck := false;
                            ActionResult := reportError (Sektion, i, Sektion.strings [i-1],
                                                     '"' + remaining + '" is no valid parameter ');
                          end;
                        end;

                     end;


                     if flag_all_ntuser and (reg_specified_basekey <> '')
                     then
                     begin
                       syntaxcheck := false;
                       ErrorInfo := 'this combination of options is impossible';
                     end;

                     if inUsercontext then
                          reg_specified_basekey := 'HKEY_USERS\' + usercontextSID;


                     if syntaxcheck then
                     begin
                       if flag_all_ntuser
                       then
                       begin
                         if registryformat = trfSysdiff
                         then
                             ActionResult := reportError (Sektion, i, Sektion.strings [i-1],
                                         '"' + Remaining + '": sysdiff format not possible with option "for all nt user"')
                         else
                            ActionResult := doRegistryAllNTUserDats (ArbeitsSektion, registryformat, flag_force64);
                       end
                       else if flag_ntuser
                       then
                       begin
                         if registryformat = trfSysdiff
                         then
                             ActionResult := reportError (Sektion, i, Sektion.strings [i-1],
                                         '"' + Remaining + '": sysdiff format not possible with option "ntuser"')
                         else
                            ActionResult := doRegistryNTUserDat (ArbeitsSektion, registryformat, flag_force64,ntuserpath);
                       end
                       else
                         case registryformat of
                          trfWinst   :
                             ActionResult := doRegistryHack (ArbeitsSektion, reg_specified_basekey, flag_force64);

                          trfSysdiff :
                             ActionResult := doRegistryHackInfSource (ArbeitsSektion, reg_specified_basekey, flag_force64);

                          trfRegedit :
                             ActionResult := doRegistryHackRegeditFormat (ArbeitsSektion, reg_specified_basekey, flag_force64);

                         end;
                     end;
                     {$ELSE WINDOWS}
                    logdatei.DependentAdd('Registry sections are not implemented for Linux.', LLWarning);
                    {$ENDIF WINDOWS}
                   end;


                tsXMLPatch:
                  begin
                    {$IFDEF WINDOWS}
                     EvaluateString (Remaining, Remaining, Parameter, InfoSyntaxError);
                     if Remaining = ''
                     then
                        ActionResult := doXMLPatch (ArbeitsSektion, Parameter, output)
                     else
                        ActionResult := reportError (Sektion, i, Sektion.strings [i-1],
                                         ' end of line expected');
                     {$ELSE WINDOWS}
                    logdatei.DependentAdd('XMLPatch sections are not implemented for Linux right now', LLWarning);
                    {$ENDIF WINDOWS}
                  end;

                tsOpsiServiceCall:
                  begin
                     Parameter := Remaining;
                     ActionResult := doOpsiServiceCall (ArbeitsSektion, Parameter, output)
                  end;

                  tsOpsiServiceHashList:
                  begin
                     Parameter := Remaining;
                     ActionResult := doOpsiServiceHashList (ArbeitsSektion, Parameter, output)
                  end;

                {$IFDEF WINDOWS}
                tsIdapiConfig:
                   begin
                        GetWordOrStringExpression (Remaining, Filename, Remaining, ErrorInfo);
                        ActionResult := doIdapiConfig (ArbeitsSektion, Filename);
                        //ActionResult := doIdapiConfig (ArbeitsSektion, Remaining);
                    end;
                {$ENDIF WINDOWS}

                tsLDAPsearch:
                  begin
                    EvaluateString (Remaining, Remaining, Parameter, InfoSyntaxError);
                    if produceLDAPsearchParameters(Remaining, cacheRequest, outputRequest, InfoSyntaxError)
                    then
                      ActionResult := doLDAPSearch (ArbeitsSektion, cacheRequest, outputRequest, output)
                    else
                      ActionResult := reportError (Sektion, i, Sektion.strings [i-1], InfoSyntaxError);
                  end;

                tsFileActions:
                  begin
                   flag_all_ntuser := false;
                   // if this is a 'ProfileActions' which is called as sub in Machine mode
                   // so run registry sections implicit as /Allntuserdats
                   if runProfileActions then
                        flag_all_ntuser := true;
                   ActionResult := doFileActions (ArbeitsSektion, Remaining);
                  end;

                tsLinkFolder:
                  begin
                    {$IFDEF WIN32}
                    if Remaining = ''
                    then
                        doLinkFolderActions (ArbeitsSektion, true)
                    else
                    Begin
                        GetWord (remaining, expression, remaining, WorddelimiterSet0);
                        if not (lowercase (expression) = lowercase (Parameter_AllNTUser))
                        then
                          ActionResult := reportError (Sektion, i, Sektion.strings [i-1],
                                          'No valid parameter')
                        else
                           doLinkFolderActions (ArbeitsSektion, false);
                    End
                    {$ELSE WIN32}
                    logdatei.DependentAdd('Linkfolder sections are not implemented for Linux right now', LLWarning);
                    {$ENDIF WIN32}
                  end;


                tsWinBatch:
                 begin
                  {$IFDEF WINDOWS}
                   runAs := traInvoker;
                   {$IFDEF WIN32}
                   opsiSetupAdmin_runElevated := false;
                   {$ENDIF WIN32}
                   WaitSecs := 0;
                   flag_force64 := false;
                   GetWord (Remaining, expr, Remaining, WordDelimiterSet0);
                   SyntaxCheck := true;

                   ident := '';
                   WaitConditions := [ttpWaitOnTerminate];

                   while SyntaxCheck and (length (expr) > 0)
                   do
                   Begin
                     {$IFDEF WIN32}
                     if LowerCase (expr) = LowerCase (ParameterRunAsAdmin)
                     then
                     Begin
                         runAs := traAdmin;
                     End

                     else if LowerCase (expr) = LowerCase (ParameterRunAsAdmin1)
                     then
                     Begin
                         runAs := traAdmin;
                     End

                     else if LowerCase (expr) = LowerCase (ParameterRunAsAdmin2)
                     then
                     Begin
                         runAs := traAdminProfile;
                     End

                     else if LowerCase (expr) = LowerCase (ParameterRunAsAdmin3)
                     then
                     Begin
                         runAs := traAdminProfileImpersonate;
                     End

                     else if LowerCase (expr) = LowerCase (ParameterRunAsAdmin4)
                     then
                     Begin
                         runAs := traAdminProfileImpersonateExplorer;
                     End

                     else if LowerCase (expr) = LowerCase (ParameterRunAsInvoker)
                     then
                     Begin
                         runAs := traInvoker;
                     End

                     else if LowerCase (expr) = LowerCase (ParameterRunElevated)
                     then
                     Begin
                         opsiSetupAdmin_runElevated := true;
                     End

                     else if LowerCase (expr) = LowerCase (ParameterRunAsLoggedOnUser)
                     then
                     Begin
                       if runLoginScripts then
                         runAs := traLoggedOnUser
                       else
                         LogDatei.DependentAdd('Warning: Not in UserLoginScript mode: /RunAsLoggedinUser ignored', LLWarning);
                     End

                     else if (LowerCase (expr) = LowerCase (Parameter_64Bit)) and Is64BitSystem
                     then
                     Begin
                         flag_force64 := true;
                     End

                     else if LowerCase (expr) = LowerCase (Parameter_32Bit)
                     then
                     Begin
                         flag_force64 := false;
                     End

                     else if (LowerCase (expr) = LowerCase (Parameter_SysNative)) and Is64BitSystem
                     then
                     Begin
                         flag_force64 := true;
                     End

                     else if (LowerCase (expr) = LowerCase (Parameter_SysNative)) and (not Is64BitSystem)
                     then
                     Begin
                         flag_force64 := false;
                     End

                     else {$ENDIF WIN32}  if LowerCase (expr) = LowerCase (ParameterWaitSecs)
                     then
                     Begin
                       WaitConditions := WaitConditions + [ttpWaitTime];
                       // WaitConditions := WaitConditions - [ttpWaitOnTerminate];

                       GetWord (Remaining, expr, Remaining, WordDelimiterSet0);
                       try
                         WaitSecs := StrToInt64 (expr);
                       except
                         on EConvertError do
                         Begin
                            InfoSyntaxError := 'Integer number expected';
                            SyntaxCheck := false;
                         End
                       end;
                     End

                     {$IFDEF WIN32}
                     else if LowerCase (expr) = LowerCase (ParameterCloseOnWindow)
                     then
                     Begin
                       runAs := traInvoker;
                       WaitConditions := WaitConditions + [ttpWaitForWindowAppearing];

                       if EvaluateString (Remaining, Remaining, ident, InfoSyntaxError)
                       then
                       Begin
                         if Remaining <> ''
                         then
                         Begin
                           SyntaxCheck := false;
                           InfoSyntaxError := 'not expected chars after "';
                         End;
                       End
                       else
                          SyntaxCheck := false;
                     End


                     else if LowerCase (expr) = LowerCase (ParameterCloseBehindWindow)
                     then
                     Begin
                       runAs := traInvoker;
                       WaitConditions := WaitConditions + [ttpWaitForWindowVanished];

                       if EvaluateString (Remaining, Remaining, ident, InfoSyntaxError)
                       then
                       Begin
                         if Remaining <> ''
                         then
                         Begin
                           SyntaxCheck := false;
                           InfoSyntaxError := 'unexpected characters after "';
                         End;
                       End
                       else
                         SyntaxCheck := false;
                     End
                     {$ENDIF WIN32}

                     else if LowerCase (expr) = LowerCase (ParameterWaitProcessTimeoutSecs)
                     then
                     Begin
                       WaitConditions := WaitConditions - [ttpWaitTime];
                       WaitConditions := WaitConditions + [ttpWaitTimeout];

                       GetWord (Remaining, expr, Remaining, WordDelimiterSet0);
                       try
                         WaitSecs := StrToInt64 (expr);
                       except
                         on EConvertError do
                         Begin
                           try
                             EvaluateString (expr, expr, seconds, InfoSyntaxError);
                             WaitSecs := StrToInt64 (seconds);
                           except
                             on EConvertError do
                             Begin
                               InfoSyntaxError := 'Integer number expected '+InfoSyntaxError;
                              SyntaxCheck := false;
                            end;
                           end
                         End
                       end
                     End

                     else if LowerCase (expr) = LowerCase (ParameterWaitForProcessEnding)
                     then
                     Begin
                       WaitConditions := WaitConditions + [ttpWaitForProcessEnding];
  (*
                       GetWord (Remaining, ident, Remaining, WordDelimiterSet0);
                       if ident = '' then
                       begin
                         SyntaxCheck := false;
                         InfoSyntaxError := 'process name expected';
                       end;
  *)
                       if not EvaluateString (Remaining, Remaining, ident, InfoSyntaxError)  then
                          SyntaxCheck := false;
  (*
                       then
                       Begin
                         if Remaining <> ''
                         then
                         Begin
                           SyntaxCheck := false;
                           InfoSyntaxError := 'unexpected chars after "';
                         End
                       End
                       else
                         SyntaxCheck := false;
  *)
                     End

                     else if UpperCase (expr) = UpperCase (ParameterDontWait)
                     then
                     Begin
                         WaitConditions := WaitConditions - [ttpWaitOnTerminate];
                         WaitConditions := WaitConditions - [ttpWaitTimeout];
                     End

                     else if UpperCase (expr) = UpperCase (ParameterWaitOnTerminate)
                     then
                     Begin
                         WaitConditions := WaitConditions + [ttpWaitOnTerminate];
                     End



                     else
                     Begin
                           SyntaxCheck := false;
                           InfoSyntaxError := expr + ' not legal WinBatch parameter';
                     End;

                     GetWord (Remaining, expr, Remaining, WordDelimiterSet0);
                   end;

                   if SyntaxCheck
                   then
                     ActionResult := execWinBatch (ArbeitsSektion, Remaining, WaitConditions, Ident, WaitSecs, runAs,flag_force64)
                   else
                     ActionResult := reportError (Sektion, i, 'Expression', InfoSyntaxError);
                   {$ELSE WINDOWS}
                    logdatei.DependentAdd('Winbatch sections are not implemented for Linux right now', LLWarning);
                    {$ENDIF WINDOWS}
                 end;

                {$IFDEF WIN32}
                tsStayWhileWindowOpen:
                 begin
                   SyntaxCheck := false;
                   if EvaluateString (Remaining, Remaining, ident, InfoSyntaxError)
                   then
                   if Remaining = ''
                   then SyntaxCheck := true
                   else InfoSyntaxError := 'unexpected chars after "';
                   if SyntaxCheck
                   then
                     while FindWindowEx (0, 0, nil, PChar (ident) ) <> 0
                     do ProcessMess
                   else
                     ActionResult := reportError (Sektion, i, Expression, InfoSyntaxError);
                 end;
                 {$ENDIF WIN32}

                tsDosBatchFile:
                    ActionResult := execDOSBatch (ArbeitsSektion, Remaining,
                             SW_ShowNormal, false {dont catch out},
                             [ttpWaitOnTerminate], output);

                tsDosInAnIcon:
                   ActionResult := execDOSBatch (ArbeitsSektion, Remaining,
                             SW_Minimize, true {catch out},
                             [ttpWaitOnTerminate], output);

                tsShellBatchFile:
                   ActionResult := execDOSBatch (ArbeitsSektion, Remaining,
                             SW_ShowNormal, false {dont catch out},
                             [ttpWaitOnTerminate], output);

                tsShellInAnIcon:
                   ActionResult := execDOSBatch (ArbeitsSektion, Remaining,
                             SW_Minimize, true {catch out},
                             [ttpWaitOnTerminate], output);

                tsExecutePython :
                  ActionResult := execPython (ArbeitsSektion, Remaining,
                             true {catch out},
                             [ttpWaitOnTerminate], output);

                tsExecuteWith, tsExecuteWith_escapingStrings:
                  if
                    produceExecLine(remaining, p1, p2, p3, p4,
                      InfoSyntaxError)
                  then
                    ActionResult := executeWith (ArbeitsSektion, Remaining,
                             true {catch out},
                             output)
                  else
                    ActionResult := reportError (Sektion, i, Expression, InfoSyntaxError);

                tsWorkOnStringList:
                   Begin
                     ActionResult := reportError (Sektion, i, Expression, 'not yet implemented');
                   end;

                  tsDDEwithProgman:
                    //ActionResult := doDDEwithProgman (ArbeitsSektion, Remaining, SaveddeWithProgman);
                    ActionResult := doDDEwithProgman (ArbeitsSektion, Remaining, false);

                {$IFDEF WIN32}
                tsAddConnection:
                 Begin
                                       syntaxCheck := true;
                     GetWord (Remaining, localname, Remaining, WordDelimiterWhiteSpace);
                     GetWord (Remaining, remotename, Remaining, WordDelimiterWhiteSpace);
                     (* GetWord (Remaining, username, Remaining, WordDelimiterWhiteSpace); *)
                     GetWord (Remaining, trytime, Remaining, WordDelimiterWhiteSpace);

                     try
                       timeout := StrToInt (trytime);
                     except
                       syntaxCheck := false;
                       InfoSyntaxError := trytime + ' is not an integer value';
                     end;

                     if syntaxCheck
                     then
                       ActionResult := startConnection (localname, remotename, timeout)
                     else
                       ActionResult := reportError (Sektion, i, Expression, InfoSyntaxError);
                 End;
                 {$ENDIF WIN32}

                tsDefineVar:
                 Begin
                   call := Remaining;
                   GetWord (Remaining, Expression, Remaining, WordDelimiterSet1);
                   if Remaining <> ''
                   then
                     reportError (Sektion, i, Expression, 'not allowed char following variable name')
                   else if findKindOfStatement (Expression, SectionSpecifier, call) <> tsNotDefined then
                     reportError (Sektion, i, Expression,
                       'Reserved name, must not be used in a variable definition')
                   else if VarList.IndexOf (lowercase(Expression)) >= 0 then
                     reportError (Sektion, i, Expression, 'name is already in use')
                   else
                   Begin
                     VarList.Add (lowercase(Expression));
                     ValuesList.Add ('');
                   End;
                 End;

                 tsDefineStringList:
                 Begin
                   call := Remaining;
                   GetWord (Remaining, Expression, Remaining, WordDelimiterSet1);
                   if Remaining <> ''
                   then
                     reportError (Sektion, i, Expression, 'char not allowed following variable name')
                   else if findKindOfStatement (Expression, SectionSpecifier, call) <> tsNotDefined then
                     reportError (Sektion, i, Expression,
                       'Reserved name, must not be used in a variable definition')
                   else if VarList.IndexOf (lowercase(Expression))  or listOfStringLists.IndexOf(lowercase(Expression)) >= 0 then
                     reportError (Sektion, i, Expression, 'Name already in use')
                   else

                   Begin
                     listOfStringLists.Add (lowercase(Expression));
                     ContentOfStringLists.Add (TStringList.create);
                     LogDatei.DependentAdd( '', leveldebug);
                     LogDatei.DependentAdd( '(created string list ' + expression + ')', leveldebug );
                   End;
                 End;


                tsSetVar:
                 Begin
                   //writeln('set');
                   Expression := Remaining;
                   doLogEntries (PStatNames^ [tsSetVar] + '  '  + Expression, LLnotice);
                   if doSetVar (sektion, Expression, Remaining, InfoSyntaxError)
                   then
                   Begin
                     if Remaining <> ''
                     then
                       reportError (Sektion, i, Remaining, 'Remaining char(s) not allowed here');
                   End
                   else

                      reportError (Sektion, i, Expression, InfoSyntaxError);
                 End

                else
                 ActionResult := reportError (Sektion, i, Expression, 'undefined');

              End (* case *);
            End;
          End;

         (* LogFile in Memo-Komponente laden, aber nur wenn es Sinn macht
            und sie genuegend Platz bietet *)
  (* removed by detlef 08.05.2010
          if not DontUpdateMemo
          then
          Begin
            LogDatei.Close;
            if Logdatei.logfileexists then
            begin
              if SizeOfFile (LogDatei.FileName) > 30000
              then
              Begin
                CentralForm.Memo1.Lines.Add ('');
                CentralForm.Memo1.Lines.Add (' LogFile too big for memo list, view it by another tool');
                DontUpdateMemo := true;
              End
              else
                CentralForm.Memo1.Lines.LoadFromFile (LogDatei.FileName);
              LogDatei.Reopen;
            end;
          end;
                *)
          ProcessMess;
        end;


        if inloop
        then
        begin
          if looplist.count = 0 //loop will finish
          then
          begin
            inloop := false;
            // clearing the loop variable from the list of variables, first the value
            ValuesList.Delete( varlist.indexOf (loopvar));
            varlist.Delete( varlist.indexOf (loopvar) );
            LogDatei.LogSIndentLevel := LogDatei.LogSIndentLevel - 1;
            LogDatei.DependentAdd ('', LevelInfo);
            LogDatei.DependentAdd ('~~~~~~ End Loop', LevelInfo);

          end;

        end;

      until not inloop;

      inc (i);
    end;

    if not scriptstopped then
    begin
      if (ActLevel > NestLevel) and (actionresult > tsrFatalError)
      then
        reportError (Sektion, i, PStatNames^ [tsCondClose], 'expected');

      if (NestLevel > Sektion.NestingLevel) and (actionresult > tsrFatalError)
      then
        reportError (Sektion, i, PStatNames^ [tsCondClose], 'expected');
    end;


    if ActionResult <= tsrFatalError
    then
      doLogEntries (AbortedInfo, BaseLevel)
    else if ActionResult <= tsrExitProcess
    then
      doLogEntries (StopInfo, BaseLevel);

    ArbeitsSektion.free;

    LogDatei.LogSIndentLevel := StartIndentLevel;

    result := ActionResult;
    output.Free;
  except
    on e: exception do
    Begin
      LogDatei.log('Exception in doAktionen: General' + e.message, LLError);
      ActionResult := tsrFatalError;
    End;
  end;
end;



procedure CreateAndProcessScript (Const Scriptdatei : String;
                         NestingLevel : Integer; SaveddeWithProgman : Boolean;
                         var extremeErrorLevel : TErrorLevel);


 var
  StartlineOfSection: Integer=0;
  Aktionsliste : TWorkSection;
  //Script : TuibInstScript;
  nrErrors : Integer=0;
  i : Integer=0;
  nrWarnings : Integer=0;
  oldNumberOfErrors : Integer=0;
  oldNumberOfWarnings : Integer=0;
  weiter : Integer=0;
  ValueToTake : String='';
  s : String='';
  ErrorInfo : String='';
  saveIndent : Integer=0;
  hostnaming : String='';
  computernaming : String='';
  ipName : String='';
  ipAddress : String='';
  usedEncoding : String='';
  Encoding2use : String='';
  {$IFDEF WINDOWS}
  Regist : TuibRegistry;
  {$ENDIF WINDOWS}


begin
  try
    Script := TuibInstScript.Create;
    readconfig;
    {$IFDEF LINUX} computername := getHostnameLin; {$ENDIF LINUX}
    {$IFDEF GUI}
    CentralForm.Label1.Caption := '';
    FBatchOberflaeche.setInfoLabel('');

    CentralForm.Label2.caption := '';
    FBatchOberflaeche.setDetailLabel(CentralForm.Label2.caption);
    {$ENDIF GUI}
    {$IFDEF LINUX}
    lispecfolder.retrieveFolders4Linux;
    {$ENDIF LINUX}
    if Scriptdatei <> ''
    then
    Begin
      //s := 'Drives found: ' + GetDrives;
      if not CheckFileExists (Scriptdatei, ErrorInfo)
      then
      Begin
        LogDatei.DependentAddWarning ('Script  ' + Scriptdatei + '  not found ' + ErrorInfo+' - retrying',LLWarning);
        Sleep(1000);
        if not CheckFileExists (Scriptdatei, ErrorInfo) then
        begin
          LogDatei.DependentAddWarning ('Script  ' + Scriptdatei + '  not found ' + ErrorInfo+' - retrying',LLWarning);
          Sleep(1000);
          if not CheckFileExists (Scriptdatei, ErrorInfo) then
          begin
            LogDatei.DependentAddError ('Script  ' + Scriptdatei + '  not found ' + ErrorInfo+' - giving up',LLError);
            ExtremeErrorLevel := LevelFatal;
            LogDatei.DependentAdd('Error level set to fatal', LLnotice);
            exit;
          end;
        end;
      end;
      //Scriptdatei := ExpandFileName(Scriptdatei);
      Script.LoadFromFile(Scriptdatei);
      Encoding2use := searchencoding(Script.Text);
      if Encoding2use = '' then Encoding2use := 'system';
      Script.Text:= reencode(Script.Text, Encoding2use,usedEncoding);
      Script.FFilename:=Scriptdatei;
      for i := 1 to script.Count do
      begin
        script.FLinesOriginList.Append(script.FFilename+' line: '+inttostr(i+1));
        //writeln('i='+inttostr(i)+' = '+Script.FLinesOriginList.Strings[i-1]);
      end;
    End
    else
    Begin
      {$IFDEF GUI}
      // Run Viewlist as script
      Script.Assign (CentralForm.Memo1.lines);
      for i := 1 to script.Count do
      begin
        script.FLinesOriginList.Append('Viewlist line: '+inttostr(i));
        //writeln('i='+inttostr(i)+' = '+Script.FLinesOriginList.Strings[i-1]);
        //writeln('i='+inttostr(i));
      end;
      {$ENDIF GUI}
    End;


    LogDatei.TraceMode := Script.TraceMode;
    //LogDatei.LogLevel := Script.LogLevel;

    LogDatei.DependentAdd ('', LLessential);


    ps := '============ ' + WinstVersionName + ' script "' + Scriptdatei   + '"';
    LogDatei.DependentAdd (ps, LLessential);
    ps :=  '             used script encoding: '  +  usedEncoding;
    LogDatei.DependentAdd (ps, LLessential);
    ps :=  '             used system encoding: '  +  mysystemEncoding;
    LogDatei.DependentAdd (ps, LLessential);

    ps := FormatDateTime('yyyy-mm-dd  hh:mm:ss ', now);

    computernaming := osconf.computername;

    if computernaming = '' then computernaming := oslog.getComputerName;


    ps :=  '             start: '  +  ps;
    LogDatei.DependentAdd (ps, LLessential);

    if opsidata <> nil then
    begin
      ps :=  '             installing product: '+Topsi4data(opsidata).getActualProductId+'_'+opsidata.getActualProductVersion;
      LogDatei.DependentAdd (ps, LLessential);
    end;

    ps :=  '             on client named    "' + computernaming + '"';
    LogDatei.DependentAdd (ps, LLessential);

    ps :=  '             loggedin user    "' + getLoggedInUser + '"';
    LogDatei.DependentAdd (ps, LLessential);

    GetNetUser ('', ps, ErrorInfo);
    ps :=  '             winst running as    "' + ps + '"';
    LogDatei.DependentAdd (ps, LLessential);

     If runningAsAdmin then
       LogDatei.DependentAdd ('             winst running with admin privileges', LLessential)
    else
       LogDatei.DependentAddWarning ('             winst not running with admin privileges', LLWarning);

     If runloginscripts then
    begin
       LogDatei.DependentAdd ('             winst running in loginscript mode', LLessential);
       LogDatei.DependentAdd ('             using context: '+usercontext+' with SID '+usercontextsid, LLessential);
    end
    else
      if runproductlist then LogDatei.DependentAdd ('             winst running in productlist script mode', LLessential)
       else LogDatei.DependentAdd ('             winst running in standard script mode', LLessential);


    ps := 'executing: "' + ParamStr(0) + '"';
    LogDatei.DependentAdd (ps, LLessential);

    //LogDatei.DependentAdd ('PC MAC address, method1 ' + getMACAddress1, BaseLevel);

    LogDatei.DependentAdd ('system infos:', LLessential);

    FindLocalIPData (ipName, ipAddress);
    LogDatei.DependentAdd (GetMACAddress2  + '  -  PC hardware address', LLessential);
    LogDatei.DependentAdd (ipName +  '  -  IP name ', LLessential);
    LogDatei.DependentAdd (ipAddress + '  -  IP address', LLessential);
    {$IFDEF WINDOWS}
    LogDatei.DependentAdd (GetSystemDefaultLocale(LOCALE_SABBREVLANGNAME)
                          + '  -  System default locale ',
                            LLessential);
    if Is64BitSystem then
      LogDatei.DependentAdd ('MS Windows ' +GetSystemOSVersionInfoEx('major_version')
       +'.'+GetSystemOSVersionInfoEx('minor_version')+' 64 Bit', LLessential)
    else LogDatei.DependentAdd ('MS Windows ' +GetSystemOSVersionInfoEx('major_version')
       +'.'+GetSystemOSVersionInfoEx('minor_version')+' 32 Bit', LLessential);
    {$ENDIF WINDOWS}

    if opsidata <> nil then
    begin
      LogDatei.DependentAdd ('opsi service version : '+opsidata.getOpsiServiceVersion, LLessential);
      //Logdatei.DependentAdd('Setup script name: '+opsidata.getProductScriptPath(tacSetup), LLessential);
    end;

    // backup the start working dir
    opsiWinstStartdir := GetCurrentDir;

    LogDatei.DependentAdd ('', LLessential);


    {ps := '        (Assuming the shell is "';
    if ShellIsExplorer
    then ps := ps + 'explorer.exe'
    else ps := ps + 'progman.exe';
    ps := ps + '")';

    LogDatei.DependentAdd (ps, BaseLevel);
    }

    //ProcessIncludes;


    (* Definieren der globalen Systemvariablen *)
    with Script do
    Begin
      //System directories:
      {$IFDEF WINDOWS}
      FConstList.add ('%Systemroot%');
      ValueToTake := GetWinDirectory;
         (* delete closing back slash *)
      System.delete (ValueToTake, length (ValueToTake), 1);
      FConstValuesList.add (ValueToTake);

      FConstList.add ('%System%');
      ValueToTake := GetWinSystemDirectory;
         (* delete closing back slash *)
      System.delete (ValueToTake, length (ValueToTake), 1);
      FConstValuesList.add (ValueToTake);

      FConstList.add ('%SystemDrive%');
      ValueToTake := extractfiledrive (GetWinDirectory);
      FConstValuesList.add (ValueToTake);
      {$ENDIF WINDOWS}
      FConstList.add('%ProfileDir%');
      ValueToTake := getProfilesPath;
      FConstValuesList.add (ValueToTake);

       FConstList.add('%DefaultUserProfileDir%');
      ValueToTake := getDefaultUsersProfilesPath;
      FConstValuesList.add (ValueToTake);


      saveIndent := Logdatei.LogSIndentLevel;
      {$IFDEF WINDOWS}
      ValueToTake := getSpecialFolder(CSIDL_PROGRAM_FILES);
      LogDatei.LogSIndentLevel := saveIndent;

      FConstList.add('%ProgramFilesDir%');
      FConstValuesList.add (ValueToTake);
      FConstList.add('%ProgramFiles32Dir%');
      FConstValuesList.add (ValueToTake);
      try
        if (GetNTVersionMajor = 5) and (GetNTVersionMinor = 0) then
        begin
          // we are on win 2000 which can't handle redirections flags
          Regist := Tuibregistry.Create;
        end
        else // we are on xp or higher
        begin
          Regist := Tuibregistry.Create(true);
        end;
        regist.OpenExistingKey ('HKLM', 'SOFTWARE\Microsoft\Windows\CurrentVersion');
        ValueToTake := regist.ReadString ('ProgramFilesDir');
        Regist.free; Regist := nil;
      except
        ValueToTake := 'C:\Program Files'
      end;
      FConstList.add('%ProgramFiles64Dir%');
      FConstValuesList.add (ValueToTake);
      FConstList.add('%ProgramFilesSysnativeDir%');
      FConstValuesList.add (ValueToTake);



      //Usercontext data

      FConstList.add('%Usercontext%');
      FConstValuesList.add (usercontext);

      FConstList.add('%UsercontextSID%');
      FConstValuesList.add (usercontextSID);
      {$ENDIF WINDOWS}
   (*
      FConstList.add('%UsercontextAppdataDir%');
      ValueToTake := '';
      if wispecfolder.specialfolders.indexOf('UsercontextAppdata') > 0
      then valueToTake := wispecfolder.specialfolders.values['UsercontextAppdata'];
      FConstValuesList.add (ValueToTake);
   *)
  //  Common (AllUsers) directories:
      FConstList.add('%CommonAppDataDir%');
      ValueToTake := GetCommonAppDataPath;
      FConstValuesList.add (ValueToTake);

      FConstList.add('%AllUsersProfileDir%');
      ValueToTake := guessCommonProfilesPath;
      FConstValuesList.add (ValueToTake);
      FConstList.add('%CommonProfileDir%');
      FConstValuesList.add (ValueToTake);

      FConstList.add('%CommonStartmenuDir%');
      ValueToTake := GetCommonStartmenuPath;
      FConstValuesList.add (ValueToTake);
      FConstList.add ('%CommonStartmenuPath%');
      FConstValuesList.add (ValueToTake);

      FConstList.add('%CommonDesktopDir%');
      ValueToTake := GetCommonDesktopPath;
      FConstValuesList.add (ValueToTake);

      FConstList.add('%CommonStartupDir%');
      ValueToTake := GetCommonStartupPath;
      FConstValuesList.add (ValueToTake);

      FConstList.add('%CommonProgramsDir%');
      ValueToTake := GetCommonProgramsPath;
      FConstValuesList.add (ValueToTake);

      FConstList.add('%AppDataDir%');
      ValueToTake := GetAppDataPath;
      FConstValuesList.add (ValueToTake);
      FConstList.add('%CurrentAppDataDir%');
      FConstValuesList.add (ValueToTake);

      FConstList.add('%CurrentStartmenuDir%');
      ValueToTake := GetStartmenuPath;
      FConstValuesList.add (ValueToTake);

      FConstList.add('%CurrentDesktopDir%');
      ValueToTake := GetDesktopPath;
      FConstValuesList.add (ValueToTake);

      FConstList.add('%CurrentStartupDir%');
      ValueToTake := GetStartupPath;
      FConstValuesList.add (ValueToTake);

      FConstList.add('%CurrentProgramsDir%');
      ValueToTake := GetProgramsPath;
      FConstValuesList.add (ValueToTake);

      FConstList.add('%CurrentSendToDir%');
      ValueToTake := GetSendToPath;
      FConstValuesList.add (ValueToTake);

      FConstList.add('%CurrentProfileDir%');
      ValueToTake := getUserProfilePath;
      FConstValuesList.add (ValueToTake);

      ///AllNtUserProfiles directory constants:
      // they are not defined here and will be replaced
      // at the working section code


      //opsi-winst-Path and Directories
      FConstList.add ('%ScriptDrive%');
      ValueToTake := extractfiledrive ( ExpandFilename(Scriptdatei));
      FConstValuesList.add (ValueToTake);

      FConstList.add ('%Scriptpath%');
      ValueToTake := ExtractFileDir (Scriptdatei);
      FConstValuesList.add (ValueToTake);
      FConstList.add ('%ScriptDir%');
      FConstValuesList.add (ValueToTake);

      FConstList.add('%WinstDir%');
      ValueToTake := ExtractFileDir (Paramstr(0));
      FConstValuesList.add (ValueToTake);

      FConstList.add('%WinstVersion%');
      ValueToTake := osconf.WinstVersion;
      FConstValuesList.add (ValueToTake);

      FConstList.add ('%LogFile%');
      FConstValuesList.add ( LogDatei.FileName );

      FConstList.add ('%opsiTmpDir%');
      {$IFDEF WINDOWS}FConstValuesList.add ( 'c:\opsi.org\tmp' ); {$ENDIF WINDOWS}
      {$IFDEF LINUX}FConstValuesList.add ( '/tmp' ); {$ENDIF LINUX}

      FConstList.add ('%opsiLogDir%');
      {$IFDEF WINDOWS}FConstValuesList.add ( 'c:\opsi.org\log' ); {$ENDIF WINDOWS}
      {$IFDEF LINUX}FConstValuesList.add ( '/var/log/opsi-client-agent/opsi-script' ); {$ENDIF LINUX}

      {$IFDEF WINDOWS}
      FConstList.add('%opsiScriptHelperPath%');
      ValueToTake := getSpecialFolder(CSIDL_PROGRAM_FILES)+'\opsi.org\opsiScriptHelper';
      FConstValuesList.add (ValueToTake);



      //Network informations
      FConstList.add ('%PCNAME%');
      ValueToTake := ValueOfEnvVar ('PCNAME');
      if valueToTake =  valueEnvVarNotFound
        then
            valueToTake := ValueOfEnvVar ('computername');
      FConstValuesList.add (ValueToTake);

      FConstList.add ('%HOST%');
      ValueToTake := ValueOfEnvVar ('HOST');
      FConstValuesList.add (ValueToTake);
      {$ENDIF WINDOWS}

      {$IFDEF LINUX}
      FConstList.add ('%PCNAME%');
      ValueToTake := GetHostName;
      if valueToTake =  valueEnvVarNotFound
        then
            valueToTake := getCommandResult('hostname');
      FConstValuesList.add (ValueToTake);

      FConstList.add ('%HOST%');
      ValueToTake := getCommandResult('hostname');
      FConstValuesList.add (ValueToTake);
      {$ENDIF LINUX}



      (*
      FConstList.add ('%MacAddress%');
      FConstValuesList.add (GetMACAddress2);
    *)

      FConstList.add ('%IPAddress%');
      FConstValuesList.add (ipAddress);

      FConstList.add ('%IPName%');
      FConstValuesList.add (ipName);


      FConstList.add ('%Username%');
      GetNetUser ('', ValueToTake, ErrorInfo);
      FConstValuesList.add (ValueToTake);

      {$IFDEF WINDOWS}
      FConstList.add ('%TempUser%');
      FConstValuesList.add (TempUserRegKey);
      {$ENDIF WINDOWS}

      //FConstList.add ('%Wow64%');
      //FConstValuesList.add (IntToStr( iswow64));


      //opsi service values

      FConstList.add ('%opsiserviceURL%');
      FConstValuesList.add (opsiserviceURL);

      FConstList.add ('%opsiserviceUser%');
      FConstValuesList.add (opsiserviceUser);

      FConstList.add ('%opsiservicePassword%');
      FConstValuesList.add (opsiservicePassword);

      FConstList.add ('%hostID%');
      FConstValuesList.add (computernaming);

      FConstList.add ('%opsiServer%');    //

      valuetotake := copy(opsiserviceUrl, pos('//', opsiserviceUrl)+2, length(opsiserviceurl));
      valuetotake := copy(valuetotake, 1, pos(':', valuetotake) - 1);
      FConstValuesList.add (valuetotake);

      FConstList.add ('%opsiDepotId%');
      if opsidata = nil
      then
          FConstValuesList.add ('')
      else
          FConstValuesList.add (trim(Topsi4data(opsidata).depotId));

      FConstList.add ('%installingProdName%');
      if opsidata = nil
      then
          FConstValuesList.add ('')
      else
          FConstValuesList.add (Topsi4data(opsidata).getActualProductId);

      FConstList.add ('%installingProdVersion%');
      if opsidata = nil
      then
          FConstValuesList.add ('')
      else FConstValuesList.add (opsidata.getActualProductVersion);

      FConstList.add ('%installingProduct%');
      if opsidata = nil
      then
          FConstValuesList.add ('')
      else
          FConstValuesList.add (Topsi4data(opsidata).getActualProductId);
    End;




    Aktionsliste := TWorkSection.Create (NestingLevel);
    {$IFDEF GUI}
    FBatchOberflaeche.LoadSkin('');
    FBatchOberflaeche.setPicture ('', '');
    {$ENDIF GUI}
    // initial section
    AktionsListe.Name := NameInitSektion ;
    Script.GetSectionLines(NameInitSektion, TXStringList (Aktionsliste),
                           StartlineOfSection, true, true, true);
    //Script.ApplyTextConstants (TXStringList (Aktionsliste));

    try
      if Aktionsliste.count > 0
      then
         weiter := Script.doAktionen (Aktionsliste, Aktionsliste)
      else
         weiter := tsrPositive;

      // profile actions section : run it only on loginscript
      if (weiter > 0) and runloginscripts then
      begin
        Aktionsliste.clear;
        AktionsListe.Name := NameProfileActionsSection ;
        Aktionsliste.StartLineNo := StartlineOfSection;
        Script.GetSectionLines(NameProfileActionsSection, TXStringList (Aktionsliste),
                               StartlineOfSection, true, true, true);
        Script.ApplyTextConstants (TXStringList (Aktionsliste), false);
        if Aktionsliste.count > 0  then
        begin
          Aktionsliste.StartLineNo := StartlineOfSection;
           weiter := Script.doAktionen (Aktionsliste, Aktionsliste);
           // do not run actions after profileActions
           weiter := 0;
        end
        else
           weiter := tsrPositive;
      end;


      if weiter > 0 then
      Begin
        Aktionsliste.clear;
        Aktionsliste.Name := NameAktionenSektion;
        Aktionsliste.StartLineNo := StartlineOfSection;

        Script.GetSectionLines(NameAktionenSektion, TXStringList (Aktionsliste),
                               StartlineOfSection, true, true, true);
        Script.ApplyTextConstants (TXStringList (Aktionsliste), false);

        if Aktionsliste.count > 0
        then
        Begin
          Aktionsliste.StartLineNo := StartlineOfSection;
          weiter := Script.doAktionen (Aktionsliste, Aktionsliste);
        End;
      End;
      (*
      if opsidata <> nil then
      begin
        LogDatei.DependentAdd ('opsi service version: '+opsidata.getOpsiServiceVersion, LLessential);
        Logdatei.DependentAdd('Setup script name: '+opsidata.getProductScriptPath(tacSetup), LLessential);
      end;
      *)
      try
        Aktionsliste.free; Aktionsliste := nil;
      except
       on e: exception do
       {$IFDEF GUI}
       MyMessageDlg.wiMessage ('CreateAndProcessScript : free Aktionsliste: '+e.Message, [mrOK]);
       {$ELSE GUI}
       writeln('CreateAndProcessScript : free Aktionsliste: '+e.Message);
       {$ENDIF GUI}
      end;
    except
      on e: exception do
      Begin
        LogDatei.log('Exception in CreateAndProcessScript: Handling Aktionsliste' + e.message, LLError);
        extremeErrorLevel := levelFatal;
      End;
    end;


    {$IFDEF GUI}
    CentralForm.Memo1.SelectAll;
    CentralForm.Memo1.SelStart := CentralForm.Memo1.SelLength;
    {$ENDIF GUI}

    // write final messages to log


    LogDatei.LogSIndentLevel := 0;

    ps := ('___________________');
    LogDatei.DependentAdd (ps, LLessential);
    ps := ('script finished');
    LogDatei.DependentAdd (ps, LLessential);
    ps := IntToStr (Script.NumberOfErrors) + ' error';
    if Script.NumberOfErrors <> 1 then ps := ps + 's';
    LogDatei.DependentAdd (ps, LLessential);

    ps := IntToStr (Script.NumberOfWarnings) + ' warning';
    if Script.NumberOfWarnings <> 1 then ps := ps + 's';
    LogDatei.DependentAdd (ps, LLessential);
    ps := '';
    LogDatei.DependentAdd (ps, LLessential);
    if opsidata <> nil then
    begin
      if runLoginScripts then
        LogDatei.DependentAdd ('Executed login script for : '+Topsi4data(opsidata).getActualProductId+' Version: '+opsidata.getActualProductVersion , LLessential)
      else
      if runproductlist then
        LogDatei.DependentAdd ('Executed via runproductlist setup script for : '+Topsi4data(opsidata).getActualProductId+' Version: '+opsidata.getActualProductVersion , LLessential)
      else
      begin
        LogDatei.DependentAdd ('installed product: '+Topsi4data(opsidata).getActualProductId+' Version: '+opsidata.getActualProductVersion , LLessential);
        LogDatei.log2history ('installed : '+Topsi4data(opsidata).getActualProductId+' Version: '+opsidata.getActualProductVersion );
      end;

      //LogDatei.DependentAdd ('opsi service version: '+opsidata.getOpsiServiceVersion, LLessential);
    end;
    LogDatei.DependentAdd (ps, LLessential);

    if LogDatei.ReportErrorsToUser and (Script.NumberOfErrors > 0)
    then
    Begin
     //if Script.NumberOfErrors = 1
       //then ps := 'is '
       //else ps := 'are ';
       {$IFDEF GUI}
       MyMessageDlg.WiMessage ('On installing ' + ps + #10 +
                   IntToStr (Script.NumberOfErrors) +  '  '  +
                   'error(s) occurred ' + #10 +
                   'Please inform your administrator',
                               [mrOK]);
       {$ENDIF GUI}
    End;
    {$IFDEF WIN32}
    if opsiSetupAdmin_created then
      if DeleteTemporaryLocalAdmin then
        LogDatei.DependentAdd ('Temporary Local Admin dieleted', LLDebug2);
    {$ENDIF WIN32}
    deleteTempBatFiles('');
    LogDatei.DependentAdd ('Temp cmd files deleted, next: free script ', LLDebug2);

    if Script.FExtremeErrorLevel < extremeErrorLevel
    then extremeErrorLevel := Script.FExtremeErrorLevel;

    // reset current dir to the start value
    SetCurrentDir(opsiWinstStartdir);
    scriptsuspendstate := script.Suspended;

    {$IFDEF WIN32}
    // Unblock Input
    winBlockInput(false);
    {$ENDIF WIN32}

    try
      Script.free; Script := nil;
    except
     on e: exception do
     {$IFDEF GUI}
     MyMessageDlg.wiMessage ('CreateAndProcessScript : free Aktionsliste: '+e.Message, [mrOK]);
     {$ELSE GUI}
     writeln('CreateAndProcessScript : free Aktionsliste: '+e.Message);
     {$ENDIF GUI}
    end;
    LogDatei.log ('End of CreateAndProcessScript', LLDebug2);
  except
    on e: exception do
    Begin
      LogDatei.log('Exception in CreateAndProcessScript: General' + e.message, LLError);
    End;
  end;
end;



begin
  randomize;

  //PreDefinedVariableSkinDirectory  := '$skindirectory$';
  //PreDefinedVariableSkinDirectoryValue := ExtractFileDir (Paramstr(0));

  GetMem (PStatNames, sizeof (TStatementNames));
  PStatNames^ [tsNotDefined]          := '';
  PStatNames^ [tsActions]             := 'Sub';
   PStatNames^ [tsProfileActions]      := 'ProfileAction';
  PStatNames^ [tsPatchAnyTextfile]    := 'PatchTextFile';
  PStatNames^ [tsTests]               := 'Tests';
  //PStatNames^ [tsTestCommand]         := 'Testcommand';
  PStatNames^ [tsPatchIniFile]        := 'Patches';
  PStatNames^ [tsHostsPatch]          := 'PatchHosts';

  PStatNames^ [tsRegistryHack]        := 'Registry';
  PStatNames^ [tsXMLPatch]            := 'XMLPatch';
  PStatNames^ [tsIdapiConfig]         := 'IdapiConfig';
  PStatNames^ [tsLDAPsearch]          := 'LDAPsearch';
  PStatNames^ [tsFileActions]         := 'Files';
  PStatNames^ [tsLinkFolder]          := 'LinkFolder';
  PStatNames^ [tsWinBatch]            := 'WinBatch';
  PStatNames^ [tsDOSBatchFile]        := 'DOSBatch';
  PStatNames^ [tsDOSInAnIcon]         := 'DOSInAnIcon';
  PStatNames^ [tsShellBatchFile]      := 'ShellBatch';
  PStatNames^ [tsShellInAnIcon]       := 'ShellInAnIcon';
  PStatNames^ [tsExecutePython]       := 'ExecPython';
  PStatNames^ [tsExecuteWith]         := 'ExecWith';
  PStatNames^ [tsExecuteWith_escapingStrings] := 'ExecWith_escapingStrings'; // is implemented via parameterEscapeStrings
  PStatNames^ [tsKillTask]            := 'KillTask';
  PStatNames^ [tsOpsiServiceCall]     := 'OpsiServiceCall';
  PStatNames^ [tsOpsiServiceHashList] := 'OpsiServiceHashList';
  PStatNames^ [tsDDEwithProgman]      := 'ProgmanGroups';

  PStatNames^ [tsWorkOnStringList]    := 'WorkOnStringList';

  PStatNames^ [tsStayWhileWindowOpen] := 'StayWhileWindowOpen';
                   (* fuer Testzwecke, nicht dokumentiert *)

  PStatNames^ [tsCondOpen]            := 'If';
  PStatNames^ [tsCondThen]            := 'Then';
  PStatNames^ [tsCondElse]            := 'Else';
  PStatNames^ [tsCondClose]           := 'EndIf';

  PStatNames^ [tsLoopStringList]      := 'for';

  PStatNames^ [tsMessage]             := 'Message';
  PStatNames^ [tsMessageFile]         := 'ShowMessageFile';
  PStatNames^ [tsShowBitmap]          := 'ShowBitmap';
  PStatNames^ [tsPause]               := 'Pause';
  PStatNames^ [tsSleep]               := 'SleepSeconds';
  PStatNames^ [tsStop]                := 'Stop';
  PStatNames^ [tsComment]             := 'Comment';
  PStatNames^ [tsActionProgress]      := 'setActionProgress';
  PStatNames^ [tsLogError]            := 'LogError';
  PStatNames^ [tsLogWarning]          := 'LogWarning';
  PStatNames^ [tsSetSkinDir]          := 'SetSkinDirectory';
  PStatNames^ [tsIncludeInsert]       := 'Include_Insert';
  PStatNames^ [tsIncludeAppend]       := 'Include_Append';
  PStatNames^ [tsIncludeLog]          := 'IncludeLog';
  PStatNames^ [tsShrinkFileToMB]      := 'ShrinkFileToMB';
  PStatNames^ [tsChangeDirectory]     := 'ChangeDirectory';



  PStatNames^ [tsExitWindows]         := 'ExitWindows';
  PStatNames^ [tsLocalAdmin]          := 'LocalAdmin';
  PStatNames^ [tsBlockInput]          := 'BlockInput';


  PStatNames^ [tsAddConnection]       := 'AddConnection';
                 (* nicht dokumentiert *)

  PStatNames^ [tsSetOldLogLevel]         := 'LogLevel';
  PStatNames^ [tsSetLogLevel]            := 'SetLogLevel';
  PStatNames^ [tsSetOutputLevel]         := 'SetOutputLevel';
  PStatNames^ [tsSetExitOnError]         := 'ExitOnError';
  PStatNames^ [tsFatalOnSyntaxError]     := 'FatalOnSyntaxError';
  PStatNames^ [tsFatalOnRuntimeError]    := 'FatalOnRuntimeError';
  PStatNames^ [tsAutoActivityDisplay]    := 'AutoActivityDisplay';

  PStatNames^ [tsSetConfidential]        := 'SetConfidential';

  PStatNames^ [tsSetFatalError]          := 'IsFatalError';
  PStatNames^ [tsSetSuccess]             := 'IsSuccess';
  PStatNames^ [tsSetSuspended]           := 'IsSuspended';
  PStatNames^ [tsSetNoUpdate]            := 'noUpdateScript';
  PStatNames^ [tsSetMarkerErrorNumber]   := 'MarkErrornumber';
  PStatNames^ [tsSetReportMessages]      := 'ScriptErrorMessages';
  PStatNames^ [tsSetTimeMark]            := 'MarkTime';
  PStatNames^ [tsLogDiffTime]            := 'DiffTime';
  PStatNames^ [tsSetTraceMode]        := 'TraceMode';
  PStatNames^ [tsSetStayOnTop]        := 'StayOnTop';
  PStatNames^ [tsIconizeWinst]        := 'IconizeWinst';
  PStatNames^ [tsRestoreWinst]        := 'RestoreWinst';
  PStatNames^ [tsNormalizeWinst]      := 'NormalizeWinst';
  PStatNames^ [tsEncoding]            := 'encoding';

  PStatNames^ [tsWinstVersionRequired] := 'RequiredWinstVersion';
  PStatNames^ [tsSetUsercontext]       := 'SetUserContext';
  PStatNames^ [tsSaveVersionToProfile]       := 'saveVersionToProfile';



  PStatNames^ [tsDefineVar]           := 'DefVar';
  PStatNames^ [tsDefineStringList]    := 'DefStringList';
  PStatNames^ [tsSetVar]              := 'Set';

  runProfileActions := false;
  runLoginScripts := False;
  allLoginScripts := True;
  inUsercontext := False;
  runSilent := False;
  flag_all_ntuser := False;
  runproductlist := False;
  scriptMode := tsmMachine;


end.
