function varargout=Whos(varargin)
%Whos (Upper case W) is a customized version of whos (lower case w).
%
%The differences are
%
% (1) "Whos" will compute/display memory in kilobytes whereas "whos" displays in bytes.
%
% (2) "Whos" will always display all array dimensions whereas "whos" will
% not display array dimensions for 4th and higher dimensional arrays.
%
%
%EXAMPLE: Given arrays
%
% A=rand(10,20,30,40);
% B=rand(5,10,15,20,25,'single')*i;
%
%using "whos" displays the following:
%
%>> whos
% Name Size Bytes Class Attributes
%
% A 4-D 1920000 double
% B 5-D 3000000 single complex
%
%
%whereas "Whos" will display the following
%
%>> Whos
% Name Size Kilobytes Class Attributes
%
% A 10x20x30x40 1875 double
% B 5x10x15x20x25 2930 single complex
%
%
%An unfortunate limitation is that Whos relies on EVALIN and so will not work
%correctly in a workspace context reached using DBUP and DBDOWN.
%I elaborate on this somewhat in this Newsgroup thread:
%
% http://www.mathworks.com/matlabcentral/newsreader/view_thread/303357
%
%Hopefully, TMW will provide a way around this eventually.
%
%by Matt Jacobson
%
%Copyright, Xoran Technologies, Inc. 2011
if nargin==0
cmdstr='whos;';
s=evalin('caller', cmdstr) ;
else
in=['''' varargin{1} ''''];
numargs=length(varargin);
if numargs>1
for ii=2:numargs
in= [in ',' '''' varargin{ii} ''''];
end
end
cmdstr=['whos(' in ');'];
s=evalin('caller', cmdstr) ;
end
flds=fieldnames(s);
idx=strmatch('bytes',flds);
flds{idx}='kilobytes';
S=rmfield(s,'bytes');
[S.kilobytes]=deal([]);
S=orderfields(S,flds);
deepestLevel=S(1).nesting.level;
setAns=strmatch('ans',{S.name});
idx=[];
for ii=setAns(:).'
if isequal(S(ii).class,'(unassigned)') && S(ii).nesting.level==deepestLevel
idx=ii;
end
end
S(idx)=[];
N=length(S);
sizeStrings=cell(N,1);
memStrings=cell(N,1);
attributesStrings=cell(N,1);
nestFuncs=cell(1,N);
nestLevels=nan(N,1);
lastLevel=nan;
blockCounts=zeros(1,N);
blockIndex=0;
for ii=1:N
sizeStrings{ii}=regexprep(num2str(S(ii).size),'\s*','x');
S(ii).kilobytes=s(ii).bytes/2^10;
if S(ii).kilobytes>=10
memStrings{ii}=num2str(ceil(S(ii).kilobytes));
else
memStrings{ii}=num2str(S(ii).kilobytes,'%2.3f');
end
str='';
if S(ii).persistent, str=[str,'persistent, ']; end
if S(ii).global, str=[str,'global, ']; end
if S(ii).sparse, str=[str,'sparse, ']; end
if S(ii).complex, str=[str,'complex, ']; end
idx=find(str==',',1,'last');
str(idx:end)='';
if isempty(str), str=' '; end
attributesStrings{ii}=str;
thisLevel=S(ii).nesting.level;
nestLevels(ii)=thisLevel;
if thisLevel~=lastLevel
lastLevel=thisLevel;
blockIndex=blockIndex+1;
nestFuncs{ii}=S(ii).nesting.function;
end
blockCounts(blockIndex)=blockCounts(blockIndex)+1;
end
if ~nargout
blockCounts=nonzeros(blockCounts);
nestFuncs=nestFuncs( ~cellfun('isempty',nestFuncs)) ;
nestFuncs=cellfun(@(str) [' ---- ',str,' -'] , nestFuncs(:), 'UniformOutput',0);
NameCol=char('Name',' ',S.name);
SizeCol=char('Size',' ',sizeStrings{:});
ClassCol=char('Class',' ',S.class);
AttributesCol=char('Attributes',' ',attributesStrings{:});
%%Right justify the memory footprints
memStrings=cellfun(@fliplr, memStrings,'UniformOutput',0);
MegCol=fliplr( char(fliplr('Kilobytes'),' ',memStrings{:}));
%% set up the display table
d=repmat(' ',N+2,1);
dd=[d,d];
ddd=[dd,d];
DisplayTable=[dd,NameCol,ddd,...
SizeCol,ddd,dd,...
MegCol, ddd,dd,...
ClassCol, ddd,...
AttributesCol];
DisplayTable=char(DisplayTable,' ');
if length(blockCounts)>1
subTable=DisplayTable(3:end-1,:);
subTable=mat2cell(subTable,blockCounts,size(subTable,2));
subTable=[repmat({' '},size(subTable,1),1) , nestFuncs,subTable ];
subTable=subTable.';
subTable=char(subTable{:});
DisplayTable=char( DisplayTable(1,:), subTable, DisplayTable(end,:) );
divs=strmatch(' ----',DisplayTable);
for ii=1:length(divs)
jj=divs(ii);
kk=find(DisplayTable(jj,:)=='-',1,'last');
DisplayTable(jj,kk+1:end)='-';
end
end
disp(DisplayTable)
else
varargout{1}=S;
end