/* Migrationsprozedur fr Symantec Antivirus */
/* Erstellt am 22. Mai 03 durch Chris Clayton */
/* Frei nutzbar fr die Allgemeinheit, sowohl ganz als auch in Teilen, */
/* aber ein Hinweis auf den Autor wird gern gesehen */

/*  Vom Nutzer vernderbare Definitionen: */
  /* erstelle WPS-Ordner, knnte aber auch durch z. B. einen */
  /* erweiterten ObjectDesktop-Ordner ersetzt werden */
  clFolderClass = 'WpFolder'  /* ''TSEnhFolder' */

  /* Logdatei - falls nicht bentigt, ndern zu '' */
  fLogFile = 'SymaMigr.log'

  /* Wie Anpassungen an der config.sys gehandhabt werden */
  /* 'Y' = config.sys verndern (die alte wird als config.mig gespeichert) */
  /* 'N' = nderungen in config.mig speichern (config.sys bleibt unverndert) */
  sCommitCgs = 'N'

  /* die zu verndernde INI-Datei - Symantec verwendet os2.ini: 'USER' */
  /* hier wird zum Test 'symatest.ini' verwendet */
  fDestINI = 'symatest.ini'

  /* Symantec AntiVirus-Program- und Virusdefinitionsverzeichnisse, die in */
  /* INI-Datei gespeichert werden sollen - anpassen, soweit ntig */
  sSymantec = 'e:\symantec'
  sDefsDir = sSymantec||'\common\shared\virusdef'
  sVirusDir1 = sDefsDir||'\20001113.002'
  sVirusDir2 = sDefsDir||'\20001113.002'
  sVirusDir3 = sDefsDir||'\20030326.002'  /* verwendet das 'Neueste'(siehe DEFINFO.DAT) */
  sVirusDir4 = sDefsDir||'\20001113.002'

  /*  Mein Verzeichnis fr Icons (Symbole) */
  sIcons = 'E:\UTILITY\ICONS\'

/* Ermitteln des OS/2-Laufwerks (des Systemstartlaufwerks) */
sBootDrive =
Substr(Translate(Value('PATH',,'OS2ENVIRONMENT')),Pos('\OS2\SYSTEM',Translate(Value('PATH',,'OS2ENVIRONMENT')))-2,2)
/* Fundort der config.sys - normalerweise sBootdrive, hier '.' zum Test */
sCfigDrive = '.' /* sBootDrive */

/* Alle RexxUtil-Funktionen laden, auch wenn nur einige davon verwendet werden */
Call RxFuncAdd 'SysLoadFuncs', 'REXXUTIL', 'SysLoadFuncs';
Call SysLoadFuncs;

/* Zustzliche globale Definitionen */
/* Variablen zur Aufnahme von Zustzen zur config.sys fr: */
sNewBook = ''           /* BOOKSHELF-Umgebungsvariable */
sNewDpath = ''          /* DPATH-Umgebungsvariable */
sNewHelp = ''           /* HELP-Umgebungsvariable */
sNewLib = ''            /* LIBPATH-Anweisung */
sNewPath = ''           /* PATH-Umgebungsvariable */

/* die folgende Verbundvariable dient zur Aufnahme zustzlicher config.sys- */
/* Eintrge */
stAddlCfg.0 = 0     /* die Erste enthlt die Anzahl der Eintrge */
                   /* .1 .. .n wird die eigentlichen Eintrge enthalten */

bOK = 'FALSE'                            /* hat die Migration funktioniert? */

/* Anlegen eines Zielordners auf dem Desktop */
/* Geben sie eine eindeutige Kombination aus Objekt-ID und Ordnernamen */
/* Alternativ knnen Sie einen existierenden Ordner angeben - Sie mssen */
/* nur seine Objekt-ID kennen. Unimaint bietet ein WPS-Tool, mit welchem */
/* man sich die Eigenschaften von WPS-Objekten anzeigen lassen kann. In diesem */
/* Fall kann das folgende Kode-Objekt entfernt und die Variable sUtility mu */
/* mit der Objekt-ID des angestrebten Zielordners gefllt werden. */
sFolder = '<CMC_MY_PROGS>'
sName = 'Mein Ordner'
rc = Message(  'Lege Desktop-Ordner an: '||sName )
rc = SysSetObjectData(sFolder,'' )              /* prfen, ob Objekt existiert */
if RC = 1 THEN
  DO
    rc = Message( ' Ordner '||sName||' kann nicht angelegt werden, weil Objekt-ID '||sFolder||' bereits existiert' )
    EXIT
  END
ELSE
  DO
    sOptions = 'OBJECTID='||sFolder||';CONCURRENTVIEW=NO;'
    sOptions = sOptions||'VIEWBUTTON=MINIMIZE;MINWIN=HIDE;'
    sOptions = sOptions||'ICONVIEW=NONGRID,NORMAL;ICONVIEWPOS=25,10,50,70'
    rc = SysCreateObject( clFolderClass, sName, '<WP_DESKTOP>', sOptions, 'fail' )
    IF RC = 0 THEN
      DO
        rc = Message(  '  Ordner '||sName|| ' kann nicht angelegt werden.' )
        rc = Message(  '  Sicherstellen, dass er geloescht ist, und erneut versuchen.' )
        EXIT
      END
  END  /* sObject else */

/*  Nun werden die Unterordner angelegt */
sApplicat = CreateFolder( sFolder, 'Application', '<CMC_MY_APPS>' )
sUtility = CreateFolder( sFolder, 'Utility', '<CMC_MY_UTIL>' )

/* Symantec Antivirus migrieren, falls vorhanden */
fFile =  'E:\SYMANTEC\NAVOS2.EXE'
rc = stream( fFile, 'c', 'query exist' )
if rc = fFile then
 DO
  sName = 'Symantec Antivirus'
  /* Neuen Ordner im sUtility-Ordner anlegen */
  sFolder = CreateFolder( sUtility, sName, '<SKC_AV_FOLDER>' )
  IF sFolder = sUtility THEN   /* Anlegen des Ordners hat nicht geklappt */
    rc = Message( '      So not migrating '||sName||' applications' )
  ELSE  /* der gewnschte Ordner konnte angelegt werden, also fgen wir die Programmobjekte hinzu */
   DO
    /* Hauptprogramm von Symantec Antivirus */
    /* Dies ist ein WPS-Prgramm, welches keine zustzlichen Objekt- */
    /* einstellungen bentigt. Also geben wir nur einen Zielordner */
    /* (sFolder), einen Objekttitel (sName), eine eindeutige Objekt-ID (<SKC_AV_PROG>) */
    /* und den Programmtyp (PM fr ein WPS-Program) an. Die Zusatzparameter */
    /* werden als Null-String '' bergeben */
    rc = CreateApp( sFolder, sName, fFile, '<SKC_AV_PROG>', 'PM', '' )

    /* Installations-Utility */
    /* Hier wird ein Programm verwendet, welches in einem Befehlsprozessor luft; */
    /* beachten Sie, da der komplette Pfad zu cmd.exe angegeben wird, und zwar */
    /* weil CreateApp die Existenz des Programms berprft, bevor es  */
    /* ein Objekt anlegt. Also mu CreateApp bekanntgegeben werden, wo das Programm steht. */
    /* Hierbei ist der Programmtyp WINDOWABLEVIO fr eine OS/2-Fenstersitzung. */
    /* Schlielich mssen wir das Feld 'parameters' fllen, wobei die Variable */
    /* sParms verwendet wird, die die zustzlichen Objekteigenschaften enthlt. */
    /* Zustzlich geben wir ein Icon an, wobei wir die einzelnen Angaben der  */
    /* Objekteigenschaften durch ';' voneinander trennen */
    sParms = 'PARAMETERS=/c e:\Symantec\epfinsts.exe /c:e:\Symantec\navos2.icf /o:drive;'
    sParms = sParms||'ICONFILE=E:\SYMANTEC\EPFIICIS.ICO'
    rc = CreateApp( sFolder, 'Installation Utility', sBootDrive||'\OS2\CMD.EXE', '<SKC_AV_INST>', 'WINDOWABLEVIO', sParms )

    /* Live Update */
    rc = CreateApp( sFolder, 'Live Update', 'E:\SYMANTEC\NAVLUOS2.EXE', '<SKC_AV_UPDT>', 'PM', '' )

    /* Objekt 'Scanne a:' */
    sParms = 'PARAMETERS=a:\*.* /doallfiles /repair /s+;ICONFILE='||sIcons||'VIRUS.ICO'
    rc = CreateApp( sFolder, 'Scanne a:', 'E:\SYMANTEC\NAVDXOS2.EXE', '<SKC_AV_SCANA>', 'WINDOWABLEVIO', sParms )

    /* Anlegen des Programmobjekts 'Startup Norton Program Scheduler' */
    rc = CreateApp( sFolder, 'Startup Norton Program Scheduler', 'E:\SYMANTEC\OS2SCHED.EXE', '<SKC_AV_STRT>', 'PM', '' )

    /* Nun legen wir das Programmobjekt 'Uninstall Norton Antivirus' an */
    rc = CreateApp( sFolder, 'Uninstall Norton Antivirus', 'E:\SYMANTEC\VDEFINST.EXE', '<SKC_AV_UNINST>', 'PM', 'PARAMETERS=/u' )

    /* Anpassungen der config.sys: Symantec Antivirus bentigt diese Eintrge */
    /* eigentlich nicht. Sie sind als Beispiel aufgefhrt, wie man nderungen */
    /* vornimmt an: a) den diversen Pfad-Umgebungsvariablen. Die folgende Funktion */
    /* fgt einen Pfad hinzu, der in die LIBPATH= Anweisung aufgenommen werden */
    /* soll. Die Variable sNewLib wird sowohl bergeben als auch gefllt. Das */
    /* ist so kodiert, weil alle Pfadangaben kumuliert werden, falls spter */
    /* weitere Anwendungen migriert werden (ConcactPath ist in der Lage, die */
    /* Eintrge mit ';' voneinander zu trennen). Da die Funktion fr die unter- */
    /* schiedlichsten Pfadvariablen verwendet wird, (s. die Liste der Definitionen */
    /* weiter oben) wird die Zeichenkette 'LIBPATH' zu Logging-Zwecken bergeben  */
    sNewLib = ConcactPath( sNewLib, 'E:\SYMANTEC', 'LIBPATH' )
    sNewHelp = ConcactPath( sNewHelp, 'E:\SYMANTEC', 'HELP' )
    sNewPath = ConcactPath( sNewPath, 'E:\SYMANTEC', 'PATH' )
    /* b) AddCfgEntry wird zum Einfgen ganzer config.sys-Zeilen in eine Stamm- */
    /* variable verwendet, die spter am Ende der neuen config.sys erscheinen sollen. */
    /* Hier fgen wir einen Kommentar sowie eine Umgebungsvariable hinzu. */
    /* Wir knnten hiermit alles hinzufgen, was eine Anwendung ggf. bentigt, */
    /* wie z. B. Einheitentreiber. */
    rc = AddCfgEntry( 'REM  Symantec Antivirus' )
    rc = AddCfgEntry( 'SET SYMANTEC=E:\SYMANTEC' )

    /* Generieren von Eintrgen in INI-Dateien */
    /* Das Hinzufgen von Eintrgen zu INI-Dateien ist ein Kinderspiel, */
    /* wenn Sie dazu nicht zu ngstlich sein sollten. */
    /* Sie mssen eine INI-Datei angeben: 'USER' fr die os2.ini, 'SYSTEM' fr */
    /* die os2sys.ini (die meisten Anwendungen sollten hier die Finger weg lassen), */
    /* oder einen Dateinamen. Im vorliegenden Fall geben wir fDestINI an. */ 
    /* Sollte die angegebene Datei noch nicht vorhanden sein, wird sie unter */
    /* Verwendung des in fDestINI angegebenen Pfades fr Sie erstellt. Achtung: */
    /* Symantec erwartet diese Eintrge in der OS/2-Userdatei, os2.ini. In diesem */
    /* Beispielkode wird zu Testzwecken ein Dateiname angegeben. Wenn alles  */
    /* geklappt hat, wird fDestINI auf 'USER' gesetzt. */
    /* Die nchste Variable in CreateINIentry ist der Name der Anwendung, gefolgt */
    /* von der Bezeichnung des Schlssels. Die Routine prft, ob diese Kombination */
    /* aus Anwendung und Schlssel in der angegebenen Datei schon vorhanden ist.  */
    /* Falls ja, wird der Schlssel gelesen und ohne Modifikation in die Variable */
    /* rc gestellt. Falls nein, werden Anwendung und Schlssel mit dem angegebenen */
    /* Schlsselwert hinzugefgt (hier der Inhalt von sDefsDir). REXX-Zeichenketten */
    /* sind nicht Null-terminiert, weshalb die letzte Variable bestimmt, ob dem */
    /* Schlsselwert ein Nullterminator hinzugefgt wird ('Y') oder nicht ('N'). */
    /* Beim Funktionsende enthlt rc eine Nullzeichenkette '', wenn das Anlegen */
    /* des Schlssels erfolgreich war, oder die Zeichenkette 'ERROR:', falls nicht. */
    rc = CreateINIentry( fDestINI, 'SymantecInstalledApps', 'AVENGEDEFS', sDefsDir, 'Y' )
    rc = CreateINIentry( fDestINI, 'SymantecNAV', 'AVDefsDir', sDefsDir, 'Y' )
    rc = CreateINIentry( fDestINI, 'SymantecNAV', 'InstallDir', sSymantec, 'Y' )
    rc = CreateINIentry( fDestINI, 'SymantecNAV', 'InstallVersion', '5.0', 'Y' )
    rc = CreateINIentry( fDestINI, 'SymantecSharedDefs', 'NAVOS2_50_AP1', sVirusDir1, 'Y' )
    rc = CreateINIentry( fDestINI, 'SymantecSharedDefs', 'NAVOS2_50_AP2', sVirusDir2, 'Y' )
    rc = CreateINIentry( fDestINI, 'SymantecSharedDefs', 'NAVOS2_50_NAVOS2', sVirusDir3, 'Y' )
    rc = CreateINIentry( fDestINI, 'SymantecSharedDefs', 'NAVOS2_50_QUAR', sVirusDir4, 'Y' )

    /* scheint, als htte die Migration funktioniert, */
    /* allerdings habe ich die Rckgabewerte nicht sehr grndlich geprft */
    bOK = 'TRUE'
   END /* Neuen Ordner anlegen else */
 END  /*  Symantec AntiVirus-Ordner */

/* Wenn die Migration geklappt hat, config.sys anpassen */
/* Das Flag sCommitCfs gibt an, ob die nderungen in */
/* config.sys oder config.mig vorgenommen werden sollen. S. oben. */
IF bOK = 'TRUE' THEN rc = UpdateConfigSys( sCommitCgs )

EXIT bOK \= 'TRUE'

/* Die folgenden Funktionen machen die eigentliche Arbeit der Migration. */
/* Als alter 'C'-Programmer gebe ich immer etwas an das aufrufende Programm zurck. */
/* Hier sind fast alle Rckgaben Indikatoren des Erfolgs der jeweiligen Aktion. */
/* Jede in diesen Routinen verwendete Variable, die nicht als Argumant bergeben */
/* wird, ist global (wird im gesamten Programm verwendet), deshalb muss darauf */
/* geachtet werden, dass sie ordentlich definiert sind, bevor die Routine */
/* aufgerufen wird. Zudem werden einige (wie rc) intern von REXX verwendet, */
/* weshalb sich ihr Inhalt verndern kann. Daher ist Vorsicht vonnten, wenn */
/* solche Variablen im Hauptteil des Programms verwendet werden. */

/*---------------------------------------------------------------------------
  rc = Message( sMessage )

  gibt eine Meldung auf der Konsole aus und schreibt sie in eine Log-Datei 
  (falls definiert)

  Argumente
        sMessage        Inhalt der Meldung. Bitte beachten: bei Verwendung 
                        mehrerer Zeichenketten und/oder REXX-Variablen ist der
                        Verkettungsoperator (||) zu empfehlen
  Rckgabe
        rc              der Rckgabewert von LINEOUT ( 0 = ok, alles andere ?)
  Globalvariable
        fLogFile        enthlt den Namen der Log-Datei oder '' wenn nicht bentigt
  Intern
        rc              LINEOUT-Rckgabewert
  ---------------------------------------------------------------------------*/
Message:
  PARSE ARG sMessage

  SAY sMessage
  rc = 0
  IF fLogFile \= '' THEN DO
    rc = LINEOUT( fLogFile, sMessage )   /* open file & write message */
    rc = LINEOUT( fLogFile )              /* close file */
  END  /* fLogFile IF */
  return rc  /* Ende von Message */

/*---------------------------------------------------------------------------
  sReturn = CreateApp( sDest, sName, fFile, sObject, sType, sExtras )

  erstellt ein Programmobjelt namens sName im Ordner sDest
  Hinweis: Die Funktion setzt als Arbeitsverzeichnis automatisch den Programm-
           Pfad. Sollte ein anderes Arbeitsverzeichnis bentigt werden, so mssen
           Sie mit SysSetObjectData die bentigte Korrektur vornehmen:
           rc = SysSetObjectData( sDest, 'STARTUPDIR=path' )

  Argumente
        sDest           Objekt-ID des Zielordners - muss vorhanden sein
        sName           Symboltitel
        fFile           Programmdatei mit vollem Pfad
        sObject         Objekt-ID - muss einzigartig sein
        sType           Typ des Programms wie (wegen weiterer s. WinCreateObject):
                                PM - WPS-Program
                                WINDOWABLEVIO - im OS/2-Fenster
                                WINDOWEDVDM - im DOS-Fenster
        sExtras         weitere additions to object creation options, such as parameters
                        format is:  option1=value1;option2=value2; ...
                        values may contain blanks but must be terminated by ';'
  Rckgabe
        sReturn         1 falls erfolgreich, ansonsten 0
  Intern
        rc              Rckgabewert von Funktionsaufrufen
        sDir            Programmpfad
        sOptions        Objektgenerierungsoptionen
        sReturn         Rckgabewert von SysCreateObject() oder 0
  ---------------------------------------------------------------------------*/
CreateApp:
  PARSE ARG sDest, sName, fFile, sObject, sType, sExtras

  sReturn = 0
  rc = stream( fFile, 'c', 'query exist' )
  if rc = fFile then
   DO
    rc = SysSetObjectData( sObject, '' )    /* prfen, ob Objekt existiert */
    if rc = 1 THEN
      rc = Message( ' Kann '||sName||' nicht anlegen, weil die Objekt-ID '||sObject||' existiert' )
    ELSE
     DO
      sDir = filespec( "drive", fFile )||filespec( "path", fFile)
      rc = Message(  'Creating '||sName||' object' )
      sOptions = 'OBJECTID='||sObject||';STARTUPDIR='sDir';EXENAME='||fFile||';'
      sOptions = sOptions||'PROGTYPE='||sType||';CONCURRENTVIEW=NO;MINWIN=VIEWER'
      IF sExtras \= '' THEN sOptions = sOptions||';'||sExtras
      sReturn = SysCreateObject( 'WpProgram', sName, sDest, sOptions, 'replace' )
      IF sReturn = 0 THEN
        rc = Message(  '  Kann Objekt '||sName||' nicht anlegen' )
     END   /* sObject else */
   END  /* fFile if */
  ELSE
    rc = Message(  sName||' nicht vorhanden - Programmobjekt nicht erstellt' )

  return sReturn  /* Ende von CreateApp */

/*---------------------------------------------------------------------------
  sReturn = CreateFolder( sDest, sName, sObject )

  Erstellt einen Ordner namens sName im Ordner sDest
  Anmerkung: diese Routine wird einen Ordner gleichen Namens, falls ein
  solcher im Zielordner bereits vorhanden sein sollte, hchstwahrscheinlich
  ersetzen. Die Objekt-ID wird zwar geprft, um sicherzustellen, da sie nicht
  der eines existierenden Objekts entspricht, nicht aber der Ordnername.
  Die WPS ist mglicherweise schlau genug, um mit einem doppelten Namen
  umgehen zu knnen, getestet wurde dies jedoch nicht.

  Argumente
        sDest           Objekt-ID des Zielordners - mu vorhanden sein
        sName           Ordnername
        sObject         Object-ID des zu erstellenden Ordners, muss neu sein
  Rckgabe
        sReturn         Objekt-ID: falls erfolgreich, die des angelegten Ordners,
                        sonst die des Zielordners
  Globalvariable
        clFolderClass   Klasse des anzulegenden Ordnertyps
  Intern
        rc              Rckgabewert von Funktionsaufrufen
        sObject         Ordner-Objekt-ID
        sOptions        Objektgenerierungsoptionen
  ---------------------------------------------------------------------------*/
CreateFolder:
  PARSE ARG sDest, sName, sObject

  sReturn = sDest
  rc = Message(  '  Erstelle Ordner: '||sName )
  rc = SysSetObjectData( sObject,'' )            /* prfen, ob Objekt existiert */
  if rc = 1 THEN
    rc = Message( '    Kann '||sName||' nicht erstellen, weil Objekt-ID '||sObject||' existiert' )
  ELSE
   DO
     sOptions = 'OBJECTID='||sObject||';CONCURRENTVIEW=NO;VIEWBUTTON=MINIMIZE;'
     sOptions = sOptions||'MINWIN=HIDE;ICONVIEW=NONGRID,NORMAL'
     rc = SysCreateObject( clFolderClass, sName, sDest, sOptions, 'replace' )
     IF rc = 0 THEN
       rc = Message(  '    Ordner '||sName||' konnte nicht erstellt werden' )
     ELSE
       sReturn = sObject
   END  /* sObject else */

  return sReturn  /* Ende von CreateFolder */

/*---------------------------------------------------------------------------
   sResult = MoveObject( sSource, sDest, sName )

   Eine Routine zum Verschieben von Objekten zwischen zwei Lokationen
   Argumente
           sSource      Objekt-ID, die verschoben werden soll
        sDest           Objekt-ID, zu welcher verschoben werden soll
        sName           Beschreibung des Quellobjektes (fr das Log)
   Rckgabe
        sResult         Erfolg der Operation: 1 = verschoben, 0 = nicht verschoben
   Intern
	rc	Rckgabewert der Message-Funktion
	sResult	Rckgabewert der Objektfunktion
  ---------------------------------------------------------------------------*/
MoveObject:
  PARSE ARG sSource, sDest, sName

  rc = Message(  '  Verschiebe Objekt: '||sName )
  sResult = SysSetObjectData( sSource, '' )      /* prfen, ob Objekt existiert */
  if sResult = 0 THEN
    rc = Message( "    Nicht verschoben - existiert nicht!" )
  ELSE
   DO
    sResult = SysMoveObject( sSource, sDest )
    IF sResult = 0 THEN
      rc = Message( '    Nicht verschoben - Objekt-IDs pruefen' )
   END

  RETURN sResult  /* Ende von MoveObject */

/*---------------------------------------------------------------------------
   sResult = ShadowObject( sSource, sDest, sName )

   Einer Routine zur Erstellung einer Referenz eines Objektes
   Argumente
        sSource         Object-ID des Quellobjektes
        sDest           Object-ID des Zielordners der Referenz
        sName           Beschreibung des Quellobjektes (fr das Log)
   Rckgabewert
        sResult         Erfolg der Operation:  1 = Referenz erstellt, 0 = nicht erstellt
   Intern
	rc	Rckgabewert der Message-Funktion
	sResult	Rckgabewert der Objektfunktion
  ---------------------------------------------------------------------------*/
ShadowObject:
  PARSE ARG sSource, sDest, sName

  rc = Message(  '  Erstelle Referenz fuer Objekt: '||sName )
  sResult = SysSetObjectData( sSource, '' )       /* prfen, ob Objekt existiert */
  if sResult = 0 THEN
    rc = Message( "    Keine Referenz erstellt - Quellobjekt nicht vorhanden!" )
  ELSE
   DO
    sResult = SysCreateShadow( sSource, sDest )
    IF sResult = 0 THEN
      rc = Message( '    Keine Referenz erstellt - Objekt-IDs pruefen' )
   END

  RETURN sResult  /* Ende von ShadowObject */

/*---------------------------------------------------------------------------
  sReturn = CreateINIentry( sINIfile, sApp, sKey, sVal, sNull )

  versucht, einen Eintrag in einer INI-Datei fr die Anwendung sAdd mit dem
  Schlssel sKey und dem Schlsselwert sVal anzulegen. Wenn sKey bereits
  existiert, dann wird sein derzeitiger Wert zurckgegeben und nichts verndert

  Eingabe:
        sINIfile        zu verndernde INI-Datei: 'USER', 'SYSTEM' oder ein
                        Dateiname
                        Anmerkung: ist die Datei nicht vorhanden, wird sie erstellt
        sApp            Anwendungsname zum Abspeichern von Profilangaben
        sKey            Schlsselname zum Abspeichern der Profilangaben
        sVal            Schlsselwert der Anwendung
        sNull           Nullterminator an Schlsselwert anhngen? 'Y' = ja, 'N' = nein
  Rckgabe
        sReturn         Rckgabewert von SysIni
  Intern
        rc              Rckgabewert der Funktion Message
        sReturn         Rckgabewert von SysIni
  ---------------------------------------------------------------------------*/
CreateINIentry:
  PARSE ARG sINIfile, sApp, sKey, sVal, sNull

    rc = Message(  '    pruefe INI-Dateieintrag "'sApp'"' )
    sReturn = SysIni( sIniFile, sApp, sKey )
    IF sReturn = 'ERROR:' THEN
    DO
      rc = Message(  '      erstelle INI-Dateieintrag fuer Schluessel "'sKey'"' )
      IF TRANSLATE( sNull ) = 'Y' THEN sVal = sVal||'0'x
      sReturn = SysIni( sIniFile, sApp, sKey, sVal )
      IF sReturn = '' THEN
         rc = Message(  '      erfolgreich hinzugefuegt: "'sVal'"' )
      ELSE
         rc = Message(  '      nicht erfolgreich:  SysIni Rueckgabewert = "'sReturn'"' )
    END
    ELSE  rc = Message(  '      Eintrag bereits vorhanden: "'sReturn'"' )

  return sReturn  /* Ende von CreateINIentry */

/*---------------------------------------------------------------------------
   sDest = Concactpath( sDest, sSource, sPlace )

   Routine zum Anhngen eines einzelnen Verzeichnispfades zu einer Variablen,
   die eine Pfadzeichenkette enthlt, die einer gegebenen Umgebungsvariablen
   der config.sys hinzugefgt werden soll

   Argumente
        sDest           die Variable, die die Pfadzeichenkette enthlt
        sSource         der anzuhngende Pfad
        sPlace          der Name der betr. Umgebungsvariablen (wie z. B. PATH)
                        wird fr LOG-Ausgaben bentigt
   Rckgabe
        sDest           die erweiterte Pfadzeichenkette
   Intern
        dPos            Position von ';' in sSource
        dLen            Lnge von sSource
        rc              Rckgabewert von Funktionsaufrufen
        sCurDir         aktuelles Verzeichnis
        sNewDir         Verzeichnis, zu dem mit DIRECTORY gewechselt wird
  ---------------------------------------------------------------------------*/
ConcactPath:
  PARSE ARG sDest, sSource, sPlace

  IF sSource \= '' THEN DO                   /* etwas zum anhngen, also los */
    rc = Message( '    Anhaengen von "'||sSource||'" an '||sPlace )
    sCurDir = DIRECTORY()   /* prfen ob sSource ein vorhandenes Verzeichnis ist */
    sNewDir = DIRECTORY( sSource )                    /* Versuch, dorthin zu wechseln */
    IF TRANSLATE( sNewDir ) = TRANSLATE( sSource ) THEN         /* hat geklappt */
       rc = DIRECTORY( sCurDir )                /* ist da, also zurck */
    ELSE                    /* nicht vorhanden, also Warnung ausgeben und trotzdem verwenden */
       rc = Message( '      WARNUNG: '||sSource||' existiert nicht' )
    sDest = sDest||sSource             /* neuen Pfad an vh. String anhngen */
    dPos = LASTPOS( ';', sSource )        /* prfe auf ';' am Stringende */
    dLen = LENGTH( sSource )
    IF dPos \= dLen THEN sDest = sDest||';' /* kein ';' am Ende, also eines anhngen */
  END  /* sSource if */

  return  sDest /* Ende von ConcactPath */

/*---------------------------------------------------------------------------
  rc = AddCfgEntry( sEntry )

  Hinzufgen einer einzelnen Zeile zur Stammvariablen, die die Eintrge fr
  die config.sys enthlt

  Argumente
        sEntry          die hinzuzufgende Zeichenkette
  Rckgabe
        stAddlCfg.0     die Anzahl der Elemente der Stammvariablen
  Intern
        i               Anzahl Eintrge
  ---------------------------------------------------------------------------*/
AddCfgEntry:
  PARSE ARG sEntry

  IF sEntry \= '' THEN DO  /* etwas hinzuzufgen */
    i = stAddlCfg.0  /* prfe, wieviele schon da sind */
    i = i + 1          /* auf den nchsten Eintrag erhhen */
    stAddlCfg.i = sEntry  /*  Zeile im nchsten Eintrag ablegen */
    stAddlCfg.0 = i  /* Aktualisieren des Eintragszhlers */
    rc = Message( '    config.sys-Zeile hinzugefuegt: "'||sEntry||'"' )
  END  /* sEntry if */

  return  stAddlCfg.0 /* Ende von AddCfgEntry */

/*---------------------------------------------------------------------------
  rc = UpdateConfigSys( sReplace )

  Ergnzt config.sys um die sNew.... Pfadvariablenanpassungen
  und fgt alle Eintrge aus stAddlCfg hinzu
  Anmerkung: Diese Routine ist modifizierter Kode von IBMs Works-Migrationsskript
  (und hier besser lesbar und kompakter)

  Argumente
        sReplace        Y = Eintrge ndern und in sBootDrive\config.sys speichern
                            (die originale config.sys gesichert als config.mig)
                        N = Vernderungen in sBootDrive\config.mig speichern
                            (die originale config.sys bleibt unangetastet)
  Rckgabewert
        sReturn         der Rckgabewert von LINOUT ( 0 = ok, alles andere ?)
  Globalvariablen
        sBootDrive      derzeitiges OS/2-Systemlaufwerk (oder '.' im Testfall)
        sNewBook        hinzuzufgende BOOKSHELF-Pfade
        sNewDpath       hinzuzufgende DPATH-Pfade
        sNewPath        hinzuzufgende PATH-Pfade
        sNewLib         hinzuzufgende LIBPATH-Pfade
        stAddlCfg       Stammvariable, die die zur config.sys hinzuzufgenden Zeilen enthlt
  Intern
        fCurConfig      die originale config.sys
        fNewConfig      die zu erstellende config-Datei
        tmpconfig       Temporrdatei fr Kopieroperationen
        rc              Rckgabewert von Funktionsaufrufen
        sReturn         Rckgabewert von LINOUT
        sInLine         einzelne config.sys-Zeile
        sOS2var         config.sys-Variable (der Teil vor dem '=')
        sOS2value       dazugehriger Wert (nach dem '"' )
  ---------------------------------------------------------------------------*/
UpdateConfigSys:
  PARSE ARG sReplace

  fCurConfig = sCfigDrive||'\CONFIG.SYS'           /* momentane config.sys */
  fNewConfig = sCfigDrive||'\CONFIG.MIG'         /* die neue samt Anpassungen */
  tmpconfig = sCfigDrive||'\IWTMP.SYS' /* temp file (could use REXX routine) */

  '@del 'fNewConfig ' 2>nul >nul'    /* config.mig vorsorglich lschend */

  DO WHILE LINES( fCurConfig )            /*  gesamte Datei durchsuchen */
   sInLine = LINEIN( fCurConfig )         /*  und dabei Zeile fr Zeile lesen */
                                          /* Variablen und Wert auseinandernehmen */
    PARSE VALUE sInLine WITH sOS2var '=' sOS2value
    sOS2var = TRANSLATE( sOS2var )               /* in Groschrift umsetzen */
    SELECT
       WHEN sOS2var = 'SET BOOKSHELF' THEN         /* BOOKSHELF-Eintrge hinzu */
         sReturn = UpdateConfLine( fNewConfig, sInLine, sNewBook )
       WHEN sOS2var = 'SET DPATH' THEN                 /*  auch DPATH-Eintrge */
         sReturn = UpdateConfLine( fNewConfig, sInLine, sNewDpath )
       WHEN sOS2var = 'SET HELP' THEN                   /* und HELP-Eintrge */
         sReturn = UpdateConfLine( fNewConfig, sInLine, sNewHelp )
       WHEN sOS2var = 'SET PATH' THEN                   /*  und PATH entries */
         sReturn = UpdateConfLine( fNewConfig, sInLine, sNewPath )
       WHEN sOS2var = 'LIBPATH' THEN                 /*  und LIBPATH entries */
         sReturn = UpdateConfLine( fNewConfig, sInLine, sNewLib )
/*---------------------------------------------------------------------------
   Da hier sowieso gerade die gesamte config.sys verarbeitet wird, wre das eine
   gute Gelegenheit, vorhandene Zeilen an Ort und Stelle anzupassen und/oder
   zustzliche Zeilen am Ende anzuhngen. Hier ein paar Beispiele dazu:

       WHEN sOS2var = 'PROTSHELL' THEN DO       /* c-a-d PROTSHELL-Eintrag einbauen */
         sReturn = lineout( fNewConfig, sInLine )
         sReturn = lineout( fNewConfig, 'rem ** PROTSHELL=E:\CADCMDR\CADCMDR.EXE' )
        END
       WHEN sOS2var = 'SWAPPATH' THEN               /* SWAPPATH-Eintrag verndern */
         sReturn = lineout( fNewConfig, 'SWAPPATH=E:\ 4096 98304' )
   Beachten Sie, da das folgende Beispiel den Werteteil des Eintrags verwendet
       WHEN sOS2value = 'USBMSD.ADD' THEN       /* USB-Massenspeichereintrag aktivieren (REM wegwerfen) */
         sReturn = lineout( fNewConfig, 'BASEDEV=USBMSD.ADD /FLOPPIES:0 /REMOVABLES:1' )

   Ende der Beiepiele
  ---------------------------------------------------------------------------*/
       OTHERWISE       /* die vorhandene Zeile in die neue Konfigurationsdatei schreiben */
           sReturn = lineout( fNewConfig, sInLine )
    END  /* select */
  END /* LINES DO */

  IF stAddlCfg.0 > 0 THEN DO  /* weitere Eintrge hinzufgen */
    DO i = 1 TO stAddlCfg.0
      sReturn = LINEOUT( fNewConfig, stAddlCfg.i )
   END  /* i DO */
  END  /* stAddlCfg IF */

  sReturn = LINEOUT( fNewConfig )                       /* Dateien schlieen */
  sReturn = LINEOUT( fCurConfig )

                             /* originale config.sys durch neue ersetzen */
  IF TRANSLATE( sReplace ) = 'Y' THEN DO
    '@erase 'tmpconfig' 2>nul >nul'        /* vorsorgliches Lschen der temp-Datei */
    '@rename 'fCurConfig' 'tmpconfig' >nul'   /* umbenennen: originale nach temp */
    '@rename 'fNewConfig' 'fCurConfig' >nul'  /* umbenennen: neue nach config.sys */
    '@rename 'tmpconfig' 'fNewConfig' 2>nul >nul'  /* umbenennen: temp nach neu */
    rc = Message( '  '||fCurConfig||' erfolgreich angepasst. Die bisherige Datei wurde als '||fNewConfig||' gesichert' )
  END
  ELSE rc = Message( '  '||fNewConfig||' enthlt alle Anpassungen. Die originale '||fCurConfig||' ist unverndert.' )

return  sReturn /* Ende von UpdateConfigSys */

/*---------------------------------------------------------------------------
  rc = UpdateConfLine( fOutFile, sInput, sAddition )

  Einer vorhandenen Zeile einen Text hinzufgen und das Resultat in die neue config.sys aufnehmen

  Argumente
        fOutFile        Ausgabedatei fr den modifizierten Eintrag
        sInput          derzeitiger Wert der config.sys-Zeile
        sAddition       Zeichenkette, die zu sInput hinzugefgt werden soll
  Rckgabewert
        sReturn         der Rckgabewert von LINOUT ( 0 = ok, alles andere ?)
  Intern
        sLen            Lnge einer Zeichenkette
        sPos            Position einer Unterzeichenkette in einer Zeichenkette
        sReturn         Rckgabewert von LINEOUT
  ---------------------------------------------------------------------------*/
UpdateConfLine:
  PARSE ARG fOutFile, sInput, sAddition

  IF sAddition \= '' THEN DO             /* etwas ist hinzuzufgen, also los */
    /* die folgende Zeile prft, ob der hinzuzufgende Pfad im existierenden */
    /* Pfad bereits vorhanden ist. Das ist zwar ntzlich, klappt aber nur, wenn */
    /* die gesamte Zeichenkette doppelt ist. Man sollte wirklich jeden Pfadeintrag */
    /* auf Dubletten prfen. Nicht allzu schwer, aber womglich verwirrend. */
    /* Vielleicht in einer zuknftigen Version zu implementieren. */
    sPos = POS( TRANSLATE( sAddition ), TRANSLATE( sInput ))
    IF sPos = 0 THEN DO                        /* nicht vh., also dazunehmen */
      sPos = LASTPOS( ';', sInput )                /* auf ';' am Ende prfen */
      sLen = LENGTH( sInput )
      IF sPos \= sLen THEN sInput = sInput||';'    /* kein ';' also anhngen */
      sInput = sInput||sAddition                         /* Anpassungen dazu */
    END  /* pos if */
  END  /* sAddition IF */

  sReturn = LINEOUT( fOutFile, sInput ) /* Resultat in neue config schreiben */

return result  /* Ende von UpdateConfLine */

/*---------------------------------------------------------------------------
  sDest = ConcactTabID( sDest, iTab, sObjID, sPlace )

  Eine Routine zum anfgen eines Tab Launchbar-Objektes zu einer Variablen, die
  eine Kette von Tab-Objekten enthlt

  Argumente
	sDest	enthlt die Tab-Objekt-IDs, die hinzukommen sollen
	iTab	die TAB-Nummer, zu der etwas hinzugefgt werden soll
	sObjID	die hinzuzufgende Objekt-ID
	sPlace	hinzuzufgender Ordner-/Programmname (fr das Log)
  Rckgabewert
	sDest           die neuen Objekt-ID-Eintrge
  Intern
	rc	Rckgabewerte von Funktionsaufrufen
   ---------------------------------------------------------------------------*/
ConcactTabID:
  PARSE ARG sDest, iTab, sObjID, sPlace

  IF sObjID \= '' THEN DO                /* etwas ist hinzuzufgen, also los */
    rc = Message( '  Eintrag "'||sPlace||'" wird dem Tabulator '||iTab||' hinzugefuegt' )
    rc = SysSetObjectData(sObjID,'' )         /* prfen, ob Objekt existiert */
    IF rc = 0 THEN                       /* existiert nicht, also ignorieren */
      rc = Message( '      WARNUNG: '||sPlace||' existiert nicht, nicht hinzugefuegt' )
    ELSE           /* existiert, also gewnschten Tabulatoreintrag vornehmen */
      sDest = sDest||iTab||'='||sObjID||','
  END  /* sObjID if */

  return  sDest /* Ende von ConcactTabID */
