In older versions of slickedit you could look up the source for _parse_project_command but in V19 it seems to be in the core so below is a copy of some of the function from slick V16 - look for where %ON is decoded. The code snippets at the start are roughly what you need to look at. Note how it calls itself recursively in case _ProjectGet_OutputFile contains % sequences.
You may be able to just call _parse_project_command to get what you want
message(_parse_project_command('%O',"",_project_name, "");
_ProjectGet_ActiveConfigOrExt(project_name,handle,config);
info=_ProjectGet_OutputFile(handle,config);
absOutputDir=_parse_project_command(info, buf_name, project_name, cword, argline,
ToolName, ClassPath, recursionStatus, recursionMonitorHash);
_str _parse_project_command(_str command,_str buf_name,
_str project_name,_str cword,_str argline='',
_str ToolName='',_str ClassPath='', int* recursionStatus = null,
_str (*recursionMonitorHash):[] = null,
int handle=0,_str config='')
{
/*
* 12:37pm 7/16/1999
* Important!!!!
* From now on when we change this function, we must consider whether to
* duplicate the functionality in _parse_project_command in vsbuild.cpp
* <P>
* Note - this function is also used to parse print commands.
*/
if (project_name!='' && _workspace_filename!='' && (handle==0 || config=='')) {
_ProjectGet_ActiveConfigOrExt(project_name,handle,config);
}
_str s = "";
_str lastOption = "";
_str ext="";
_str member,dsname;
_str info,dirname;
boolean recurseRepString = false;
boolean forceUnixFileSeps = false;
int i,j=1,k;
for (;;) {
// reset the recursion information
recurseRepString = false;
lastOption = "";
j=pos(PARSE_CHAR,command,j);
if ( ! j ) {
break;
}
_str ch=upcase(substr(command,j+1,1));
_str ch2='';
int len=2;
if ( ch=='P' ) {
s=strip_filename(buf_name,'N');
} else if ( ch=='Q' ) {
_str count=substr(command,j+2,1);
if (!isinteger(count)) {
s='';
} else {
len=3;
s=strip_filename(buf_name,'N');
#if _NAME_HAS_DRIVE
s=strip_filename(s,'D');
--count;
#endif
while (count>0) {
parse substr(s,2) with (FILESEP) +0 s ;
--count;
}
}
} else if (ch=='D') {
if (upcase(substr(command,j+2,2))=='EF') {
if (project_name != "") {
_str ch4=upcase(substr(command,j+4,1));
if (ch4 == 'S' || ch4 == 'D') {
s='';
len=5;
_str rep_char='/';
if (ch4=='D') {
rep_char='-';
}
lastOption = "%def";
// attempt to prevent infinite loops by checking to see if this variable has
// already been replaced during recursion
if (recursionMonitorHash != null && (*recursionMonitorHash):[lastOption] == 1) {
_message_box(nls(get_message(VSBUILDRC_INFINITE_LOOP_DETECTED_IN_COMMAND), "", lastOption));
if (recursionStatus != null) {
*recursionStatus = -1;
}
return "";
}
_str temp_s=_ProjectGet_Defines(handle,config);
while (temp_s!='') {
_str define=parse_next_option(temp_s,false);
if (s!='') {
strappend(s,' ');
}
_str lead_char=substr(define,1,1);
if (lead_char=='/' || lead_char=='-') {
strappend(s,'"':+rep_char:+substr(define,2):+'"');
} else {
strappend(s,'"':+define:+'"');
}
}
recurseRepString = true;
}
}
} else {
ch2=upcase(substr(command,j+2,1));
len=2;
s="";
switch (ch2) {
case 'Q':
len=3;
member=_DataSetMemberOnly(buf_name);
dsname=_DataSetNameOnly(buf_name);
_str digit=substr(command,j+3,1);
if (isdigit(digit)) {
len=4;
_str result='';
while (digit-- >0) {
_str before;
parse dsname with before '.' dsname;
if (before=='') {
break;
}
result=before;
}
dsname=result;
}
s=dsname;
break;
case 'M': // member
len=3;
s=strip_filename(buf_name,'P');
break;
case 'S': // ds.name
len=3;
member=_DataSetMemberOnly(buf_name);
dsname=_DataSetNameOnly(buf_name);
digit=substr(command,j+3,1);
if (isdigit(digit)) {
len=4;
while (digit-- >0) {
dsname=strip_filename(dsname,'E');
}
}
s=dsname;
break;
case 'F': // ds.name
len=3;
member=_DataSetMemberOnly(buf_name);
dsname=_DataSetNameOnly(buf_name);
if (member!='') {
s='"'dsname'('member')"';
} else {
s='"'dsname'"';
}
}
}
} else if (ch=='O') {
s = '';
if (project_name != '') {
ch2 = upcase(substr(command, j+2, 1));
_str associatedProject=_ProjectGet_AssociatedFile(_ProjectHandle(project_name));
if (file_eq(get_extension(associatedProject,true),VISUAL_STUDIO_INTEL_CPP_PROJECT_EXT)) {
associatedProject = getICProjAssociatedProjectFile(associatedProject);
}
_str absOutputDir='';
if ( associatedProject!='' && _IsVisualStudioProjectFilename(associatedProject) ) {
_str outputDir='';
_GetExeFromVisualStudioFile(associatedProject,config,outputDir);
info=absOutputDir=absolute(outputDir,_file_path(project_name));
} else {
if (_isMac()) {
//Xcode projects are associated to the vpj since there is only a workspace file
if ( associatedProject!='' && _IsVSEProjectFilename(associatedProject) ) {
info=_xcode_get_output_file(project_name,config,absOutputDir);
} else {
info=_ProjectGet_OutputFile(handle,config);
}
} else {
info=_ProjectGet_OutputFile(handle,config);
}
// parse the output dir for %placeholders. necessary for %on and %op
absOutputDir=_parse_project_command(info, buf_name, project_name, cword, argline,
ToolName, ClassPath, recursionStatus, recursionMonitorHash);
}
switch (ch2) {
case 'N':
// attempt to prevent infinite loops by checking to see if this variable has
// already been replaced during recursion
if (recursionMonitorHash != null && (*recursionMonitorHash):["%on"] == 1) {
_message_box(nls(get_message(VSBUILDRC_INFINITE_LOOP_DETECTED_IN_COMMAND), "", "%on"));
if (recursionStatus != null) {
*recursionStatus = -1;
}
return "";
}
len = 3;
s = strip_filename(absOutputDir, 'PE');
// set recursion info
recurseRepString = true;
lastOption = "%on";
break;
case 'P':
// attempt to prevent infinite loops by checking to see if this variable has
// already been replaced during recursion
if (recursionMonitorHash != null && (*recursionMonitorHash):["%op"] == 1) {
_message_box(nls(get_message(VSBUILDRC_INFINITE_LOOP_DETECTED_IN_COMMAND), "", "%op"));
if (recursionStatus != null) {
*recursionStatus = -1;
}
return "";
}
len = 3;
s = strip_filename(absOutputDir, 'N');
// set recursion info
recurseRepString = true;
lastOption = "%op";
break;
case 'E':
// attempt to prevent infinite loops by checking to see if this variable has
// already been replaced during recursion
if (recursionMonitorHash != null && (*recursionMonitorHash):["%oe"] == 1) {
_message_box(nls(get_message(VSBUILDRC_INFINITE_LOOP_DETECTED_IN_COMMAND), "", "%oe"));
if (recursionStatus != null) {
*recursionStatus = -1;
}
return "";
}
// look for a compile command that applies to the current buffer
_str outputExtension = "";
getExtSpecificCompileInfo(buf_name, _ProjectHandle(project_name), GetCurrentConfigName(),
"", outputExtension, auto compileRuleTargetNode=0, auto linkObject=false, true);
len = 3;
// remove the wildcard
if (first_char(outputExtension) == '*') {
outputExtension = substr(outputExtension, 2);
}
s = outputExtension;
// set recursion info
recurseRepString = true;
lastOption = "%oe";
break;
case 'B':
if (upcase(substr(command,j+3,2))=='JS') {
if (recursionMonitorHash != null && (*recursionMonitorHash):["%objx"] == 1) {
_message_box(nls(get_message(VSBUILDRC_INFINITE_LOOP_DETECTED_IN_COMMAND), "", "%objs"));
if (recursionStatus != null) {
*recursionStatus = -1;
}
return "";
}
// objs
len=5;
// assume a list of objects is in buf_name (true when generating linker
// commands)
_str obj_list=buf_name;
_str lib_list=_ProjectGet_LibsList(handle,config);
_str preObjectLibs=_ProjectGet_PreObjectLibs(handle,config);
s=_generate_objs_list(obj_list,lib_list,preObjectLibs);
// set recursion info
recurseRepString = true;
lastOption = "%objs";
}
break;
default:
// attempt to prevent infinite loops by checking to see if this variable has
// already been replaced during recursion
if (recursionMonitorHash != null && (*recursionMonitorHash):["%o"] == 1) {
_message_box(nls(get_message(VSBUILDRC_INFINITE_LOOP_DETECTED_IN_COMMAND), "", "%o"));
if (recursionStatus != null) {
*recursionStatus = -1;
}
return "";
}
s = info;
// set recursion info
recurseRepString = true;
lastOption = "%o";
break;
}
}
} else if (ch=='L') {
// <<<<<<<<<<<<<< snip
return(command);
}