Ejemplo n.º 1
0
static bool perl_kvs_cmd_begin(KviKvsModuleCommandCall * c)
{
	// This command is somewhat special in the fact that has a dedicated
	// parsing routine in the KVS core parser.
	// The parser sets the perl code as the first parameter of our call,
	// the remaining params are the context name and the arguments

	QString szCode,szContext;
	KviKvsVariantList vList;
	KVSM_PARAMETERS_BEGIN(c)
		KVSM_PARAMETER("code",KVS_PT_STRING,0,szCode)
		KVSM_PARAMETER("context",KVS_PT_STRING,KVS_PF_OPTIONAL,szContext)
		KVSM_PARAMETER("args",KVS_PT_VARIANTLIST,KVS_PF_OPTIONAL,vList)
	KVSM_PARAMETERS_END(c)

	KVS_CHECK_MODULE_STATE(m,c)

#ifdef COMPILE_PERL_SUPPORT
	KviPerlCoreCtrlCommand_execute ex;
	ex.uSize = sizeof(KviPerlCoreCtrlCommand_execute);
	ex.pKvsContext = c->context();
	ex.szContext = szContext;
	ex.szCode = szCode;
	for(KviKvsVariant * v = vList.first();v;v = vList.next())
	{
		QString tmp;
		v->asString(tmp);
		ex.lArgs.append(tmp);
	}
	ex.bQuiet = c->switches()->find('q',"quiet");

	if(!g_pPerlCoreModule->ctrl(KVI_PERLCORECTRLCOMMAND_EXECUTE,&ex))
	{
		if(!c->switches()->find('q',"quiet"))
			c->warning(__tr2qs_ctx("The perlcore module failed to execute the code: something is wrong with the perl support","perl"));
		return true;
	}

	if(!ex.lWarnings.isEmpty())
	{
		for(QStringList::Iterator it = ex.lWarnings.begin();it != ex.lWarnings.end();++it)
			c->warning(*it);
	}

	if(!ex.bExitOk)
	{
		if(!c->switches()->find('q',"quiet"))
		{

			if(c->switches()->find('f',"fail-on-error"))
			{
				c->warning(__tr2qs_ctx("Perl execution error:","perl"));
				c->warning(ex.szError);
				return false;
			} else {
				c->warning(__tr2qs_ctx("Perl execution error:","perl"));
				c->error(ex.szError);
			}
		}
	}

	if(!c->switches()->find('n',"no-return"))
		c->context()->returnValue()->setString(ex.szRetVal);

#endif //COMPILE_PERL_SUPPORT

	return true;
}
bool KviKvsTreeNodeSpecialCommandForeach::execute(KviKvsRunTimeContext * c)
{
    KviKvsVariantList l;
    l.setAutoDelete(true);
    if(!m_pIterationData->evaluate(c,&l))
        return false;

    KviKvsSwitchList swl;
    if(m_pSwitches)
    {
        if(!(m_pSwitches->evaluate(c,&swl)))
            return false;
    }

    bool bIncludeEmptyScalars = swl.find('a',"all") != 0;

    for(KviKvsVariant * pArg = l.first(); pArg; pArg = l.next())
    {
        switch(pArg->type())
        {
        case KviKvsVariantData::Array:
        {
            unsigned int uCnt = pArg->array()->size();
            unsigned int idx = 0;
            while(idx < uCnt)
            {
                // we evaluate this each time (as it may actually be killed at each iteration)
                // FIXME: maybe some kind of reference counting or a observer pattern might be a bit more efficient here
                //        (but might be far less efficient everywhere else...)
                KviKvsRWEvaluationResult * v = m_pIterationVariable->evaluateReadWrite(c);
                if(!v)
                    return false;
                KviKvsVariant * pOne = pArg->array()->at(idx);
                if(pOne)
                {
                    if(bIncludeEmptyScalars || (!pOne->isEmpty()))
                    {
                        v->result()->copyFrom(*pOne);
                    } else {
                        delete v; // we're done with it for this iteration
                        idx++;
                        continue;
                    }
                } else {
                    if(bIncludeEmptyScalars)
                    {
                        v->result()->setNothing();
                    } else {
                        delete v; // we're done with it for this iteration
                        idx++;
                        continue;
                    }

                }
                delete v; // we're done with it for this iteration

                if(!m_pLoop->execute(c))
                {
                    if(c->error())
                        return false;

                    // break allowed!
                    if(c->breakPending())
                    {
                        c->handleBreak();
                        return true;
                    }

                    if(c->continuePending())
                    {
                        c->handleContinue();
                        idx++;
                        continue;
                    }

                    return false; // propagate the false return value
                }

                idx++;
            }
        }
        break;
        case KviKvsVariantData::Hash:
        {
            KviKvsHashIterator it(*(pArg->hash()->dict()));
            while(KviKvsVariant * pOne = it.current())
            {
                // we evaluate this each time (as it may actually be killed at each iteration)
                // FIXME: maybe some kind of reference counting or a observer pattern might be a bit more efficient here
                //        (but might be far less efficient everywhere else...)
                KviKvsRWEvaluationResult * v = m_pIterationVariable->evaluateReadWrite(c);
                if(!v)
                    return false;

                if(bIncludeEmptyScalars || (!pOne->isEmpty()))
                {
                    v->result()->copyFrom(*pOne);
                } else {
                    delete v; // we're done with it for this iteration
                    ++it;
                    continue;
                }
                delete v; // we're done with it for this iteration

                if(!m_pLoop->execute(c))
                {
                    if(c->error())
                        return false;

                    // break allowed!
                    if(c->breakPending())
                    {
                        c->handleBreak();
                        return true;
                    }

                    if(c->continuePending())
                    {
                        c->handleContinue();
                        ++it;
                        continue;
                    }

                    return false; // propagate the false return value
                }

                ++it;
            }
        }
        break;
        default:
            if(bIncludeEmptyScalars || (!pArg->isEqualToNothing()))
            {
                // we evaluate this each time (as it may actually be killed at each iteration)
                // FIXME: maybe some kind of reference counting or a observer pattern might be a bit more efficient here
                //        (but might be far less efficient everywhere else...)
                KviKvsRWEvaluationResult * v = m_pIterationVariable->evaluateReadWrite(c);
                if(!v)
                    return false;
                v->result()->copyFrom(*pArg);
                delete v; // we're done with it for this iteration

                if(!m_pLoop->execute(c))
                {
                    if(c->error())
                        return false;

                    // break allowed!
                    if(c->breakPending())
                    {
                        c->handleBreak();
                        return true;
                    }

                    if(c->continuePending())
                    {
                        c->handleContinue();
                        continue;
                    }

                    return false; // propagate the false return value
                }
            }
            break;
        }
    }

    return true;
}
bool KviKvsTreeNodeSpecialCommandClass::execute(KviKvsRunTimeContext * c)
{
	KviKvsVariantList l;
	if(!m_pParams->evaluate(c,&l))return false;

	KviKvsVariant * pClassName = l.first();
	if(!pClassName)
	{
		c->error(this,__tr2qs_ctx("Missing class name","kvs"));
		return false;
	}


        KviKvsVariant * pBaseClassName = l.next();

	QString szClassName;
	QString szBaseClassName;
	pClassName->asString(szClassName);
        QRegExp re("[\\w:]+");
        if(!re.exactMatch(szClassName))
        {
                 c->error(this,__tr2qs_ctx("Class names can contain only letters, digits, underscores and '::' namespace separators","kvs"));
                 return false;
        }
	if(pBaseClassName)
		pBaseClassName->asString(szBaseClassName);

	if(szClassName.isEmpty())
	{
		c->error(this,__tr2qs_ctx("Missing class name","kvs"));
		return false;
	}

	if(szBaseClassName.isEmpty())szBaseClassName = "object";

	// avoid infinite recursion in loading the base class
	if(KviQString::equalCI(szBaseClassName,szClassName))
	{
		c->error(__tr2qs_ctx("A class can't be a subclass of itself","kvs"));
		return false;
	}

	KviKvsObjectClass * pBaseClass = KviKvsKernel::instance()->objectController()->lookupClass(szBaseClassName);
	if(!pBaseClass)
	{
		c->error(this,__tr2qs_ctx("Couln't find base class named '%Q'","kvs"),&szBaseClassName);
		return false;
	}

	// walk the inheritance tree of the base class in order to detect loops
	KviKvsObjectClass * pClass = pBaseClass;
	while(pClass)
	{
		if(KviQString::equalCI(pClass->name(),szClassName))
		{
			c->error(this,__tr2qs_ctx("Detected a loop in the inheritance tree of the base class '%Q': redefine that class first","kvs"),&szBaseClassName);
			return false;
		}
		pClass = pClass->parentClass();
	}

	KviKvsObjectClass * pActualClass = KviKvsKernel::instance()->objectController()->lookupClass(szClassName,true);
	if(pActualClass)
	{
		c->error(this,__tr2qs_ctx("Can't override the builtin class '%Q'","kvs"),&szClassName);
		return false;
	}
	pActualClass = new KviKvsObjectClass(pBaseClass,szClassName,0,false);

	for(KviKvsTreeNodeSpecialCommandClassFunctionDefinition * d = m_pFunctions->first();d;d = m_pFunctions->next())
	{
                pActualClass->registerFunctionHandler(d->name(),d->buffer(),d->reminder(),d->handlerFlags());
	}
	return true;
}