Beispiel #1
0
/**
 * Call a program based on a prepare done before.
 * @param \ToolkitApi\CW\DataDescription $program   Program object created in the preparation stage.
 * @param array           $params    Input params with key=>value pairs (possibly nested),
 *                                   keys matching what was specified in prepare stage.
 * @param array            $retvals  Output params (optional)
 *                                   Fields get created based on names of output parms.
 * @return boolean         True if successful, false if not.
 */
function i5_program_call(\ToolkitApi\CW\DataDescription $program, $params, $retvals = array())
{
    // @todo check type of $program and give toolkit-like messages
    $inputValues = $params;
    // convert from old to new param format, inserting input values
    $newInputParams = $program->generateNewToolkitParams($inputValues);
    if ($program->callProgram($newInputParams)) {
        if ($retvals && is_array($retvals)) {
            $pgmOutput = $program->getPgmOutput();
            $exportedThem = $program->getConnection()->setOutputVarsToExport($retvals, $pgmOutput);
            //$exportedThem = exportPgmOutputVars($retvals, $pgmOutput);
            if (!$exportedThem) {
                return false;
            }
        }
        noError();
        return true;
    } else {
        // @todo if particular xml errors,
        // such as errnoxml = 1000005 or errnoile = 3025 means can't find program,
        // specify them.
        // Return "toolkit-style" CPF errno codes/messages
        // Set the i5error object based on this.
        $conn = $program->getConnection();
        if ($conn->getErrorCode()) {
            i5CpfError($conn->getErrorCode(), $conn->getErrorMsg());
            return false;
        }
        return false;
    }
}
 /**
  * Constructor takes a PCML string and converts to an array-based old toolkit data description string.
  *
  * @param string $pcml The string of PCML
  * @param Toolkit $connection connection object for toolkit
  * @throws \Exception
  */
 public function __construct($pcml, Toolkit $connection)
 {
     $this->setConnection($connection);
     // Convert PCML from ANSI format (which old toolkit required) to UTF-8 (which SimpleXML requires).
     $encoding = $connection->getConfigValue('system', 'encoding', 'ISO-8859-1');
     // XML encoding
     /*
      * Look for optionally set <?xml encoding attribute
      * and change encoding if attribute is set and not UTF-8
      * or change encoding if attribute is not set and ini encoding is not UTF-8
      */
     $pcml = trim($pcml);
     $matches = array();
     $regex = '/^<\\?xml\\s.*?encoding=["\']([^"\']+)["\'].*?\\?>/is';
     if (preg_match($regex, $pcml, $matches) && $matches[1] != 'UTF-8') {
         //remove xml-tag
         $pcml = substr($pcml, strlen($matches[0]));
         $pcml = mb_convert_encoding($pcml, 'UTF-8', $matches[1]);
     } elseif ($encoding != 'UTF-8') {
         $pcml = mb_convert_encoding($pcml, 'UTF-8', $encoding);
     }
     //program name is stored as: /pcml/program name="/qsys.lib/eacdemo.lib/teststruc.pgm"
     $xmlObj = new \SimpleXMLElement($pcml);
     // get root node and make sure it's named 'pcml'
     if (!isset($xmlObj[0]) || $xmlObj[0]->getName() != 'pcml') {
         throw new \Exception("PCML file must contain pcml tag");
     }
     $pcmlObj = $xmlObj[0];
     // get program name, path, etc.
     if (!isset($pcmlObj->program) || !$pcmlObj->program) {
         throw new \Exception("PCML file must contain program tag");
     }
     $programNode = $pcmlObj->program;
     $pgmAttrs = $programNode->attributes();
     /**
      * sample:
      * <program name="name"
      * [ entrypoint="entry-point-name" ]
      * [ epccsid="ccsid" ]
      * [ path="path-name" ]
      * [ parseorder="name-list" ]
      * [ returnvalue="{ void | integer }" ]
      * [ threadsafe="{ true | false }" ]>
      * </program>
      */
     // let's focus on name, path, and entrypoint, the only attributes likely to be used here.
     $path = isset($pgmAttrs['path']) ? $pgmAttrs['path'] : '';
     $entrypoint = isset($pgmAttrs['entrypoint']) ? $pgmAttrs['entrypoint'] : '';
     // Note: if entrypoint is supplied, it's the function in a service program. "name" will be the same as entrypoint.
     // if entrypoint is not supplied, name is the actual program name.
     // Therefore, "name" seems somewhat worthless.
     // break up path, separated now by slashes. can be varied lib and pgm.
     // remove the /qsys.lib that may be in front but only if it's simply qualifying another library. qsys may be the actual program library, too.
     $objArray = $this->splitPcmlProgramPath($path);
     if ($objArray['lib']) {
         $pgmName = "{$objArray['lib']}/{$objArray['obj']}";
     } else {
         $pgmName = $objArray['obj'];
     }
     // now add the entrypoint, if any, as a procedure/function.
     if ($entrypoint) {
         // append the entry point enclosed in parentheses.
         $pgmName .= "({$entrypoint})";
     }
     // Now create data description array.
     $dataDescriptionArray = $this->pcmlToArray($xmlObj);
     //Change the encoding back to the one wanted by the user, since SimpleXML encodes its output always in UTF-8
     $pgmName = mb_convert_encoding($pgmName, $encoding, 'UTF-8');
     mb_convert_variables($encoding, 'UTF-8', $dataDescriptionArray);
     // call parent's constructor with:
     //$descObj = new DataDescriptionPcml($description, $connection);
     parent::__construct($pgmName, $dataDescriptionArray, $connection);
 }