MATLAB Answers

1

Within a function : get complete command-line calling text, a la dbstack()..?

Asked by Brad Stiritz on 25 Sep 2011
Latest activity Commented on by Matthew
on 15 Dec 2017
Hi everyone,
I understand how to use dbstack(), within a saved M-function, to get the complete text of the command which called the current function. For example, if we have two M-files, A.m & B.m, where A() calls (B):
FILE 'A.m'
function output = A(input)
output = B(input);
FILE 'B.m'
function output = B(input)
% ---------------------------------------------------------------------
% What line of text called this function..?
% ---------------------------------------------------------------------
% Get call-stack info:
stDebug = dbstack;
% We know a-priori that this function's caller info is in (stDebug)(2)
% Get caller file name & line number of code which called this function:
callerFileName = stDebug(2).file;
callerLineNumber = stDebug(2).line;
% Open caller file:
fCaller = fopen(callerFileName);
% Iterate through lines to get to desired line number:
for iLine = 1 : callerLineNumber
% Read current line of text:
currLine = fgetl(fCaller);
end
% (currLine) now reflects calling desired code: display this code:
fprintf('Complete text of calling code is : ''%s''\n',currLine);
% Close caller file:
fclose(fCaller);
% ---------------------------------------------------------------------
% Determine function output
% ---------------------------------------------------------------------
% Arbitrary operation just for demonstration:
output = input + 5;
If we call A() from the command-line, we get:
>> A(10)
Complete text of calling code is : 'output = B(input);'
ans = 15
However, if we call B() directly from the command-line, we get an error, b/c there is no 2nd element in the dbstack() output. In other words, for this case dbstack() output is a single-element structure containing info for the local function B() context only:
>> B(10)
Index exceeds matrix dimensions.
Error in B (line 12)
callerFileName = stDebug(2).file;
My problem : I need a way to programmatically get the complete literal calling text, within function B(), no matter whether the caller is another M-file or the command-line.
I thought of looking in the MATLAB diary file, but apparently it's not guaranteed the last line of the diary text file will reflect the currently-executing command-line command at any given point in the executing call stack..
Any suggestions greatly appreciated!
Thanks, Brad

  1 Comment

This isn't an answer to the question as it won't work for command line calls, but its worth noting that there are ways to get a calling line without scanning the file the calling line is in.
A pretty simple way is to create an error, and then use the getReport function on the MatlabException object.
try
error('DummyError');
catch ME
callStackDetails = getReport(ME);
end
callLine = regexp(callStackDetails,'(?<=Error in [^\n]*\n)[^\n]*','match','once');
callLine = strtrim(callLine);

Sign in to comment.

3 Answers

Answer by Brad Stiritz on 29 Sep 2011
 Accepted Answer

I was able to find a solution, with help from Google, by searching for : matlab "command history". After all that tedious debate above, it's nice to see a four-line solution, which I've verified with limited testing. Note that it relies completely on undocumented MATLAB functionality.
Sincere thanks to StackOverflow.com for this solution. Hope it can help s/o else as well..
function str = getLastMATLABcommandLineStr()
% Function returns a string containing the last command entered in the Matlab Command Window..
% Code via : http://stackoverflow.com/questions/5053692/how-do-i-search-through-matlab-command-history
% Get session history from Java object:
history = ...
com.mathworks.mlservices.MLCommandHistoryServices.getSessionHistory;
% Convert to a vector of char strings:
historyText = char(history);
% Convert to a cell vector of strings:
cvHistory = cellstr(historyText);
% Extract last string:
str = cvHistory{end};
end

Answer by Jan
on 25 Sep 2011

Sorry for this not being an direct answer:
There are very likely cleaner methods than parsing the contents of the calling line. The input can be a function, which has side-effects such that a textual pasing will not be successful. This method will fail if called from a Mex function or a P-coded fail also.
Reading the program text of the caller is another variant of the old EVAL problems. Therefore I strongly recommend to find a more direct solution, which si safer, cleaner and is less prone to errors.

  7 Comments

Hi Jan,
OK, I acknowledge your warning ;)
However, I can't accept your specific "solution" to my question. As I understand it, you are simply suggesting that I manually duplicate the command-line function call as a literal string (minus the duplication) & pass this as an additional function argument.
On a philosophical basis, I don't think this is a good idea. It's certainly prone to typos & therefore not foolproof to "obscure side-effects" in that respect. Furthermore, it places additional cognitive burden on the user to perform another level of careful error-checking.
As I'm sure you're aware, one of the benefits of machine processing is to *reduce* the chance for human error. IMHO, your proposed solution actually increases this harmful possibility.
In some contexts, such as when running software prompts the user to enter & re-enter a new password, it makes sense to ask the user for duplicate entry of the same info. But given that your solution does not provide for the duplicated content to be cross-verified, I don't think this can qualify as a legitimate request of the user. Can you think of any software which asks the user to enter the same information twice, but does not validate the entries against each other..? I can't think of any.
Brad
p.s. thank you anyway for your time & consideration. I appreciate you giving my problem some thought :)
@Brad: "Can you think of any software which asks the user to enter the same information twice, but does not validate the entries against each other?" Yes, Windows UAC. And I agree that it is a good idea not to compete with it.
And I agree, that my answer does *not* solve your problem.

Sign in to comment.


Answer by Daniel Shub
on 25 Sep 2011

I think you always want the last function on the stack:
callerFileName = stDebug(end).file;
callerLineNumber = stDebug(end).line;

  2 Comments

Daniel,
Thanks for your response, but did you try your suggested code..? Here's what I get when I execute your modified function B():
>> B(10)
Complete text of calling code is : 'stDebug = dbstack;'
Just to clarify, here's the call-stack output we wish to generate when B() is called from the command-line:
>>B(10)
Complete text of calling code is : 'B(10)'

Sign in to comment.