2394 lines
61 KiB
C
2394 lines
61 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these librararies and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
/* $TOG: ActionFind.c /main/11 1998/07/30 12:09:31 mgreess $ */
|
|
/*************************************<+>*************************************
|
|
*****************************************************************************
|
|
**
|
|
** File: ActionFind.c
|
|
**
|
|
** Project: DT
|
|
**
|
|
** Description: Source file for the action database sorting and
|
|
** locating functions.
|
|
**
|
|
** (c) Copyright 1993, 1994 Hewlett-Packard Company
|
|
** (c) Copyright 1993, 1994 International Business Machines Corp.
|
|
** (c) Copyright 1993, 1994 Sun Microsystems, Inc.
|
|
** (c) Copyright 1993, 1994 Novell, Inc.
|
|
**
|
|
****************************************************************************
|
|
************************************<+>*************************************/
|
|
|
|
/*LINTLIBRARY*/
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <string.h>
|
|
#include <X11/Intrinsic.h>
|
|
|
|
#include <Xm/Xm.h>
|
|
#include <Xm/XmP.h>
|
|
|
|
#include <Tt/tttk.h>
|
|
|
|
#include <Dt/DtP.h>
|
|
#include <Dt/Message.h>
|
|
#include <Dt/DbReader.h>
|
|
#include <Dt/Connect.h>
|
|
#include <Dt/DtNlUtils.h>
|
|
#include <Dt/UserMsg.h>
|
|
#include <Dt/CommandM.h>
|
|
|
|
#include <Dt/ActionP.h>
|
|
#include <Dt/ActionDb.h>
|
|
#include <Dt/ActionUtilP.h>
|
|
#include <Dt/ActionFind.h>
|
|
#include "myassertP.h"
|
|
|
|
#include <Dt/Utility.h>
|
|
#include <Dt/DtsDb.h>
|
|
#include <Dt/DtsMM.h>
|
|
#include <Dt/Dts.h>
|
|
#include "DtSvcLock.h"
|
|
|
|
/******** Private Function Declarations ********/
|
|
|
|
DtDtsMMRecord *
|
|
_DtActionLocateRecord(
|
|
DtShmBoson actQuark,
|
|
unsigned long mask,
|
|
DtShmBoson arg_type,
|
|
int arg_count,
|
|
DtDtsMMDatabase *act_db);
|
|
|
|
|
|
/******** End Private Function Declarations ********/
|
|
|
|
|
|
/******** Static Function Declarations ********/
|
|
|
|
static int _DtActMMCompareObjClassMask(
|
|
unsigned long objClassMask,
|
|
char *actClass);
|
|
static int _DtActMMCompareMode(
|
|
unsigned long objMask,
|
|
char *actMode);
|
|
static int _DtActMMCompareType(
|
|
DtShmBoson reqType,
|
|
char *actType);
|
|
static int _DtActMMCompareCount(
|
|
int reqCount,
|
|
char *actCount);
|
|
static int _DtActionCompareRecordQuarks(
|
|
DtDtsDbRecord ** record1,
|
|
DtDtsDbRecord ** record2) ;
|
|
static void _DtActionGetRecordWeight(
|
|
DtDtsDbRecord ** record,
|
|
long * primaryWeightPtr,
|
|
long * secondaryWeightPtr );
|
|
static void ParseMessage(
|
|
register ActionPtr action,
|
|
register char * str,
|
|
register parsedMsg * msg) ;
|
|
static Boolean ValidKeyword(
|
|
char *start,
|
|
char *end,
|
|
char **prompt,
|
|
int *keywordId,
|
|
int *argNum,
|
|
Boolean *isFile );
|
|
|
|
static unsigned long _DtActMMParseArgTypesList(
|
|
char *tlist,
|
|
DtShmBoson **quarkAddr,
|
|
int *countp);
|
|
static unsigned long _DtActMMParseClassList(
|
|
char *clist);
|
|
static unsigned long _DtActMMParseArgCountString(
|
|
char *countStr,
|
|
int *countp);
|
|
static unsigned long _DtActMMParseActionType(
|
|
char *actionTypeStr);
|
|
static void _DtActMMGetCmdInfo(
|
|
DtDtsMMRecord *actRecp,
|
|
ActionPtr actp);
|
|
static void _DtActMMGetTtMsgInfo(
|
|
DtDtsMMRecord *actRecp,
|
|
ActionPtr actp);
|
|
static int _DtActInputSeqCheck(
|
|
DtDtsDbRecord *r1,
|
|
DtDtsDbRecord *r2);
|
|
static char * _DtActDbChooseLabel(
|
|
DtDtsDbRecord *rec);
|
|
static char * _DtActMMChooseLabel(
|
|
DtDtsMMRecord *rec);
|
|
static void _DtCheckForDuplicateRecord(
|
|
DtDtsDbRecord *rec,
|
|
DtDtsDbRecord *duprec);
|
|
static char * _DtActGetDtsDbField(
|
|
DtDtsDbRecord *recp,
|
|
char * fieldName );
|
|
static char *
|
|
_DtActGetDtsMMField ( DtDtsMMRecord *actRecp, char *name );
|
|
static void _DtSearchDuplicateRecord(
|
|
DtDtsDbDatabase *db);
|
|
|
|
#ifdef _DT_ALLOW_DT_MSGS
|
|
static void _DtActDbGetDtNtfyInfo(
|
|
DtDtsDbRecord *actRecp,
|
|
ActionPtr actp);
|
|
static void _DtActDbGetDtReqInfo(
|
|
DtDtsDbRecord *actRecp,
|
|
ActionPtr actp);
|
|
#endif /* _DT_ALLOW_DT_MSGS */
|
|
|
|
|
|
/******** End Static Function Declarations ********/
|
|
|
|
|
|
#define SPECIFIC_ARG_CLASS 8
|
|
#define SPECIFIC_ARG_TYPE 4
|
|
#define SPECIFIC_ARG_MODE 2
|
|
#define SPECIFIC_ARG_COUNT 1
|
|
|
|
#define SECONDARY_SPECIFIC 4
|
|
#define SECONDARY_LESS_THAN 3
|
|
#define SECONDARY_GREATER_THAN 2
|
|
#define SECONDARY_WILDCARD 1
|
|
|
|
#define _MAX_MAP_ATTEMPTS 100
|
|
|
|
/******************************************************************************
|
|
* External data
|
|
******************************************************************************/
|
|
extern XtAppContext _DtAppContext;
|
|
|
|
/******************************************************************************
|
|
******************************************************************************
|
|
*
|
|
* Public API Functions
|
|
*
|
|
******************************************************************************
|
|
******************************************************************************/
|
|
|
|
/*****************************************************************************
|
|
* DtActionDescription:
|
|
*---------------------
|
|
* This function returns the description associated with an action of the
|
|
* given name, "actionName". If there are multiple actions with the desired
|
|
* name, then the description of the "most generic" action of the given name
|
|
* is returned.
|
|
*
|
|
* NOTE: A new copy of the description string is returned.
|
|
* It is up to the calling function to free the space allocated
|
|
* for the description string.
|
|
*****************************************************************************/
|
|
static char *_DtActionDbDescription(char *s);
|
|
static char *_DtActionMMDescription(char *s);
|
|
|
|
char *
|
|
DtActionDescription (
|
|
char *s
|
|
)
|
|
{
|
|
char *actionDesc;
|
|
|
|
_DtSvcAppLockDefault();
|
|
actionDesc = (use_in_memory_db) ? _DtActionDbDescription(s) :
|
|
_DtActionMMDescription(s);
|
|
_DtSvcAppUnlockDefault();
|
|
|
|
return actionDesc;
|
|
}
|
|
|
|
static char *
|
|
_DtActionDbDescription ( char *s )
|
|
{
|
|
int n;
|
|
XrmQuark tmpq;
|
|
DtDtsDbRecord **act_rec;
|
|
DtDtsDbRecord **last_rec_found = NULL;
|
|
DtDtsDbDatabase *act_db;
|
|
|
|
_DtSvcProcessLock();
|
|
act_db = _DtDtsDbGet(_DtACTION_NAME);
|
|
myassert(s);
|
|
if ( !s ) {
|
|
_DtSvcProcessUnlock();
|
|
return NULL;
|
|
}
|
|
|
|
tmpq = XrmStringToQuark(s);
|
|
n = act_db->recordCount;
|
|
|
|
for ( act_rec = act_db->recordList;
|
|
n && act_rec && *act_rec ;
|
|
act_rec++, n--)
|
|
{
|
|
if ( (*act_rec)->recordName == (long) tmpq )
|
|
last_rec_found = act_rec;
|
|
|
|
/*
|
|
* Since actions are in name "quark" order, there is
|
|
* no sense searching past the desired quark value.
|
|
*/
|
|
|
|
if ( (*act_rec)->recordName > (long) tmpq )
|
|
break;
|
|
}
|
|
|
|
if ( last_rec_found ) {
|
|
_DtSvcProcessUnlock();
|
|
return XtNewString(_DtActGetDtsDbField(
|
|
*last_rec_found,_DtACTION_DESCRIPTION));
|
|
}
|
|
|
|
_DtSvcProcessUnlock();
|
|
return NULL;
|
|
}
|
|
|
|
static char *
|
|
_DtActionMMDescription ( char *s )
|
|
{
|
|
int n;
|
|
DtShmBoson tmpq;
|
|
DtDtsMMRecord *act_rec;
|
|
DtDtsMMRecord *act_rec_list;
|
|
DtDtsMMRecord *last_rec_found = NULL;
|
|
DtDtsMMDatabase *act_db;
|
|
int *start;
|
|
|
|
_DtSvcProcessLock();
|
|
act_db = _DtDtsMMGet(_DtACTION_NAME);
|
|
myassert(s);
|
|
if ( !s ) {
|
|
_DtSvcProcessUnlock();
|
|
return NULL;
|
|
}
|
|
|
|
if((tmpq = _DtDtsMMStringToBoson(s)) == -1)
|
|
{
|
|
_DtSvcProcessUnlock();
|
|
return(NULL);
|
|
}
|
|
|
|
act_rec_list = _DtDtsMMGetPtr(act_db->recordList);
|
|
start = (int*)_DtDtsMMGetDbName(act_db,tmpq);
|
|
|
|
for ( n = *start; n < act_db->recordCount; n++)
|
|
{
|
|
act_rec = &act_rec_list[n];
|
|
if ( act_rec->recordName == tmpq )
|
|
last_rec_found = act_rec;
|
|
|
|
/*
|
|
* Since actions are in name "boson" order, there is
|
|
* no sense searching past the desired quark value.
|
|
*/
|
|
|
|
if ( act_rec->recordName > tmpq )
|
|
break;
|
|
}
|
|
|
|
if ( last_rec_found ) {
|
|
_DtSvcProcessUnlock();
|
|
return _DtActGetDtsMMField(last_rec_found,
|
|
_DtACTION_DESCRIPTION);
|
|
}
|
|
_DtSvcProcessUnlock();
|
|
return NULL;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* DtActionExists --
|
|
* Given a string return True; if the string corresponds to an
|
|
* action name; False otherwise.
|
|
*
|
|
******************************************************************************/
|
|
static Boolean _DtActionDbExists(char *s);
|
|
static Boolean _DtActionMMExists(char *s);
|
|
|
|
Boolean
|
|
DtActionExists( char *s)
|
|
{
|
|
Boolean actionExists;
|
|
|
|
_DtSvcAppLockDefault();
|
|
actionExists = (use_in_memory_db) ? _DtActionDbExists(s) :
|
|
_DtActionMMExists(s);
|
|
_DtSvcAppUnlockDefault();
|
|
|
|
return actionExists;
|
|
}
|
|
|
|
static Boolean
|
|
_DtActionDbExists(char *s)
|
|
{
|
|
int n;
|
|
XrmQuark tmpq;
|
|
DtDtsDbRecord **act_rec;
|
|
DtDtsDbDatabase *act_db;
|
|
|
|
_DtSvcProcessLock();
|
|
act_db = _DtDtsDbGet(_DtACTION_NAME);
|
|
myassert(s);
|
|
if (!s) {
|
|
_DtSvcProcessUnlock();
|
|
return False;
|
|
}
|
|
|
|
tmpq = XrmStringToQuark(s);
|
|
n = act_db->recordCount;
|
|
|
|
myassert (act_db);
|
|
|
|
for ( act_rec = act_db->recordList;
|
|
n && act_rec && *act_rec;
|
|
act_rec++, n--)
|
|
{
|
|
if ( (*act_rec)->recordName == (long) tmpq ) {
|
|
_DtSvcProcessUnlock();
|
|
return True;
|
|
}
|
|
}
|
|
_DtSvcProcessUnlock();
|
|
return False;
|
|
}
|
|
|
|
static Boolean
|
|
_DtActionMMExists(char *s)
|
|
{
|
|
DtShmBoson tmpq;
|
|
DtDtsMMDatabase *act_db;
|
|
|
|
_DtSvcProcessLock();
|
|
act_db = _DtDtsMMGet(_DtACTION_NAME);
|
|
myassert(s);
|
|
if (!s) {
|
|
_DtSvcProcessUnlock();
|
|
return False;
|
|
}
|
|
|
|
tmpq = _DtDtsMMStringToBoson(s);
|
|
|
|
myassert (act_db);
|
|
|
|
if(tmpq != -1 && _DtDtsMMGetDbName(act_db,tmpq))
|
|
{
|
|
_DtSvcProcessUnlock();
|
|
return True;
|
|
}
|
|
|
|
_DtSvcProcessUnlock();
|
|
return False;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* DtActionLabel --
|
|
* Given an action name string return the label string
|
|
* (localizable name) for the action. return NULL if no action is found.
|
|
*
|
|
* Return the label associated with the "most generic" action of the
|
|
* given name in the database. In this case, we do not track down
|
|
* MAP actions since even a MAP action may have its own label.
|
|
******************************************************************************/
|
|
static char *_DtActionDbLabel(char *s);
|
|
static char *_DtActionMMLabel(char *s);
|
|
|
|
char *
|
|
DtActionLabel( char *s)
|
|
{
|
|
char *actionLabel;
|
|
|
|
_DtSvcAppLockDefault();
|
|
actionLabel = (use_in_memory_db) ? _DtActionDbLabel(s) :
|
|
_DtActionMMLabel(s);
|
|
_DtSvcAppUnlockDefault();
|
|
|
|
return actionLabel;
|
|
}
|
|
|
|
static char *
|
|
_DtActionDbLabel ( char *s )
|
|
{
|
|
int n;
|
|
XrmQuark tmpq;
|
|
char *label;
|
|
DtDtsDbRecord **act_rec;
|
|
DtDtsDbRecord **last_rec_found = NULL;
|
|
DtDtsDbDatabase *act_db;
|
|
|
|
_DtSvcProcessLock();
|
|
act_db = _DtDtsDbGet(_DtACTION_NAME);
|
|
myassert(s);
|
|
if ( !s ) {
|
|
_DtSvcProcessUnlock();
|
|
return NULL;
|
|
}
|
|
|
|
tmpq = XrmStringToQuark(s);
|
|
n = act_db->recordCount;
|
|
|
|
for ( act_rec = act_db->recordList;
|
|
n && act_rec && *act_rec;
|
|
act_rec++, n--)
|
|
{
|
|
if ( (*act_rec)->recordName == (long) tmpq )
|
|
last_rec_found = act_rec;
|
|
/*
|
|
* Since actions are in name "quark" order, there is
|
|
* no sense searching past the desired quark value.
|
|
*/
|
|
|
|
if ( (*act_rec)->recordName > (long) tmpq )
|
|
break;
|
|
}
|
|
|
|
if ( last_rec_found )
|
|
{
|
|
/*
|
|
* We have found the desired action
|
|
* Obtain the associated label (if any).
|
|
*/
|
|
_DtSvcProcessUnlock();
|
|
return _DtActDbChooseLabel(*last_rec_found);
|
|
|
|
}
|
|
|
|
/*
|
|
* We failed to find the desired action -- therefore return NULL.
|
|
*/
|
|
_DtSvcProcessUnlock();
|
|
return NULL;
|
|
}
|
|
|
|
static char *
|
|
_DtActionMMLabel ( char *s )
|
|
{
|
|
int n;
|
|
DtShmBoson tmpq;
|
|
char *label;
|
|
DtDtsMMRecord *act_rec;
|
|
DtDtsMMRecord *act_rec_list;
|
|
DtDtsMMRecord *last_rec_found = NULL;
|
|
DtDtsMMDatabase *act_db;
|
|
int *start;
|
|
|
|
_DtSvcProcessLock();
|
|
act_db = _DtDtsMMGet(_DtACTION_NAME);
|
|
myassert(s);
|
|
if ( !s ) {
|
|
_DtSvcProcessUnlock();
|
|
return NULL;
|
|
}
|
|
|
|
if((tmpq = _DtDtsMMStringToBoson(s)) == -1)
|
|
{
|
|
_DtSvcProcessUnlock();
|
|
return(NULL);
|
|
}
|
|
|
|
act_rec_list = _DtDtsMMGetPtr(act_db->recordList);
|
|
start = (int*)_DtDtsMMGetDbName(act_db,tmpq);
|
|
if ( !start ) {
|
|
_DtSvcProcessUnlock();
|
|
return NULL;
|
|
}
|
|
|
|
for ( n = *start; n < act_db->recordCount; n++)
|
|
{
|
|
act_rec = &act_rec_list[n];
|
|
if ( act_rec->recordName == tmpq )
|
|
last_rec_found = act_rec;
|
|
/*
|
|
* Since actions are in name "boson" order, there is
|
|
* no sense searching past the desired quark value.
|
|
*/
|
|
|
|
if ( act_rec->recordName > tmpq )
|
|
break;
|
|
}
|
|
|
|
if ( last_rec_found )
|
|
{
|
|
/*
|
|
* We have found the desired action
|
|
* Obtain the associated label (if any).
|
|
*/
|
|
_DtSvcProcessUnlock();
|
|
return _DtActMMChooseLabel(last_rec_found);
|
|
|
|
}
|
|
|
|
/*
|
|
* We failed to find the desired action -- therefore return NULL.
|
|
*/
|
|
_DtSvcProcessUnlock();
|
|
return NULL;
|
|
}
|
|
|
|
/******************************************************************************
|
|
* DtActionIcon --
|
|
* Given an action name string return the icon name string
|
|
* for the action. return NULL if no action is found.
|
|
*
|
|
* Return the icon associated with the "most generic" action of the
|
|
* given name in the database. In this case, we do not track down
|
|
* MAP actions since even a MAP action may have its own icon.
|
|
******************************************************************************/
|
|
static char *_DtActionDbIcon(char *s);
|
|
static char *_DtActionMMIcon(char *s);
|
|
|
|
char *
|
|
DtActionIcon( char *s)
|
|
{
|
|
char *actionIcon;
|
|
|
|
_DtSvcAppLockDefault();
|
|
actionIcon = (use_in_memory_db) ? _DtActionDbIcon(s) :
|
|
_DtActionMMIcon(s);
|
|
_DtSvcAppUnlockDefault();
|
|
|
|
return actionIcon;
|
|
}
|
|
|
|
static char *
|
|
_DtActionDbIcon ( char *s )
|
|
{
|
|
int n;
|
|
XrmQuark tmpq;
|
|
char *iconString;
|
|
DtDtsDbRecord **act_rec;
|
|
DtDtsDbRecord **last_rec_found = NULL;
|
|
DtDtsDbDatabase *act_db;
|
|
|
|
_DtSvcProcessLock();
|
|
act_db = _DtDtsDbGet(_DtACTION_NAME);
|
|
myassert(s);
|
|
if ( !s ) {
|
|
_DtSvcProcessUnlock();
|
|
return NULL;
|
|
}
|
|
|
|
tmpq = XrmStringToQuark(s);
|
|
n = act_db->recordCount;
|
|
|
|
for ( act_rec = act_db->recordList;
|
|
n && act_rec && *act_rec;
|
|
act_rec++, n--)
|
|
{
|
|
if ( (*act_rec)->recordName == (long) tmpq )
|
|
last_rec_found = act_rec;
|
|
/*
|
|
* Since actions are in name "quark" order, there is
|
|
* no sense searching past the desired quark value.
|
|
*/
|
|
|
|
if ( (*act_rec)->recordName > (long) tmpq )
|
|
break;
|
|
}
|
|
|
|
if ( last_rec_found )
|
|
{
|
|
/*
|
|
* We have found the desired action
|
|
* Obtain the associated icon name (if any).
|
|
*/
|
|
if ((iconString =
|
|
_DtActGetDtsDbField(*last_rec_found,_DtACTION_ICON))
|
|
!= NULL ) {
|
|
_DtSvcProcessUnlock();
|
|
return XtNewString(iconString);
|
|
}
|
|
|
|
/*
|
|
* If no icon name is specified for this action
|
|
* return the default action icon name.
|
|
*/
|
|
_DtSvcProcessUnlock();
|
|
return _DtGetActionIconDefault();
|
|
}
|
|
|
|
/*
|
|
* We failed to find the desired action -- therefore return NULL.
|
|
*/
|
|
_DtSvcProcessUnlock();
|
|
return NULL;
|
|
}
|
|
|
|
static char *
|
|
_DtActionMMIcon ( char *s )
|
|
{
|
|
int n;
|
|
DtShmBoson tmpq;
|
|
char *iconString;
|
|
DtDtsMMRecord *act_rec;
|
|
DtDtsMMRecord *act_rec_list;
|
|
DtDtsMMRecord *last_rec_found = NULL;
|
|
DtDtsMMDatabase *act_db;
|
|
int *start;
|
|
|
|
_DtSvcProcessLock();
|
|
act_db = _DtDtsMMGet(_DtACTION_NAME);
|
|
myassert(s);
|
|
if ( !s ) {
|
|
_DtSvcProcessUnlock();
|
|
return NULL;
|
|
}
|
|
|
|
if((tmpq = _DtDtsMMStringToBoson(s)) == -1)
|
|
{
|
|
_DtSvcProcessUnlock();
|
|
return(NULL);
|
|
}
|
|
|
|
act_rec_list = _DtDtsMMGetPtr(act_db->recordList);
|
|
start = (int*)_DtDtsMMGetDbName(act_db,tmpq);
|
|
for ( n = *start; n < act_db->recordCount; n++)
|
|
{
|
|
act_rec = &act_rec_list[n];
|
|
if ( act_rec->recordName == tmpq )
|
|
last_rec_found = act_rec;
|
|
/*
|
|
* Since actions are in name "boson" order, there is
|
|
* no sense searching past the desired quark value.
|
|
*/
|
|
|
|
if ( act_rec->recordName > tmpq )
|
|
break;
|
|
}
|
|
|
|
if ( last_rec_found )
|
|
{
|
|
/*
|
|
* We have found the desired action
|
|
* Obtain the associated icon name (if any).
|
|
*/
|
|
if ((iconString =
|
|
_DtActGetDtsMMField(last_rec_found,_DtACTION_ICON))
|
|
!= NULL ) {
|
|
_DtSvcProcessUnlock();
|
|
return iconString;
|
|
}
|
|
|
|
/*
|
|
* If no icon name is specified for this action
|
|
* return the default action icon name.
|
|
*/
|
|
_DtSvcProcessUnlock();
|
|
return _DtGetActionIconDefault();
|
|
}
|
|
|
|
/*
|
|
* We failed to find the desired action -- therefore return NULL.
|
|
*/
|
|
_DtSvcProcessUnlock();
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/******************************************************************************
|
|
******************************************************************************
|
|
*
|
|
* Private API Functions
|
|
*
|
|
******************************************************************************
|
|
******************************************************************************/
|
|
|
|
/******************************************************************************
|
|
*
|
|
* _DtActGetDtsDbField( recp, *name )
|
|
*
|
|
* This function is a wrapper around _DtDtsGetFieldByName() which provides
|
|
* default values for certain fields if they are not present in the
|
|
* action database record.
|
|
*
|
|
******************************************************************************/
|
|
|
|
static char *
|
|
_DtActGetDtsDbField ( DtDtsDbRecord *actRecp, char *name )
|
|
{
|
|
char *val = _DtDtsDbGetFieldByName( actRecp, name );
|
|
|
|
if ( val )
|
|
return val;
|
|
|
|
/*
|
|
* Return defaults for certain necessary fields.
|
|
*/
|
|
if ( !strcmp( name, _DtACTION_TYPE ) )
|
|
return _DtACT_TYPE_DFLT;
|
|
if ( !strcmp( name, _DtACTION_ARG_CLASS ) )
|
|
return _DtACT_ARG_CLASS_DFLT;
|
|
if ( !strcmp( name, _DtACTION_ARG_TYPE ) )
|
|
return _DtACT_ARG_TYPE_DFLT;
|
|
if ( !strcmp( name, _DtACTION_ARG_COUNT ) )
|
|
return _DtACT_ARG_CNT_DFLT;
|
|
if ( !strcmp( name, _DtACTION_ARG_MODE ) )
|
|
return _DtACT_ARG_MODE_DFLT;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
static char *
|
|
_DtActGetDtsMMField ( DtDtsMMRecord *actRecp, char *name )
|
|
{
|
|
char *val = (char *)_DtDtsMMGetFieldByName( actRecp, name );
|
|
|
|
if ( val )
|
|
return _DtDtsMMExpandValue(val);
|
|
|
|
/*
|
|
* Return defaults for certain necessary fields.
|
|
*/
|
|
if ( !strcmp( name, _DtACTION_TYPE ) )
|
|
return strdup(_DtACT_TYPE_DFLT);
|
|
if ( !strcmp( name, _DtACTION_ARG_CLASS ) )
|
|
return strdup(_DtACT_ARG_CLASS_DFLT);
|
|
if ( !strcmp( name, _DtACTION_ARG_TYPE ) )
|
|
return strdup(_DtACT_ARG_TYPE_DFLT);
|
|
if ( !strcmp( name, _DtACTION_ARG_COUNT ) )
|
|
return strdup(_DtACT_ARG_CNT_DFLT);
|
|
if ( !strcmp( name, _DtACTION_ARG_MODE ) )
|
|
return strdup(_DtACT_ARG_MODE_DFLT);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* _DtActDbChooseLabel
|
|
* This function returns a label string for the given action record.
|
|
* If the record does not contain a specified label then the action name
|
|
* name itself is returned.
|
|
*
|
|
******************************************************************************/
|
|
|
|
static char *
|
|
_DtActDbChooseLabel(DtDtsDbRecord *rec)
|
|
{
|
|
char *label;
|
|
|
|
if ( !rec )
|
|
return NULL;
|
|
|
|
if ((label=
|
|
_DtActGetDtsDbField(rec, _DtACTION_LABEL)) != NULL)
|
|
return XtNewString(label);
|
|
|
|
/*
|
|
* If no label is specified for this action
|
|
* return the action name itself.
|
|
*/
|
|
return XtNewString(XrmQuarkToString(rec->recordName));
|
|
}
|
|
|
|
static char *
|
|
_DtActMMChooseLabel(DtDtsMMRecord *rec)
|
|
{
|
|
char *label;
|
|
|
|
if ( !rec )
|
|
return NULL;
|
|
|
|
label= _DtActGetDtsMMField(rec, _DtACTION_LABEL);
|
|
if (NULL != label)
|
|
{
|
|
/*
|
|
* Fix FMM Purify error.
|
|
*/
|
|
char *rtn = XtNewString(label);
|
|
free((void*) label);
|
|
return rtn;
|
|
}
|
|
|
|
/*
|
|
* If no label is specified for this action
|
|
* return the action name itself.
|
|
*/
|
|
return XtNewString((char *)_DtDtsMMBosonToString(rec->recordName));
|
|
}
|
|
|
|
/*
|
|
* This function is invoked by DtDbLoad(), once the complete
|
|
* action database has been loaded. It will first sort lexically each of
|
|
* the fields within all of the records. It will then sort the records,
|
|
* based upon the specificity of the action defined within the record.
|
|
* Lastly, it will replace the record 'compare' function associated with
|
|
* this database, so that it can be used to help locate a record, based
|
|
* on certain criteria.
|
|
*/
|
|
|
|
/* used for building only */
|
|
void
|
|
_DtSortActionDb( void )
|
|
{
|
|
DtDtsDbDatabase * actionDB;
|
|
int i;
|
|
|
|
_DtSvcProcessLock();
|
|
actionDB = _DtDtsDbGet(_DtACTION_NAME);
|
|
|
|
for (i = 0; i < actionDB->recordCount; i++)
|
|
{
|
|
/*
|
|
* Use the internal default DtsDb fieldsort function
|
|
* which sorts fields lexically by name; by passing a
|
|
* NULL for the compare function address.
|
|
*/
|
|
_DtDtsDbFieldSort(actionDB->recordList[i], NULL);
|
|
}
|
|
|
|
|
|
_DtDtsDbRecordSort(actionDB, _DtActionCompareRecordQuarks);
|
|
/*
|
|
* We will mark duplicate records for deletion by setting
|
|
* the "pathId" field to zero.
|
|
*/
|
|
_DtSearchDuplicateRecord(actionDB);
|
|
|
|
/*
|
|
* Search for and delete action records which have been marked
|
|
* for deletion by setting PathId to zero. These should be
|
|
* duplicate records which have been overidden.
|
|
*/
|
|
for ( i=0; i < actionDB->recordCount; i++ )
|
|
{
|
|
if (actionDB->recordList[i]->pathId == 0)
|
|
{
|
|
_DtDtsDbDeleteRecord(actionDB->recordList[i],actionDB);
|
|
/*
|
|
* Record deletion has adjusted the recordCount field for the
|
|
* database. We must now adjust our counter (i) because record
|
|
* deletion shifts all subsequent records down to backfill holes
|
|
* in the record array. This means we must check the record at "i"
|
|
* again because it is now a new, unchecked record.
|
|
*/
|
|
i--;
|
|
|
|
/*
|
|
* RWV: We should probably add the capacity to announce removal of
|
|
* such duplicate records.
|
|
*/
|
|
}
|
|
}
|
|
_DtSvcProcessUnlock();
|
|
}
|
|
|
|
/* used for building only */
|
|
static void
|
|
_DtSearchDuplicateRecord(DtDtsDbDatabase *db)
|
|
{
|
|
int i, j;
|
|
DtDtsDbRecord *rec1, *rec2;
|
|
|
|
i = 0;
|
|
while(i < db->recordCount - 1) {
|
|
rec1 = db->recordList[i];
|
|
j = ++i;
|
|
|
|
/* see if rec1 is already marked as a duplicate */
|
|
if ( rec1->pathId == 0 )
|
|
continue;
|
|
|
|
while(j < db->recordCount) {
|
|
rec2 = db->recordList[j];
|
|
if(rec1->recordName == rec2->recordName) {
|
|
if(rec2->pathId != 0)
|
|
_DtCheckForDuplicateRecord(rec1, rec2);
|
|
j++;
|
|
}
|
|
else
|
|
j = db->recordCount;
|
|
}
|
|
}
|
|
}
|
|
|
|
/******************************************************************************
|
|
*
|
|
* _DtCheckForDuplicateRecord
|
|
*
|
|
* Compare the name, class, type, mode and arg_counts of the two input records.
|
|
* These are the selection criteria fields for actions.
|
|
* If they are identical then mark the potential duplicate (duprec) for
|
|
* deletion by setting its "pathId" field to zero. If the records are not
|
|
* really duplicates do nothing.
|
|
******************************************************************************/
|
|
/* used for building only */
|
|
|
|
static void
|
|
_DtCheckForDuplicateRecord( DtDtsDbRecord *rec, DtDtsDbRecord *duprec)
|
|
{
|
|
char *field1, *field2;
|
|
|
|
/*
|
|
* Compare action record name quarks
|
|
*/
|
|
|
|
myassert(rec->recordName == duprec->recordName);
|
|
if (rec->recordName != duprec->recordName)
|
|
return; /* action names differ */
|
|
|
|
/*
|
|
* Compare class fields
|
|
*/
|
|
field1 = _DtActGetDtsDbField(rec,_DtACTION_ARG_CLASS);
|
|
field2 = _DtActGetDtsDbField(duprec,_DtACTION_ARG_CLASS);
|
|
|
|
if ( strcmp(field1,field2) )
|
|
return; /* arg_class fields differ */
|
|
|
|
/*
|
|
* Compare type fields
|
|
*/
|
|
field1 = _DtActGetDtsDbField(rec,_DtACTION_ARG_TYPE);
|
|
field2 = _DtActGetDtsDbField(duprec,_DtACTION_ARG_TYPE);
|
|
|
|
if ( strcmp(field1,field2) )
|
|
return; /* arg_type fields differ */
|
|
|
|
/*
|
|
* Compare mode fields
|
|
*/
|
|
field1 = _DtActGetDtsDbField(rec,_DtACTION_ARG_MODE);
|
|
field2 = _DtActGetDtsDbField(duprec,_DtACTION_ARG_MODE);
|
|
|
|
if ( strcmp(field1,field2) )
|
|
return; /* arg_mode fields differ */
|
|
|
|
/*
|
|
* Compare arg_count fields
|
|
*/
|
|
field1 = _DtActGetDtsDbField(rec,_DtACTION_ARG_COUNT);
|
|
field2 = _DtActGetDtsDbField(duprec,_DtACTION_ARG_COUNT);
|
|
|
|
if ( strcmp(field1,field2) )
|
|
return; /* arg_count fields differ */
|
|
|
|
/*
|
|
* Mark the potential duplicate record for later deletion
|
|
*/
|
|
duprec->pathId = 0;
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* This function is used to sort the action database records; the
|
|
* records are sorted first by name (i.e. quark value) and then, if the names
|
|
* match, according to their specificity; the more specific
|
|
* a definition is, the higher it is in the database. Records which have
|
|
* the same specificity will maintain their relative ordering. Each record
|
|
* is assigned a 'weight', which is based upon the specificity of a
|
|
* prioritized set of fields within that record (i.e. the 'signiture'
|
|
* fields). The weight is assigned according to the following table;
|
|
* the higher the table value, the more specific the action record is.
|
|
*
|
|
* -------------------------------------------
|
|
* ARG_CLASS | S | S | S | S | N | N | N | N |
|
|
* -------------------------------------------
|
|
* ARG_TYPE | S | S | W | W | S | S | W | W |
|
|
* -------------------------------------------
|
|
* ARG_COUNT | S | W | S | W | S | W | S | W |
|
|
* -------------------------------------------
|
|
* weight -> 7 6 5 4 3 2 1 0
|
|
*
|
|
* KEY: S = Value is very specific
|
|
* N = Value is not specific (i.e. "*", ">n", "<n")
|
|
*
|
|
* For action records which have a non-specific ARG_COUNT setting, there
|
|
* is a second weight calculated. Non-specific ARG_COUNT values are
|
|
* weighted using the following guidelines:
|
|
*
|
|
* specific -> highest
|
|
* "<n"
|
|
* ">n"
|
|
* "*" -> lowest
|
|
*/
|
|
|
|
/* used for building only */
|
|
static int
|
|
_DtActionCompareRecordQuarks(
|
|
DtDtsDbRecord ** record1,
|
|
DtDtsDbRecord ** record2 )
|
|
{
|
|
long r1PrimaryWeight, r1SecondaryWeight;
|
|
long r2PrimaryWeight, r2SecondaryWeight;
|
|
|
|
if ( (*record1)->recordName < (*record2)->recordName )
|
|
return -1;
|
|
else if ( (*record1)->recordName > (*record2)->recordName )
|
|
return 1;
|
|
|
|
/*
|
|
* For actions whose names (i.e. quarks) match, apply the weighting
|
|
* algorithm described above.
|
|
*/
|
|
|
|
_DtActionGetRecordWeight(record1, &r1PrimaryWeight, &r1SecondaryWeight);
|
|
_DtActionGetRecordWeight(record2, &r2PrimaryWeight, &r2SecondaryWeight);
|
|
|
|
if (r1PrimaryWeight > r2PrimaryWeight)
|
|
return(-1);
|
|
else if ( r1PrimaryWeight < r2PrimaryWeight)
|
|
return(1);
|
|
else
|
|
{
|
|
/* If primary weights are the same, check the secondary weight */
|
|
if (r1SecondaryWeight > r2SecondaryWeight)
|
|
return(-1);
|
|
else if (r1SecondaryWeight < r2SecondaryWeight)
|
|
return(1);
|
|
else
|
|
{
|
|
/*
|
|
* If everything matches we must preserve input order.
|
|
* We cannot simply assume that record1 preceded record2 in
|
|
* the input order since the quick sort itself may have done some
|
|
* rearranging, we must compare sequence numbers to determine
|
|
* which action was defined first.
|
|
*
|
|
*/
|
|
return ((*record1)->seq - (*record2)->seq);
|
|
}
|
|
}
|
|
/*myassert (0);
|
|
return 0;
|
|
*/
|
|
}
|
|
|
|
/*
|
|
* This function determines the weight which is to be assigned to an
|
|
* action database entry. The algorithm used was described earlier,
|
|
* and will not be repeated here. A higher weight is assigned for
|
|
* more specifically defined actions (i.e. the 'signiture' fields
|
|
* have not been wildcarded.
|
|
*/
|
|
|
|
static void
|
|
_DtActionGetRecordWeight(
|
|
DtDtsDbRecord ** record,
|
|
long * primaryWeightPtr,
|
|
long * secondaryWeightPtr )
|
|
{
|
|
char * argClass = _DtActGetDtsDbField(*record, _DtACTION_ARG_CLASS);
|
|
char * argType = _DtActGetDtsDbField(*record, _DtACTION_ARG_TYPE);
|
|
char * argMode = _DtActGetDtsDbField(*record, _DtACTION_ARG_MODE);
|
|
char * argCount = _DtActGetDtsDbField(*record, _DtACTION_ARG_COUNT);
|
|
char * p;
|
|
|
|
(*primaryWeightPtr) = 0;
|
|
(*secondaryWeightPtr) = 0;
|
|
|
|
if (strcmp(argClass, _DtACT_ANY))
|
|
(*primaryWeightPtr) += SPECIFIC_ARG_CLASS;
|
|
|
|
if (strcmp(argType, _DtACT_ANY))
|
|
(*primaryWeightPtr) += SPECIFIC_ARG_TYPE;
|
|
|
|
if (strcmp(argMode, _DtACT_ARG_MODE_ANY))
|
|
(*primaryWeightPtr) += SPECIFIC_ARG_MODE;
|
|
|
|
strtol(argCount, &p, 10);
|
|
if ((p == argCount) || (*p != '\0'))
|
|
{
|
|
/* The ARG_COUNT field is not a simple integer value */
|
|
if (DtStrchr(argCount, '<'))
|
|
(*secondaryWeightPtr) = SECONDARY_LESS_THAN;
|
|
else if (DtStrchr(argCount, '>'))
|
|
(*secondaryWeightPtr) = SECONDARY_GREATER_THAN;
|
|
else
|
|
(*secondaryWeightPtr) = SECONDARY_WILDCARD;
|
|
}
|
|
else
|
|
{
|
|
(*primaryWeightPtr) += SPECIFIC_ARG_COUNT;
|
|
(*secondaryWeightPtr) = SECONDARY_SPECIFIC;
|
|
}
|
|
}
|
|
|
|
static unsigned long
|
|
_DtActMMParseArgTypesList(char *tlist, DtShmBoson **quarkAddr, int *countp)
|
|
{
|
|
static DtShmBoson quark_for_wild_char = 0;
|
|
unsigned long mask = 0;
|
|
int tcount;
|
|
DtShmBoson *qp;
|
|
char **typeVec, **tvp;
|
|
char buf[_DtAct_MAX_BUF_SIZE];
|
|
|
|
_DtSvcProcessLock();
|
|
if ( !quark_for_wild_char )
|
|
quark_for_wild_char = _DtDtsMMStringToBoson(_DtACT_ANY);
|
|
_DtSvcProcessUnlock();
|
|
|
|
strcpy(buf,tlist);
|
|
tvp = typeVec = _DtVectorizeInPlace(buf,_DtACT_LIST_SEPARATOR_CHAR);
|
|
|
|
/*
|
|
* Determine the number of types in the list
|
|
*/
|
|
for ( tcount = 0; *tvp; tvp++, tcount++ );
|
|
|
|
*countp = tcount;
|
|
myassert(tcount != 0);
|
|
qp = *quarkAddr = (DtShmBoson *) XtCalloc(tcount + 1,sizeof(DtShmBoson));
|
|
|
|
for ( tvp = typeVec; *tvp; tvp++ )
|
|
{
|
|
*qp = _DtDtsMMStringToBoson(*tvp);
|
|
if ( *qp == quark_for_wild_char )
|
|
SET_ARG_TYPE_WILD(mask);
|
|
qp++;
|
|
}
|
|
|
|
/*
|
|
* use XtFree because it deal with free of a NULL string.
|
|
*/
|
|
XtFree((char *)typeVec);
|
|
return mask;
|
|
}
|
|
|
|
/*
|
|
* Parse the string containing a coma-separated list of supported classes
|
|
* and convert it to an array of integers. Allocate space for the int
|
|
* array and fill it in with the internal representation number for each
|
|
* supported class. Return a mask (long) with the bits representating the
|
|
* supported classes set.
|
|
*/
|
|
static unsigned long
|
|
_DtActMMParseClassList(char *clist)
|
|
{
|
|
char buf[_DtAct_MAX_BUF_SIZE];
|
|
char *bp;
|
|
char **classVec, **cvp;
|
|
unsigned long mask = 0;
|
|
|
|
if ( !DtStrchr(clist, _DtACT_LIST_SEPARATOR_CHAR ) )
|
|
{
|
|
/*
|
|
* Only a single class is specified
|
|
*/
|
|
if ( !strcmp(clist,_DtACT_ANY) )
|
|
SET_ARG_CLASS_WILD(mask);
|
|
else if ( !strcmp(clist,_DtACTION_FILE) )
|
|
SET_ARG_CLASS_FILE(mask);
|
|
else if ( !strcmp(clist,_DtACTION_BUFFER) )
|
|
SET_ARG_CLASS_BUFFER(mask);
|
|
else if ( !strcmp(clist,_DtACTION_STRING) )
|
|
SET_ARG_CLASS_STRING(mask);
|
|
|
|
myassert(mask != 0 );
|
|
return mask;
|
|
}
|
|
|
|
/*
|
|
* A list of classes was specified in the action definition
|
|
* Make a local copy of the class string.
|
|
* Then vectorize it in place.
|
|
*/
|
|
strcpy(buf,clist);
|
|
cvp = classVec = _DtVectorizeInPlace(buf,_DtACT_LIST_SEPARATOR_CHAR);
|
|
|
|
for ( bp = *cvp; bp; bp = *cvp )
|
|
{
|
|
if ( !strcmp(bp,_DtACT_ANY) )
|
|
{
|
|
/* If its wild -- don't bother with any more parsing */
|
|
XtFree((char *)classVec);
|
|
return SET_ARG_CLASS_WILD(mask);
|
|
}
|
|
|
|
if ( !strcmp(bp,_DtACTION_FILE) )
|
|
SET_ARG_CLASS_FILE(mask);
|
|
else if ( !strcmp(bp,_DtACTION_BUFFER) )
|
|
SET_ARG_CLASS_BUFFER(mask);
|
|
else if ( !strcmp(bp,_DtACTION_STRING) )
|
|
SET_ARG_CLASS_STRING(mask);
|
|
cvp++;
|
|
}
|
|
|
|
XtFree((char *)classVec);
|
|
myassert(mask != 0 );
|
|
return mask;
|
|
}
|
|
|
|
static unsigned long
|
|
_DtActMMParseArgCountString( char *countStr, int *countp)
|
|
{
|
|
unsigned long mask = 0;
|
|
|
|
if ( !strcmp(countStr,_DtACT_ANY) )
|
|
return SET_ARG_COUNT_WILD(mask);
|
|
|
|
if ( *countStr == _DtACT_GT_CHAR )
|
|
{
|
|
SET_ARG_COUNT_GT(mask);
|
|
*countp = atoi(countStr + 1);
|
|
} else if ( *countStr == _DtACT_LT_CHAR )
|
|
{
|
|
SET_ARG_COUNT_LT(mask);
|
|
*countp = atoi(countStr + 1);
|
|
} else
|
|
*countp = atoi(countStr);
|
|
|
|
return mask;
|
|
}
|
|
|
|
static unsigned long
|
|
_DtActMMParseActionType(char *actionTypeStr)
|
|
{
|
|
unsigned long mask = 0;
|
|
|
|
if ( !strcmp(actionTypeStr,_DtACTION_COMMAND) )
|
|
return SET_CMD_ACTION(mask);
|
|
if ( !strcmp(actionTypeStr,_DtACTION_TT_MSG) )
|
|
return SET_TT_MSG(mask);
|
|
#ifdef _DT_ALLOW_DT_MSGS
|
|
if ( !strcmp(actionTypeStr,_DtACTION_DT_REQUEST) )
|
|
return SET_DT_REQUEST_MSG(mask);
|
|
if ( !strcmp(actionTypeStr,_DtACTION_DT_NOTIFY) )
|
|
return SET_DT_NOTIFY_MSG(mask);
|
|
#endif /* _DT_ALLOW_DT_MSGS */
|
|
|
|
myassert(0); /* we should never get here */
|
|
if ( !strcmp(actionTypeStr,_DtACTION_MAP) )
|
|
return SET_MAP_ACTION(mask);
|
|
|
|
return mask;
|
|
}
|
|
|
|
|
|
static void
|
|
_DtActMMGetCmdInfo(DtDtsMMRecord *actRecp, ActionPtr actp)
|
|
{
|
|
char *s;
|
|
char *tmp = NULL;
|
|
int amtToAlloc;
|
|
static char *titleStr = "-title \"";
|
|
|
|
/* set the WINDOW_TYPE action mask bits */
|
|
|
|
s = _DtActGetDtsMMField(actRecp,_DtACTION_WINDOW_TYPE);
|
|
if ( !s )
|
|
{
|
|
/*
|
|
* WINDOW_TYPE not set -- default to PERM_TERM
|
|
*/
|
|
SET_PERM_TERM(actp->mask);
|
|
} else if ( !strcmp(s,_DtACTION_TERMINAL) )
|
|
SET_TERMINAL(actp->mask);
|
|
else if ( !strcmp(s, _DtACTION_NO_STDIO) )
|
|
SET_NO_STDIO(actp->mask);
|
|
else if ( !strcmp(s, _DtACTION_PERM_TERMINAL) )
|
|
SET_PERM_TERM(actp->mask);
|
|
else
|
|
{
|
|
/* unrecognized terminal type was obtained */
|
|
myassert(0); /* this should never happen */
|
|
SET_PERM_TERM(actp->mask);
|
|
}
|
|
_DtDtsMMSafeFree(s);
|
|
|
|
/* Get the (optional) CWD info */
|
|
if ( (s = _DtActGetDtsMMField(actRecp,_DtACTION_CWD)) != NULL)
|
|
{
|
|
/*
|
|
* HOST:CWD syntax is no longer recognized here.
|
|
* actp->u.cmd.contextHost = _DtHostString(s);
|
|
* actp->u.cmd.contextDir = _DtPathname(s);
|
|
*/
|
|
|
|
/* Keywords are not allowed in the CWD field */
|
|
actp->u.cmd.contextDir = XtNewString(s);
|
|
}
|
|
_DtDtsMMSafeFree(s);
|
|
|
|
/* Get the (required) Exec String */
|
|
if ( (s = _DtActGetDtsMMField(actRecp,_DtACTION_EXEC_STRING)) != NULL)
|
|
{
|
|
ParseMessage(actp,s,&(actp->u.cmd.execString));
|
|
} else
|
|
{
|
|
/*
|
|
* Should never get here -- actions without exec strings
|
|
* should have been rejected by the action converter.
|
|
*/
|
|
myassert(0);
|
|
ParseMessage(actp,getenv("SHELL"),&(actp->u.cmd.execString));
|
|
}
|
|
_DtDtsMMSafeFree(s);
|
|
|
|
/* Get the (optional) Exec Host List */
|
|
if ( (s = _DtActGetDtsMMField(actRecp,_DtACTION_EXEC_HOST)) != NULL)
|
|
{
|
|
ParseMessage(actp,s,&(actp->u.cmd.execHosts));
|
|
/*
|
|
* The execHostCount field will be filled in later when
|
|
* the parsed message is interpreted and the execHostArray
|
|
* is filled in.
|
|
*/
|
|
} else
|
|
{
|
|
/* set to default exec host */
|
|
tmp = _DtGetExecHostsDefault();
|
|
ParseMessage(actp,tmp,&(actp->u.cmd.execHosts));
|
|
if (tmp)
|
|
XtFree(tmp);
|
|
}
|
|
_DtDtsMMSafeFree(s);
|
|
|
|
|
|
/* Get the (optional) Term Opts */
|
|
s = _DtActGetDtsMMField(actRecp,_DtACTION_TERM_OPTS);
|
|
/*
|
|
* Prepend with internally generated title
|
|
* -- user supplied titles will appear
|
|
* afterwards and therefore take precedence (for most terminal
|
|
* emulators.) Allocate enough space for the required strings
|
|
* space separators, quotes and NULL terminator.
|
|
*/
|
|
amtToAlloc = strlen(titleStr) + strlen(actp->label) + 2;
|
|
if (s)
|
|
amtToAlloc += strlen(s) + 1;
|
|
tmp = XtMalloc(amtToAlloc);
|
|
strcpy(tmp, titleStr);
|
|
strcat(tmp, actp->label);
|
|
strcat(tmp, "\"");
|
|
if (s)
|
|
{
|
|
strcat(tmp, " ");
|
|
strcat(tmp, s);
|
|
}
|
|
_DtDtsMMSafeFree(s);
|
|
|
|
ParseMessage(actp,tmp,&(actp->u.cmd.termOpts));
|
|
if (tmp)
|
|
XtFree(tmp);
|
|
|
|
}
|
|
|
|
|
|
static void
|
|
_DtActMMGetTtMsgInfo(DtDtsMMRecord *actRecp, ActionPtr actp)
|
|
{
|
|
char argNname[ sizeof(_DtACTION_TTN_ARG) /* space for prefix */
|
|
+ 3 /* enough space for three decimal digits */
|
|
+ sizeof(_DtACTION_TTN_REP_TYPE)]; /* space for longest suffix */
|
|
int i;
|
|
char *s;
|
|
char *tmp = NULL;
|
|
|
|
/* Get the (required) tt_class field */
|
|
s = _DtActGetDtsMMField(actRecp,_DtACTION_TT_CLASS);
|
|
if (!s)
|
|
{
|
|
myassert(0); /* should never get here */
|
|
actp->u.tt_msg.tt_class = TT_CLASS_UNDEFINED;
|
|
}
|
|
else if ( !strcmp(s,_DtACTION_TT_REQUEST ))
|
|
{
|
|
actp->u.tt_msg.tt_class = TT_REQUEST;
|
|
}
|
|
else if ( !strcmp(s,_DtACTION_TT_NOTICE) )
|
|
{
|
|
actp->u.tt_msg.tt_class = TT_NOTICE;
|
|
}
|
|
else /* unrecognized string */
|
|
{
|
|
/*
|
|
* We should never get here -- such records should have
|
|
* been weeded out by the Action converter.
|
|
*/
|
|
myassert(0);
|
|
actp->u.tt_msg.tt_class = TT_CLASS_UNDEFINED;
|
|
}
|
|
_DtDtsMMSafeFree(s);
|
|
|
|
/* Get the (required) TT_SCOPE field */
|
|
s = _DtActGetDtsMMField(actRecp,_DtACTION_TT_SCOPE);
|
|
if (!s)
|
|
{
|
|
myassert(0); /* should never get here */
|
|
actp->u.tt_msg.tt_scope = TT_SCOPE_NONE;
|
|
}
|
|
else if ( !strcmp(s,_DtACTION_TT_SESSION) )
|
|
{
|
|
actp->u.tt_msg.tt_scope = TT_SESSION;
|
|
}
|
|
else if ( !strcmp(s,_DtACTION_TT_FILE) )
|
|
{
|
|
actp->u.tt_msg.tt_scope = TT_FILE;
|
|
}
|
|
else if ( !strcmp(s,_DtACTION_TT_BOTH) )
|
|
{
|
|
actp->u.tt_msg.tt_scope = TT_BOTH;
|
|
}
|
|
else if ( !strcmp(s,_DtACTION_TT_FILE_IN_SESSION) )
|
|
{
|
|
actp->u.tt_msg.tt_scope = TT_FILE_IN_SESSION;
|
|
}
|
|
else
|
|
{
|
|
/* unrecognized tt_scope */
|
|
myassert(0); /* should never happen */
|
|
actp->u.tt_msg.tt_scope = TT_SCOPE_NONE;
|
|
}
|
|
_DtDtsMMSafeFree(s);
|
|
|
|
/* Get the (required) TT_OPERATION field */
|
|
if ( (s = _DtActGetDtsMMField(actRecp,_DtACTION_TT_OPERATION)) )
|
|
ParseMessage(actp,s,&(actp->u.tt_msg.tt_op));
|
|
else
|
|
{
|
|
myassert(0); /* should never get here */
|
|
}
|
|
_DtDtsMMSafeFree(s);
|
|
|
|
/* Get the (optional) TT_FILE field */
|
|
if ( (s = _DtActGetDtsMMField(actRecp,_DtACTION_TT_FILE)) )
|
|
{
|
|
/*
|
|
* Special considerations:
|
|
* >> %Args% keyword is invalid.
|
|
* >> This value must reference a single file
|
|
* >> host:syntax needs to be parsed.
|
|
*/
|
|
|
|
ParseMessage(actp,s,&(actp->u.tt_msg.tt_file));
|
|
}
|
|
_DtDtsMMSafeFree(s); s = (char *) 0;
|
|
|
|
/*
|
|
* Get message argument values
|
|
*/
|
|
|
|
for ( i=0; True; i++ )
|
|
{
|
|
sprintf(argNname,"%s%d%s",
|
|
_DtACTION_TTN_ARG,i,_DtACTION_TTN_MODE);
|
|
if ( !(s = _DtActGetDtsMMField(actRecp,argNname)) )
|
|
break; /* no more args */
|
|
actp->u.tt_msg.tt_argn_mode =
|
|
(int *)XtRealloc(
|
|
(char *)actp->u.tt_msg.tt_argn_mode,
|
|
sizeof(int) * (i+1) );
|
|
if ( !strcmp(s,_DtACTION_TT_MODE_IN) )
|
|
actp->u.tt_msg.tt_argn_mode[i] = TT_IN;
|
|
else if ( !strcmp(s,_DtACTION_TT_MODE_OUT) )
|
|
actp->u.tt_msg.tt_argn_mode[i] = TT_OUT;
|
|
else if ( !strcmp(s,_DtACTION_TT_MODE_INOUT) )
|
|
actp->u.tt_msg.tt_argn_mode[i] = TT_INOUT;
|
|
else
|
|
{
|
|
myassert(0); /* should never reach here */
|
|
actp->u.tt_msg.tt_argn_mode[i] = TT_IN;
|
|
}
|
|
|
|
/* get tt_argn_vtype info */
|
|
sprintf(argNname,"%s%d%s",
|
|
_DtACTION_TTN_ARG,i,_DtACTION_TTN_VTYPE);
|
|
actp->u.tt_msg.tt_argn_vtype =
|
|
(parsedMsg *)XtRealloc(
|
|
(char *)actp->u.tt_msg.tt_argn_vtype,
|
|
sizeof(parsedMsg) * (i+1) );
|
|
_DtDtsMMSafeFree(s); s = (char *)0;
|
|
s = _DtActGetDtsMMField(actRecp,argNname);
|
|
ParseMessage(actp,s,actp->u.tt_msg.tt_argn_vtype + i);
|
|
|
|
/* get tt_argn_value info */
|
|
sprintf(argNname,"%s%d%s",
|
|
_DtACTION_TTN_ARG,i,_DtACTION_TTN_VALUE);
|
|
actp->u.tt_msg.tt_argn_value =
|
|
(parsedMsg *)XtRealloc(
|
|
(char *)actp->u.tt_msg.tt_argn_value,
|
|
sizeof(parsedMsg) * (i+1) );
|
|
_DtDtsMMSafeFree(s); s = (char *)0;
|
|
s = _DtActGetDtsMMField(actRecp,argNname);
|
|
ParseMessage(actp,s,actp->u.tt_msg.tt_argn_value + i);
|
|
|
|
/* get tt_argn_rep_type info */
|
|
sprintf(argNname,"%s%d%s",
|
|
_DtACTION_TTN_ARG,i,_DtACTION_TTN_REP_TYPE);
|
|
actp->u.tt_msg.tt_argn_rep_type =
|
|
(int *)XtRealloc(
|
|
(char *)actp->u.tt_msg.tt_argn_rep_type,
|
|
sizeof(int) * (i+1) );
|
|
_DtDtsMMSafeFree(s); s = (char *)0;
|
|
if ( !(s = _DtActGetDtsMMField(actRecp,argNname)) )
|
|
actp->u.tt_msg.tt_argn_rep_type[i] =
|
|
DtACT_TT_REP_UNDEFINED;
|
|
else if ( !(strcmp(s,_DtACTION_TT_RTYP_UND)) )
|
|
actp->u.tt_msg.tt_argn_rep_type[i] =
|
|
DtACT_TT_REP_UNDEFINED;
|
|
else if ( !(strcmp(s,_DtACTION_TT_RTYP_INT)) )
|
|
actp->u.tt_msg.tt_argn_rep_type[i] =
|
|
DtACT_TT_REP_INT;
|
|
else if ( !(strcmp(s,_DtACTION_TT_RTYP_STR)) )
|
|
actp->u.tt_msg.tt_argn_rep_type[i] =
|
|
DtACT_TT_REP_STRING;
|
|
else if ( !(strcmp(s,_DtACTION_TT_RTYP_BUF)) )
|
|
actp->u.tt_msg.tt_argn_rep_type[i] =
|
|
DtACT_TT_REP_BUFFER;
|
|
else
|
|
{
|
|
myassert(0); /* should never reach here */
|
|
actp->u.tt_msg.tt_argn_rep_type[i] =
|
|
DtACT_TT_REP_UNDEFINED;
|
|
}
|
|
_DtDtsMMSafeFree(s); s = (char *)0;
|
|
}
|
|
_DtDtsMMSafeFree(s); s = (char *)0;
|
|
/*
|
|
* Perhaps we can make do with a single count if the assumption that
|
|
* the counts for mode,vtype,reptype and value always match is valid.
|
|
*/
|
|
actp->u.tt_msg.mode_count = actp->u.tt_msg.vtype_count =
|
|
actp->u.tt_msg.rep_type_count = actp->u.tt_msg.value_count = i;
|
|
|
|
}
|
|
|
|
#ifdef _DT_ALLOW_DT_MSGS
|
|
static void
|
|
_DtActDbGetDtNtfyInfo(
|
|
DtDtsDbRecord *actRecp,
|
|
ActionPtr actp)
|
|
{
|
|
int i;
|
|
char argNval[ sizeof(_DtACTION_DTN_ARG) /* space for prefix */
|
|
+ 3 /* enough space for three decimal digits */
|
|
+ sizeof(_DtACTION_DTN_VALUE)]; /* space for suffix */
|
|
char *s;
|
|
char *tmp = NULL;
|
|
|
|
/* Get the (required) dt_ngroup field */
|
|
if ( !(s = _DtActGetDtsDbField(actRecp,_DtACTION_DT_NGROUP)) )
|
|
{
|
|
myassert(0); /* should never get here */
|
|
}
|
|
ParseMessage(actp,s,&(actp->u.dt_notify.ngroup));
|
|
|
|
/* Get the (required) dt_notify_string field */
|
|
if ( !(s = _DtActGetDtsDbField(actRecp,_DtACTION_DT_NOTIFY_NAME)) )
|
|
{
|
|
myassert(0); /* should never get here */
|
|
}
|
|
ParseMessage(actp,s,&(actp->u.dt_notify.notify));
|
|
|
|
/*
|
|
* Get message argument values
|
|
*/
|
|
|
|
for ( i=0; True; i++ )
|
|
{
|
|
sprintf(argNval,"%s%d%s",
|
|
_DtACTION_DTN_ARG,i,_DtACTION_DTN_VALUE);
|
|
if ( !(s = _DtActGetDtsDbField(actRecp,argNval)) )
|
|
break; /* no more args */
|
|
actp->u.dt_notify.argn_value =
|
|
(parsedMsg *)XtRealloc(
|
|
(char *)actp->u.dt_notify.argn_value,
|
|
sizeof(parsedMsg) * (i+1) );
|
|
ParseMessage(actp,s,actp->u.dt_notify.argn_value + i);
|
|
}
|
|
actp->u.dt_notify.value_count = i;
|
|
}
|
|
|
|
static void
|
|
_DtActDbGetDtReqInfo(
|
|
DtDtsDbRecord *actRecp,
|
|
ActionPtr actp)
|
|
{
|
|
int i;
|
|
char argNval[ sizeof(_DtACTION_DTN_ARG) /* space for prefix */
|
|
+ 3 /* enough space for three decimal digits */
|
|
+ sizeof(_DtACTION_DTN_VALUE)]; /* space for suffix */
|
|
char *s;
|
|
char *tmp = NULL;
|
|
|
|
/* Get the (required) dt_svc field */
|
|
if ( !(s = _DtActGetDtsDbField(actRecp,_DtACTION_DT_SVC)) )
|
|
{
|
|
myassert(0); /* should never get here */
|
|
}
|
|
ParseMessage(actp,s,&(actp->u.dt_req.service));
|
|
|
|
/* Get the (required) dt_request_name field */
|
|
if ( !(s = _DtActGetDtsDbField(actRecp,_DtACTION_DT_REQUEST_NAME)) )
|
|
{
|
|
myassert(0); /* should never get here */
|
|
}
|
|
ParseMessage(actp,s,&(actp->u.dt_req.request));
|
|
|
|
for ( i=0; True; i++ )
|
|
{
|
|
sprintf(argNval,"%s%d%s",
|
|
_DtACTION_DTN_ARG,i,_DtACTION_DTN_VALUE);
|
|
if ( !(s = _DtActGetDtsDbField(actRecp,argNval)) )
|
|
break; /* no more args */
|
|
actp->u.dt_req.argn_value =
|
|
(parsedMsg *) XtRealloc(
|
|
(char *)actp->u.dt_req.argn_value,
|
|
sizeof(parsedMsg) * (i+1) );
|
|
ParseMessage(actp,s,actp->u.dt_req.argn_value + i);
|
|
}
|
|
actp->u.dt_req.value_count = i;
|
|
|
|
}
|
|
#endif /* _DT_ALLOW_DT_MSGS */
|
|
|
|
static int
|
|
_DtActMMCompareObjClassMask( unsigned long objClassMask, char *actClass)
|
|
{
|
|
char buf[_DtAct_MAX_BUF_SIZE];
|
|
char *bp;
|
|
char **classVec, **cvp;
|
|
|
|
|
|
if ( ! DtStrchr(actClass, _DtACT_LIST_SEPARATOR_CHAR ) )
|
|
{
|
|
/*
|
|
* Only a single class is specified
|
|
*/
|
|
if ( !strcmp(actClass,_DtACT_ANY) )
|
|
return True;
|
|
if ( !strcmp(actClass,_DtACTION_FILE) )
|
|
/*
|
|
* Is this object REALLY a file (not a tmp file
|
|
* generated for a buffer object.
|
|
*/
|
|
if ( IS_FILE_OBJ(objClassMask)
|
|
&& !(IS_BUFFER_OBJ(objClassMask)) )
|
|
return True;
|
|
if ( !strcmp(actClass,_DtACTION_BUFFER) )
|
|
if ( IS_BUFFER_OBJ(objClassMask) )
|
|
return True;
|
|
if ( !strcmp(actClass,_DtACTION_STRING) )
|
|
if ( IS_STRING_OBJ(objClassMask) )
|
|
return True;
|
|
|
|
/* no single class spec match found */
|
|
return False;
|
|
}
|
|
|
|
/*
|
|
* A list of classes was specified in the action.
|
|
* Make a local copy of the class string
|
|
* Then vectorize it in place.
|
|
*/
|
|
strcpy(buf,actClass);
|
|
cvp = classVec = _DtVectorizeInPlace(buf,_DtACT_LIST_SEPARATOR_CHAR);
|
|
|
|
for ( bp = *cvp; bp; bp = *cvp )
|
|
{
|
|
if ( !strcmp(actClass,_DtACT_ANY) )
|
|
{
|
|
XtFree((char *)classVec);
|
|
return True;
|
|
}
|
|
|
|
if ( !strcmp(bp,_DtACTION_FILE) )
|
|
{
|
|
if ( IS_ARG_CLASS_FILE(objClassMask) )
|
|
{
|
|
XtFree((char *)classVec);
|
|
return True;
|
|
}
|
|
}
|
|
else if ( !strcmp(bp,_DtACTION_BUFFER) )
|
|
{
|
|
if (IS_ARG_CLASS_BUFFER(objClassMask))
|
|
{
|
|
XtFree((char *)classVec);
|
|
return True;
|
|
}
|
|
}
|
|
else if ( !strcmp(bp,_DtACTION_STRING) )
|
|
{
|
|
if (IS_ARG_CLASS_STRING(objClassMask))
|
|
{
|
|
XtFree((char *)classVec);
|
|
return True;
|
|
}
|
|
}
|
|
cvp++;
|
|
}
|
|
|
|
XtFree((char *)classVec);
|
|
return False;
|
|
}
|
|
|
|
static int
|
|
_DtActMMCompareMode( unsigned long objMask, char *actMode)
|
|
{
|
|
if ( !actMode
|
|
|| !strcmp(actMode,_DtACT_ARG_MODE_ANY)
|
|
|| !strcmp(actMode,DtDTS_DT_UNKNOWN))
|
|
return True; /* We don't care about the mode */
|
|
|
|
if ( !strcmp(actMode,_DtACT_ARG_MODE_WRITE) && IS_WRITE_OBJ(objMask) )
|
|
return True;
|
|
|
|
if ( !strcmp(actMode,_DtACT_ARG_MODE_NOWRITE)
|
|
&& !(IS_WRITE_OBJ(objMask)) )
|
|
return True;
|
|
|
|
return False;
|
|
}
|
|
|
|
static int
|
|
_DtActMMCompareType( DtShmBoson reqType, char *actType)
|
|
{
|
|
char buf[_DtAct_MAX_BUF_SIZE];
|
|
char *reqTypeStr = (char *)_DtDtsMMBosonToString(reqType);
|
|
char **typeVec;
|
|
char **tvp;
|
|
char *tp;
|
|
|
|
if ( ! DtStrchr(actType, _DtACT_LIST_SEPARATOR_CHAR ) )
|
|
{
|
|
/*
|
|
* Only a single type is specified
|
|
*/
|
|
if ( !strcmp(actType,_DtACT_ANY) )
|
|
return True;
|
|
if ( !strcmp(actType,reqTypeStr) )
|
|
return True;
|
|
|
|
/* no single type spec match found */
|
|
return False;
|
|
}
|
|
|
|
|
|
/*
|
|
* Make a local copy of the class string
|
|
* Then vectorize it in place.
|
|
*/
|
|
strcpy(buf,actType);
|
|
tvp = typeVec = _DtVectorizeInPlace(buf,_DtACT_LIST_SEPARATOR_CHAR);
|
|
|
|
for ( tp = *tvp; tp; tp = *tvp )
|
|
{
|
|
if ( !strcmp(tp,reqTypeStr) )
|
|
{
|
|
XtFree((char *)typeVec);
|
|
return True;
|
|
}
|
|
tvp++;
|
|
}
|
|
|
|
return False;
|
|
}
|
|
|
|
static int
|
|
_DtActMMCompareCount( int reqCount, char *actCount)
|
|
{
|
|
|
|
if ( !strcmp(actCount,_DtACT_ANY) )
|
|
return True;
|
|
|
|
if ( *actCount == _DtACT_GT_CHAR )
|
|
{
|
|
if ( reqCount > atoi( actCount+1 ))
|
|
return True;
|
|
return False;
|
|
}
|
|
|
|
if ( *actCount == _DtACT_LT_CHAR )
|
|
{
|
|
if ( reqCount < atoi( actCount+1 ))
|
|
return True;
|
|
return False;
|
|
}
|
|
|
|
if ( reqCount == atoi(actCount) )
|
|
return True;
|
|
|
|
return False;
|
|
}
|
|
|
|
|
|
/*
|
|
* This function is used when a request is made to locate the first
|
|
* action record meeting the criteria specified with the requestCriteria.
|
|
* The only fields within the requestCriteria which are of interest are
|
|
* the 'signiture' fields (ARG_CLASS, ARG_TYPE and ARG_COUNT). Of
|
|
* course, the action name is also important.
|
|
* This assumes the action database has already been sorted.
|
|
* and that default ARG_CLASS, ARG_TYPE and ARG_COUNT values have been
|
|
* entered into the database as needed.
|
|
*/
|
|
|
|
DtDtsMMRecord *
|
|
_DtActionLocateRecord(
|
|
DtShmBoson actQuark,
|
|
unsigned long obj_mask,
|
|
DtShmBoson arg_type,
|
|
int arg_count,
|
|
DtDtsMMDatabase *act_db)
|
|
{
|
|
int n;
|
|
DtDtsMMRecord *act_rec;
|
|
DtDtsMMRecord *act_rec_list;
|
|
DtDtsMMRecord *last_rec_found = NULL;
|
|
char *tmp = 0;
|
|
int *start;
|
|
|
|
|
|
myassert (act_db);
|
|
act_rec_list = _DtDtsMMGetPtr(act_db->recordList);
|
|
|
|
start = (int*)_DtDtsMMGetDbName(act_db,actQuark);
|
|
if(!start)
|
|
{
|
|
return(NULL);
|
|
}
|
|
for ( n = *start; n < act_db->recordCount; n++)
|
|
{
|
|
act_rec = &act_rec_list[n];
|
|
/*
|
|
* compare the name quark field to the action quark
|
|
*/
|
|
|
|
if ( act_rec->recordName != actQuark )
|
|
break;
|
|
|
|
_DtDtsMMSafeFree(tmp);
|
|
if ( !_DtActMMCompareObjClassMask(obj_mask,
|
|
tmp =_DtActGetDtsMMField(act_rec,_DtACTION_ARG_CLASS)))
|
|
continue;
|
|
|
|
_DtDtsMMSafeFree(tmp);
|
|
if ( !_DtActMMCompareType(arg_type,
|
|
tmp =_DtActGetDtsMMField(act_rec,_DtACTION_ARG_TYPE)))
|
|
continue;
|
|
|
|
_DtDtsMMSafeFree(tmp);
|
|
if ( !_DtActMMCompareCount(arg_count,
|
|
tmp =_DtActGetDtsMMField(act_rec,_DtACTION_ARG_COUNT)))
|
|
continue;
|
|
|
|
_DtDtsMMSafeFree(tmp);
|
|
if ( !_DtActMMCompareMode(obj_mask,
|
|
tmp =_DtActGetDtsMMField(act_rec,_DtACTION_ARG_MODE)))
|
|
continue;
|
|
_DtDtsMMSafeFree(tmp);
|
|
/*
|
|
* We've found a match
|
|
*/
|
|
|
|
return act_rec;
|
|
}
|
|
|
|
_DtDtsMMSafeFree(tmp);
|
|
/*
|
|
* No match found
|
|
*/
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/***************************************************************************/
|
|
/***************************************************************************/
|
|
/* Message Parsing Functions */
|
|
/***************************************************************************/
|
|
/***************************************************************************/
|
|
|
|
|
|
/*
|
|
* Given pointers to the beginning and end of a possible keyword, see if
|
|
* the string matches any of the known keywords. Return TRUE if a match
|
|
* is found. The format for a keyword is:
|
|
*
|
|
* <Optional Qualifier><Keyword><Optional Prompt>
|
|
*
|
|
* The string passed in already has the leading and trailing `%' removed.
|
|
*/
|
|
|
|
static Boolean
|
|
ValidKeyword(
|
|
char *start,
|
|
char *end,
|
|
char **prompt,
|
|
int *keywordId,
|
|
int *argNum,
|
|
Boolean *isFile )
|
|
|
|
{
|
|
/*
|
|
* Fill in the length of the keywords at compile time by
|
|
* using the "sizeof" operator (and subtracting one for the NULL).
|
|
*/
|
|
static localHostLen = sizeof(_DtACT_LOCALHOST_STR) - 1;
|
|
static databaseHostLen = sizeof(_DtACT_DATABASEHOST_STR) - 1;
|
|
static displayHostLen = sizeof(_DtACT_DISPLAYHOST_STR) - 1;
|
|
static sessionHostLen = sizeof(_DtACT_SESSIONHOST_STR) - 1;
|
|
static argsLen = sizeof(_DtACT_ARGS_STR) - 1;
|
|
static arg_Len = sizeof(_DtACT_ARG_UNDER_STR) - 1;
|
|
static stringQualifierLen = sizeof(_DtACT_STRING_QUALIFIER) - 1;
|
|
static fileQualifierLen = sizeof(_DtACT_FILE_QUALIFIER) - 1;
|
|
int len = end - start + 1;
|
|
char *stop;
|
|
char *lastCh;
|
|
int lastChLen;
|
|
char savedChar;
|
|
Boolean FoundQualifier=False;
|
|
|
|
|
|
*keywordId = NO_KEYWORD;
|
|
*argNum = NO_ARG;
|
|
|
|
|
|
/*
|
|
* Determine if an optional qualifier was specified. For now, the
|
|
* only qualifiers we know about are "(String)" and "(File)", which
|
|
* are only valid for the "Args" , "Arg_<n>" or "Prompt" keywords.
|
|
* Is no qualifier is specified we default to String.
|
|
*/
|
|
if ((len >= stringQualifierLen) &&
|
|
(strncmp(_DtACT_STRING_QUALIFIER,start,(size_t)stringQualifierLen) == 0))
|
|
{
|
|
FoundQualifier=True;
|
|
*isFile = False;
|
|
start += stringQualifierLen;
|
|
} else if (( len >= fileQualifierLen) &&
|
|
(strncmp(_DtACT_FILE_QUALIFIER, start,(size_t)fileQualifierLen) == 0))
|
|
{
|
|
FoundQualifier=True;
|
|
*isFile = True;
|
|
start += fileQualifierLen;
|
|
} else
|
|
*isFile = False; /* default to string behavior (except for Arg*) */
|
|
|
|
|
|
/* Compare the first portion of the string to each known keyword */
|
|
if ((len >= localHostLen) &&
|
|
(strncmp(_DtACT_LOCALHOST_STR, start, (size_t)localHostLen) == 0))
|
|
{
|
|
*isFile = False;
|
|
|
|
/* Flag that a keyword was found */
|
|
*keywordId = LOCAL_HOST;
|
|
*argNum = NO_ARG;
|
|
|
|
start += localHostLen;
|
|
}
|
|
else if ((len >= databaseHostLen) &&
|
|
(strncmp(_DtACT_DATABASEHOST_STR,start,(size_t)databaseHostLen)==0))
|
|
{
|
|
*isFile = False;
|
|
|
|
/* Flag that a keyword was found */
|
|
*keywordId = DATABASE_HOST;
|
|
*argNum = NO_ARG;
|
|
|
|
start += databaseHostLen;
|
|
}
|
|
else if ((len >= displayHostLen) &&
|
|
(strncmp(_DtACT_DISPLAYHOST_STR,start,(size_t)displayHostLen)==0))
|
|
{
|
|
*isFile = False;
|
|
|
|
/* Flag that a keyword was found */
|
|
*keywordId = DISPLAY_HOST;
|
|
*argNum = NO_ARG;
|
|
|
|
start += displayHostLen;
|
|
}
|
|
else if ((len >= sessionHostLen) &&
|
|
(strncmp(_DtACT_SESSIONHOST_STR,start,(size_t)sessionHostLen)==0))
|
|
{
|
|
*isFile = False;
|
|
|
|
/* Flag that a keyword was found */
|
|
*keywordId = SESSION_HOST;
|
|
*argNum = NO_ARG;
|
|
|
|
start += sessionHostLen;
|
|
}
|
|
else if ((len >= argsLen) &&
|
|
(strncmp(_DtACT_ARGS_STR, start, (size_t)argsLen) == 0))
|
|
{
|
|
/* Flag that a keyword was found */
|
|
*keywordId = ARG;
|
|
*argNum = ALL_ARGS;
|
|
/*
|
|
* Args keyword should default to File unless
|
|
* a String qualifier was encountered.
|
|
*/
|
|
if ( !FoundQualifier )
|
|
*isFile=True;
|
|
|
|
start += argsLen;
|
|
}
|
|
else if ((len >= arg_Len) &&
|
|
(strncmp(_DtACT_ARG_UNDER_STR, start, (size_t)arg_Len) == 0))
|
|
{
|
|
/* Flag that a keyword was found */
|
|
*keywordId = ARG;
|
|
/*
|
|
* Args keyword should default to File unless
|
|
* a String qualifier was encountered.
|
|
*/
|
|
if ( !FoundQualifier )
|
|
*isFile=True;
|
|
|
|
/* Determine which argument is to be used */
|
|
start += arg_Len;
|
|
*argNum = strtol(start, &stop, 10);
|
|
|
|
if (*argNum > 0)
|
|
start = stop;
|
|
else
|
|
{
|
|
/* Keyword was invalidly formed */
|
|
return(False);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* See if this is the end of the keyword, or whether a prompt is
|
|
* there also.
|
|
*/
|
|
if (start > end)
|
|
{
|
|
if (*keywordId != NO_KEYWORD)
|
|
{
|
|
/* All done */
|
|
*prompt = NULL;
|
|
return(True);
|
|
}
|
|
else
|
|
{
|
|
/* We never found a keyword */
|
|
return(False);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* We've may have extracted a keyword, and the string still contains
|
|
* more characters; let's see if an optional prompt was specified. If
|
|
* the next character is a '"', then the last character in the string
|
|
* must also be a '"'; otherwise, the keyword was invalid. If the next
|
|
* character is not a '"', then the keyword is invalid.
|
|
*/
|
|
savedChar = *DtNextChar(end);
|
|
lastCh = DtPrevChar(start, end+1);
|
|
lastChLen = mblen(lastCh, MB_LEN_MAX);
|
|
|
|
if ((start != end) && (*start == '"') && (lastChLen == 1) &&(*lastCh == '"'))
|
|
{
|
|
/* Valid prompt found; skip the quotes */
|
|
start++;
|
|
*prompt = (char *)XtMalloc((Cardinal)(end - start + 1));
|
|
(void)strncpy(*prompt, start, (size_t)(end - start));
|
|
(*prompt)[end - start] = '\0';
|
|
return(True);
|
|
}
|
|
|
|
|
|
/* If we made it down here, then the keyword was invalid */
|
|
return(False);
|
|
}
|
|
|
|
ActionPtr
|
|
_DtActionFindDBEntry( ActionRequest *reqp,
|
|
DtShmBoson actQuark )
|
|
{
|
|
int numSearches = 0;
|
|
DtDtsMMRecord *actRecp;
|
|
char *mapto = NULL;
|
|
long mask = 0;
|
|
DtShmBoson type = 0;
|
|
int num = 0;
|
|
ActionPtr actp = NULL;
|
|
char *origLabel = NULL;
|
|
char *tmp = 0;
|
|
DtDtsMMDatabase *act_db;
|
|
|
|
_DtSvcProcessLock();
|
|
act_db = _DtDtsMMGet(_DtACTION_NAME);
|
|
if ( reqp && reqp->numObjects && reqp->objects )
|
|
{
|
|
mask = reqp->objects[0].mask;
|
|
type = reqp->objects[0].type;
|
|
num = reqp->numObjects;
|
|
} else /* Treat missing objects as writable */
|
|
SET_WRITE_OBJ(mask);
|
|
|
|
|
|
/*
|
|
* Get the action record structure from the action database
|
|
*/
|
|
|
|
for (actRecp = _DtActionLocateRecord(actQuark,mask,type,num, act_db);
|
|
actRecp;
|
|
actRecp = _DtActionLocateRecord(_DtDtsMMStringToBoson(mapto),
|
|
mask,type,num, act_db), numSearches++)
|
|
{
|
|
/*
|
|
* Check to see if this is a map action
|
|
*/
|
|
if(!(mapto=_DtActGetDtsMMField(actRecp,_DtACTION_MAP_ACTION)))
|
|
break;
|
|
|
|
/*
|
|
* Save the label/name of the original action for displays.
|
|
*/
|
|
if ( !origLabel )
|
|
origLabel = _DtActMMChooseLabel(actRecp);
|
|
|
|
if ( numSearches++ > _MAX_MAP_ATTEMPTS )
|
|
{
|
|
if ( reqp )
|
|
SET_TOO_MANY_MAPS(reqp->mask);
|
|
_DtSvcProcessUnlock();
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Fill in Action structure
|
|
* -- do some parsing here.
|
|
*/
|
|
if ( actRecp )
|
|
{
|
|
actp = (Action *)XtCalloc(1,sizeof(Action));
|
|
|
|
actp->action = actRecp->recordName; /* save action quark */
|
|
|
|
/* pathId is boson; file_name_id needs to be quark! */
|
|
actp->file_name_id =
|
|
XrmStringToQuark(_DtDtsMMBosonToString(actRecp->pathId));
|
|
if ( origLabel )
|
|
actp->label = origLabel;
|
|
else
|
|
actp->label = _DtActMMChooseLabel(actRecp);
|
|
actp->description = _DtActGetDtsMMField(actRecp,
|
|
_DtACTION_DESCRIPTION);
|
|
|
|
actp->mask |= _DtActMMParseClassList(
|
|
tmp =_DtActGetDtsMMField(actRecp,_DtACTION_ARG_CLASS));
|
|
_DtDtsMMSafeFree(tmp);
|
|
|
|
actp->mask |= _DtActMMParseArgTypesList(
|
|
tmp =_DtActGetDtsMMField(actRecp,_DtACTION_ARG_TYPE),
|
|
&actp->arg_types, &actp->type_count );
|
|
_DtDtsMMSafeFree(tmp);
|
|
|
|
actp->mask |= _DtActMMParseArgCountString(
|
|
tmp =_DtActGetDtsMMField(actRecp,_DtACTION_ARG_COUNT),
|
|
&actp->arg_count);
|
|
_DtDtsMMSafeFree(tmp);
|
|
|
|
actp->mask |= _DtActMMParseActionType(
|
|
tmp =_DtActGetDtsMMField(actRecp,_DtACTION_TYPE));
|
|
_DtDtsMMSafeFree(tmp);
|
|
|
|
switch ( actp->mask & _DtAct_ACTION_TYPE_BITS )
|
|
{
|
|
case _DtAct_CMD_BIT:
|
|
_DtActMMGetCmdInfo(actRecp,actp);
|
|
break;
|
|
case _DtAct_TT_MSG_BIT:
|
|
_DtActMMGetTtMsgInfo(actRecp,actp);
|
|
break;
|
|
#ifdef _DT_ALLOW_DT_MSGS
|
|
case _DtAct_DT_REQ_MSG_BIT:
|
|
_DtActMMGetDtReqInfo(actRecp,actp);
|
|
break;
|
|
case _DtAct_DT_NTFY_MSG_BIT:
|
|
_DtActMMGetDtNtfyInfo(actRecp,actp);
|
|
break;
|
|
#endif /* _DT_ALLOW_DT_MSGS */
|
|
case _DtAct_MAP_BIT:
|
|
myassert(0); /* should never get here */
|
|
_DtFreeActionStruct(actp);
|
|
_DtSvcProcessUnlock();
|
|
return NULL;
|
|
break;
|
|
default: /* unkown action type */
|
|
myassert(0); /* should never get here */
|
|
_DtFreeActionStruct(actp);
|
|
_DtSvcProcessUnlock();
|
|
return NULL;
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* actRecp is NULL -- therefore we were unable to locate an action.
|
|
* It may be that the action we could not locate was a mapped action.
|
|
* To give the user as much information as possible about the
|
|
* problem, put the name of the mapped action (if any) into the
|
|
* request's action name field -- this information will later be
|
|
* displayed in an error dialog.
|
|
*/
|
|
if ( mapto )
|
|
{
|
|
XtFree(reqp->actionName);
|
|
reqp->actionName = mapto;
|
|
}
|
|
|
|
_DtSvcProcessUnlock();
|
|
return actp;
|
|
}
|
|
|
|
/*
|
|
* Take a message string, and break it up into its components. A component
|
|
* is composed of preceding text, a keyword and an optional prompt. The
|
|
* parsing will make our job easier when it comes time to substitute in
|
|
* the supplied set of parameters.
|
|
*
|
|
* During the parse operation, `string' always points to the beginning
|
|
* of where the last segment ended, and the next segment starts. 'start'
|
|
* always points to where within `string' the search for a keyword should
|
|
* start.
|
|
*/
|
|
|
|
static void
|
|
ParseMessage(
|
|
register ActionPtr action,
|
|
register char * str,
|
|
register parsedMsg * msg )
|
|
|
|
{
|
|
char *start;
|
|
register char *string;
|
|
char *keywordStart, *keywordEnd;
|
|
char *prompt;
|
|
int keyword, argNum;
|
|
Boolean isFile;
|
|
register MsgComponent *newBlock;
|
|
|
|
/* Initialize all fields */
|
|
msg->parsedMessage = NULL;
|
|
msg->numMsgParts = 0;
|
|
msg->compiledMessage = NULL;
|
|
|
|
/* Make sure there is a message to parse */
|
|
if ((start = string = str) == NULL)
|
|
return;
|
|
|
|
/*
|
|
* This would be a good place to allow popen invocations
|
|
* for load balancing, etc. (See expand_shell() in Dts.c)
|
|
*/
|
|
|
|
/* Parse out each keyword */
|
|
while (1)
|
|
{
|
|
/* Look for the start and end of a keyword */
|
|
if (keywordStart = DtStrchr(start, '%'))
|
|
keywordEnd = DtStrchr(keywordStart+1, '%');
|
|
else
|
|
keywordEnd = NULL;
|
|
|
|
/* See if a keyword was found */
|
|
if ((keywordStart == NULL) || (keywordEnd == NULL))
|
|
{
|
|
/*
|
|
* No more keywords left; bundle the remaining string into
|
|
* a parse block, and return.
|
|
*/
|
|
if (strlen(string) > 0)
|
|
{
|
|
msg->numMsgParts++;
|
|
msg->parsedMessage = (MsgComponent *)
|
|
XtRealloc((char *)msg->parsedMessage,
|
|
(Cardinal)(sizeof(MsgComponent) * msg->numMsgParts));
|
|
|
|
newBlock = msg->parsedMessage + (msg->numMsgParts - 1);
|
|
newBlock->precedingText = XtNewString(string);
|
|
newBlock->prompt = NULL;
|
|
newBlock->keyword = NO_KEYWORD;
|
|
newBlock->argNum = NO_ARG;
|
|
newBlock->mask = 0;
|
|
}
|
|
|
|
/* Free up the old msg string; we no longer need it */
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* We've encountered what looks to be a keyword; see if it is
|
|
* a valid one. If it's not valid, then continue looking;
|
|
* otherwise, save it, and continue the parsing processing.
|
|
*/
|
|
if (ValidKeyword(keywordStart+1, keywordEnd-1, &prompt,
|
|
&keyword, &argNum, &isFile))
|
|
{
|
|
msg->numMsgParts++;
|
|
msg->parsedMessage = (MsgComponent *)
|
|
XtRealloc((char *)msg->parsedMessage,
|
|
(Cardinal)(sizeof(MsgComponent) * msg->numMsgParts));
|
|
|
|
newBlock = msg->parsedMessage + (msg->numMsgParts - 1);
|
|
if (keywordStart != string)
|
|
{
|
|
/* Extract what we need; convert to NULL terminated */
|
|
newBlock->precedingText = (char *)
|
|
XtMalloc((Cardinal)(keywordStart - string + 1));
|
|
(void)strncpy(newBlock->precedingText, string,
|
|
(size_t)(keywordStart-string));
|
|
newBlock->precedingText[keywordStart - string] = '\0';
|
|
}
|
|
else
|
|
newBlock->precedingText = NULL;
|
|
|
|
newBlock->prompt = prompt;
|
|
newBlock->keyword = keyword;
|
|
newBlock->argNum = argNum;
|
|
newBlock->mask = 0;
|
|
if (isFile)
|
|
SET_TREAT_AS_FILE(newBlock->mask);
|
|
|
|
if (keyword == ARG)
|
|
{
|
|
/* Are we a single parameter action? */
|
|
if (argNum == 1)
|
|
{
|
|
if (IS_ARG_NONE_FOUND(action->mask))
|
|
SET_ARG_SINGLE_ARG(action->mask);
|
|
}
|
|
else
|
|
SET_ARG_MULTI_ARG(action->mask);
|
|
}
|
|
|
|
/* Continue the search following this keyword */
|
|
string = start = keywordEnd + 1;
|
|
}
|
|
else
|
|
{
|
|
/* Invalid keyword; keep searching */
|
|
start = keywordEnd;
|
|
}
|
|
}
|
|
}
|
|
}
|