|
|
Here is a bug (and a bugfix) for a problem with the "Shell
Command Return Actions" (see 5.2.4.3 of the helpfile). These
are the INI-options Pre_Frame_Return=, Post_Frame_Return=,
Pre_Scene_Return= etc. It problem affects all these options,
but in the following examples I refer only to Pre_Frame_Return
for reasons of simplicity. I experienced the following problem
on Windows 2000 running the precompiled version of PoV 3.5,
but looking at the source code other platforms could
experience the same problems.
*** What PoV *should* do (see 5.2.4.3 of PoV-3.5 docs):
According to the documentation, the Pre_Frame_Return=S option
should work together with the Pre_Frame_Command=commandline
option. Pre_Frame_Command runs an external command before each
frame, and Pre_Frame_Return=... specifies what action PoV
should perform after the external application has finished
based on the return code of that external application. For
example, Pre_Frame_Return=S should skip the next frame of an
animation if the return code from the external application is
non-zero. For external applications which return zero instead
of non-zero to indicate success, we should specify "-S"
instead of "S" to skip the next frame for zero return values.
*** What PoV does (I think it's a BUG!):
Unfortunately the INI-option Pre_Frame_Return=S doesn't work
(the Post_... and _Scene_ variations also don't work, I take
Pre_Frame_... as an example to illustrate the problem). The
problem is this:
Pre_Frame_Return is only useful when combined with
Pre_Frame_Command. Because of a bug in the INI-parser,
whenever a Pre_Frame_Return option is encountered, a
commandline previously set with Pre_Frame_Command is reset to
an empty string. So if you place Pre_Frame_Return after
Pre_Frame_Command in the INI-file, the external application is
never called, because Pre_Frame_Return clears the commandline
for it. Just swapping the INI-options doesn't work either: If
you put Pre_Frame_Return first and Pre_Frame_Command second,
when the parser parses the Pre_Frame_Command option, it resets
the return-action to "I" (ignore return value), so the
external application is called, but the return value is always
ignored (thus, actions like skip-frame or abort-scene are
never carried out). The bugfix below will fix this.
There is also a second bug in the original sourcecode of PoV
3.5: According to the docs, preceeding the Pre_Frame_Return
option with a "-" or "!" should carry out the action if the
return value is zero (instead of non-zero), so
"Pre_Frame_Return=-S" would skip the frame if the commandline
of "Pre_Frame_Command=commandline" returns zero. Unfortunately
the parser completely fails to recognize the "-" or "!" prefix
to the option (only the first character of the parameter is
examined to be a letter S,A,F,etc., but something like "-S" is
two characters long, the parser fails to see this). I wonder
how this was ever meant to work. Probably the option-parsing-
code has undergone major changes in version 3.5. Anyway, the
bugfix shown below fixes this also.
*** Bugfix:
The following few lines must be replaced/added to two
sourcefiles in order to make it work as expected. To easier
find the lines, I show the original code and the modified
code.
mofification 1: "optin.cpp", function process_ini_option,
estimated lines 1234 to 1255, remove this code:
case kPOVAttrib_FatalErrorCommand:
case kPOVAttrib_PostFrameCommand:
case kPOVAttrib_PostSceneCommand:
case kPOVAttrib_PreFrameCommand:
case kPOVAttrib_PreSceneCommand:
case kPOVAttrib_UserAbortCommand:
POVMSObject cmdobj;
err = POVMSObject_New(&cmdobj, kPOVMSType_WildCard);
if(toupper(*(option->keyword + strlen(option->keyword) - 1)) == 'D')
{
if(err == kNoErr)
err = POVMSUtil_SetString(&cmdobj, kPOVAttrib_CommandString, param);
}
else
{
if(err == kNoErr)
err = POVMSUtil_SetInt(&cmdobj, kPOVAttrib_ReturnAction,
tolower(*param));
}
if(err == kNoErr)
err = POVMSObject_Set(obj, &cmdobj, option->key);
break;
and replace it with this code:
case kPOVAttrib_FatalErrorCommand:
case kPOVAttrib_PostFrameCommand:
case kPOVAttrib_PostSceneCommand:
case kPOVAttrib_PreFrameCommand:
case kPOVAttrib_PreSceneCommand:
case kPOVAttrib_UserAbortCommand:
POVMSObject cmdobj;
// did we a previous option for this kind of command?
err = POVMSObject_Exist(obj, option->key);
if(err == kNoErr)
{
// There is already an object for that kind of command, this
// happens if both ..._Command and ..._Return options are
// set in the Ini-file, for example a Pre_Frame_Command=...
// followed by a Pre_Frame_Return=S to evaluate the return
// value of the command. Now get the object for that command
// and modify it later.
err = POVMSObject_Get(obj, &cmdobj, option->key);
// POVMSObject_Get could fail despite the fact that we
// called POVMSObject_Exist before, for example if it
// runs out of memory, so we have to check here.
if(err != kNoErr)
break;
}
else if(err != kFalseErr) // POVMSObject_Exist failed with an
break; // error, just exist with that error.
else // object doesn't exist for this command, create a new one:
err = POVMSObject_New(&cmdobj, kPOVMSType_WildCard);
if(toupper(*(option->keyword + strlen(option->keyword) - 1)) == 'D')
{
if(err == kNoErr)
err = POVMSUtil_SetString(&cmdobj, kPOVAttrib_CommandString, param);
}
else
{
if(err == kNoErr)
{
int iReturnAction;
// Get the return-action character from the parameter
// Just the character, ignore - or ! prefix here
if((*param == '-') || (*param == '!'))
iReturnAction = (int)tolower(param[1]);
else
iReturnAction = tolower(*param);
// Do some primitive error checking
// (I could do better given more time...)
if((iReturnAction != 'i')
&& (iReturnAction != 'q')
&& (iReturnAction != 'u')
&& (iReturnAction != 'f')
&& (iReturnAction != 's')
&& (iReturnAction != 'a'))
{
PossibleError("Unknown return action in %s=%s", option->keyword,
param);
err = kParamErr;
break;
}
// Encode the - or ! prefix to iReturnAction (change sign). This
// is later decoded in SetCommandOption in povmsrec.cpp
if((*param == '-') || (*param == '!'))
iReturnAction = -iReturnAction;
err = POVMSUtil_SetInt(&cmdobj, kPOVAttrib_ReturnAction,
iReturnAction);
}
}
if(err == kNoErr)
err = POVMSObject_Set(obj, &cmdobj, option->key);
break;
mofification 2: "optin.cpp", function output_ini_option,
estimated lines 604 to 608, remove this code:
if(POVMSUtil_GetInt(&cmdobj, kPOVAttrib_ReturnAction, &intval) == 0)
{
chr = intval;
file->printf("%s=%c\n", option->keyword, chr);
}
and replace it with this code:
if(POVMSUtil_GetInt(&cmdobj, kPOVAttrib_ReturnAction, &intval) == 0)
{
if(intval < 0)
{
chr = -intval;
file->printf("%s=-%c\n", option->keyword, chr);
}
else
{
chr = intval;
file->printf("%s=%c\n", option->keyword, chr);
}
}
mofification 3: "povmsrec.cpp", function SetCommandOption, at
line 137 add a few lines (shown in context):
int ret = 0;
err = POVMSUtil_GetInt(&obj, kPOVAttrib_ReturnAction, &ret);
if(err == 0)
{
// HERE BEGINS ADDED CODE >>>>
if(ret < 0)
{
data->Inverse = true;
ret = -ret;
}
else
data->Inverse = false;
// <<<< HERE ENDS ADDED CODE
switch(ret)
{
That should fix the problem. Comments welcome.
Post a reply to this message
|
|