Code covered by the BSD License  

Highlights from
choose_profile_limits

image thumbnail
from choose_profile_limits by Kevin Bartlett
Allows user to choose limits of oceanographic profile (e.g., CTD cast)

parse_args(varargin)
function argStruct = parse_args(varargin)
%
% parse_args.m--Parses input arguments for a client function. Arguments are
% assumed to be in parameter/value pair form. 
%
% The following example shows the steps involved in using parse_args.m:
%
% (1) Create m-file "myfunc.m" with the following function declaration:
%        function [] = myfunc(varargin)
%
% (2) Inside myfunc.m, include the following lines:
%        defaultVals.figureWidth = 0.8; 
%        defaultVals.figureHeight = 0.5;
%        argStruct = parse_args(defaultVals,varargin{:});
%
% (3) Call your function with the following syntax:
%        myfunc('figureHeight',0.99)
%
% Inside myfunc.m, the structured variable argStruct will contain fields
% named 'figureWidth' and 'figureHeight'. The 'figureWidth' field will
% contain the default value of 0.8, since no non-default value was passed
% to myfunc.m, but the 'figureHeight' field will contain the value 0.99,
% over-riding the default value of 0.5.
%
% There are variations on this pattern:
%
% (a) Your "myfunc.m" program may take arguments in addition to varargin,
%     but they must precede varargin. For example, your function
%     declaration could look like this:
%         function [] = myfunc(numFiles,pathName,varargin)
%
% (b) It is not necessary to declare any default values. Your "myfunc.m"
%     program can call parse_args.m like this:
%         argStruct = parse_args(varargin{:});
%
% (c) You can call myfunc.m with all parameter/value pairs specified, none
%     of them specified, or anything in between. In the example above,
%     myfunc.m could be called like this:
%         myfunc('figureHeight',0.99,'figureWidth',0.2);
%     or like this:
%         myfunc;
%
% (d) Your "myfunc.m" program  can call parse_args.m with two additional
%     arguments:
%         argStruct = parse_args(...,allowNewFields,isCaseSensitive);
%     where allowNewFields and isCaseSensitive are both Boolean values. By
%     default, isCaseSensitive is true, so parse_args.m will treat the
%     parameters 'lineColour' and 'linecolour' (for example) as different
%     parameters. The allowNewFields parameter is also true by default,
%     meaning that parse_args.m will accept parameters whose names are NOT
%     included as fields in the default values structured variable. You can
%     over-ride the default behaviour by specifying a different value for
%     allowNewFields or isCaseSensitive, but in this case, BOTH of these
%     arguments must be specified in the call to parse_args.m as shown
%     above.
%
% N.B., program originally named parvalpairs.m. Program is based on the
% (University of Hawaii) Firing Group's fillstruct.m.
%
% Syntax: argStruct = parse_args(<defaultStruct>,par1,val1,par2,val2,...,<allowNewFields,isCaseSensitive>)
%
% e.g.,   argStruct = parse_args('Position',[256 308 512 384],'Units','pixels','Color',[1 0 1])
%
% e.g.,   defaultStruct.a = pi; 
%         defaultStruct.b = 'hello'; 
%         defaultStruct.c = [1;2;3];
%         allowNewFields = 1; 
%         isCaseSensitive = 0; 
%         argStruct = parse_args(defaultStruct,varargin{:},allowNewFields,isCaseSensitive);
%         % N.B., for demonstration on command line (where you won't have a
%         varargin variable), use this syntax: 
%         argStruct = parse_args(defaultStruct,'A',pi/2,'b','bye','z','new field',allowNewFields,isCaseSensitive)

% Developed in Matlab 6.1.0.450 (R12.1) on Linux. Kevin
% Bartlett(kpb@hawaii.edu), 2003/04/08, 11:49
%--------------------------------------------------------------------------

% Handle input arguments.
args = varargin;

if nargin == 0
    argStruct = struct([]);
    return;
end % if

% If a structured variable containing default field values has been
% supplied, separate it from the other input arguments.
defaultStruct = struct([]);

if isstruct(args{1})

    defaultStruct = args{1};

    if length(args) > 1
        args = args(2:end);
    else
        args = {};
    end % if

end % if

argStruct = defaultStruct;

% Determine if values of the variables "allowNewFields" and
% "isCaseSensitive" have been specified.

% ...Default values:
allowNewFields = 1;
isCaseSensitive = 1;

if length(args) > 1
    
    % If no values of allowNewFields and isCaseSensitive have been
    % specified, then all the remaining arguments will be parameter/value
    % pairs. The second-to-last argument should then be a string.
    if ~isstr(args{end-1})
    
        % The second-to-last argument is NOT a string, so it must be the
        % Boolean variable allowNewFields.
        allowNewFields = args{end-1};
        
        % ...and the last input argument is the Boolean variable
        % isCaseSensitive.
        isCaseSensitive = args{end};
        
        if length(args) > 1
           args = args(1:end-2);
        else
            args = {};
        end % if
        
    end % if
        
end % if

% If no arguments remain after extracting the default field values and the
% Boolean variables "allowNewFields" and "isCaseSensitive", then exit now.
% The value of argStruct returned will contain the same values as
% defaultStruct.
if length(args) == 0
    return;
end % if

if ~ismember(allowNewFields,[1 0])
    error([mfilename '.m--Value for "allowNewFields" must be 1 or 0.']);
end % if

if ~ismember(isCaseSensitive,[1 0])
    error([mfilename '.m--Value for "isCaseSensitive" must be 1 or 0.']);
end % if

% Remaining input arguments should be parameter/value pairs.
existingFieldNames = fieldnames(defaultStruct);
lowerExistingFieldNames = lower(existingFieldNames);

for iArg = 1:2:length(args)

    thisFieldName = args{iArg};

    if ~isstr(thisFieldName)
        error([mfilename '.m--Parameter names must be strings.']);
    end % if

    thisField = args{iArg+1};

    % Find out if field already exists.
    if isCaseSensitive == 1

        if ismember(thisFieldName,existingFieldNames)
            fieldExists = 1;
            fieldNameToInsert = thisFieldName;
        else
            fieldExists = 0;
            fieldNameToInsert = thisFieldName;
        end % if

    else

        if ismember(lower(thisFieldName),lowerExistingFieldNames)
            fieldExists = 1;
            matchIndex = strmatch(lower(thisFieldName),lowerExistingFieldNames,'exact');
            fieldNameToInsert = existingFieldNames{matchIndex};
        else
            fieldExists = 0;
            fieldNameToInsert = thisFieldName;
        end % if

    end % if

    % If new fields are not permitted to be added, test that field already exists.
    if allowNewFields == 0 && fieldExists == 0
        
        % If the default structure is empty, and the user is not permitting
        % the addition of new fields, there is no point in running this
        % program; probably the user doesn't intend this.
        if isempty(defaultStruct)
            error([mfilename '.m--Need to permit the addition of new fields if no default structure specified.']);
        end % if

        if isCaseSensitive == 1
            %error([mfilename '.m--Attempt to add new parameter to existing set (case-sensitive). Use allowNewFields=1 to allow this.']);
            error([mfilename '.m--Unrecognised input argument ''' thisFieldName '''. (arguments are case-sensitive).']);
        else
            %error([mfilename '.m--Attempt to add new parameter to existing set. Use allowNewFields=1 to allow this.']);
            error([mfilename '.m--Unrecognised input argument ''' thisFieldName '''.']);
        end % if

    end % if

    if isempty(argStruct)
        argStruct = struct(fieldNameToInsert,thisField);
    else
        argStruct.(fieldNameToInsert) = thisField;
    end % if
            
end % for

Contact us at files@mathworks.com