<commit_before>//===-- PhiElimination.cpp - Eliminate PHI nodes by inserting copies ------===//
//
// This pass eliminates machine instruction PHI nodes by inserting copy
// instructions.  This destroys SSA information, but is the desired input for
// some register allocators.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/SSARegMap.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"

namespace {
  struct PNE : public MachineFunctionPass {
    bool runOnMachineFunction(MachineFunction &Fn) {
      bool Changed = false;

      // Eliminate PHI instructions by inserting copies into predecessor blocks.
      //
      for (MachineFunction::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I)
	Changed |= EliminatePHINodes(Fn, *I);

      //std::cerr << "AFTER PHI NODE ELIM:\n";
      //Fn.dump();
      return Changed;
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addPreserved<LiveVariables>();
      MachineFunctionPass::getAnalysisUsage(AU);
    }

  private:
    /// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions
    /// in predecessor basic blocks.
    ///
    bool EliminatePHINodes(MachineFunction &MF, MachineBasicBlock &MBB);
  };

  RegisterPass<PNE> X("phi-node-elimination",
		      "Eliminate PHI nodes for register allocation");
}

const PassInfo *PHIEliminationID = X.getPassInfo();

/// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions in
/// predecessor basic blocks.
///
bool PNE::EliminatePHINodes(MachineFunction &MF, MachineBasicBlock &MBB) {
  if (MBB.empty() || MBB.front()->getOpcode() != TargetInstrInfo::PHI)
    return false;   // Quick exit for normal case...

  LiveVariables *LV = getAnalysisToUpdate<LiveVariables>();
  const TargetInstrInfo &MII = MF.getTarget().getInstrInfo();
  const MRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo();

  while (MBB.front()->getOpcode() == TargetInstrInfo::PHI) {
    MachineInstr *MI = MBB.front();
    // Unlink the PHI node from the basic block... but don't delete the PHI yet
    MBB.erase(MBB.begin());

    assert(MI->getOperand(0).isVirtualRegister() &&
           "PHI node doesn't write virt reg?");

    unsigned DestReg = MI->getOperand(0).getAllocatedRegNum();

    // Create a new register for the incoming PHI arguments
    const TargetRegisterClass *RC = MF.getSSARegMap()->getRegClass(DestReg);
    unsigned IncomingReg = MF.getSSARegMap()->createVirtualRegister(RC);

    // Insert a register to register copy in the top of the current block (but
    // after any remaining phi nodes) which copies the new incoming register
    // into the phi node destination.
    //
    MachineBasicBlock::iterator AfterPHIsIt = MBB.begin();
    if (AfterPHIsIt != MBB.end())
      while ((*AfterPHIsIt)->getOpcode() == TargetInstrInfo::PHI) ++AfterPHIsIt;
    RegInfo->copyRegToReg(MBB, AfterPHIsIt, DestReg, IncomingReg, RC);

    // Update live variable information if there is any...
    if (LV) {
      MachineInstr *PHICopy = *(AfterPHIsIt-1);

      // Add information to LiveVariables to know that the incoming value is
      // dead.  This says that the register is dead, not killed, because we
      // cannot use the live variable information to indicate that the variable
      // is defined in multiple entry blocks.  Instead, we pretend that this
      // instruction defined it and killed it at the same time.
      //
      LV->addVirtualRegisterDead(IncomingReg, PHICopy);

      // Since we are going to be deleting the PHI node, if it is the last use
      // of any registers, or if the value itself is dead, we need to move this
      // information over to the new copy we just inserted...
      //
      std::pair<LiveVariables::killed_iterator, LiveVariables::killed_iterator>
        RKs = LV->killed_range(MI);
      if (RKs.first != RKs.second) {
        for (LiveVariables::killed_iterator I = RKs.first; I != RKs.second; ++I)
          LV->addVirtualRegisterKilled(I->second, PHICopy);
        LV->removeVirtualRegistersKilled(RKs.first, RKs.second);
      }

      RKs = LV->dead_range(MI);
      if (RKs.first != RKs.second) {
        for (LiveVariables::killed_iterator I = RKs.first; I != RKs.second; ++I)
          LV->addVirtualRegisterDead(I->second, PHICopy);
        LV->removeVirtualRegistersDead(RKs.first, RKs.second);
      }
    }

    // Now loop over all of the incoming arguments, changing them to copy into
    // the IncomingReg register in the corresponding predecessor basic block.
    //
    for (int i = MI->getNumOperands() - 1; i >= 2; i-=2) {
      MachineOperand &opVal = MI->getOperand(i-1);

      // Get the MachineBasicBlock equivalent of the BasicBlock that is the
      // source path the PHI.
      MachineBasicBlock &opBlock = *MI->getOperand(i).getMachineBasicBlock();

      // Figure out where to insert the copy, which is at the end of the
      // predecessor basic block, but before any terminator/branch
      // instructions...
      MachineBasicBlock::iterator I = opBlock.end();
      if (I != opBlock.begin()) {  // Handle empty blocks
        --I;
        // must backtrack over ALL the branches in the previous block
        while (MII.isTerminatorInstr((*I)->getOpcode()) &&
               I != opBlock.begin())
          --I;

        // move back to the first branch instruction so new instructions
        // are inserted right in front of it and not in front of a non-branch
        if (!MII.isTerminatorInstr((*I)->getOpcode()))
          ++I;
      }

      // Check to make sure we haven't already emitted the copy for this block.
      // This can happen because PHI nodes may have multiple entries for the
      // same basic block.  It doesn't matter which entry we use though, because
      // all incoming values are guaranteed to be the same for a particular bb.
      //
      // If we emitted a copy for this basic block already, it will be right
      // where we want to insert one now.  Just check for a definition of the
      // register we are interested in!
      //
      bool HaveNotEmitted = true;

      if (I != opBlock.begin()) {
        MachineInstr *PrevInst = *(I-1);
        for (unsigned i = 0, e = PrevInst->getNumOperands(); i != e; ++i) {
          MachineOperand &MO = PrevInst->getOperand(i);
          if (MO.isVirtualRegister() && MO.getReg() == IncomingReg)
            if (MO.opIsDef() || MO.opIsDefAndUse()) {
              HaveNotEmitted = false;
              break;
            }
        }
      }

      if (HaveNotEmitted) {
        assert(opVal.isVirtualRegister() &&
               "Machine PHI Operands must all be virtual registers!");
        RegInfo->copyRegToReg(opBlock, I, IncomingReg, opVal.getReg(), RC);
      }
    }

    // really delete the PHI instruction now!
    delete MI;
  }

  return true;
}
<commit_msg>Fix bug where we could iterate off the end of a basic block<commit_after>//===-- PhiElimination.cpp - Eliminate PHI nodes by inserting copies ------===//
//
// This pass eliminates machine instruction PHI nodes by inserting copy
// instructions.  This destroys SSA information, but is the desired input for
// some register allocators.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/SSARegMap.h"
#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"

namespace {
  struct PNE : public MachineFunctionPass {
    bool runOnMachineFunction(MachineFunction &Fn) {
      bool Changed = false;

      // Eliminate PHI instructions by inserting copies into predecessor blocks.
      //
      for (MachineFunction::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I)
	Changed |= EliminatePHINodes(Fn, *I);

      //std::cerr << "AFTER PHI NODE ELIM:\n";
      //Fn.dump();
      return Changed;
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addPreserved<LiveVariables>();
      MachineFunctionPass::getAnalysisUsage(AU);
    }

  private:
    /// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions
    /// in predecessor basic blocks.
    ///
    bool EliminatePHINodes(MachineFunction &MF, MachineBasicBlock &MBB);
  };

  RegisterPass<PNE> X("phi-node-elimination",
		      "Eliminate PHI nodes for register allocation");
}

const PassInfo *PHIEliminationID = X.getPassInfo();

/// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions in
/// predecessor basic blocks.
///
bool PNE::EliminatePHINodes(MachineFunction &MF, MachineBasicBlock &MBB) {
  if (MBB.empty() || MBB.front()->getOpcode() != TargetInstrInfo::PHI)
    return false;   // Quick exit for normal case...

  LiveVariables *LV = getAnalysisToUpdate<LiveVariables>();
  const TargetInstrInfo &MII = MF.getTarget().getInstrInfo();
  const MRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo();

  while (MBB.front()->getOpcode() == TargetInstrInfo::PHI) {
    MachineInstr *MI = MBB.front();
    // Unlink the PHI node from the basic block... but don't delete the PHI yet
    MBB.erase(MBB.begin());

    assert(MI->getOperand(0).isVirtualRegister() &&
           "PHI node doesn't write virt reg?");

    unsigned DestReg = MI->getOperand(0).getAllocatedRegNum();

    // Create a new register for the incoming PHI arguments
    const TargetRegisterClass *RC = MF.getSSARegMap()->getRegClass(DestReg);
    unsigned IncomingReg = MF.getSSARegMap()->createVirtualRegister(RC);

    // Insert a register to register copy in the top of the current block (but
    // after any remaining phi nodes) which copies the new incoming register
    // into the phi node destination.
    //
    MachineBasicBlock::iterator AfterPHIsIt = MBB.begin();
    while (AfterPHIsIt != MBB.end() &&
           (*AfterPHIsIt)->getOpcode() == TargetInstrInfo::PHI)
      ++AfterPHIsIt;    // Skip over all of the PHI nodes...
    RegInfo->copyRegToReg(MBB, AfterPHIsIt, DestReg, IncomingReg, RC);

    // Update live variable information if there is any...
    if (LV) {
      MachineInstr *PHICopy = *(AfterPHIsIt-1);

      // Add information to LiveVariables to know that the incoming value is
      // dead.  This says that the register is dead, not killed, because we
      // cannot use the live variable information to indicate that the variable
      // is defined in multiple entry blocks.  Instead, we pretend that this
      // instruction defined it and killed it at the same time.
      //
      LV->addVirtualRegisterDead(IncomingReg, PHICopy);

      // Since we are going to be deleting the PHI node, if it is the last use
      // of any registers, or if the value itself is dead, we need to move this
      // information over to the new copy we just inserted...
      //
      std::pair<LiveVariables::killed_iterator, LiveVariables::killed_iterator>
        RKs = LV->killed_range(MI);
      if (RKs.first != RKs.second) {
        for (LiveVariables::killed_iterator I = RKs.first; I != RKs.second; ++I)
          LV->addVirtualRegisterKilled(I->second, PHICopy);
        LV->removeVirtualRegistersKilled(RKs.first, RKs.second);
      }

      RKs = LV->dead_range(MI);
      if (RKs.first != RKs.second) {
        for (LiveVariables::killed_iterator I = RKs.first; I != RKs.second; ++I)
          LV->addVirtualRegisterDead(I->second, PHICopy);
        LV->removeVirtualRegistersDead(RKs.first, RKs.second);
      }
    }

    // Now loop over all of the incoming arguments, changing them to copy into
    // the IncomingReg register in the corresponding predecessor basic block.
    //
    for (int i = MI->getNumOperands() - 1; i >= 2; i-=2) {
      MachineOperand &opVal = MI->getOperand(i-1);

      // Get the MachineBasicBlock equivalent of the BasicBlock that is the
      // source path the PHI.
      MachineBasicBlock &opBlock = *MI->getOperand(i).getMachineBasicBlock();

      // Figure out where to insert the copy, which is at the end of the
      // predecessor basic block, but before any terminator/branch
      // instructions...
      MachineBasicBlock::iterator I = opBlock.end();
      if (I != opBlock.begin()) {  // Handle empty blocks
        --I;
        // must backtrack over ALL the branches in the previous block
        while (MII.isTerminatorInstr((*I)->getOpcode()) &&
               I != opBlock.begin())
          --I;

        // move back to the first branch instruction so new instructions
        // are inserted right in front of it and not in front of a non-branch
        if (!MII.isTerminatorInstr((*I)->getOpcode()))
          ++I;
      }

      // Check to make sure we haven't already emitted the copy for this block.
      // This can happen because PHI nodes may have multiple entries for the
      // same basic block.  It doesn't matter which entry we use though, because
      // all incoming values are guaranteed to be the same for a particular bb.
      //
      // If we emitted a copy for this basic block already, it will be right
      // where we want to insert one now.  Just check for a definition of the
      // register we are interested in!
      //
      bool HaveNotEmitted = true;

      if (I != opBlock.begin()) {
        MachineInstr *PrevInst = *(I-1);
        for (unsigned i = 0, e = PrevInst->getNumOperands(); i != e; ++i) {
          MachineOperand &MO = PrevInst->getOperand(i);
          if (MO.isVirtualRegister() && MO.getReg() == IncomingReg)
            if (MO.opIsDef() || MO.opIsDefAndUse()) {
              HaveNotEmitted = false;
              break;
            }
        }
      }

      if (HaveNotEmitted) {
        assert(opVal.isVirtualRegister() &&
               "Machine PHI Operands must all be virtual registers!");
        RegInfo->copyRegToReg(opBlock, I, IncomingReg, opVal.getReg(), RC);
      }
    }

    // really delete the PHI instruction now!
    delete MI;
  }

  return true;
}
<|endoftext|>


<commit_before>/*
 * DeliverMissionObjectiveImplementation.cpp
 *
 *  Created on: 20/08/2010
 *      Author: dannuic
 */

#include "server/zone/objects/mission/DeliverMissionObjective.h"
#include "server/zone/objects/area/MissionSpawnActiveArea.h"
#include "server/ServerCore.h"
#include "server/zone/objects/waypoint/WaypointObject.h"
#include "server/zone/objects/creature/AiAgent.h"
#include "server/zone/objects/player/PlayerObject.h"
#include "server/zone/objects/region/Region.h"
#include "server/zone/Zone.h"
#include "server/zone/ZoneServer.h"
#include "server/zone/managers/object/ObjectManager.h"
#include "server/zone/managers/creature/CreatureManager.h"
#include "server/zone/managers/mission/MissionManager.h"
#include "server/zone/managers/terrain/TerrainManager.h"
#include "server/zone/managers/planet/PlanetManager.h"
#include "server/zone/packets/object/NpcConversationMessage.h"
#include "server/zone/packets/object/StartNpcConversation.h"
#include "server/zone/packets/object/StopNpcConversation.h"
#include "server/zone/objects/mission/MissionObject.h"
#include "server/zone/objects/mission/MissionObserver.h"

void DeliverMissionObjectiveImplementation::activate() {
	if (activated) {
		return;
	}

	MissionObjectiveImplementation::activate();

	if (!activateWithResult()) {
		//Send error message to player.
		ManagedReference<CreatureObject*> owner = getPlayerOwner();
		if (owner == NULL) {
			return;
		}

		int randomNumber = System::random(4) + 1;
		StringIdChatParameter message("@mission/mission_generic:mission_incomplete_0" + String::valueOf(randomNumber));

		owner->sendSystemMessage(message);

		removeMissionFromPlayer();
	}
}

void DeliverMissionObjectiveImplementation::deactivate() {
	if (activated) {
		MissionObjectiveImplementation::deactivate();
		despawnNpcs();
	}
}

bool DeliverMissionObjectiveImplementation::activateWithResult() {
	ManagedReference<CreatureObject*> owner = getPlayerOwner();
	ManagedReference<MissionObject* > mission = this->mission.get();

	if (owner == NULL) {
		return false;
	}
	Zone* zone = owner->getZone();
	if (zone == NULL) {
		return false;
	}

	CreatureManager* creatureManager = zone->getCreatureManager();

	PlanetManager* planetManager = zone->getPlanetManager();
	if (planetManager == NULL) {
		return false;
	}
	TerrainManager* terrainManager = planetManager->getTerrainManager();
	if (terrainManager == NULL) {
		return false;
	}

	ZoneServer* zoneServer = owner->getZoneServer();
	if (zoneServer == NULL) {
		return false;
	}

	MissionManager* missionManager = zoneServer->getMissionManager();
	if (missionManager == NULL) {
		return false;
	}

	//Select spawn type.
	int spawnType = NpcSpawnPoint::NEUTRALSPAWN;
	switch (mission->getFaction()) {
	case MissionObject::FACTIONIMPERIAL:
		spawnType = NpcSpawnPoint::IMPERIALSPAWN;
		break;
	case MissionObject::FACTIONREBEL:
		spawnType = NpcSpawnPoint::REBELSPAWN;
		break;
	default:
		spawnType = NpcSpawnPoint::NEUTRALSPAWN;
		break;
	}

	//Spawn target and destination NPC's.

	//Target NPC
	//Find a free spawn point.
	targetSpawnPoint = missionManager->getRandomFreeNpcSpawnPoint(mission->getStartPlanetCRC(), mission->getStartPositionX(), mission->getStartPositionY(), spawnType);
	if (targetSpawnPoint == NULL) {
		return false;
	}
	Vector3* targetPosition = targetSpawnPoint->getPosition();
	if (targetPosition == NULL) {
		return false;
	}

	//Destination NPC.
	//Find a free spawn point.
	int retries = 10;
	destinationSpawnPoint = NULL;
	while (retries > 0 && (destinationSpawnPoint == NULL || destinationSpawnPoint == targetSpawnPoint)) {
		destinationSpawnPoint = missionManager->getRandomFreeNpcSpawnPoint(mission->getEndPlanet().hashCode(), mission->getEndPositionX(), mission->getEndPositionY(), spawnType);
		retries--;
	}
	if (destinationSpawnPoint == NULL || destinationSpawnPoint == targetSpawnPoint) {
		return false;
	}

	missionManager->allocateMissionNpcs(targetSpawnPoint, destinationSpawnPoint, terrainManager, creatureManager);

	//Create waypoint and activate it.
	if (objectiveStatus == 0) {
		WaypointObject* waypoint = mission->getWaypointToMission();

		if (waypoint == NULL) {
			waypoint = mission->createWaypoint();
		}

		waypoint->setPlanetCRC(mission->getStartPlanetCRC());
		waypoint->setPosition(targetPosition->getX(), 0, targetPosition->getY());
		waypoint->setActive(true);

		mission->updateMissionLocation();
	} else {
		updateMissionTarget(getPlayerOwner().get());
	}

	return true;
}

void DeliverMissionObjectiveImplementation::abort() {
	MissionObjectiveImplementation::abort();

	despawnNpcs();
}

void DeliverMissionObjectiveImplementation::complete() {
	despawnNpcs();

	MissionObjectiveImplementation::complete();
}

void DeliverMissionObjectiveImplementation::despawnNpcs() {
	ZoneServer* zoneServer = ServerCore::getZoneServer();
	MissionManager* missionManager = zoneServer->getMissionManager();

	if (targetSpawnPoint != NULL)
		missionManager->freeMissionNpc(targetSpawnPoint);

	if (destinationSpawnPoint != NULL)
		missionManager->freeMissionNpc(destinationSpawnPoint);
}

void DeliverMissionObjectiveImplementation::updateMissionStatus(CreatureObject* player) {
	ManagedReference<MissionObject* > mission = this->mission.get();

	StringBuffer itemEntry;
	itemEntry << "m" << mission->getMissionNumber();

	ManagedReference<SceneObject*> inventory = player->getSlottedObject("inventory");
	StringId itemName;

	Locker lock(player);

	switch (objectiveStatus) {
	case 0:
		itemEntry << "l";
		item = NULL;
		//TODO: create correct item.
		item = (player->getZoneServer()->createObject(String("object/tangible/mission/mission_datadisk.iff").hashCode(), 2)).castTo<TangibleObject*>();
		if (item == NULL) {
			abort();
			return;
		}

		itemName.setStringId("mission/mission_deliver_neutral_easy", itemEntry.toString());
		item->setObjectName(itemName);

		//Give player the item to deliver
		if (inventory->transferObject(item, -1, true)) {
			item->sendTo(player, true);
		} else {
			abort();
			item->destroyObjectFromDatabase(true);
			return;
		}

		updateMissionTarget(player);

		objectiveStatus = PICKEDUPSTATUS;
		break;
	case 1:
		// check for item, then remove item
		if (item == NULL || !inventory->hasObjectInContainer(item->getObjectID())) {
			return;
		}

		item->destroyObjectFromWorld(true);
		item->destroyObjectFromDatabase(true);

		complete();

		objectiveStatus = DELIVEREDSTATUS;
		break;
	default:
		break;
	}
}

bool DeliverMissionObjectiveImplementation::updateMissionTarget(CreatureObject* player) {
	//Now update the waypoint to the new target
	ManagedReference<MissionObject* > mission = this->mission.get();

	WaypointObject* waypoint = mission->getWaypointToMission();
	if (waypoint == NULL) {
		waypoint = mission->createWaypoint();
	}

	waypoint->setPlanetCRC(mission->getEndPlanet().hashCode());
	waypoint->setPosition(destinationSpawnPoint->getPosition()->getX(), 0, destinationSpawnPoint->getPosition()->getY());
	waypoint->setActive(true);

	mission->updateMissionLocation();

	return true;
}
<commit_msg>[Fixed] stability issue<commit_after>/*
 * DeliverMissionObjectiveImplementation.cpp
 *
 *  Created on: 20/08/2010
 *      Author: dannuic
 */

#include "server/zone/objects/mission/DeliverMissionObjective.h"
#include "server/zone/objects/area/MissionSpawnActiveArea.h"
#include "server/ServerCore.h"
#include "server/zone/objects/waypoint/WaypointObject.h"
#include "server/zone/objects/creature/AiAgent.h"
#include "server/zone/objects/player/PlayerObject.h"
#include "server/zone/objects/region/Region.h"
#include "server/zone/Zone.h"
#include "server/zone/ZoneServer.h"
#include "server/zone/managers/object/ObjectManager.h"
#include "server/zone/managers/creature/CreatureManager.h"
#include "server/zone/managers/mission/MissionManager.h"
#include "server/zone/managers/terrain/TerrainManager.h"
#include "server/zone/managers/planet/PlanetManager.h"
#include "server/zone/packets/object/NpcConversationMessage.h"
#include "server/zone/packets/object/StartNpcConversation.h"
#include "server/zone/packets/object/StopNpcConversation.h"
#include "server/zone/objects/mission/MissionObject.h"
#include "server/zone/objects/mission/MissionObserver.h"

void DeliverMissionObjectiveImplementation::activate() {
	if (activated) {
		return;
	}

	MissionObjectiveImplementation::activate();

	if (!activateWithResult()) {
		//Send error message to player.
		ManagedReference<CreatureObject*> owner = getPlayerOwner();
		if (owner == NULL) {
			return;
		}

		int randomNumber = System::random(4) + 1;
		StringIdChatParameter message("@mission/mission_generic:mission_incomplete_0" + String::valueOf(randomNumber));

		owner->sendSystemMessage(message);

		removeMissionFromPlayer();
	}
}

void DeliverMissionObjectiveImplementation::deactivate() {
	if (activated) {
		MissionObjectiveImplementation::deactivate();
		despawnNpcs();
	}
}

bool DeliverMissionObjectiveImplementation::activateWithResult() {
	ManagedReference<CreatureObject*> owner = getPlayerOwner();
	ManagedReference<MissionObject* > mission = this->mission.get();

	if (owner == NULL) {
		return false;
	}
	Zone* zone = owner->getZone();
	if (zone == NULL) {
		return false;
	}

	CreatureManager* creatureManager = zone->getCreatureManager();

	PlanetManager* planetManager = zone->getPlanetManager();
	if (planetManager == NULL) {
		return false;
	}
	TerrainManager* terrainManager = planetManager->getTerrainManager();
	if (terrainManager == NULL) {
		return false;
	}

	ZoneServer* zoneServer = owner->getZoneServer();
	if (zoneServer == NULL) {
		return false;
	}

	MissionManager* missionManager = zoneServer->getMissionManager();
	if (missionManager == NULL) {
		return false;
	}

	//Select spawn type.
	int spawnType = NpcSpawnPoint::NEUTRALSPAWN;
	switch (mission->getFaction()) {
	case MissionObject::FACTIONIMPERIAL:
		spawnType = NpcSpawnPoint::IMPERIALSPAWN;
		break;
	case MissionObject::FACTIONREBEL:
		spawnType = NpcSpawnPoint::REBELSPAWN;
		break;
	default:
		spawnType = NpcSpawnPoint::NEUTRALSPAWN;
		break;
	}

	//Spawn target and destination NPC's.

	//Target NPC
	//Find a free spawn point.
	targetSpawnPoint = missionManager->getRandomFreeNpcSpawnPoint(mission->getStartPlanetCRC(), mission->getStartPositionX(), mission->getStartPositionY(), spawnType);
	if (targetSpawnPoint == NULL) {
		return false;
	}
	Vector3* targetPosition = targetSpawnPoint->getPosition();
	if (targetPosition == NULL) {
		return false;
	}

	//Destination NPC.
	//Find a free spawn point.
	int retries = 10;
	destinationSpawnPoint = NULL;
	while (retries > 0 && (destinationSpawnPoint == NULL || destinationSpawnPoint == targetSpawnPoint)) {
		destinationSpawnPoint = missionManager->getRandomFreeNpcSpawnPoint(mission->getEndPlanet().hashCode(), mission->getEndPositionX(), mission->getEndPositionY(), spawnType);
		retries--;
	}
	if (destinationSpawnPoint == NULL || destinationSpawnPoint == targetSpawnPoint) {
		return false;
	}

	missionManager->allocateMissionNpcs(targetSpawnPoint, destinationSpawnPoint, terrainManager, creatureManager);

	//Create waypoint and activate it.
	if (objectiveStatus == 0) {
		WaypointObject* waypoint = mission->getWaypointToMission();

		if (waypoint == NULL) {
			waypoint = mission->createWaypoint();
		}

		waypoint->setPlanetCRC(mission->getStartPlanetCRC());
		waypoint->setPosition(targetPosition->getX(), 0, targetPosition->getY());
		waypoint->setActive(true);

		mission->updateMissionLocation();
	} else {
		updateMissionTarget(getPlayerOwner().get());
	}

	return true;
}

void DeliverMissionObjectiveImplementation::abort() {
	MissionObjectiveImplementation::abort();

	despawnNpcs();
}

void DeliverMissionObjectiveImplementation::complete() {
	despawnNpcs();

	MissionObjectiveImplementation::complete();
}

void DeliverMissionObjectiveImplementation::despawnNpcs() {
	ZoneServer* zoneServer = ServerCore::getZoneServer();
	MissionManager* missionManager = zoneServer->getMissionManager();

	if (targetSpawnPoint != NULL)
		missionManager->freeMissionNpc(targetSpawnPoint);

	if (destinationSpawnPoint != NULL)
		missionManager->freeMissionNpc(destinationSpawnPoint);
}

void DeliverMissionObjectiveImplementation::updateMissionStatus(CreatureObject* player) {
	ManagedReference<MissionObject* > mission = this->mission.get();

	StringBuffer itemEntry;
	itemEntry << "m" << mission->getMissionNumber();

	ManagedReference<SceneObject*> inventory = player->getSlottedObject("inventory");
	StringId itemName;

	Locker lock(player);

	if (objectiveStatus == 0) {
		itemEntry << "l";
		item = NULL;
		//TODO: create correct item.
		item = (player->getZoneServer()->createObject(String("object/tangible/mission/mission_datadisk.iff").hashCode(), 2)).castTo<TangibleObject*>();
		if (item == NULL) {
			abort();
			return;
		}

		Locker clocker(item, player);

		itemName.setStringId("mission/mission_deliver_neutral_easy", itemEntry.toString());
		item->setObjectName(itemName);

		//Give player the item to deliver
		if (inventory->transferObject(item, -1, true)) {
			item->sendTo(player, true);
		} else {
			abort();
			item->destroyObjectFromDatabase(true);
			return;
		}

		updateMissionTarget(player);

		objectiveStatus = PICKEDUPSTATUS;

	} else if (objectiveStatus == 1) {
		// check for item, then remove item
		if (item == NULL || !inventory->hasObjectInContainer(item->getObjectID())) {
			return;
		}

		Locker clocker2(item, player);

		item->destroyObjectFromWorld(true);
		item->destroyObjectFromDatabase(true);

		complete();

		objectiveStatus = DELIVEREDSTATUS;
	}
}

bool DeliverMissionObjectiveImplementation::updateMissionTarget(CreatureObject* player) {
	//Now update the waypoint to the new target
	ManagedReference<MissionObject* > mission = this->mission.get();

	WaypointObject* waypoint = mission->getWaypointToMission();
	if (waypoint == NULL) {
		waypoint = mission->createWaypoint();
	}

	waypoint->setPlanetCRC(mission->getEndPlanet().hashCode());
	waypoint->setPosition(destinationSpawnPoint->getPosition()->getX(), 0, destinationSpawnPoint->getPosition()->getY());
	waypoint->setActive(true);

	mission->updateMissionLocation();

	return true;
}
<|endoftext|>


<commit_before>// ------------------------------------------------------------------------
// Pion is a development platform for building Reactors that process Events
// ------------------------------------------------------------------------
// Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Pion is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// Pion 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 Affero General Public License for
// more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Pion.  If not, see <http://www.gnu.org/licenses/>.
//

#include <fstream>
#include <boost/filesystem/operations.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
#include <pion/PionScheduler.hpp>
#include <pion/platform/ConfigManager.hpp>
#include <pion/platform/CodecFactory.hpp>
#include <pion/platform/ReactionEngine.hpp>
#include "LogInputReactor.hpp"

using namespace pion::platform;
namespace bfs = boost::filesystem;

namespace pion {		// begin namespace pion
namespace plugins {		// begin namespace plugins

// static members of LogInputReactor

const boost::uint32_t		LogInputReactor::DEFAULT_FREQUENCY = 1;
const std::string			LogInputReactor::CODEC_ELEMENT_NAME = "Codec";
const std::string			LogInputReactor::DIRECTORY_ELEMENT_NAME = "Directory";
const std::string			LogInputReactor::FILENAME_ELEMENT_NAME = "Filename";
const std::string			LogInputReactor::JUST_ONE_ELEMENT_NAME = "JustOne";
const std::string			LogInputReactor::FREQUENCY_ELEMENT_NAME = "Frequency";

// LogInputReactor member functions

void LogInputReactor::setConfig(const Vocabulary& v, const xmlNodePtr config_ptr)
{
	// first set config options for the Reactor base class
	boost::unique_lock<boost::mutex> reactor_lock(m_mutex);
	Reactor::setConfig(v, config_ptr);

	// get the Codec that the Reactor should use
	if (! ConfigManager::getConfigOption(CODEC_ELEMENT_NAME, m_codec_id, config_ptr))
		throw EmptyCodecException(getId());
	m_codec_ptr = getCodecFactory().getCodec(m_codec_id);
	PION_ASSERT(m_codec_ptr);

	// get the directory where the Reactor will look for new log files
	if (! ConfigManager::getConfigOption(DIRECTORY_ELEMENT_NAME, m_log_directory, config_ptr))
		throw EmptyDirectoryException(getId());

	// resolve paths relative to the ReactionEngine's config file location
	m_log_directory = getReactionEngine().resolveRelativePath(m_log_directory);

	// make sure that the directory exists
	if (! boost::filesystem::exists(m_log_directory) )
		throw DirectoryNotFoundException(m_log_directory);
	if (! boost::filesystem::is_directory(m_log_directory) )
		throw NotADirectoryException(m_log_directory);

	// get the filename regex to use for finding log files
	std::string filename_str;
	if (! ConfigManager::getConfigOption(FILENAME_ELEMENT_NAME, filename_str, config_ptr))
		throw EmptyFilenameException(getId());
	m_log_regex = filename_str;

	// check if the the Reactor should only read the first Event & duplicate it (for testing)
	m_just_one = false;
	std::string just_one_option;
	if (ConfigManager::getConfigOption(JUST_ONE_ELEMENT_NAME, just_one_option,
									   config_ptr))
	{
		if (just_one_option == "true")
			m_just_one = true;
	}

	// get the frequency to check for new logs (if defined)
	std::string frequency_str;
	if (ConfigManager::getConfigOption(FREQUENCY_ELEMENT_NAME, frequency_str, config_ptr)) {
		const boost::uint32_t frequency_value = boost::lexical_cast<boost::uint32_t>(frequency_str);
		if (frequency_value <= 0)
			throw BadFrequencyException(getId());
		m_frequency = frequency_value;
	} else {
		m_frequency = DEFAULT_FREQUENCY;
	}
}

void LogInputReactor::updateVocabulary(const Vocabulary& v)
{
	// first update anything in the Reactor base class that might be needed
	boost::unique_lock<boost::mutex> reactor_lock(m_mutex);
	Reactor::updateVocabulary(v);
	if (m_codec_ptr)
		m_codec_ptr->updateVocabulary(v);
}

void LogInputReactor::updateCodecs(void)
{
	// check if the codec was deleted (if so, stop now!)
	if (! getCodecFactory().hasPlugin(m_codec_id)) {
		stop();
	    boost::unique_lock<boost::mutex> reactor_lock(m_mutex);
		m_codec_ptr.reset();
	} else {
		// update the codec pointer
    	boost::unique_lock<boost::mutex> reactor_lock(m_mutex);
		m_codec_ptr = getCodecFactory().getCodec(m_codec_id);
	}
}

void LogInputReactor::operator()(const EventPtr& e)
{
	if (isRunning()) {
		boost::mutex::scoped_lock reactor_lock(m_mutex);
		incrementEventsIn();
		deliverEvent(e);
	}
}

void LogInputReactor::start(void)
{
	boost::unique_lock<boost::mutex> reactor_lock(m_mutex);
	if (! m_is_running) {
		// schedule a check for new log files
		scheduleLogFileCheck(0);
		m_is_running = true;
	}
}

void LogInputReactor::stop(void)
{
	boost::unique_lock<boost::mutex> reactor_lock(m_mutex);
	if (m_is_running) {
		// set flag to notify reader thread to shutdown
		PION_LOG_DEBUG(m_logger, "Stopping input log thread: " << getId());
		m_is_running = false;
		m_timer_ptr.reset();
	}
}

void LogInputReactor::scheduleLogFileCheck(boost::uint32_t seconds)
{
	if (seconds == 0) {
		getScheduler().post(boost::bind(&LogInputReactor::checkForLogFiles, this));
	} else {
		if (! m_timer_ptr)
			m_timer_ptr.reset(new boost::asio::deadline_timer(getScheduler().getIOService()));
		m_timer_ptr->expires_from_now(boost::posix_time::seconds(seconds));
		m_timer_ptr->async_wait(boost::bind(&LogInputReactor::checkForLogFiles, this));
	}
}

void LogInputReactor::checkForLogFiles(void)
{
	// make sure that the reactor is still running
	boost::unique_lock<boost::mutex> reactor_lock(m_mutex);
	if (! isRunning())
		return;

	PION_LOG_DEBUG(m_logger, "Checking for new log files in " << m_log_directory);

	// get the current logs located in the log directory
	LogFileCollection current_logs;
	getLogFilesInLogDirectory(current_logs);

	// remove logs from the consumed collection that are no longer there
	LogFileCollection::iterator temp_itr;
	LogFileCollection::iterator log_itr = m_logs_consumed.begin();
	while (log_itr != m_logs_consumed.end()) {
		temp_itr = log_itr++;
		if (current_logs.find(*temp_itr) == current_logs.end())
			m_logs_consumed.erase(temp_itr);
	}

	// check for an existing log that has not yet been consumed
	for (log_itr = current_logs.begin(); log_itr != current_logs.end(); ++log_itr) {
		if (m_logs_consumed.find(*log_itr) == m_logs_consumed.end())
			break;
	}

	if (log_itr == current_logs.end()) {
		// no new logs to consume

		// sleep until it is time to check again
		PION_LOG_DEBUG(m_logger, "No new logs (sleeping for " << m_frequency
					   << " seconds): " << m_log_directory);
		scheduleLogFileCheck(m_frequency);

	} else {
		// found a new log to consume
		m_logs_consumed.insert(*log_itr);

		// re-calculate the full path to the file
		bfs::path full_path(m_log_directory);
		full_path /= *log_itr;
		m_log_file = full_path.file_string();

		PION_LOG_DEBUG(m_logger, "Found a new log file to consume: " << m_log_file);
		scheduleReadFromLog(true);
	}
}

void LogInputReactor::readFromLog(bool use_one_thread)
{
	// make sure that the reactor is still running
	if (! isRunning())
		return;

	try {
		// open up the log file for reading (if not open already)
		if (! m_log_stream.is_open()) {
			m_log_stream.open(m_log_file.c_str(), std::ios::in | std::ios::binary);
			if (! m_log_stream.is_open())
				throw OpenLogException(m_log_file);
			else if (m_log_stream.eof())
				throw EmptyLogException(m_log_file);
		}

		const Event::EventType event_type(m_codec_ptr->getEventType());
		EventFactory event_factory;
		EventPtr event_ptr;
		do {
			// get a new event from the EventFactory
			event_factory.create(event_ptr, event_type);
			// read an Event from the log file (convert into an Event using the Codec)
			boost::unique_lock<boost::mutex> reactor_lock(m_mutex);
			if (! m_codec_ptr->read(m_log_stream, *event_ptr))
				throw ReadEventException(m_log_file);

			// check if only Event should be read
			if (m_just_one) {
				PION_LOG_DEBUG(m_logger, "JustOne: generating lots of event copies for testing");
				m_log_stream.close();
				m_log_stream.clear();

				// just duplicate the event repeatedly until the Reactor is stopped
				EventPtr original_event_ptr(event_ptr);
				while (isRunning()) {
					// duplicate the original event
					event_factory.create(event_ptr, event_type);
					*event_ptr += *original_event_ptr;
					// deliver the Event to connected Reactors
					incrementEventsIn();
					deliverEvent(event_ptr);
				}
				break;
			}

			// check for end of file
			if (m_log_stream.eof()) {
				// all done with this log file
				PION_LOG_DEBUG(m_logger, "Finished consuming log file: " << m_log_file);
				m_log_stream.close();
				m_log_stream.clear();

				// check for more logs
				scheduleLogFileCheck(0);

				// deliver the Event to connected Reactors
				incrementEventsIn();
				deliverEvent(event_ptr);
				break;
			} else {
				// more available: schedule another read operation?
				if (! use_one_thread) {
					scheduleReadFromLog(false);

					// deliver the Event to connected Reactors
					incrementEventsIn();
					deliverEvent(event_ptr);
					break;
				}

				// deliver the Event to connected Reactors
				incrementEventsIn();
				deliverEvent(event_ptr);
			}

		} while (isRunning());

	} catch (std::exception& e) {
		PION_LOG_ERROR(m_logger, e.what());
		m_log_stream.close();
		m_log_stream.clear();
		scheduleLogFileCheck(0);
	}
}

void LogInputReactor::getLogFilesInLogDirectory(LogFileCollection& files)
{
	bfs::path dir_path(m_log_directory);
	for (bfs::directory_iterator itr(dir_path); itr!=bfs::directory_iterator(); ++itr) {
		if (bfs::is_regular(itr->status())) {
			const std::string filename(itr->path().leaf());
			if (boost::regex_search(filename, m_log_regex))
				files.insert(filename);
		}
	}
}

}	// end namespace plugins
}	// end namespace pion

/// creates new LogInputReactor objects
extern "C" PION_PLUGIN_API pion::platform::Reactor *pion_create_LogInputReactor(void) {
	return new pion::plugins::LogInputReactor();
}

/// destroys LogInputReactor objects
extern "C" PION_PLUGIN_API void pion_destroy_LogInputReactor(pion::plugins::LogInputReactor *reactor_ptr) {
	delete reactor_ptr;
}
<commit_msg>Fixed deadlock involving the JustOne LogInputReactor parameter<commit_after>// ------------------------------------------------------------------------
// Pion is a development platform for building Reactors that process Events
// ------------------------------------------------------------------------
// Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Pion is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// Pion 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 Affero General Public License for
// more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Pion.  If not, see <http://www.gnu.org/licenses/>.
//

#include <fstream>
#include <boost/filesystem/operations.hpp>
#include <boost/date_time/posix_time/posix_time_duration.hpp>
#include <pion/PionScheduler.hpp>
#include <pion/platform/ConfigManager.hpp>
#include <pion/platform/CodecFactory.hpp>
#include <pion/platform/ReactionEngine.hpp>
#include "LogInputReactor.hpp"

using namespace pion::platform;
namespace bfs = boost::filesystem;

namespace pion {		// begin namespace pion
namespace plugins {		// begin namespace plugins

// static members of LogInputReactor

const boost::uint32_t		LogInputReactor::DEFAULT_FREQUENCY = 1;
const std::string			LogInputReactor::CODEC_ELEMENT_NAME = "Codec";
const std::string			LogInputReactor::DIRECTORY_ELEMENT_NAME = "Directory";
const std::string			LogInputReactor::FILENAME_ELEMENT_NAME = "Filename";
const std::string			LogInputReactor::JUST_ONE_ELEMENT_NAME = "JustOne";
const std::string			LogInputReactor::FREQUENCY_ELEMENT_NAME = "Frequency";

// LogInputReactor member functions

void LogInputReactor::setConfig(const Vocabulary& v, const xmlNodePtr config_ptr)
{
	// first set config options for the Reactor base class
	boost::unique_lock<boost::mutex> reactor_lock(m_mutex);
	Reactor::setConfig(v, config_ptr);

	// get the Codec that the Reactor should use
	if (! ConfigManager::getConfigOption(CODEC_ELEMENT_NAME, m_codec_id, config_ptr))
		throw EmptyCodecException(getId());
	m_codec_ptr = getCodecFactory().getCodec(m_codec_id);
	PION_ASSERT(m_codec_ptr);

	// get the directory where the Reactor will look for new log files
	if (! ConfigManager::getConfigOption(DIRECTORY_ELEMENT_NAME, m_log_directory, config_ptr))
		throw EmptyDirectoryException(getId());

	// resolve paths relative to the ReactionEngine's config file location
	m_log_directory = getReactionEngine().resolveRelativePath(m_log_directory);

	// make sure that the directory exists
	if (! boost::filesystem::exists(m_log_directory) )
		throw DirectoryNotFoundException(m_log_directory);
	if (! boost::filesystem::is_directory(m_log_directory) )
		throw NotADirectoryException(m_log_directory);

	// get the filename regex to use for finding log files
	std::string filename_str;
	if (! ConfigManager::getConfigOption(FILENAME_ELEMENT_NAME, filename_str, config_ptr))
		throw EmptyFilenameException(getId());
	m_log_regex = filename_str;

	// check if the the Reactor should only read the first Event & duplicate it (for testing)
	m_just_one = false;
	std::string just_one_option;
	if (ConfigManager::getConfigOption(JUST_ONE_ELEMENT_NAME, just_one_option,
									   config_ptr))
	{
		if (just_one_option == "true")
			m_just_one = true;
	}

	// get the frequency to check for new logs (if defined)
	std::string frequency_str;
	if (ConfigManager::getConfigOption(FREQUENCY_ELEMENT_NAME, frequency_str, config_ptr)) {
		const boost::uint32_t frequency_value = boost::lexical_cast<boost::uint32_t>(frequency_str);
		if (frequency_value <= 0)
			throw BadFrequencyException(getId());
		m_frequency = frequency_value;
	} else {
		m_frequency = DEFAULT_FREQUENCY;
	}
}

void LogInputReactor::updateVocabulary(const Vocabulary& v)
{
	// first update anything in the Reactor base class that might be needed
	boost::unique_lock<boost::mutex> reactor_lock(m_mutex);
	Reactor::updateVocabulary(v);
	if (m_codec_ptr)
		m_codec_ptr->updateVocabulary(v);
}

void LogInputReactor::updateCodecs(void)
{
	// check if the codec was deleted (if so, stop now!)
	if (! getCodecFactory().hasPlugin(m_codec_id)) {
		stop();
	    boost::unique_lock<boost::mutex> reactor_lock(m_mutex);
		m_codec_ptr.reset();
	} else {
		// update the codec pointer
    	boost::unique_lock<boost::mutex> reactor_lock(m_mutex);
		m_codec_ptr = getCodecFactory().getCodec(m_codec_id);
	}
}

void LogInputReactor::operator()(const EventPtr& e)
{
	if (isRunning()) {
		boost::mutex::scoped_lock reactor_lock(m_mutex);
		incrementEventsIn();
		deliverEvent(e);
	}
}

void LogInputReactor::start(void)
{
	boost::unique_lock<boost::mutex> reactor_lock(m_mutex);
	if (! m_is_running) {
		// schedule a check for new log files
		scheduleLogFileCheck(0);
		m_is_running = true;
	}
}

void LogInputReactor::stop(void)
{
	boost::unique_lock<boost::mutex> reactor_lock(m_mutex);
	if (m_is_running) {
		// set flag to notify reader thread to shutdown
		PION_LOG_DEBUG(m_logger, "Stopping input log thread: " << getId());
		m_is_running = false;
		m_timer_ptr.reset();
	}
}

void LogInputReactor::scheduleLogFileCheck(boost::uint32_t seconds)
{
	if (seconds == 0) {
		getScheduler().post(boost::bind(&LogInputReactor::checkForLogFiles, this));
	} else {
		if (! m_timer_ptr)
			m_timer_ptr.reset(new boost::asio::deadline_timer(getScheduler().getIOService()));
		m_timer_ptr->expires_from_now(boost::posix_time::seconds(seconds));
		m_timer_ptr->async_wait(boost::bind(&LogInputReactor::checkForLogFiles, this));
	}
}

void LogInputReactor::checkForLogFiles(void)
{
	// make sure that the reactor is still running
	boost::unique_lock<boost::mutex> reactor_lock(m_mutex);
	if (! isRunning())
		return;

	PION_LOG_DEBUG(m_logger, "Checking for new log files in " << m_log_directory);

	// get the current logs located in the log directory
	LogFileCollection current_logs;
	getLogFilesInLogDirectory(current_logs);

	// remove logs from the consumed collection that are no longer there
	LogFileCollection::iterator temp_itr;
	LogFileCollection::iterator log_itr = m_logs_consumed.begin();
	while (log_itr != m_logs_consumed.end()) {
		temp_itr = log_itr++;
		if (current_logs.find(*temp_itr) == current_logs.end())
			m_logs_consumed.erase(temp_itr);
	}

	// check for an existing log that has not yet been consumed
	for (log_itr = current_logs.begin(); log_itr != current_logs.end(); ++log_itr) {
		if (m_logs_consumed.find(*log_itr) == m_logs_consumed.end())
			break;
	}

	if (log_itr == current_logs.end()) {
		// no new logs to consume

		// sleep until it is time to check again
		PION_LOG_DEBUG(m_logger, "No new logs (sleeping for " << m_frequency
					   << " seconds): " << m_log_directory);
		scheduleLogFileCheck(m_frequency);

	} else {
		// found a new log to consume
		m_logs_consumed.insert(*log_itr);

		// re-calculate the full path to the file
		bfs::path full_path(m_log_directory);
		full_path /= *log_itr;
		m_log_file = full_path.file_string();

		PION_LOG_DEBUG(m_logger, "Found a new log file to consume: " << m_log_file);
		scheduleReadFromLog(true);
	}
}

void LogInputReactor::readFromLog(bool use_one_thread)
{
	// make sure that the reactor is still running
	if (! isRunning())
		return;

	try {
		// open up the log file for reading (if not open already)
		if (! m_log_stream.is_open()) {
			m_log_stream.open(m_log_file.c_str(), std::ios::in | std::ios::binary);
			if (! m_log_stream.is_open())
				throw OpenLogException(m_log_file);
			else if (m_log_stream.eof())
				throw EmptyLogException(m_log_file);
		}

		const Event::EventType event_type(m_codec_ptr->getEventType());
		EventFactory event_factory;
		EventPtr event_ptr;
		do {
			// get a new event from the EventFactory
			event_factory.create(event_ptr, event_type);

			// read an Event from the log file (convert into an Event using the Codec)
			boost::unique_lock<boost::mutex> reactor_lock(m_mutex);
			if (! m_codec_ptr->read(m_log_stream, *event_ptr))
				throw ReadEventException(m_log_file);

			// check if only Event should be read
			if (m_just_one) {
				PION_LOG_DEBUG(m_logger, "JustOne: generating lots of event copies for testing");
				m_log_stream.close();
				m_log_stream.clear();
				reactor_lock.unlock();

				// just duplicate the event repeatedly until the Reactor is stopped
				EventPtr original_event_ptr(event_ptr);
				while (isRunning()) {
					// duplicate the original event
					event_factory.create(event_ptr, event_type);
					*event_ptr += *original_event_ptr;
					// deliver the Event to connected Reactors
					boost::unique_lock<boost::mutex> delivery_lock(m_mutex);
					incrementEventsIn();
					deliverEvent(event_ptr);
				}
				break;
			}

			// check for end of file
			if (m_log_stream.eof()) {
				// all done with this log file
				PION_LOG_DEBUG(m_logger, "Finished consuming log file: " << m_log_file);
				m_log_stream.close();
				m_log_stream.clear();

				// check for more logs
				scheduleLogFileCheck(0);

				// deliver the Event to connected Reactors
				incrementEventsIn();
				deliverEvent(event_ptr);
				break;
			} else {
				// more available: schedule another read operation?
				if (! use_one_thread) {
					scheduleReadFromLog(false);

					// deliver the Event to connected Reactors
					incrementEventsIn();
					deliverEvent(event_ptr);
					break;
				}

				// deliver the Event to connected Reactors
				incrementEventsIn();
				deliverEvent(event_ptr);
			}

		} while (isRunning());

	} catch (std::exception& e) {
		PION_LOG_ERROR(m_logger, e.what());
		m_log_stream.close();
		m_log_stream.clear();
		scheduleLogFileCheck(0);
	}
}

void LogInputReactor::getLogFilesInLogDirectory(LogFileCollection& files)
{
	bfs::path dir_path(m_log_directory);
	for (bfs::directory_iterator itr(dir_path); itr!=bfs::directory_iterator(); ++itr) {
		if (bfs::is_regular(itr->status())) {
			const std::string filename(itr->path().leaf());
			if (boost::regex_search(filename, m_log_regex))
				files.insert(filename);
		}
	}
}

}	// end namespace plugins
}	// end namespace pion

/// creates new LogInputReactor objects
extern "C" PION_PLUGIN_API pion::platform::Reactor *pion_create_LogInputReactor(void) {
	return new pion::plugins::LogInputReactor();
}

/// destroys LogInputReactor objects
extern "C" PION_PLUGIN_API void pion_destroy_LogInputReactor(pion::plugins::LogInputReactor *reactor_ptr) {
	delete reactor_ptr;
}
<|endoftext|>


<commit_before>/* $Id$ */

/*
 * Copyright (c) 2010 SURFnet bv
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "log.h"
#include "ObjectStore.h"
#include "Token.h"
#include "OSAttribute.h"
#include "ByteString.h"
#include "SecureDataManager.h"

#include <sys/time.h>

// Constructor
Token::Token()
{
	tokenMutex = MutexFactory::i()->getMutex();

	token = NULL;
	sdm = NULL;
	valid = false;
}

// Constructor
Token::Token(OSToken* token)
{
	tokenMutex = MutexFactory::i()->getMutex();

	this->token = token;

	ByteString soPINBlob, userPINBlob;

	valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);

	sdm = new SecureDataManager(soPINBlob, userPINBlob);
}

// Destructor
Token::~Token()
{
	if (sdm != NULL) delete sdm;

	MutexFactory::i()->recycleMutex(tokenMutex);
}

// Check if the token is still valid
bool Token::isValid()
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	return (valid && token->isValid());
}

// Check if the token is initialized
bool Token::isInitialized()
{
	if (token == NULL) return false;

	return true;
}

// Check if SO is logged in
bool Token::isSOLoggedIn()
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (sdm == NULL) return false;

	return sdm->isSOLoggedIn();
}

// Check if user is logged in
bool Token::isUserLoggedIn()
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (sdm == NULL) return false;

	return sdm->isUserLoggedIn();
}

// Login SO
CK_RV Token::loginSO(ByteString& pin)
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (sdm == NULL) return CKR_GENERAL_ERROR;

	// User cannot be logged in
	if (sdm->isUserLoggedIn()) return CKR_USER_ANOTHER_ALREADY_LOGGED_IN;

	// SO cannot be logged in
	if (sdm->isSOLoggedIn()) return CKR_USER_ALREADY_LOGGED_IN;

	return sdm->loginSO(pin) ? CKR_OK : CKR_PIN_INCORRECT;
}

// Login user
CK_RV Token::loginUser(ByteString& pin)
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (sdm == NULL) return CKR_GENERAL_ERROR;

	// SO cannot be logged in
	if (sdm->isSOLoggedIn()) return CKR_USER_ANOTHER_ALREADY_LOGGED_IN;

	// User cannot be logged in
	if (sdm->isUserLoggedIn()) return CKR_USER_ALREADY_LOGGED_IN;

	// The user PIN has to be initialized;
	if (sdm->getUserPINBlob().size() == 0) return CKR_USER_PIN_NOT_INITIALIZED;

	return sdm->loginUser(pin) ? CKR_OK : CKR_PIN_INCORRECT;
}

// Logout any user on this token;
void Token::logout()
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (sdm == NULL) return;

	sdm->logout();
}

// Change SO PIN
CK_RV Token::setSOPIN(ByteString& oldPIN, ByteString& newPIN)
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (sdm == NULL) return CKR_GENERAL_ERROR;

	// Verify oldPIN
	SecureDataManager *verifier = new SecureDataManager(sdm->getSOPINBlob(), sdm->getUserPINBlob());
	bool result = verifier->loginSO(oldPIN);
	delete verifier;
	if (result == false) return CKR_PIN_INCORRECT;

	if (sdm->setSOPIN(newPIN) == false) return CKR_GENERAL_ERROR;

	// Save PIN to token file
	if (token->setSOPIN(sdm->getSOPINBlob()) == false) return CKR_GENERAL_ERROR;

	ByteString soPINBlob, userPINBlob;
	valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);

	return CKR_OK;
}

// Change the user PIN
CK_RV Token::setUserPIN(ByteString& oldPIN, ByteString& newPIN)
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (sdm == NULL) return CKR_GENERAL_ERROR;

	// Check if user should stay logged in
	bool stayLoggedIn = sdm->isUserLoggedIn();

	// Verify oldPIN
	SecureDataManager *newSdm = new SecureDataManager(sdm->getSOPINBlob(), sdm->getUserPINBlob());
	if (newSdm->loginUser(oldPIN) == false)
	{
		delete newSdm;
		return CKR_PIN_INCORRECT;
	}

	// Set the new user PIN
	if (newSdm->setUserPIN(newPIN) == false)
	{
		delete newSdm;
		return CKR_GENERAL_ERROR;
	}

	// Save PIN to token file
	if (token->setUserPIN(sdm->getUserPINBlob()) == false)
	{
		delete newSdm;
		return CKR_GENERAL_ERROR;
	}

	// Restore previous login state
	if (!stayLoggedIn) newSdm->logout();

	// Switch sdm
	delete sdm;
	sdm = newSdm;

	ByteString soPINBlob, userPINBlob;
	valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);

	return CKR_OK;
}

// Init the user PIN
CK_RV Token::initUserPIN(ByteString& pin)
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (sdm == NULL) return CKR_GENERAL_ERROR;

	if (sdm->setUserPIN(pin) == false) return CKR_GENERAL_ERROR;

	// Save PIN to token file
	if (token->setUserPIN(sdm->getUserPINBlob()) == false) return CKR_GENERAL_ERROR;

	ByteString soPINBlob, userPINBlob;
	valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);

	return CKR_OK;
}

// Create a new token
CK_RV Token::createToken(ObjectStore* objectStore, ByteString& soPIN, CK_UTF8CHAR_PTR label)
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (objectStore == NULL) return CKR_GENERAL_ERROR;
	if (label == NULL_PTR) return CKR_ARGUMENTS_BAD;

	if (token != NULL)
	{
		if (sdm->getSOPINBlob().size() > 0 && !sdm->loginSO(soPIN))
		{
			ERROR_MSG("Incorrect SO PIN");

			return CKR_PIN_INCORRECT;
		}

		// The token is already initialised. Destroy it first.
		if (!objectStore->destroyToken(token))
		{
			ERROR_MSG("Failed to destroy existing token");

			return CKR_DEVICE_ERROR;
		}

		token = NULL;
	}

	// Generate the SO PIN blob
	SecureDataManager soPINBlobGen;

	if (!soPINBlobGen.setSOPIN(soPIN))
	{
		return CKR_GENERAL_ERROR;
	}

	// Convert the label
	ByteString labelByteStr((const unsigned char*) label, 32);

	// Create the token
	OSToken* newToken = objectStore->newToken(labelByteStr);

	if (newToken == NULL)
	{
		return CKR_DEVICE_ERROR;
	}

	// Set the SO PIN on the token
	if (!newToken->setSOPIN(soPINBlobGen.getSOPINBlob()))
	{
		ERROR_MSG("Failed to set SO PIN on new token");

		if (!objectStore->destroyToken(newToken))
		{
			ERROR_MSG("Failed to destroy incomplete token");
		}

		return CKR_DEVICE_ERROR;
	}

	token = newToken;

	ByteString soPINBlob, userPINBlob;

	valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);

	if (sdm != NULL) delete sdm;
	sdm = new SecureDataManager(soPINBlob, userPINBlob);

	return CKR_OK;
}

// Retrieve token information for the token
CK_RV Token::getTokenInfo(CK_TOKEN_INFO_PTR info)
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	ByteString label, serial;

	if (info == NULL)
	{
		return CKR_ARGUMENTS_BAD;
	}

	memset(info->label, ' ', 32);
	memset(info->serialNumber, ' ', 16);

	// Token specific information
	if (token)
	{
		if (!token->getTokenFlags(info->flags))
		{
			ERROR_MSG("Could not get the token flags");
			return CKR_GENERAL_ERROR;
		}

		if (token->getTokenLabel(label))
		{
			strncpy((char*) info->label, (char*) label.byte_str(), label.size());
		}

		if (token->getTokenSerial(serial))
		{
			strncpy((char*) info->serialNumber, (char*) serial.byte_str(), serial.size());
		}
	}
	else
	{
		info->flags =	CKF_RNG |
				CKF_LOGIN_REQUIRED |
				CKF_RESTORE_KEY_NOT_NEEDED |
				CKF_SO_PIN_LOCKED |
				CKF_SO_PIN_TO_BE_CHANGED;
	}

	// Information shared by all tokens
	char mfgID[33];
	char model[17];

	snprintf(mfgID, 33, "SoftHSM project");
	snprintf(model, 17, "SoftHSM v2");

	memset(info->manufacturerID, ' ', 32);
	memset(info->model, ' ', 16);
	strncpy((char*) info->manufacturerID, mfgID, strlen(mfgID));
	strncpy((char*) info->model, model, strlen(model));

	// TODO: Can we set these?
	info->ulSessionCount = CK_UNAVAILABLE_INFORMATION;
	info->ulRwSessionCount = CK_UNAVAILABLE_INFORMATION;

	info->ulMaxRwSessionCount = CK_EFFECTIVELY_INFINITE;
	info->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE;
	info->ulMaxPinLen = MAX_PIN_LEN;
	info->ulMinPinLen = MIN_PIN_LEN;
	info->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION;
	info->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION;
	info->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION;
	info->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION;
	info->hardwareVersion.major = VERSION_MAJOR;
	info->hardwareVersion.minor = VERSION_MINOR;
	info->firmwareVersion.major = VERSION_MAJOR;
	info->firmwareVersion.minor = VERSION_MINOR;

	// Current time
	time_t rawtime;
	time(&rawtime);
	char dateTime[17];
	strftime(dateTime, 17, "%Y%m%d%H%M%S00", gmtime(&rawtime));
	memcpy(info->utcTime, dateTime, 16);

        return CKR_OK;
}
<commit_msg>Use the correct SDM<commit_after>/* $Id$ */

/*
 * Copyright (c) 2010 SURFnet bv
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "config.h"
#include "log.h"
#include "ObjectStore.h"
#include "Token.h"
#include "OSAttribute.h"
#include "ByteString.h"
#include "SecureDataManager.h"

#include <sys/time.h>

// Constructor
Token::Token()
{
	tokenMutex = MutexFactory::i()->getMutex();

	token = NULL;
	sdm = NULL;
	valid = false;
}

// Constructor
Token::Token(OSToken* token)
{
	tokenMutex = MutexFactory::i()->getMutex();

	this->token = token;

	ByteString soPINBlob, userPINBlob;

	valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);

	sdm = new SecureDataManager(soPINBlob, userPINBlob);
}

// Destructor
Token::~Token()
{
	if (sdm != NULL) delete sdm;

	MutexFactory::i()->recycleMutex(tokenMutex);
}

// Check if the token is still valid
bool Token::isValid()
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	return (valid && token->isValid());
}

// Check if the token is initialized
bool Token::isInitialized()
{
	if (token == NULL) return false;

	return true;
}

// Check if SO is logged in
bool Token::isSOLoggedIn()
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (sdm == NULL) return false;

	return sdm->isSOLoggedIn();
}

// Check if user is logged in
bool Token::isUserLoggedIn()
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (sdm == NULL) return false;

	return sdm->isUserLoggedIn();
}

// Login SO
CK_RV Token::loginSO(ByteString& pin)
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (sdm == NULL) return CKR_GENERAL_ERROR;

	// User cannot be logged in
	if (sdm->isUserLoggedIn()) return CKR_USER_ANOTHER_ALREADY_LOGGED_IN;

	// SO cannot be logged in
	if (sdm->isSOLoggedIn()) return CKR_USER_ALREADY_LOGGED_IN;

	return sdm->loginSO(pin) ? CKR_OK : CKR_PIN_INCORRECT;
}

// Login user
CK_RV Token::loginUser(ByteString& pin)
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (sdm == NULL) return CKR_GENERAL_ERROR;

	// SO cannot be logged in
	if (sdm->isSOLoggedIn()) return CKR_USER_ANOTHER_ALREADY_LOGGED_IN;

	// User cannot be logged in
	if (sdm->isUserLoggedIn()) return CKR_USER_ALREADY_LOGGED_IN;

	// The user PIN has to be initialized;
	if (sdm->getUserPINBlob().size() == 0) return CKR_USER_PIN_NOT_INITIALIZED;

	return sdm->loginUser(pin) ? CKR_OK : CKR_PIN_INCORRECT;
}

// Logout any user on this token;
void Token::logout()
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (sdm == NULL) return;

	sdm->logout();
}

// Change SO PIN
CK_RV Token::setSOPIN(ByteString& oldPIN, ByteString& newPIN)
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (sdm == NULL) return CKR_GENERAL_ERROR;

	// Verify oldPIN
	SecureDataManager *verifier = new SecureDataManager(sdm->getSOPINBlob(), sdm->getUserPINBlob());
	bool result = verifier->loginSO(oldPIN);
	delete verifier;
	if (result == false) return CKR_PIN_INCORRECT;

	if (sdm->setSOPIN(newPIN) == false) return CKR_GENERAL_ERROR;

	// Save PIN to token file
	if (token->setSOPIN(sdm->getSOPINBlob()) == false) return CKR_GENERAL_ERROR;

	ByteString soPINBlob, userPINBlob;
	valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);

	return CKR_OK;
}

// Change the user PIN
CK_RV Token::setUserPIN(ByteString& oldPIN, ByteString& newPIN)
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (sdm == NULL) return CKR_GENERAL_ERROR;

	// Check if user should stay logged in
	bool stayLoggedIn = sdm->isUserLoggedIn();

	// Verify oldPIN
	SecureDataManager *newSdm = new SecureDataManager(sdm->getSOPINBlob(), sdm->getUserPINBlob());
	if (newSdm->loginUser(oldPIN) == false)
	{
		delete newSdm;
		return CKR_PIN_INCORRECT;
	}

	// Set the new user PIN
	if (newSdm->setUserPIN(newPIN) == false)
	{
		delete newSdm;
		return CKR_GENERAL_ERROR;
	}

	// Save PIN to token file
	if (token->setUserPIN(newSdm->getUserPINBlob()) == false)
	{
		delete newSdm;
		return CKR_GENERAL_ERROR;
	}

	// Restore previous login state
	if (!stayLoggedIn) newSdm->logout();

	// Switch sdm
	delete sdm;
	sdm = newSdm;

	ByteString soPINBlob, userPINBlob;
	valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);

	return CKR_OK;
}

// Init the user PIN
CK_RV Token::initUserPIN(ByteString& pin)
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (sdm == NULL) return CKR_GENERAL_ERROR;

	if (sdm->setUserPIN(pin) == false) return CKR_GENERAL_ERROR;

	// Save PIN to token file
	if (token->setUserPIN(sdm->getUserPINBlob()) == false) return CKR_GENERAL_ERROR;

	ByteString soPINBlob, userPINBlob;
	valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);

	return CKR_OK;
}

// Create a new token
CK_RV Token::createToken(ObjectStore* objectStore, ByteString& soPIN, CK_UTF8CHAR_PTR label)
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	if (objectStore == NULL) return CKR_GENERAL_ERROR;
	if (label == NULL_PTR) return CKR_ARGUMENTS_BAD;

	if (token != NULL)
	{
		if (sdm->getSOPINBlob().size() > 0 && !sdm->loginSO(soPIN))
		{
			ERROR_MSG("Incorrect SO PIN");

			return CKR_PIN_INCORRECT;
		}

		// The token is already initialised. Destroy it first.
		if (!objectStore->destroyToken(token))
		{
			ERROR_MSG("Failed to destroy existing token");

			return CKR_DEVICE_ERROR;
		}

		token = NULL;
	}

	// Generate the SO PIN blob
	SecureDataManager soPINBlobGen;

	if (!soPINBlobGen.setSOPIN(soPIN))
	{
		return CKR_GENERAL_ERROR;
	}

	// Convert the label
	ByteString labelByteStr((const unsigned char*) label, 32);

	// Create the token
	OSToken* newToken = objectStore->newToken(labelByteStr);

	if (newToken == NULL)
	{
		return CKR_DEVICE_ERROR;
	}

	// Set the SO PIN on the token
	if (!newToken->setSOPIN(soPINBlobGen.getSOPINBlob()))
	{
		ERROR_MSG("Failed to set SO PIN on new token");

		if (!objectStore->destroyToken(newToken))
		{
			ERROR_MSG("Failed to destroy incomplete token");
		}

		return CKR_DEVICE_ERROR;
	}

	token = newToken;

	ByteString soPINBlob, userPINBlob;

	valid = token->getSOPIN(soPINBlob) && token->getUserPIN(userPINBlob);

	if (sdm != NULL) delete sdm;
	sdm = new SecureDataManager(soPINBlob, userPINBlob);

	return CKR_OK;
}

// Retrieve token information for the token
CK_RV Token::getTokenInfo(CK_TOKEN_INFO_PTR info)
{
	// Lock access to the token
	MutexLocker lock(tokenMutex);

	ByteString label, serial;

	if (info == NULL)
	{
		return CKR_ARGUMENTS_BAD;
	}

	memset(info->label, ' ', 32);
	memset(info->serialNumber, ' ', 16);

	// Token specific information
	if (token)
	{
		if (!token->getTokenFlags(info->flags))
		{
			ERROR_MSG("Could not get the token flags");
			return CKR_GENERAL_ERROR;
		}

		if (token->getTokenLabel(label))
		{
			strncpy((char*) info->label, (char*) label.byte_str(), label.size());
		}

		if (token->getTokenSerial(serial))
		{
			strncpy((char*) info->serialNumber, (char*) serial.byte_str(), serial.size());
		}
	}
	else
	{
		info->flags =	CKF_RNG |
				CKF_LOGIN_REQUIRED |
				CKF_RESTORE_KEY_NOT_NEEDED |
				CKF_SO_PIN_LOCKED |
				CKF_SO_PIN_TO_BE_CHANGED;
	}

	// Information shared by all tokens
	char mfgID[33];
	char model[17];

	snprintf(mfgID, 33, "SoftHSM project");
	snprintf(model, 17, "SoftHSM v2");

	memset(info->manufacturerID, ' ', 32);
	memset(info->model, ' ', 16);
	strncpy((char*) info->manufacturerID, mfgID, strlen(mfgID));
	strncpy((char*) info->model, model, strlen(model));

	// TODO: Can we set these?
	info->ulSessionCount = CK_UNAVAILABLE_INFORMATION;
	info->ulRwSessionCount = CK_UNAVAILABLE_INFORMATION;

	info->ulMaxRwSessionCount = CK_EFFECTIVELY_INFINITE;
	info->ulMaxSessionCount = CK_EFFECTIVELY_INFINITE;
	info->ulMaxPinLen = MAX_PIN_LEN;
	info->ulMinPinLen = MIN_PIN_LEN;
	info->ulTotalPublicMemory = CK_UNAVAILABLE_INFORMATION;
	info->ulFreePublicMemory = CK_UNAVAILABLE_INFORMATION;
	info->ulTotalPrivateMemory = CK_UNAVAILABLE_INFORMATION;
	info->ulFreePrivateMemory = CK_UNAVAILABLE_INFORMATION;
	info->hardwareVersion.major = VERSION_MAJOR;
	info->hardwareVersion.minor = VERSION_MINOR;
	info->firmwareVersion.major = VERSION_MAJOR;
	info->firmwareVersion.minor = VERSION_MINOR;

	// Current time
	time_t rawtime;
	time(&rawtime);
	char dateTime[17];
	strftime(dateTime, 17, "%Y%m%d%H%M%S00", gmtime(&rawtime));
	memcpy(info->utcTime, dateTime, 16);

        return CKR_OK;
}
<|endoftext|>


<commit_before>//===--- ArgumentCompletion.cpp ---------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/IDE/ArgumentCompletion.h"
#include "swift/IDE/CodeCompletion.h"
#include "swift/IDE/CompletionLookup.h"
#include "swift/Sema/ConstraintSystem.h"
#include "swift/Sema/IDETypeChecking.h"

using namespace swift;
using namespace swift::ide;
using namespace swift::constraints;

bool ArgumentTypeCheckCompletionCallback::addPossibleParams(
    const ArgumentTypeCheckCompletionCallback::Result &Res,
    SmallVectorImpl<PossibleParamInfo> &Params, SmallVectorImpl<Type> &Types) {
  if (!Res.ParamIdx) {
    // We don't really know much here. Suggest global results without a specific
    // expected type.
    return true;
  }

  if (Res.HasLabel) {
    // We already have a parameter label, suggest types
    Types.push_back(Res.ExpectedType);
    return true;
  }

  ArrayRef<AnyFunctionType::Param> ParamsToPass =
      Res.FuncTy->getAs<AnyFunctionType>()->getParams();

  ParameterList *PL = nullptr;
  if (Res.FuncD) {
    PL = swift::getParameterList(Res.FuncD);
  }
  assert(!PL || PL->size() == ParamsToPass.size());

  bool ShowGlobalCompletions = false;
  for (auto Idx : range(*Res.ParamIdx, ParamsToPass.size())) {
    bool IsCompletion = (Idx == Res.ParamIdx);

    // Stop at the first param claimed by other arguments.
    if (!IsCompletion && Res.ClaimedParamIndices.count(Idx) > 0) {
      break;
    }

    const AnyFunctionType::Param *P = &ParamsToPass[Idx];
    bool Required =
        !(PL && PL->get(Idx)->isDefaultArgument()) && !P->isVariadic();

    if (P->hasLabel() && !(IsCompletion && Res.IsNoninitialVariadic)) {
      // Suggest parameter label if parameter has label, we are completing in it
      // and it is not a variadic parameter that already has arguments
      PossibleParamInfo PP(P, Required);
      if (!llvm::is_contained(Params, PP)) {
        Params.push_back(std::move(PP));
      }
    } else {
      // We have a parameter that doesn't require a label. Suggest global
      // results for that type.
      ShowGlobalCompletions = true;
      Types.push_back(P->getPlainType());
    }
    if (Required) {
      // The user should only be suggested the first required param. Stop.
      break;
    }
  }
  return ShowGlobalCompletions;
}

void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
  Type ExpectedTy = getTypeForCompletion(S, CompletionExpr);

  auto &CS = S.getConstraintSystem();

  Expr *ParentCall = CompletionExpr;
  while (ParentCall && ParentCall->getArgs() == nullptr) {
    ParentCall = CS.getParentExpr(ParentCall);
  }

  if (!ParentCall || ParentCall == CompletionExpr) {
    // We might not have a call that contains the code completion expression if
    // we type-checked the fallback code completion expression that only
    // contains the code completion token, but not the surrounding call.
    return;
  }

  auto ArgInfo = getCompletionArgInfo(ParentCall, CS);
  if (!ArgInfo) {
    assert(false && "bad parent call match?");
    return;
  }
  auto ArgIdx = ArgInfo->completionIdx;

  auto *CallLocator = CS.getConstraintLocator(ParentCall);
  auto *CalleeLocator = S.getCalleeLocator(CallLocator);
  auto SelectedOverload = S.getOverloadChoiceIfAvailable(CalleeLocator);
  if (!SelectedOverload) {
    return;
  }

  Type CallBaseTy = SelectedOverload->choice.getBaseType();
  if (CallBaseTy) {
    CallBaseTy = S.simplifyType(CallBaseTy)->getRValueType();
  }

  ValueDecl *FuncD = SelectedOverload->choice.getDeclOrNull();
  Type FuncTy = S.simplifyTypeForCodeCompletion(SelectedOverload->openedType);

  // For completion as the arg in a call to the implicit [keypath: _] subscript
  // the solver can't know what kind of keypath is expected without an actual
  // argument (e.g. a KeyPath vs WritableKeyPath) so it ends up as a hole.
  // Just assume KeyPath so we show the expected keypath's root type to users
  // rather than '_'.
  if (SelectedOverload->choice.getKind() ==
      OverloadChoiceKind::KeyPathApplication) {
    auto Params = FuncTy->getAs<AnyFunctionType>()->getParams();
    if (Params.size() == 1 && Params[0].getPlainType()->is<UnresolvedType>()) {
      auto *KPDecl = CS.getASTContext().getKeyPathDecl();
      Type KPTy =
          KPDecl->mapTypeIntoContext(KPDecl->getDeclaredInterfaceType());
      Type KPValueTy = KPTy->castTo<BoundGenericType>()->getGenericArgs()[1];
      KPTy = BoundGenericType::get(KPDecl, Type(), {CallBaseTy, KPValueTy});
      FuncTy = FunctionType::get({Params[0].withType(KPTy)}, KPValueTy);
    }
  }

  // Find the parameter the completion was bound to (if any), as well as which
  // parameters are already bound (so we don't suggest them even when the args
  // are out of order).
  Optional<unsigned> ParamIdx;
  std::set<unsigned> ClaimedParams;
  bool IsNoninitialVariadic = false;

  ConstraintLocator *ArgumentLocator;
  ArgumentLocator =
      CS.getConstraintLocator(CallLocator, ConstraintLocator::ApplyArgument);
  auto ArgMatchChoices = S.argumentMatchingChoices.find(ArgumentLocator);
  if (ArgMatchChoices != S.argumentMatchingChoices.end()) {
    // We might not have argument matching choices when applying a subscript
    // found via @dynamicMemberLookup.
    auto Bindings = ArgMatchChoices->second.parameterBindings;

    for (auto i : indices(Bindings)) {
      bool Claimed = false;
      for (auto j : Bindings[i]) {
        if (j == ArgIdx) {
          assert(!ParamIdx);
          ParamIdx = i;
          IsNoninitialVariadic = llvm::any_of(
              Bindings[i], [j](unsigned other) { return other < j; });
        }
        // Synthesized args don't count.
        if (j < ArgInfo->argCount) {
          Claimed = true;
        }
      }
      if (Claimed) {
        ClaimedParams.insert(i);
      }
    }
  } else {
    // FIXME: We currently don't look through @dynamicMemberLookup applications
    // for subscripts (rdar://90363138)
  }

  bool HasLabel = false;
  if (auto PE = CS.getParentExpr(CompletionExpr)) {
    if (auto Args = PE->getArgs()) {
      HasLabel = !Args->getLabel(ArgIdx).empty();
    }
  }

  bool IsAsync = isContextAsync(S, DC);

  // If this is a duplicate of any other result, ignore this solution.
  if (llvm::any_of(Results, [&](const Result &R) {
        return R.FuncD == FuncD && nullableTypesEqual(R.FuncTy, FuncTy) &&
               nullableTypesEqual(R.BaseType, CallBaseTy) &&
               R.ParamIdx == ParamIdx &&
               R.IsNoninitialVariadic == IsNoninitialVariadic;
      })) {
    return;
  }

  Results.push_back({ExpectedTy, isa<SubscriptExpr>(ParentCall), FuncD, FuncTy,
                     ArgIdx, ParamIdx, std::move(ClaimedParams),
                     IsNoninitialVariadic, CallBaseTy, HasLabel, IsAsync});
}

void ArgumentTypeCheckCompletionCallback::deliverResults(
    bool IncludeSignature, SourceLoc Loc, DeclContext *DC,
    ide::CodeCompletionContext &CompletionCtx,
    CodeCompletionConsumer &Consumer) {
  ASTContext &Ctx = DC->getASTContext();
  CompletionLookup Lookup(CompletionCtx.getResultSink(), Ctx, DC,
                          &CompletionCtx);

  // Perform global completion as a fallback if we don't have any results.
  bool shouldPerformGlobalCompletion = Results.empty();
  SmallVector<Type, 8> ExpectedTypes;

  if (IncludeSignature && !Results.empty()) {
    Lookup.setHaveLParen(true);
    for (auto &Result : Results) {
      auto SemanticContext = SemanticContextKind::None;
      NominalTypeDecl *BaseNominal = nullptr;
      if (Result.BaseType) {
        Type BaseTy = Result.BaseType;
        if (auto InstanceTy = BaseTy->getMetatypeInstanceType()) {
          BaseTy = InstanceTy;
        }
        if ((BaseNominal = BaseTy->getAnyNominal())) {
          SemanticContext = SemanticContextKind::CurrentNominal;
          if (Result.FuncD &&
              Result.FuncD->getDeclContext()->getSelfNominalTypeDecl() !=
                  BaseNominal) {
            SemanticContext = SemanticContextKind::Super;
          }
        } else if (BaseTy->is<TupleType>() || BaseTy->is<SubstitutableType>()) {
          SemanticContext = SemanticContextKind::CurrentNominal;
        }
      }
      if (Result.IsSubscript) {
        assert(SemanticContext != SemanticContextKind::None);
        auto *SD = dyn_cast_or_null<SubscriptDecl>(Result.FuncD);
        Lookup.addSubscriptCallPattern(Result.FuncTy->getAs<AnyFunctionType>(),
                                       SD, SemanticContext);
      } else {
        auto *FD = dyn_cast_or_null<AbstractFunctionDecl>(Result.FuncD);
        Lookup.addFunctionCallPattern(Result.FuncTy->getAs<AnyFunctionType>(),
                                      FD, SemanticContext);
      }
    }
    Lookup.setHaveLParen(false);

    shouldPerformGlobalCompletion |=
        !Lookup.FoundFunctionCalls || Lookup.FoundFunctionsWithoutFirstKeyword;
  } else if (!Results.empty()) {
    SmallVector<PossibleParamInfo, 8> Params;
    for (auto &Ret : Results) {
      shouldPerformGlobalCompletion |=
          addPossibleParams(Ret, Params, ExpectedTypes);
    }
    Lookup.addCallArgumentCompletionResults(Params);
  }

  if (shouldPerformGlobalCompletion) {
    for (auto &Result : Results) {
      ExpectedTypes.push_back(Result.ExpectedType);
    }
    Lookup.setExpectedTypes(ExpectedTypes, false);
    bool IsInAsyncContext = llvm::any_of(
        Results, [](const Result &Res) { return Res.IsInAsyncContext; });
    Lookup.setCanCurrDeclContextHandleAsync(IsInAsyncContext);
    Lookup.getValueCompletionsInDeclContext(Loc);
    Lookup.getSelfTypeCompletionInDeclContext(Loc, /*isForDeclResult=*/false);

    // Add any keywords that can be used in an argument expr position.
    addSuperKeyword(CompletionCtx.getResultSink(), DC);
    addExprKeywords(CompletionCtx.getResultSink(), DC);
  }

  deliverCompletionResults(CompletionCtx, Lookup, DC, Consumer);
}
<commit_msg>[CodeCompletion] Compute semantic context based on where the called fucntion is defined<commit_after>//===--- ArgumentCompletion.cpp ---------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2022 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/IDE/ArgumentCompletion.h"
#include "swift/IDE/CodeCompletion.h"
#include "swift/IDE/CompletionLookup.h"
#include "swift/Sema/ConstraintSystem.h"
#include "swift/Sema/IDETypeChecking.h"

using namespace swift;
using namespace swift::ide;
using namespace swift::constraints;

bool ArgumentTypeCheckCompletionCallback::addPossibleParams(
    const ArgumentTypeCheckCompletionCallback::Result &Res,
    SmallVectorImpl<PossibleParamInfo> &Params, SmallVectorImpl<Type> &Types) {
  if (!Res.ParamIdx) {
    // We don't really know much here. Suggest global results without a specific
    // expected type.
    return true;
  }

  if (Res.HasLabel) {
    // We already have a parameter label, suggest types
    Types.push_back(Res.ExpectedType);
    return true;
  }

  ArrayRef<AnyFunctionType::Param> ParamsToPass =
      Res.FuncTy->getAs<AnyFunctionType>()->getParams();

  ParameterList *PL = nullptr;
  if (Res.FuncD) {
    PL = swift::getParameterList(Res.FuncD);
  }
  assert(!PL || PL->size() == ParamsToPass.size());

  bool ShowGlobalCompletions = false;
  for (auto Idx : range(*Res.ParamIdx, ParamsToPass.size())) {
    bool IsCompletion = (Idx == Res.ParamIdx);

    // Stop at the first param claimed by other arguments.
    if (!IsCompletion && Res.ClaimedParamIndices.count(Idx) > 0) {
      break;
    }

    const AnyFunctionType::Param *P = &ParamsToPass[Idx];
    bool Required =
        !(PL && PL->get(Idx)->isDefaultArgument()) && !P->isVariadic();

    if (P->hasLabel() && !(IsCompletion && Res.IsNoninitialVariadic)) {
      // Suggest parameter label if parameter has label, we are completing in it
      // and it is not a variadic parameter that already has arguments
      PossibleParamInfo PP(P, Required);
      if (!llvm::is_contained(Params, PP)) {
        Params.push_back(std::move(PP));
      }
    } else {
      // We have a parameter that doesn't require a label. Suggest global
      // results for that type.
      ShowGlobalCompletions = true;
      Types.push_back(P->getPlainType());
    }
    if (Required) {
      // The user should only be suggested the first required param. Stop.
      break;
    }
  }
  return ShowGlobalCompletions;
}

void ArgumentTypeCheckCompletionCallback::sawSolutionImpl(const Solution &S) {
  Type ExpectedTy = getTypeForCompletion(S, CompletionExpr);

  auto &CS = S.getConstraintSystem();

  Expr *ParentCall = CompletionExpr;
  while (ParentCall && ParentCall->getArgs() == nullptr) {
    ParentCall = CS.getParentExpr(ParentCall);
  }

  if (!ParentCall || ParentCall == CompletionExpr) {
    // We might not have a call that contains the code completion expression if
    // we type-checked the fallback code completion expression that only
    // contains the code completion token, but not the surrounding call.
    return;
  }

  auto ArgInfo = getCompletionArgInfo(ParentCall, CS);
  if (!ArgInfo) {
    assert(false && "bad parent call match?");
    return;
  }
  auto ArgIdx = ArgInfo->completionIdx;

  auto *CallLocator = CS.getConstraintLocator(ParentCall);
  auto *CalleeLocator = S.getCalleeLocator(CallLocator);
  auto SelectedOverload = S.getOverloadChoiceIfAvailable(CalleeLocator);
  if (!SelectedOverload) {
    return;
  }

  Type CallBaseTy = SelectedOverload->choice.getBaseType();
  if (CallBaseTy) {
    CallBaseTy = S.simplifyType(CallBaseTy)->getRValueType();
  }

  ValueDecl *FuncD = SelectedOverload->choice.getDeclOrNull();
  Type FuncTy = S.simplifyTypeForCodeCompletion(SelectedOverload->openedType);

  // For completion as the arg in a call to the implicit [keypath: _] subscript
  // the solver can't know what kind of keypath is expected without an actual
  // argument (e.g. a KeyPath vs WritableKeyPath) so it ends up as a hole.
  // Just assume KeyPath so we show the expected keypath's root type to users
  // rather than '_'.
  if (SelectedOverload->choice.getKind() ==
      OverloadChoiceKind::KeyPathApplication) {
    auto Params = FuncTy->getAs<AnyFunctionType>()->getParams();
    if (Params.size() == 1 && Params[0].getPlainType()->is<UnresolvedType>()) {
      auto *KPDecl = CS.getASTContext().getKeyPathDecl();
      Type KPTy =
          KPDecl->mapTypeIntoContext(KPDecl->getDeclaredInterfaceType());
      Type KPValueTy = KPTy->castTo<BoundGenericType>()->getGenericArgs()[1];
      KPTy = BoundGenericType::get(KPDecl, Type(), {CallBaseTy, KPValueTy});
      FuncTy = FunctionType::get({Params[0].withType(KPTy)}, KPValueTy);
    }
  }

  // Find the parameter the completion was bound to (if any), as well as which
  // parameters are already bound (so we don't suggest them even when the args
  // are out of order).
  Optional<unsigned> ParamIdx;
  std::set<unsigned> ClaimedParams;
  bool IsNoninitialVariadic = false;

  ConstraintLocator *ArgumentLocator;
  ArgumentLocator =
      CS.getConstraintLocator(CallLocator, ConstraintLocator::ApplyArgument);
  auto ArgMatchChoices = S.argumentMatchingChoices.find(ArgumentLocator);
  if (ArgMatchChoices != S.argumentMatchingChoices.end()) {
    // We might not have argument matching choices when applying a subscript
    // found via @dynamicMemberLookup.
    auto Bindings = ArgMatchChoices->second.parameterBindings;

    for (auto i : indices(Bindings)) {
      bool Claimed = false;
      for (auto j : Bindings[i]) {
        if (j == ArgIdx) {
          assert(!ParamIdx);
          ParamIdx = i;
          IsNoninitialVariadic = llvm::any_of(
              Bindings[i], [j](unsigned other) { return other < j; });
        }
        // Synthesized args don't count.
        if (j < ArgInfo->argCount) {
          Claimed = true;
        }
      }
      if (Claimed) {
        ClaimedParams.insert(i);
      }
    }
  } else {
    // FIXME: We currently don't look through @dynamicMemberLookup applications
    // for subscripts (rdar://90363138)
  }

  bool HasLabel = false;
  if (auto PE = CS.getParentExpr(CompletionExpr)) {
    if (auto Args = PE->getArgs()) {
      HasLabel = !Args->getLabel(ArgIdx).empty();
    }
  }

  bool IsAsync = isContextAsync(S, DC);

  // If this is a duplicate of any other result, ignore this solution.
  if (llvm::any_of(Results, [&](const Result &R) {
        return R.FuncD == FuncD && nullableTypesEqual(R.FuncTy, FuncTy) &&
               nullableTypesEqual(R.BaseType, CallBaseTy) &&
               R.ParamIdx == ParamIdx &&
               R.IsNoninitialVariadic == IsNoninitialVariadic;
      })) {
    return;
  }

  Results.push_back({ExpectedTy, isa<SubscriptExpr>(ParentCall), FuncD, FuncTy,
                     ArgIdx, ParamIdx, std::move(ClaimedParams),
                     IsNoninitialVariadic, CallBaseTy, HasLabel, IsAsync});
}

void ArgumentTypeCheckCompletionCallback::deliverResults(
    bool IncludeSignature, SourceLoc Loc, DeclContext *DC,
    ide::CodeCompletionContext &CompletionCtx,
    CodeCompletionConsumer &Consumer) {
  ASTContext &Ctx = DC->getASTContext();
  CompletionLookup Lookup(CompletionCtx.getResultSink(), Ctx, DC,
                          &CompletionCtx);

  // Perform global completion as a fallback if we don't have any results.
  bool shouldPerformGlobalCompletion = Results.empty();
  SmallVector<Type, 8> ExpectedTypes;

  if (IncludeSignature && !Results.empty()) {
    Lookup.setHaveLParen(true);
    for (auto &Result : Results) {
      auto SemanticContext = SemanticContextKind::None;
      NominalTypeDecl *BaseNominal = nullptr;
      if (Result.BaseType) {
        Type BaseTy = Result.BaseType;
        if (auto InstanceTy = BaseTy->getMetatypeInstanceType()) {
          BaseTy = InstanceTy;
        }
        if ((BaseNominal = BaseTy->getAnyNominal())) {
          SemanticContext = SemanticContextKind::CurrentNominal;
          if (Result.FuncD &&
              Result.FuncD->getDeclContext()->getSelfNominalTypeDecl() !=
                  BaseNominal) {
            SemanticContext = SemanticContextKind::Super;
          }
        } else if (BaseTy->is<TupleType>() || BaseTy->is<SubstitutableType>()) {
          SemanticContext = SemanticContextKind::CurrentNominal;
        }
      }
      if (SemanticContext == SemanticContextKind::None && Result.FuncD) {
        if (Result.FuncD->getDeclContext()->isTypeContext()) {
          SemanticContext = SemanticContextKind::CurrentNominal;
        } else if (Result.FuncD->getDeclContext()->isLocalContext()) {
          SemanticContext = SemanticContextKind::Local;
        } else if (Result.FuncD->getModuleContext() == DC->getParentModule()) {
          SemanticContext = SemanticContextKind::CurrentModule;
        }
      }
      if (Result.IsSubscript) {
        assert(SemanticContext != SemanticContextKind::None);
        auto *SD = dyn_cast_or_null<SubscriptDecl>(Result.FuncD);
        Lookup.addSubscriptCallPattern(Result.FuncTy->getAs<AnyFunctionType>(),
                                       SD, SemanticContext);
      } else {
        auto *FD = dyn_cast_or_null<AbstractFunctionDecl>(Result.FuncD);
        Lookup.addFunctionCallPattern(Result.FuncTy->getAs<AnyFunctionType>(),
                                      FD, SemanticContext);
      }
    }
    Lookup.setHaveLParen(false);

    shouldPerformGlobalCompletion |=
        !Lookup.FoundFunctionCalls || Lookup.FoundFunctionsWithoutFirstKeyword;
  } else if (!Results.empty()) {
    SmallVector<PossibleParamInfo, 8> Params;
    for (auto &Ret : Results) {
      shouldPerformGlobalCompletion |=
          addPossibleParams(Ret, Params, ExpectedTypes);
    }
    Lookup.addCallArgumentCompletionResults(Params);
  }

  if (shouldPerformGlobalCompletion) {
    for (auto &Result : Results) {
      ExpectedTypes.push_back(Result.ExpectedType);
    }
    Lookup.setExpectedTypes(ExpectedTypes, false);
    bool IsInAsyncContext = llvm::any_of(
        Results, [](const Result &Res) { return Res.IsInAsyncContext; });
    Lookup.setCanCurrDeclContextHandleAsync(IsInAsyncContext);
    Lookup.getValueCompletionsInDeclContext(Loc);
    Lookup.getSelfTypeCompletionInDeclContext(Loc, /*isForDeclResult=*/false);

    // Add any keywords that can be used in an argument expr position.
    addSuperKeyword(CompletionCtx.getResultSink(), DC);
    addExprKeywords(CompletionCtx.getResultSink(), DC);
  }

  deliverCompletionResults(CompletionCtx, Lookup, DC, Consumer);
}
<|endoftext|>