]> Creatis software - CreaPhase.git/blob - octave_packages/miscellaneous-1.1.0/read_options.m
Add a useful package (from Source forge) for octave
[CreaPhase.git] / octave_packages / miscellaneous-1.1.0 / read_options.m
1 ## Copyright (C) 2002 Etienne Grossmann <etienne@isr.ist.utl.pt>
2 ##
3 ## This program is free software; you can redistribute it and/or modify it under
4 ## the terms of the GNU General Public License as published by the Free Software
5 ## Foundation; either version 3 of the License, or (at your option) any later
6 ## version.
7 ##
8 ## This program is distributed in the hope that it will be useful, but WITHOUT
9 ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11 ## details.
12 ##
13 ## You should have received a copy of the GNU General Public License along with
14 ## this program; if not, see <http://www.gnu.org/licenses/>.
15
16 ## -*- texinfo -*-
17 ## @deftypefn{Function File} {@var{[op,nread]} = } read_options ( args, varargin ) 
18 ## @cindex  
19 ##  The function read_options parses arguments to a function as,
20 ## [ops,nread] = read_options (args,...) - Read options
21 ##
22 ## The input being @var{args} a list of options and values.
23 ## The options can be any of the following,
24 ##
25 ## 'op0'    , string : Space-separated names of opt taking no argument  <''>
26 ## 
27 ## 'op1'    , string : Space-separated names of opt taking one argument <''>
28 ## 
29 ## 'extra'  , string : Name of nameless trailing arguments.             <''>
30 ## 
31 ## 'default', struct : Struct holding default option values           <none>
32 ## 
33 ## 'prefix' , int    : If false, only accept whole opt names. Otherwise, <0>
34 ##                     recognize opt from first chars, and choose 
35 ##                     shortest if many opts start alike.
36 ## 
37 ## 'nocase' , int    : If set, ignore case in option names               <0>
38 ## 
39 ## 'quiet'  , int    : Behavior when a non-string or unknown opt is met  <0>
40 ##              0    - Produce an error
41 ##              1    - Return quietly (can be diagnosed by checking 'nread')
42 ## 
43 ## 'skipnan', int    : Ignore NaNs if there is a default value.
44 ##     Note : At least one of 'op0' or 'op1' should be specified.
45 ## 
46 ## The output variables are,
47 ## @var{ops}      : struct : Struct whose key/values are option names/values
48 ## @var{nread}    : int    : Number of elements of args that were read
49 ##
50 ## USAGE 
51 ## @example
52 ## # Define options and defaults
53 ## op0 = "is_man is_plane flies"
54 ## default = struct ("is_man",1, "flies",0);
55 ##
56 ##                              # Read the options
57 ##
58 ## s = read_options (list (all_va_args), "op0",op0,"default",default)
59 ##
60 ##                              # Create variables w/ same name as options
61 ##
62 ## [is_man, is_plane, flies] = getfields (s,"is_man", "is_plane", "flies")
63 ## pre 2.1.39 function [op,nread] = read_options (args, ...)
64 ## @end example
65 ## @end deftypefn
66
67 function [op,nread] = read_options (args, varargin) ## pos 2.1.39
68
69   verbose = 0;
70
71   op = struct ();   # Empty struct
72   op0 = op1 = " ";
73   skipnan = prefix = quiet = nocase = quiet = 0;
74   extra = "";
75
76
77   nargs = nargin-1;  # nargin is now a function
78   if rem (nargs, 2), error ("odd number of optional args"); endif
79
80
81   i=1;
82   while i<nargs
83     if ! ischar (tmp = varargin{i}), error ("non-string option"); endif
84     i = i+1;
85     if     strcmp (tmp, "op0")    , op0     = varargin{i}; i=i+1;
86     elseif strcmp (tmp, "op1")    , op1     = varargin{i}; i=i+1;
87     elseif strcmp (tmp, "extra")  , extra   = varargin{i}; i=i+1;
88     elseif strcmp (tmp, "default"), op      = varargin{i}; i=i+1;
89     elseif strcmp (tmp, "prefix") , prefix  = varargin{i}; i=i+1;
90     elseif strcmp (tmp, "nocase") , nocase  = varargin{i}; i=i+1;
91     elseif strcmp (tmp, "quiet")  , quiet   = varargin{i}; i=i+1;
92     elseif strcmp (tmp, "skipnan"), skipnan = varargin{i}; i=i+1;
93     elseif strcmp (tmp, "verbose"), verbose = varargin{i}; i=i+1;
94     else 
95       error ("unknown option '%s' for option-reading function!",tmp);
96     endif
97   endwhile
98
99   if length (op0) + length (op1) < 3
100     error ("Either 'op0' or 'op1' should be specified");
101   endif
102
103   if length (op0)
104     if op0(1) != " ", op0 = [" ",op0]; endif
105     if op0(length(op0)) != " ", op0 = [op0," "]; endif
106   endif
107
108   if length (op1)
109     if op1(1) != " ", op1 = [" ",op1]; endif
110     if op1(length(op1)) != " ", op1 = [op1," "]; endif
111   endif
112
113   if length (extra)
114     lextra = lgrep (cellstr (strsplit (extra, " ")));
115   else
116     lextra = {};
117   endif
118
119   opts = [op0,op1];       # Join options
120                           # Before iend : opts w/out arg. After, opts
121   iend = length (op0);    # w/ arg
122
123   spi = find (opts == " ");
124
125   opts_orig = opts;
126
127   if nocase, opts = tolower (opts); endif
128
129
130   nread = 0;
131   optread = 0;
132   while nread < length (args)
133
134     oname = name = args{++nread};
135     if ! ischar (name)          # Whoa! Option name is not a string
136       
137       if !optread && length (lextra)
138         op.(lextra{1}) = args{nread};
139         lextra = lextra(2:length(lextra));
140         continue
141       elseif quiet, nread--; return;
142       else      error ("option name in pos %i is not a string",nread);
143       endif
144     else
145       optread = 1;
146     endif
147     if nocase, name = tolower (name); endif
148
149     ii = findstr ([" ",name], opts);
150     
151     if isempty (ii)             # Whoa! Unknown option name
152       if quiet, nread--; return;
153       else      error ("unknown option '%s'",oname);
154       endif
155     endif
156     ii++;
157
158     if length (ii) > 1          # Ambiguous option name
159
160       fullen = zeros (1,length (ii)); # Full length of each optio
161       tmp = correct = "";
162       j = 0;
163       for i = ii
164         fullen(++j) = spi(find (spi > i,1))-i ;
165         tmp = [tmp,"', '",opts(i:i+fullen(j)-1)];
166       endfor
167       tmp = tmp(5:length(tmp));
168
169       if sum (fullen == min (fullen)) > 1 || ...
170              ((min (fullen) != length(name)) && ! prefix) ,
171         error ("ambiguous option '%s'. Could be '%s'",oname,tmp);
172       endif
173       j = find (fullen == min (fullen), 1);
174       ii = ii(j);
175     endif
176
177             # Full name of option (w/ correct case)
178
179     fullname = opts_orig(ii:spi(find (spi > ii, 1))-1);
180     if ii < iend
181       if verbose, printf ("read_options : found boolean '%s'\n",fullname); endif
182       op.(fullname) = 1;
183     else
184       if verbose, printf ("read_options : found '%s'\n",fullname); endif
185       if nread < length (args)
186         tmp = args{++nread};
187         if verbose, printf ("read_options : size is %i x %i\n",size(tmp)); endif
188         if !isnumeric (tmp) || !all (isnan (tmp(:))) || ...
189            !isfield (op, fullname)
190           op.(fullname) =  tmp;
191         else
192           if verbose, printf ("read_options : ignoring nan\n"); endif
193         endif
194       else
195         error ("options end before I can read value of option '%s'",oname);
196       endif
197     endif
198   endwhile
199 endfunction