/****************************** Module Header ******************************* * * Module Name: assocs.erx * * Syntax: assocs * * with * = query | prepend | append | remove * (query returns list items found in the ini file, * separated by '|' and also with a leading '|'.) * = the name or the number of an association list item, not * required for the query action. * * Syntax for Assocs keys values: * * = OBJECT, Type:TYPE [,POS] * or * = OBJECT, Filter:FILTER [,POS] * * with * OBJECT an * TYPE a WPS association type * FILTER a WPS association filter * POS optional position number (default = 1) or L (means: last), * used for the prepend action only * * This EPM REXX file is used for the setting * Programm objects -> Set association... * * This EPM-REXX file may also be executed from non-EPM environments. It is * callable from other REXX commands. * * Copyright (c) Netlabs EPM Distribution Project 2008 * * $Id$ * * =========================================================================== * * This file is part of the Netlabs EPM Distribution package and is free * software. You can redistribute it and/or modify it under the terms of the * GNU General Public License as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * Netlabs EPM Distribution. This library is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * ****************************************************************************/ IF ADDRESS() <> 'EPM' THEN '@ECHO OFF' /* ----------------- Standard ERX initialization follows ----------------- */ SIGNAL ON HALT NAME Halt SIGNAL ON ERROR NAME Error SIGNAL ON SYNTAX NAME Error SIGNAL ON NOVALUE NAME Error SIGNAL ON FAILURE NAME Error SIGNAL ON NOTREADY NAME Error env = 'OS2ENVIRONMENT' TRUE = (1 = 1) FALSE = (0 = 1) CrLf = '0d0a'x Redirection = '>NUL 2>&1' PARSE SOURCE . . ThisFile GlobalVars = 'env TRUE FALSE Redirection ERROR. ThisFile' GlobalVars = GlobalVars 'ErrorQueueName ErrorMessage' /* some OS/2 Error codes */ ERROR.NO_ERROR = 0 ERROR.INVALID_FUNCTION = 1 ERROR.FILE_NOT_FOUND = 2 ERROR.PATH_NOT_FOUND = 3 ERROR.ACCESS_DENIED = 5 ERROR.NOT_ENOUGH_MEMORY = 8 ERROR.INVALID_FORMAT = 11 ERROR.INVALID_DATA = 13 ERROR.NO_MORE_FILES = 18 ERROR.WRITE_FAULT = 29 ERROR.READ_FAULT = 30 ERROR.SHARING_VIOLATION = 32 ERROR.GEN_FAILURE = 31 ERROR.INVALID_PARAMETER = 87 ERROR.ENVVAR_NOT_FOUND = 204 rc = ERROR.NO_ERROR ErrorQueueName = VALUE( 'NEPMD_RXQUEUE',, env) ErrorMessage = '' CALL RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs' CALL SysLoadFuncs /* ----------------- Standard ERX initialization ends -------------------- */ /* Extend the environment, if not already */ next = VALUE( 'NEPMD_NAME',, env) IF next = '' THEN DO PARSE SOURCE . . ThisFile lp = LASTPOS( '\', ThisFile) ThisDir = LEFT( ThisFile, lp - 1) 'CALL' ThisDir'\..\..\netlabs\bin\EPMENV' END /* ------------- Configuration ---------------- */ UserDir = VALUE( 'NEPMD_USERDIR',, env) Ini._Filename = UserDir'\bin\nepmd.ini' Ini._RegKeys = 'RegKeys' Ini._RegContainer = 'RegContainer' Ini._RegDefaults = 'RegDefaults' Key._MainPath = '\NEPMD\User\ProgramObjects\Assocs' Key._Name = 'Name' /* -------------------------------------------- */ GlobalVars = GlobalVars 'Ini. Key. Processed. Group. Name. Assoc.' GlobalVars = GlobalVars 'DefaultKey. FoundGroup Action ListItem' Processed._Objects = '' Processed._Types = '' Processed._Filters = '' DO 1 PARSE ARG Action ListItem Action = TRANSLATE( STRIP( Action)) ListItem = STRIP( ListItem) IF (Action = '') THEN DO rc = ERROR.INVALID_PARAMETER ErrorMessage = 'Error: No action specified. First parameter' ||, ' for ASSOCS.ERX is missing.' LEAVE END IF ((ListItem = '') & (Action <> 'QUERY')) THEN DO rc = ERROR.INVALID_PARAMETER ErrorMessage = 'Error: No list item specified. Second parameter' ||, ' for ASSOCS.ERX is missing.' LEAVE END /* Init stem var */ Group. = '' Group.0 = 0 /* Get all user keys */ CALL GetUserGroups /* Get all default keys */ /* This fills also the DefaultKey. array */ CALL GetDefaultGroups /* Get names for all available groups */ CALL GetGroupNames IF (Action = 'QUERY') THEN DO /* Return ListBoxData string */ ListBoxData = '' DO g = 1 TO Group.0 ListBoxData = ListBoxData'|'Name.g END EXIT( ListboxData) END FoundGroup = '' /* Check if valid number specified as ListItem */ DO 1 IF VERIFY( ListItem, '0123456789') <> 0 THEN LEAVE IF ListItem = 0 THEN LEAVE IF ListItem > Group.0 THEN LEAVE FoundGroup = ListItem END /* Find ListItem in group names */ IF FoundGroup = '' THEN DO g = 1 TO Group.0 IF TRANSLATE( Name.g) = TRANSLATE( ListItem) THEN DO FoundGroup = g LEAVE END END IF FoundGroup = '' THEN DO ErrorMessage = 'Error: "'ListItem'" not found in 'Key._MainPath'\*\'Key._Name' keys.' rc = ERROR.INVALID_DATA LEAVE END /* Build Assoc. array */ CALL BuildAssocArray /* Process Assoc. array */ CALL ProcessAssocArray END CALL SayErrorMessage EXIT( rc) /* ----------------------------------------------------------------------- */ GetUserGroups: PROCEDURE EXPOSE (GlobalVars) rc = ERROR.NO_ERROR /* Get user sub keys from RegContainer */ UserSubKeys = '' next = SysIni( Ini._Filename, Ini._RegContainer, Key._MainPath) next = STRIP( next, 'T', '00'x) IF \(next = '' | next = 'ERROR:') THEN UserSubKeys = next /* Add user groups to Group. */ rest = UserSubKeys DO FOREVER PARSE VAR rest SubKey'00'x''rest IF SubKey = '' THEN LEAVE /* Check items for integer > 0 */ IF VERIFY( SubKey, '0123456789') <> 0 THEN ITERATE IF SubKey = 0 THEN ITERATE /* Check if SubKey is present in Group. */ fFound = 0 DO g = 1 TO Group.0 IF SubKey = Group.g THEN DO fFound = 1 LEAVE END END IF fFound = 0 THEN DO /* Add SubKey to Group. */ n = Group.0 + 1 Group.n = SubKey Group.0 = n END END RETURN( rc) /* ----------------------------------------------------------------------- */ GetDefaultGroups: PROCEDURE EXPOSE (GlobalVars) rc = ERROR.NO_ERROR /* Get all default keys */ DefaultKey. = '' DefaultKey.0 = '' next = SysIni( Ini._Filename, Ini._RegDefaults, 'ALL:', 'DefaultKey.') SearchKey = Key._MainPath'\' SearchLen = LENGTH( SearchKey) DO k = 1 TO DefaultKey.0 /* Find keys that start with SearchKey */ IF LEFT( DefaultKey.k, SearchLen) = SearchKey THEN DO /* Get reamaining key string */ SubKey = SUBSTR( DefaultKey.k, SearchLen + 1) /* Get first path segment */ PARSE VAR SubKey SubKey'\'. /* Check items for integer > 0 */ IF VERIFY( SubKey, '0123456789') <> 0 THEN ITERATE IF SubKey = 0 THEN ITERATE /* Check if SubKey is present in Group. */ fFound = 0 DO g = 1 TO Group.0 IF SubKey = Group.g THEN DO fFound = 1 LEAVE END END IF fFound = 0 THEN DO /* Add SubKey to Group. */ n = Group.0 + 1 Group.n = SubKey Group.0 = n END END END RETURN( rc) /* ----------------------------------------------------------------------- */ GetGroupNames: PROCEDURE EXPOSE (GlobalVars) rc = ERROR.NO_ERROR /* Get names for all available groups */ Name. = '' DO g = 1 TO Group.0 next = SysIni( Ini._Filename, Ini._RegKeys, Key._MainPath'\'g'\'Key._Name) IF \(next = '' | next = 'ERROR:') THEN DO Name.g = next ITERATE END next = SysIni( Ini._Filename, Ini._RegDefaults, Key._MainPath'\'g'\'Key._Name) next = STRIP( next, 'T', '00'x) IF \(next = '' | next = 'ERROR:') THEN DO Name.g = next ITERATE END Name.g = '' END RETURN( rc) /* ----------------------------------------------------------------------- */ BuildAssocArray: PROCEDURE EXPOSE (GlobalVars) rc = ERROR.NO_ERROR /* Init stem var */ Assoc. = '' Assoc.0 = 0 /* Get user sub keys from RegContainer */ UserSubKeys = '' next = SysIni( Ini._Filename, Ini._RegContainer, Key._MainPath'\'FoundGroup) next = STRIP( next, 'T', '00'x) IF \(next = '' | next = 'ERROR:') THEN UserSubKeys = next /* Add user objects to Assoc. */ rest = UserSubKeys DO FOREVER PARSE VAR rest SubKey'00'x''rest IF SubKey = '' THEN LEAVE /* Check items for integer > 0 */ IF VERIFY( SubKey, '0123456789') <> 0 THEN ITERATE IF SubKey = 0 THEN ITERATE /* Query key */ next = SysIni( Ini._Filename, Ini._RegKeys, Key._MainPath'\'FoundGroup'\'SubKey) next = STRIP( next, 'T', '00'x) IF \(next = '' | next = 'ERROR:') THEN DO /* Add next to Assoc. */ n = Assoc.0 + 1 Assoc.n = next Assoc.0 = n END END IF Assoc.0 = 0 THEN DO /* Default keys were already queried */ SearchKey = Key._MainPath'\'FoundGroup'\' SearchLen = LENGTH( SearchKey) DO k = 1 TO DefaultKey.0 /* Find keys that start with SearchKey */ IF LEFT( DefaultKey.k, SearchLen) = SearchKey THEN DO /* Get reamaining key string */ SubKey = SUBSTR( DefaultKey.k, SearchLen + 1) /* Get first path segment */ PARSE VAR SubKey SubKey'\'. /* Check items for integer > 0 */ IF VERIFY( SubKey, '0123456789') <> 0 THEN ITERATE IF SubKey = 0 THEN ITERATE /* Query key */ next = SysIni( Ini._Filename, Ini._RegDefaults, DefaultKey.k) next = STRIP( next, 'T', '00'x) IF \(next = '' | next = 'ERROR:') THEN DO /* Add next to Assoc. */ n = Assoc.0 + 1 Assoc.n = next Assoc.0 = n END END END END RETURN( rc) /* ----------------------------------------------------------------------- */ ProcessAssocArray: PROCEDURE EXPOSE (GlobalVars) rc = ERROR.NO_ERROR DO a = 1 TO Assoc.0 PARSE VAR Assoc.a Object','Setup','Position Object = STRIP( Object) Setup = STRIP( Setup) Position = STRIP( Position) IF Object = '' THEN ITERATE /* First, save object settings for maybe just created objects. */ /* Otherwise the following configuration may fail (because the */ /* previous object call was not wriiten to the inis). */ fAsync = 0 rcx = SysSaveObject( Object, fAsync) IF Action = 'REMOVE' THEN DO IF POS( ','Object',', ','Processed._Objects) <> 0 THEN ITERATE rc = RemoveAssocs( Object) IF rc <> ERROR.NO_ERROR THEN LEAVE ITERATE END IF Setup = '' THEN ITERATE IF Position = '' THEN Position = 1 IF Action = 'APPEND' THEN Position = 'L' ThisType = '' ThisFilter = '' SELECT WHEN POS( 'TYPE:', TRANSLATE( Setup)) = 1 THEN DO PARSE VAR SETUP .':'ThisType ThisType = STRIP( ThisType) rc = ChangeAssocPos( 'TYPE', ThisType, Object, Position) IF rc <> ERROR.NO_ERROR THEN LEAVE END WHEN POS( 'FILTER:', TRANSLATE( Setup)) = 1 THEN DO PARSE VAR SETUP .':'ThisFilter ThisFilter = TRANSLATE( STRIP( ThisFilter)) rc = ChangeAssocPos( 'FILTER', ThisFilter, Object, Position) IF rc <> ERROR.NO_ERROR THEN LEAVE END OTHERWISE NOP END END if rc = ERROR.NO_ERROR THEN DO MsgArgs = ListItem'|'Action'|'Processed._Objects'|' ||, Processed._Types'|'Processed._Filters IF ADDRESS() = 'EPM' THEN 'AssocsMsgBox' MsgArgs ELSE rcx = AssocsMsg( MsgArgs) END RETURN( rc) /* ----------------------------------------------------------------------- */ AssocsMsg: PROCEDURE EXPOSE (GlobalVars) PARSE ARG ListItem'|'Action'|'Objects'|'Types'|'Filters rc = ERROR.NO_ERROR verb = '' SELECT WHEN Action = 'PREPEND' THEN verb = 'prepending associations' WHEN Action = 'APPEND' THEN verb = 'appending associations' WHEN Action = 'REMOVE' THEN verb = 'removing associations' OTHERWISE END SAY 'Result of 'verb' for 'ListItem':' SAY SAY 'Changed objects:' rest = Objects DO WHILE rest <> '' PARSE VALUE rest WITH next','rest IF next = '' THEN ITERATE SAY ' o 'next END SAY SAY 'Changed types:' rest = Types DO WHILE rest <> '' PARSE VALUE rest WITH next','rest IF next = '' THEN ITERATE SAY ' o 'next END SAY SAY 'Changed filters:' rest = Filters DO WHILE rest <> '' PARSE VALUE rest WITH next','rest IF next = '' THEN ITERATE SAY ' o 'next END RETURN( rc) /* ----------------------------------------------------------------------- */ RemoveAssocs: PROCEDURE EXPOSE (GlobalVars) PARSE ARG Object rc = ERROR.NO_ERROR CALL RxFuncAdd 'WPToolsLoadFuncs', 'WPTOOLS', 'WPToolsLoadFuncs' CALL WPToolsLoadFuncs /* Get all assocs for this object */ rcx = WPToolsQueryObject( Object, 'Class', 'Title', 'Setup', 'Location') /* Remove all types */ PARSE VAR Setup .'ASSOCTYPE='Types';' DO WHILE Types <> '' PARSE VAR Types ThisType','Types IF ThisType = '' THEN ITERATE rc = ChangeAssocPos( 'TYPE', ThisType, Object, 'REMOVE') END /* Remove all filters */ PARSE VAR Setup .'ASSOCFILTER='Filters';' DO WHILE Filters <> '' PARSE VAR Filters ThisFilter','Filters IF ThisFilter = '' THEN ITERATE rc = ChangeAssocPos( 'FILTER', ThisFilter, Object, 'REMOVE') END RETURN( rc) /* ----------------------------------------------------------------------- */ ChangeAssocPos: PROCEDURE EXPOSE (GlobalVars) PARSE ARG Category, Assoc, ObjectId, Position rc = ERROR.NO_ERROR DO 1 /* Check values */ fPassed = 0 DO 1 IF (Assoc = '') THEN LEAVE IF (ObjectId = '') THEN LEAVE IF (LEFT( ObjectId, 1) <> '<') THEN LEAVE IF (RIGHT( ObjectId, 1) <> '>') THEN LEAVE IF ((VERIFY( Position, '123456789L') <> 0) & (Position <> 'REMOVE')) THEN LEAVE fPassed = 1 END IF \(fPassed) THEN DO ErrorMessage = 'Error: Invalid args "'Category', 'Assoc', 'ObjectId ||, ', 'Position'" for ChangeAssocPos.' rc = ERROR.INVALID_DATA LEAVE END /* Get decimal object handle from object id */ Handle = GetObjHandle( ObjectId) IF (Handle = '') THEN DO ErrorMessage = 'Error: ObjectId 'ObjectId' not defined in user ini.' rc = ERROR.FILE_NOT_FOUND LEAVE END /* Get user ini assoc val for Category key */ SELECT WHEN (Category = 'TYPE') THEN IniApplication = 'PMWP_ASSOC_TYPE' WHEN (Category = 'FILTER') THEN IniApplication = 'PMWP_ASSOC_FILTER' OTHERWISE ErrorMessage = 'Error: Undefined category "'Category'" specified.' rc = ERROR.INVALID_DATA LEAVE END IniKey = Assoc next = SysIni( 'USER', IniApplication, IniKey) IF next = 'ERROR:' THEN HandleList = '' ELSE /* Convert zeros to spaces to use the WORD functions */ HandleList = STRIP( TRANSLATE( next, ' ', '00'x)) NewHandleList = HandleList /* Find Handle in list of handles and maybe remove it */ wp = WORDPOS( Handle, HandleList) IF (wp > 0) THEN NewHandleList = SPACE( DELWORD( HandleList, wp, 1)) /* Add Handle according to Position */ SELECT WHEN (Position = 'REMOVE') THEN nop WHEN (Position = 1) THEN NewHandleList = SPACE( Handle NewHandleList) WHEN ((Position = 'L') | (Position > WORDS( NewHandleList))) THEN NewHandleList = SPACE( NewHandleList Handle) OTHERWISE windex = WORDINDEX( NewHandleList, Position) NewHandleList = SPACE( INSERT( Handle' ', NewHandleList, windex - 1)) END /* Write ini key */ IF (NewHandleList <> HandleList) THEN DO val = TRANSLATE( SPACE( NewHandleList)' ', '00'x, ' ') IF val = '00'x THEN val = 'DELETE:' /*'dprintf next = SysIni( USER, 'IniApplication', 'IniKey', 'TRANSLATE( val, '.', '00'x)')'; next = ''*/ next = SysIni( 'USER', IniApplication, IniKey, val) IF next = 'ERROR:' THEN DO ErrorMessage = 'Error: List of changed handles could not be' ||, ' written for 'IniApplication'->'IniKey ||, ', value = "'TRANSLATE( val, '.', '00'x)'"') rc = ERROR.INVALID_DATA LEAVE END /* Changed, so alter global lists */ IF POS( ','ObjectId',', ','Processed._Objects) = 0 THEN Processed._Objects = Processed._Objects''ObjectId',' IF (Category = 'TYPE') THEN DO IF POS( ','Assoc',', ','Processed._Types) = 0 THEN Processed._Types = Processed._Types''Assoc',' END ELSE DO IF POS( ','Assoc',', ','Processed._Filters) = 0 THEN Processed._Filters = Processed._Filters''Assoc',' END END END RETURN( rc) /* ----------------------------------------------------------------------- */ /* Returns the decimal object handle for an object id. */ GetObjHandle: PROCEDURE PARSE ARG ObjectId next = SysIni( 'USER', 'PM_Workplace:Location', ObjectId) IF next = 'ERROR:' THEN RETURN( '') HexObjHandle = REVERSE( next) DecObjHandle = C2D( HexObjHandle) RETURN( DecObjHandle) /* --------------------- Standard ERX macros follow ---------------------- */ /* ----------------------------------------------------------------------- */ SayText: PROCEDURE EXPOSE (GlobalVars) PARSE ARG Message SELECT WHEN ADDRESS() = 'EPM' THEN 'sayerror' Message OTHERWISE SAY Message END RETURN( '') /* ----------------------------------------------------------------------- */ SayErrorMessage: PROCEDURE EXPOSE (GlobalVars) SELECT WHEN (ErrorMessage = '') THEN NOP /* Called by frame program: insert error */ /* message into private queue */ WHEN (ErrorQueueName <> '') THEN DO rcx = RXQUEUE( 'SET', ErrorQueueName) PUSH ErrorMessage END /* Called directly */ WHEN ADDRESS() = 'EPM' THEN DO /*'sayerror' ErrorMessage*/ ThisFileName = SUBSTR( ThisFile, LASTPOS( '\', ThisFile) + 1) rcx = RxMessageBox( ErrorMessage, TRANSLATE( ThisFileName),, 'OK', 'ERROR') END /* Called directly */ OTHERWISE DO SAY ErrorMessage 'PAUSE' END END RETURN( '') /* ----------------------------------------------------------------------- */ Halt: ErrorMessage = 'Interrupted by user.' CALL SayErrorMessage EXIT( ERROR.GEN_FAILURE) /* ----------------------------------------------------------------------- */ /* Give a standard REXX error message and jump to the error line */ Error: /* sigl must be saved to not get overwritten by SayErrorMessage call */ ErrorLine = sigl /* As an extension to the standard REXX error messages, */ /* the error condition will be appended to the error text. */ ConditionText = 'Condition: 'CONDITION( 'C') ConditionDescription = CONDITION( 'D') IF ConditionDescription <> '' THEN ConditionText = ConditionText', Reason: 'ConditionDescription ErrText = ERRORTEXT( rc) IF ErrText = '' THEN ErrText = ConditionText ELSE ErrText = ErrText', 'ConditionText ErrorMessage = 'REX'RIGHT( rc, 4, 0)': Error 'rc' running 'ThisFile',' ||, ' line 'sigl': 'ErrText CALL SayErrorMessage IF ADDRESS() = 'EPM' THEN "e "ThisFile" 'postme "ErrorLine"'" /* Ensure that rc <> 0 is returned */ IF rc = 0 THEN rc = ERROR.GEN_FAILURE EXIT( rc)