Mercurial > octave
comparison libinterp/corefcn/utils.cc @ 31607:aac27ad79be6 stable
maint: Re-indent code after switch to using namespace macros.
* build-env.h, build-env.in.cc, Cell.h, __betainc__.cc, __eigs__.cc,
__ftp__.cc, __ichol__.cc, __ilu__.cc, __isprimelarge__.cc, __magick_read__.cc,
__pchip_deriv__.cc, amd.cc, base-text-renderer.cc, base-text-renderer.h,
besselj.cc, bitfcns.cc, bsxfun.cc, c-file-ptr-stream.h, call-stack.cc,
call-stack.h, ccolamd.cc, cellfun.cc, chol.cc, colamd.cc, dasrt.cc, data.cc,
debug.cc, defaults.cc, defaults.h, det.cc, display.cc, display.h, dlmread.cc,
dynamic-ld.cc, dynamic-ld.h, ellipj.cc, environment.cc, environment.h,
error.cc, error.h, errwarn.h, event-manager.cc, event-manager.h,
event-queue.cc, event-queue.h, fcn-info.cc, fcn-info.h, fft.cc, fft2.cc,
file-io.cc, filter.cc, find.cc, ft-text-renderer.cc, ft-text-renderer.h,
gcd.cc, gl-render.cc, gl-render.h, gl2ps-print.cc, gl2ps-print.h,
graphics-toolkit.cc, graphics-toolkit.h, graphics.cc, gsvd.cc, gtk-manager.cc,
gtk-manager.h, help.cc, help.h, hook-fcn.cc, hook-fcn.h, input.cc, input.h,
interpreter-private.cc, interpreter-private.h, interpreter.cc, interpreter.h,
inv.cc, jsondecode.cc, jsonencode.cc, latex-text-renderer.cc,
latex-text-renderer.h, load-path.cc, load-path.h, load-save.cc, load-save.h,
lookup.cc, ls-hdf5.cc, ls-mat4.cc, ls-mat5.cc, lsode.cc, lu.cc, mappers.cc,
matrix_type.cc, max.cc, mex.cc, mexproto.h, mxarray.h, mxtypes.in.h,
oct-errno.in.cc, oct-hdf5-types.cc, oct-hist.cc, oct-hist.h, oct-map.cc,
oct-map.h, oct-opengl.h, oct-prcstrm.h, oct-process.cc, oct-process.h,
oct-stdstrm.h, oct-stream.cc, oct-stream.h, oct-strstrm.h,
octave-default-image.h, ordqz.cc, ordschur.cc, pager.cc, pager.h, pinv.cc,
pow2.cc, pr-output.cc, psi.cc, qr.cc, quadcc.cc, rand.cc, regexp.cc,
settings.cc, settings.h, sighandlers.cc, sighandlers.h, sparse-xpow.cc,
sqrtm.cc, stack-frame.cc, stack-frame.h, stream-euler.cc, strfns.cc, svd.cc,
syminfo.cc, syminfo.h, symrcm.cc, symrec.cc, symrec.h, symscope.cc, symscope.h,
symtab.cc, symtab.h, sysdep.cc, sysdep.h, text-engine.cc, text-engine.h,
text-renderer.cc, text-renderer.h, time.cc, toplev.cc, typecast.cc,
url-handle-manager.cc, url-handle-manager.h, urlwrite.cc, utils.cc, utils.h,
variables.cc, variables.h, xdiv.cc, __delaunayn__.cc, __init_fltk__.cc,
__init_gnuplot__.cc, __ode15__.cc, __voronoi__.cc, audioread.cc, convhulln.cc,
gzip.cc, cdef-class.cc, cdef-class.h, cdef-fwd.h, cdef-manager.cc,
cdef-manager.h, cdef-method.cc, cdef-method.h, cdef-object.cc, cdef-object.h,
cdef-package.cc, cdef-package.h, cdef-property.cc, cdef-property.h,
cdef-utils.cc, cdef-utils.h, ov-base-diag.cc, ov-base-int.cc, ov-base-mat.cc,
ov-base-mat.h, ov-base-scalar.cc, ov-base.cc, ov-base.h, ov-bool-mat.cc,
ov-bool-mat.h, ov-bool-sparse.cc, ov-bool.cc, ov-builtin.h, ov-cell.cc,
ov-ch-mat.cc, ov-class.cc, ov-class.h, ov-classdef.cc, ov-classdef.h,
ov-complex.cc, ov-cx-diag.cc, ov-cx-mat.cc, ov-cx-sparse.cc, ov-dld-fcn.cc,
ov-dld-fcn.h, ov-fcn-handle.cc, ov-fcn-handle.h, ov-fcn.h, ov-float.cc,
ov-flt-complex.cc, ov-flt-cx-diag.cc, ov-flt-cx-mat.cc, ov-flt-re-diag.cc,
ov-flt-re-mat.cc, ov-flt-re-mat.h, ov-intx.h, ov-java.cc, ov-lazy-idx.cc,
ov-legacy-range.cc, ov-magic-int.cc, ov-mex-fcn.cc, ov-mex-fcn.h,
ov-null-mat.cc, ov-perm.cc, ov-range.cc, ov-re-diag.cc, ov-re-mat.cc,
ov-re-mat.h, ov-re-sparse.cc, ov-scalar.cc, ov-str-mat.cc, ov-struct.cc,
ov-typeinfo.cc, ov-typeinfo.h, ov-usr-fcn.cc, ov-usr-fcn.h, ov.cc, ov.h, ovl.h,
octave.cc, octave.h, op-b-sbm.cc, op-bm-sbm.cc, op-cs-scm.cc, op-fm-fcm.cc,
op-fs-fcm.cc, op-s-scm.cc, op-scm-cs.cc, op-scm-s.cc, op-sm-cs.cc, ops.h,
anon-fcn-validator.cc, anon-fcn-validator.h, bp-table.cc, bp-table.h,
comment-list.cc, comment-list.h, filepos.h, lex.h, oct-lvalue.cc, oct-lvalue.h,
parse.h, profiler.cc, profiler.h, pt-anon-scopes.cc, pt-anon-scopes.h,
pt-arg-list.cc, pt-arg-list.h, pt-args-block.cc, pt-args-block.h,
pt-array-list.cc, pt-array-list.h, pt-assign.cc, pt-assign.h, pt-binop.cc,
pt-binop.h, pt-bp.cc, pt-bp.h, pt-cbinop.cc, pt-cbinop.h, pt-cell.cc,
pt-cell.h, pt-check.cc, pt-check.h, pt-classdef.cc, pt-classdef.h, pt-cmd.h,
pt-colon.cc, pt-colon.h, pt-const.cc, pt-const.h, pt-decl.cc, pt-decl.h,
pt-eval.cc, pt-eval.h, pt-except.cc, pt-except.h, pt-exp.cc, pt-exp.h,
pt-fcn-handle.cc, pt-fcn-handle.h, pt-id.cc, pt-id.h, pt-idx.cc, pt-idx.h,
pt-jump.h, pt-loop.cc, pt-loop.h, pt-mat.cc, pt-mat.h, pt-misc.cc, pt-misc.h,
pt-pr-code.cc, pt-pr-code.h, pt-select.cc, pt-select.h, pt-spmd.cc, pt-spmd.h,
pt-stmt.cc, pt-stmt.h, pt-tm-const.cc, pt-tm-const.h, pt-unop.cc, pt-unop.h,
pt-walk.cc, pt-walk.h, pt.cc, pt.h, token.cc, token.h, Range.cc, Range.h,
idx-vector.cc, idx-vector.h, range-fwd.h, CollocWt.cc, CollocWt.h,
aepbalance.cc, aepbalance.h, chol.cc, chol.h, gepbalance.cc, gepbalance.h,
gsvd.cc, gsvd.h, hess.cc, hess.h, lo-mappers.cc, lo-mappers.h, lo-specfun.cc,
lo-specfun.h, lu.cc, lu.h, oct-convn.cc, oct-convn.h, oct-fftw.cc, oct-fftw.h,
oct-norm.cc, oct-norm.h, oct-rand.cc, oct-rand.h, oct-spparms.cc,
oct-spparms.h, qr.cc, qr.h, qrp.cc, qrp.h, randgamma.cc, randgamma.h,
randmtzig.cc, randmtzig.h, randpoisson.cc, randpoisson.h, schur.cc, schur.h,
sparse-chol.cc, sparse-chol.h, sparse-lu.cc, sparse-lu.h, sparse-qr.cc,
sparse-qr.h, svd.cc, svd.h, child-list.cc, child-list.h, dir-ops.cc, dir-ops.h,
file-ops.cc, file-ops.h, file-stat.cc, file-stat.h, lo-sysdep.cc, lo-sysdep.h,
lo-sysinfo.cc, lo-sysinfo.h, mach-info.cc, mach-info.h, oct-env.cc, oct-env.h,
oct-group.cc, oct-group.h, oct-password.cc, oct-password.h, oct-syscalls.cc,
oct-syscalls.h, oct-time.cc, oct-time.h, oct-uname.cc, oct-uname.h,
action-container.cc, action-container.h, base-list.h, cmd-edit.cc, cmd-edit.h,
cmd-hist.cc, cmd-hist.h, f77-fcn.h, file-info.cc, file-info.h,
lo-array-errwarn.cc, lo-array-errwarn.h, lo-hash.cc, lo-hash.h, lo-ieee.h,
lo-regexp.cc, lo-regexp.h, lo-utils.cc, lo-utils.h, oct-base64.cc,
oct-base64.h, oct-glob.cc, oct-glob.h, oct-inttypes.h, oct-mutex.cc,
oct-mutex.h, oct-refcount.h, oct-shlib.cc, oct-shlib.h, oct-sparse.cc,
oct-sparse.h, oct-string.h, octave-preserve-stream-state.h, pathsearch.cc,
pathsearch.h, quit.cc, quit.h, unwind-prot.cc, unwind-prot.h, url-transfer.cc,
url-transfer.h:
Re-indent code after switch to using namespace macros.
author | Rik <rik@octave.org> |
---|---|
date | Thu, 01 Dec 2022 18:02:15 -0800 |
parents | e88a07dec498 |
children | 597f3ee61a48 |
comparison
equal
deleted
inserted
replaced
31605:e88a07dec498 | 31607:aac27ad79be6 |
---|---|
71 #include "utils.h" | 71 #include "utils.h" |
72 #include "variables.h" | 72 #include "variables.h" |
73 | 73 |
74 OCTAVE_BEGIN_NAMESPACE(octave) | 74 OCTAVE_BEGIN_NAMESPACE(octave) |
75 | 75 |
76 // Return TRUE if S is a valid identifier. | 76 // Return TRUE if S is a valid identifier. |
77 | 77 |
78 bool valid_identifier (const char *s) | 78 bool valid_identifier (const char *s) |
79 { | 79 { |
80 if (! s || ! (isalpha (*s) || *s == '_')) | 80 if (! s || ! (isalpha (*s) || *s == '_')) |
81 return false; | |
82 | |
83 while (*++s != '\0') | |
84 if (! (isalnum (*s) || *s == '_')) | |
81 return false; | 85 return false; |
82 | 86 |
83 while (*++s != '\0') | 87 return true; |
84 if (! (isalnum (*s) || *s == '_')) | 88 } |
85 return false; | 89 |
86 | 90 bool valid_identifier (const std::string& s) |
87 return true; | 91 { |
88 } | 92 return valid_identifier (s.c_str ()); |
89 | 93 } |
90 bool valid_identifier (const std::string& s) | |
91 { | |
92 return valid_identifier (s.c_str ()); | |
93 } | |
94 | 94 |
95 DEFUN (isvarname, args, , | 95 DEFUN (isvarname, args, , |
96 doc: /* -*- texinfo -*- | 96 doc: /* -*- texinfo -*- |
97 @deftypefn {} {@var{tf} =} isvarname (@var{name}) | 97 @deftypefn {} {@var{tf} =} isvarname (@var{name}) |
98 Return true if @var{name} is a valid variable name. | 98 Return true if @var{name} is a valid variable name. |
129 | 129 |
130 %!error isvarname () | 130 %!error isvarname () |
131 %!error isvarname ("foo", "bar") | 131 %!error isvarname ("foo", "bar") |
132 */ | 132 */ |
133 | 133 |
134 bool | 134 bool |
135 make_valid_name (std::string& str, const make_valid_name_options& options) | 135 make_valid_name (std::string& str, const make_valid_name_options& options) |
136 { | 136 { |
137 // If `isvarname (str)`, no modifications necessary. | 137 // If `isvarname (str)`, no modifications necessary. |
138 if (valid_identifier (str) && ! iskeyword (str)) | 138 if (valid_identifier (str) && ! iskeyword (str)) |
139 return false; | 139 return false; |
140 | 140 |
141 // Change whitespace followed by lowercase letter to uppercase, except | 141 // Change whitespace followed by lowercase letter to uppercase, except |
142 // for the first | 142 // for the first |
143 bool previous = false; | 143 bool previous = false; |
144 bool any_non_space = false; | 144 bool any_non_space = false; |
145 for (char& c : str) | |
146 { | |
147 c = ((any_non_space && previous && std::isalpha (c)) ? std::toupper (c) | |
148 : c); | |
149 previous = std::isspace (c); | |
150 any_non_space |= (! previous); // once true, always true | |
151 } | |
152 | |
153 // Remove any whitespace. | |
154 str.erase (std::remove_if (str.begin(), str.end(), | |
155 [] (unsigned char x) | |
156 { return std::isspace(x); }), | |
157 str.end()); | |
158 if (str.empty ()) | |
159 str = options.get_prefix (); | |
160 | |
161 // Add prefix and capitalize first character, if `str` is a reserved | |
162 // keyword. | |
163 if (iskeyword (str)) | |
164 { | |
165 str[0] = std::toupper (str[0]); | |
166 str = options.get_prefix () + str; | |
167 } | |
168 | |
169 // Add prefix if first character is not a letter or underscore. | |
170 if (! std::isalpha (str[0]) && str[0] != '_') | |
171 str = options.get_prefix () + str; | |
172 | |
173 // Replace non alphanumerics or underscores | |
174 if (options.get_replacement_style () == "underscore") | |
145 for (char& c : str) | 175 for (char& c : str) |
146 { | 176 c = (std::isalnum (c) ? c : '_'); |
147 c = ((any_non_space && previous && std::isalpha (c)) ? std::toupper (c) | 177 else if (options.get_replacement_style () == "delete") |
148 : c); | |
149 previous = std::isspace (c); | |
150 any_non_space |= (! previous); // once true, always true | |
151 } | |
152 | |
153 // Remove any whitespace. | |
154 str.erase (std::remove_if (str.begin(), str.end(), | 178 str.erase (std::remove_if (str.begin(), str.end(), |
155 [] (unsigned char x) | 179 [] (unsigned char x) |
156 { return std::isspace(x); }), | 180 { return ! std::isalnum (x) && x != '_'; }), |
157 str.end()); | 181 str.end()); |
158 if (str.empty ()) | 182 else if (options.get_replacement_style () == "hex") |
159 str = options.get_prefix (); | 183 { |
160 | 184 const std::string permitted_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
161 // Add prefix and capitalize first character, if `str` is a reserved | 185 "abcdefghijklmnopqrstuvwxyz" |
162 // keyword. | 186 "_0123456789"; |
163 if (iskeyword (str)) | 187 // Get the first non-permitted char. |
164 { | 188 std::size_t pos = str.find_first_not_of (permitted_chars); |
165 str[0] = std::toupper (str[0]); | 189 // Buffer for hex string "0xFF" (+1 for null terminator). |
166 str = options.get_prefix () + str; | 190 char hex_str[5]; |
167 } | 191 // Repeat until end of string. |
168 | 192 while (pos != std::string::npos) |
169 // Add prefix if first character is not a letter or underscore. | 193 { |
170 if (! std::isalpha (str[0]) && str[0] != '_') | 194 // Replace non-permitted char by it's hex value. |
171 str = options.get_prefix () + str; | 195 std::snprintf (hex_str, sizeof (hex_str), "0x%02X", str[pos]); |
172 | 196 str.replace (pos, 1, hex_str); |
173 // Replace non alphanumerics or underscores | 197 // Get the next occurrence from the last position. |
174 if (options.get_replacement_style () == "underscore") | 198 // (-1 for null terminator) |
175 for (char& c : str) | 199 pos = str.find_first_not_of (permitted_chars, |
176 c = (std::isalnum (c) ? c : '_'); | 200 pos + sizeof (hex_str) - 1); |
177 else if (options.get_replacement_style () == "delete") | 201 } |
178 str.erase (std::remove_if (str.begin(), str.end(), | 202 } |
179 [] (unsigned char x) | 203 |
180 { return ! std::isalnum (x) && x != '_'; }), | 204 return true; |
181 str.end()); | 205 } |
182 else if (options.get_replacement_style () == "hex") | 206 |
183 { | 207 make_valid_name_options::make_valid_name_options |
184 const std::string permitted_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | 208 (const octave_value_list& args) |
185 "abcdefghijklmnopqrstuvwxyz" | 209 { |
186 "_0123456789"; | 210 auto nargs = args.length (); |
187 // Get the first non-permitted char. | 211 if (nargs == 0) |
188 std::size_t pos = str.find_first_not_of (permitted_chars); | 212 return; |
189 // Buffer for hex string "0xFF" (+1 for null terminator). | 213 |
190 char hex_str[5]; | 214 // nargs = 2, 4, 6, ... permitted |
191 // Repeat until end of string. | 215 if (nargs % 2) |
192 while (pos != std::string::npos) | 216 error ("makeValidName: property/value options must occur in pairs"); |
193 { | 217 |
194 // Replace non-permitted char by it's hex value. | 218 auto str_to_lower = [] (std::string& s) |
195 std::snprintf (hex_str, sizeof (hex_str), "0x%02X", str[pos]); | |
196 str.replace (pos, 1, hex_str); | |
197 // Get the next occurrence from the last position. | |
198 // (-1 for null terminator) | |
199 pos = str.find_first_not_of (permitted_chars, | |
200 pos + sizeof (hex_str) - 1); | |
201 } | |
202 } | |
203 | |
204 return true; | |
205 } | |
206 | |
207 make_valid_name_options::make_valid_name_options | |
208 (const octave_value_list& args) | |
209 { | 219 { |
210 auto nargs = args.length (); | 220 std::transform (s.begin(), s.end(), s.begin(), |
211 if (nargs == 0) | 221 [] (unsigned char c) |
212 return; | 222 { return std::tolower(c); }); |
213 | 223 }; |
214 // nargs = 2, 4, 6, ... permitted | 224 |
215 if (nargs % 2) | 225 for (auto i = 0; i < nargs; i = i + 2) |
216 error ("makeValidName: property/value options must occur in pairs"); | 226 { |
217 | 227 std::string parameter = args(i).xstring_value ("makeValidName: " |
218 auto str_to_lower = [] (std::string& s) | 228 "option argument must be a string"); |
219 { | 229 str_to_lower (parameter); |
220 std::transform (s.begin(), s.end(), s.begin(), | 230 if (parameter == "replacementstyle") |
221 [] (unsigned char c) | 231 { |
222 { return std::tolower(c); }); | 232 m_replacement_style = args(i + 1).xstring_value ("makeValidName: " |
223 }; | 233 "'ReplacementStyle' value must be a string"); |
224 | 234 str_to_lower (m_replacement_style); |
225 for (auto i = 0; i < nargs; i = i + 2) | 235 if ((m_replacement_style != "underscore") |
226 { | 236 && (m_replacement_style != "delete") |
227 std::string parameter = args(i).xstring_value ("makeValidName: " | 237 && (m_replacement_style != "hex")) |
228 "option argument must be a string"); | 238 error ("makeValidName: invalid 'ReplacementStyle' value '%s'", |
229 str_to_lower (parameter); | 239 m_replacement_style.c_str ()); |
230 if (parameter == "replacementstyle") | 240 } |
231 { | 241 else if (parameter == "prefix") |
232 m_replacement_style = args(i + 1).xstring_value ("makeValidName: " | 242 { |
233 "'ReplacementStyle' value must be a string"); | 243 m_prefix = args(i + 1).xstring_value ("makeValidName: " |
234 str_to_lower (m_replacement_style); | 244 "'Prefix' value must be a string"); |
235 if ((m_replacement_style != "underscore") | 245 if (! valid_identifier (m_prefix) |
236 && (m_replacement_style != "delete") | 246 || iskeyword (m_prefix)) |
237 && (m_replacement_style != "hex")) | 247 error ("makeValidName: invalid 'Prefix' value '%s'", |
238 error ("makeValidName: invalid 'ReplacementStyle' value '%s'", | 248 m_prefix.c_str ()); |
239 m_replacement_style.c_str ()); | 249 } |
240 } | 250 else |
241 else if (parameter == "prefix") | 251 error ("makeValidName: unknown property '%s'", parameter.c_str ()); |
242 { | 252 } |
243 m_prefix = args(i + 1).xstring_value ("makeValidName: " | 253 } |
244 "'Prefix' value must be a string"); | |
245 if (! valid_identifier (m_prefix) | |
246 || iskeyword (m_prefix)) | |
247 error ("makeValidName: invalid 'Prefix' value '%s'", | |
248 m_prefix.c_str ()); | |
249 } | |
250 else | |
251 error ("makeValidName: unknown property '%s'", parameter.c_str ()); | |
252 } | |
253 } | |
254 | 254 |
255 DEFUN (__make_valid_name__, args, , | 255 DEFUN (__make_valid_name__, args, , |
256 doc: /* -*- texinfo -*- | 256 doc: /* -*- texinfo -*- |
257 @deftypefn {} {@var{varname} =} __make_valid_name__ (@var{str}) | 257 @deftypefn {} {@var{varname} =} __make_valid_name__ (@var{str}) |
258 @deftypefnx {} {@var{varname} =} __make_valid_name__ (@var{str}, @qcode{"ReplacementStyle"}) | 258 @deftypefnx {} {@var{varname} =} __make_valid_name__ (@var{str}, @qcode{"ReplacementStyle"}) |
287 } | 287 } |
288 else | 288 else |
289 error ("makeValidName: STR must be a string or cellstr"); | 289 error ("makeValidName: STR must be a string or cellstr"); |
290 } | 290 } |
291 | 291 |
292 // Return TRUE if F and G are both names for the same file. | 292 // Return TRUE if F and G are both names for the same file. |
293 | 293 |
294 bool same_file (const std::string& f, const std::string& g) | 294 bool same_file (const std::string& f, const std::string& g) |
295 { | 295 { |
296 return same_file_internal (f, g); | 296 return same_file_internal (f, g); |
297 } | 297 } |
298 | 298 |
299 DEFUN (is_same_file, args, , | 299 DEFUN (is_same_file, args, , |
300 doc: /* -*- texinfo -*- | 300 doc: /* -*- texinfo -*- |
301 @deftypefn {} {@var{same} =} is_same_file (@var{filepath1}, @var{filepath2}) | 301 @deftypefn {} {@var{same} =} is_same_file (@var{filepath1}, @var{filepath2}) |
302 Return true if @var{filepath1} and @var{filepath2} refer to the same file. | 302 Return true if @var{filepath1} and @var{filepath2} refer to the same file. |
403 %!error <must be strings or cell arrays of strings> is_same_file ("foo", {1}) | 403 %!error <must be strings or cell arrays of strings> is_same_file ("foo", {1}) |
404 %!error <must be strings or cell arrays of strings> is_same_file ({1}, "foo") | 404 %!error <must be strings or cell arrays of strings> is_same_file ({1}, "foo") |
405 %!error <arrays .* must be the same size> is_same_file ({"1", "2"}, {"1"; "2"}) | 405 %!error <arrays .* must be the same size> is_same_file ({"1", "2"}, {"1"; "2"}) |
406 */ | 406 */ |
407 | 407 |
408 int almost_match (const std::string& std, const std::string& s, | 408 int almost_match (const std::string& std, const std::string& s, |
409 int min_match_len, int case_sens) | 409 int min_match_len, int case_sens) |
410 { | 410 { |
411 int stdlen = std.length (); | 411 int stdlen = std.length (); |
412 int slen = s.length (); | 412 int slen = s.length (); |
413 | 413 |
414 return (slen <= stdlen | 414 return (slen <= stdlen |
415 && slen >= min_match_len | 415 && slen >= min_match_len |
416 && (case_sens | 416 && (case_sens |
417 ? (strncmp (std.c_str (), s.c_str (), slen) == 0) | 417 ? (strncmp (std.c_str (), s.c_str (), slen) == 0) |
418 : (octave_strncasecmp (std.c_str (), s.c_str (), slen) == 0))); | 418 : (octave_strncasecmp (std.c_str (), s.c_str (), slen) == 0))); |
419 } | 419 } |
420 | 420 |
421 // Ugh. | 421 // Ugh. |
422 | 422 |
423 int keyword_almost_match (const char * const *std, int *min_len, | 423 int keyword_almost_match (const char *const *std, int *min_len, |
424 const std::string& s, | 424 const std::string& s, |
425 int min_toks_to_match, int max_toks) | 425 int min_toks_to_match, int max_toks) |
426 { | 426 { |
427 int status = 0; | 427 int status = 0; |
428 int tok_count = 0; | 428 int tok_count = 0; |
429 int toks_matched = 0; | 429 int toks_matched = 0; |
430 | 430 |
431 if (s.empty () || max_toks < 1) | 431 if (s.empty () || max_toks < 1) |
432 return status; | 432 return status; |
433 | 433 |
434 char *kw = strsave (s.c_str ()); | 434 char *kw = strsave (s.c_str ()); |
435 | 435 |
436 char *t = kw; | 436 char *t = kw; |
437 while (*t != '\0') | 437 while (*t != '\0') |
438 { | 438 { |
439 if (*t == '\t') | 439 if (*t == '\t') |
440 *t = ' '; | 440 *t = ' '; |
441 t++; | 441 t++; |
442 } | 442 } |
443 | 443 |
444 char *beg = kw; | 444 char *beg = kw; |
445 while (*beg == ' ') | 445 while (*beg == ' ') |
446 beg++; | 446 beg++; |
447 | 447 |
448 if (*beg == '\0') | 448 if (*beg == '\0') |
449 return status; | 449 return status; |
450 | 450 |
451 const char **to_match = new const char * [max_toks + 1]; | 451 const char **to_match = new const char *[max_toks + 1]; |
452 const char * const *s1 = std; | 452 const char *const *s1 = std; |
453 const char **s2 = to_match; | 453 const char **s2 = to_match; |
454 | 454 |
455 if (! s1 || ! s2) | 455 if (! s1 || ! s2) |
456 goto done; | 456 goto done; |
457 | 457 |
458 s2[tok_count] = beg; | 458 s2[tok_count] = beg; |
459 char *end; | 459 char *end; |
460 while ((end = strchr (beg, ' ')) != nullptr) | 460 while ((end = strchr (beg, ' ')) != nullptr) |
461 { | 461 { |
462 *end = '\0'; | 462 *end = '\0'; |
463 beg = end + 1; | 463 beg = end + 1; |
464 | 464 |
465 while (*beg == ' ') | 465 while (*beg == ' ') |
466 beg++; | 466 beg++; |
467 | 467 |
468 if (*beg == '\0') | 468 if (*beg == '\0') |
469 break; | 469 break; |
470 | 470 |
471 tok_count++; | 471 tok_count++; |
472 if (tok_count >= max_toks) | 472 if (tok_count >= max_toks) |
473 goto done; | |
474 | |
475 s2[tok_count] = beg; | |
476 } | |
477 s2[tok_count+1] = nullptr; | |
478 | |
479 s2 = to_match; | |
480 | |
481 for (;;) | |
482 { | |
483 if (! almost_match (*s1, *s2, min_len[toks_matched], 0)) | |
484 goto done; | |
485 | |
486 toks_matched++; | |
487 | |
488 s1++; | |
489 s2++; | |
490 | |
491 if (! *s2) | |
492 { | |
493 status = (toks_matched >= min_toks_to_match); | |
473 goto done; | 494 goto done; |
474 | 495 } |
475 s2[tok_count] = beg; | 496 |
476 } | 497 if (! *s1) |
477 s2[tok_count+1] = nullptr; | 498 goto done; |
478 | 499 } |
479 s2 = to_match; | 500 |
480 | 501 done: |
481 for (;;) | 502 |
482 { | 503 delete [] kw; |
483 if (! almost_match (*s1, *s2, min_len[toks_matched], 0)) | 504 delete [] to_match; |
484 goto done; | 505 |
485 | 506 return status; |
486 toks_matched++; | 507 } |
487 | 508 |
488 s1++; | 509 // See if the given file is in the path. |
489 s2++; | 510 |
490 | 511 std::string search_path_for_file (const std::string& path, |
491 if (! *s2) | 512 const string_vector& names) |
492 { | 513 { |
493 status = (toks_matched >= min_toks_to_match); | 514 directory_path p (path); |
494 goto done; | 515 |
495 } | 516 return sys::env::make_absolute (p.find_first_of (names.std_list ())); |
496 | 517 } |
497 if (! *s1) | 518 |
498 goto done; | 519 // Find all locations of the given file in the path. |
499 } | 520 |
500 | 521 string_vector search_path_for_all_files (const std::string& path, |
501 done: | 522 const string_vector& names) |
502 | 523 { |
503 delete [] kw; | 524 directory_path p (path); |
504 delete [] to_match; | 525 |
505 | 526 string_vector sv = p.find_all_first_of (names.std_list ()); |
506 return status; | 527 |
507 } | 528 octave_idx_type len = sv.numel (); |
508 | 529 |
509 // See if the given file is in the path. | 530 for (octave_idx_type i = 0; i < len; i++) |
510 | 531 sv[i] = sys::env::make_absolute (sv[i]); |
511 std::string search_path_for_file (const std::string& path, | 532 |
512 const string_vector& names) | 533 return sv; |
513 { | 534 } |
514 directory_path p (path); | 535 |
515 | 536 static string_vector make_absolute (const string_vector& sv) |
516 return sys::env::make_absolute (p.find_first_of (names.std_list ())); | 537 { |
517 } | 538 octave_idx_type len = sv.numel (); |
518 | 539 |
519 // Find all locations of the given file in the path. | 540 string_vector retval (len); |
520 | 541 |
521 string_vector search_path_for_all_files (const std::string& path, | 542 for (octave_idx_type i = 0; i < len; i++) |
522 const string_vector& names) | 543 retval[i] = sys::env::make_absolute (sv[i]); |
523 { | 544 |
524 directory_path p (path); | 545 return retval; |
525 | 546 } |
526 string_vector sv = p.find_all_first_of (names.std_list ()); | |
527 | |
528 octave_idx_type len = sv.numel (); | |
529 | |
530 for (octave_idx_type i = 0; i < len; i++) | |
531 sv[i] = sys::env::make_absolute (sv[i]); | |
532 | |
533 return sv; | |
534 } | |
535 | |
536 static string_vector make_absolute (const string_vector& sv) | |
537 { | |
538 octave_idx_type len = sv.numel (); | |
539 | |
540 string_vector retval (len); | |
541 | |
542 for (octave_idx_type i = 0; i < len; i++) | |
543 retval[i] = sys::env::make_absolute (sv[i]); | |
544 | |
545 return retval; | |
546 } | |
547 | 547 |
548 DEFMETHOD (file_in_loadpath, interp, args, , | 548 DEFMETHOD (file_in_loadpath, interp, args, , |
549 doc: /* -*- texinfo -*- | 549 doc: /* -*- texinfo -*- |
550 @deftypefn {} {@var{fname} =} file_in_loadpath (@var{file}) | 550 @deftypefn {} {@var{fname} =} file_in_loadpath (@var{file}) |
551 @deftypefnx {} {@var{fname} =} file_in_loadpath (@var{file}, "all") | 551 @deftypefnx {} {@var{fname} =} file_in_loadpath (@var{file}, "all") |
571 int nargin = args.length (); | 571 int nargin = args.length (); |
572 | 572 |
573 if (nargin < 1 || nargin > 2) | 573 if (nargin < 1 || nargin > 2) |
574 print_usage (); | 574 print_usage (); |
575 | 575 |
576 string_vector names = args(0).xstring_vector_value ("file_in_loadpath: FILE argument must be a string"); | 576 string_vector names = args( |
577 0).xstring_vector_value ("file_in_loadpath: FILE argument must be a string"); | |
577 | 578 |
578 if (names.empty ()) | 579 if (names.empty ()) |
579 error ("file_in_loadpath: FILE argument must not be empty"); | 580 error ("file_in_loadpath: FILE argument must not be empty"); |
580 | 581 |
581 load_path& lp = interp.get_load_path (); | 582 load_path& lp = interp.get_load_path (); |
582 | 583 |
583 if (nargin == 1) | 584 if (nargin == 1) |
584 return ovl (sys::env::make_absolute (lp.find_first_of (names))); | 585 return ovl (sys::env::make_absolute (lp.find_first_of (names))); |
585 else | 586 else |
586 { | 587 { |
587 std::string opt = args(1).xstring_value ("file_in_loadpath: optional second argument must be a string"); | 588 std::string opt = args( |
589 1).xstring_value ("file_in_loadpath: optional second argument must be a string"); | |
588 | 590 |
589 if (opt != "all") | 591 if (opt != "all") |
590 error (R"(file_in_loadpath: "all" is only valid second argument)"); | 592 error (R"(file_in_loadpath: "all" is only valid second argument)"); |
591 | 593 |
592 return ovl (Cell (make_absolute (lp.find_all_first_of (names)))); | 594 return ovl (Cell (make_absolute (lp.find_all_first_of (names)))); |
684 %!error file_in_path ([]) | 686 %!error file_in_path ([]) |
685 %!error file_in_path (path (), []) | 687 %!error file_in_path (path (), []) |
686 %!error file_in_path (path (), "plot.m", "bar") | 688 %!error file_in_path (path (), "plot.m", "bar") |
687 */ | 689 */ |
688 | 690 |
689 std::string file_in_path (const std::string& name, const std::string& suffix) | 691 std::string file_in_path (const std::string& name, const std::string& suffix) |
690 { | 692 { |
691 std::string nm = name; | 693 std::string nm = name; |
692 | 694 |
693 if (! suffix.empty ()) | 695 if (! suffix.empty ()) |
694 nm.append (suffix); | 696 nm.append (suffix); |
695 | 697 |
696 load_path& lp = __get_load_path__ (); | 698 load_path& lp = __get_load_path__ (); |
697 | 699 |
698 return sys::env::make_absolute (lp.find_file (nm)); | 700 return sys::env::make_absolute (lp.find_file (nm)); |
699 } | 701 } |
700 | 702 |
701 std::string find_data_file_in_load_path (const std::string& fcn, | 703 std::string find_data_file_in_load_path (const std::string& fcn, |
702 const std::string& file, | 704 const std::string& file, |
703 bool require_regular_file) | 705 bool require_regular_file) |
704 { | 706 { |
705 std::string fname = file; | 707 std::string fname = file; |
706 | 708 |
707 if (! (sys::env::absolute_pathname (fname) | 709 if (! (sys::env::absolute_pathname (fname) |
708 || sys::env::rooted_relative_pathname (fname))) | 710 || sys::env::rooted_relative_pathname (fname))) |
709 { | 711 { |
710 // Load path will also search "." first, but we don't want to | 712 // Load path will also search "." first, but we don't want to |
711 // issue a warning if the file is found in the current directory, | 713 // issue a warning if the file is found in the current directory, |
712 // so do an explicit check for that. | 714 // so do an explicit check for that. |
713 sys::file_stat fs (fname); | 715 sys::file_stat fs (fname); |
714 | 716 |
715 bool local_file_ok | 717 bool local_file_ok |
716 = fs.exists () && (fs.is_reg () || ! require_regular_file); | 718 = fs.exists () && (fs.is_reg () || ! require_regular_file); |
717 | 719 |
718 if (! local_file_ok) | 720 if (! local_file_ok) |
719 { | 721 { |
720 load_path& lp = __get_load_path__ (); | 722 load_path& lp = __get_load_path__ (); |
721 | 723 |
722 // Not directly found; search load path. | 724 // Not directly found; search load path. |
723 std::string tmp = sys::env::make_absolute (lp.find_file (fname)); | 725 std::string tmp = sys::env::make_absolute (lp.find_file (fname)); |
724 | 726 |
725 if (! tmp.empty ()) | 727 if (! tmp.empty ()) |
728 { | |
729 warn_data_file_in_path (fcn, tmp); | |
730 | |
731 fname = tmp; | |
732 } | |
733 } | |
734 } | |
735 | |
736 return fname; | |
737 } | |
738 | |
739 // See if there is an function file in the path. | |
740 // If so, return the full path to the file. | |
741 | |
742 std::string fcn_file_in_path (const std::string& name) | |
743 { | |
744 std::string retval; | |
745 | |
746 int len = name.length (); | |
747 | |
748 if (len > 0) | |
749 { | |
750 if (sys::env::absolute_pathname (name)) | |
751 { | |
752 sys::file_stat fs (name); | |
753 | |
754 if (fs.exists () && ! fs.is_dir ()) | |
755 retval = name; | |
756 } | |
757 else if (len > 2 && name[len - 2] == '.' && name[len - 1] == 'm') | |
758 { | |
759 load_path& lp = __get_load_path__ (); | |
760 | |
761 retval = lp.find_fcn_file (name.substr (0, len-2)); | |
762 } | |
763 else | |
764 { | |
765 std::string fname = name; | |
766 std::size_t pos = name.find_first_of ('>'); | |
767 if (pos != std::string::npos) | |
768 fname = name.substr (0, pos); | |
769 | |
770 load_path& lp = __get_load_path__ (); | |
771 | |
772 retval = lp.find_fcn_file (fname); | |
773 } | |
774 } | |
775 | |
776 return retval; | |
777 } | |
778 | |
779 // See if there is a directory called "name" in the path and if it | |
780 // contains a Contents.m file. If so, return the full path to this file. | |
781 | |
782 std::string contents_file_in_path (const std::string& dir) | |
783 { | |
784 std::string retval; | |
785 | |
786 if (! dir.empty ()) | |
787 { | |
788 load_path& lp = __get_load_path__ (); | |
789 | |
790 std::string tcontents | |
791 = sys::file_ops::concat (lp.find_dir (dir), "Contents.m"); | |
792 | |
793 sys::file_stat fs (tcontents); | |
794 | |
795 if (fs.exists ()) | |
796 retval = sys::env::make_absolute (tcontents); | |
797 } | |
798 | |
799 return retval; | |
800 } | |
801 | |
802 // Replace backslash escapes in a string with the real values. | |
803 | |
804 std::string do_string_escapes (const std::string& s) | |
805 { | |
806 std::string retval; | |
807 | |
808 std::size_t i = 0; | |
809 std::size_t j = 0; | |
810 std::size_t len = s.length (); | |
811 | |
812 retval.resize (len); | |
813 | |
814 while (j < len) | |
815 { | |
816 if (s[j] == '\\' && j+1 < len) | |
817 { | |
818 switch (s[++j]) | |
819 { | |
820 case 'a': // alarm | |
821 retval[i] = '\a'; | |
822 break; | |
823 | |
824 case 'b': // backspace | |
825 retval[i] = '\b'; | |
826 break; | |
827 | |
828 case 'f': // formfeed | |
829 retval[i] = '\f'; | |
830 break; | |
831 | |
832 case 'n': // newline | |
833 retval[i] = '\n'; | |
834 break; | |
835 | |
836 case 'r': // carriage return | |
837 retval[i] = '\r'; | |
838 break; | |
839 | |
840 case 't': // horizontal tab | |
841 retval[i] = '\t'; | |
842 break; | |
843 | |
844 case 'v': // vertical tab | |
845 retval[i] = '\v'; | |
846 break; | |
847 | |
848 case '\\': // backslash | |
849 retval[i] = '\\'; | |
850 break; | |
851 | |
852 case '\'': // quote | |
853 retval[i] = '\''; | |
854 break; | |
855 | |
856 case '"': // double quote | |
857 retval[i] = '"'; | |
858 break; | |
859 | |
860 case '0': | |
861 case '1': | |
862 case '2': | |
863 case '3': | |
864 case '4': | |
865 case '5': | |
866 case '6': | |
867 case '7': // octal input | |
726 { | 868 { |
727 warn_data_file_in_path (fcn, tmp); | 869 std::size_t k; |
728 | 870 int tmpi = s[j] - '0'; |
729 fname = tmp; | 871 for (k = j+1; k < std::min (j+3, len); k++) |
730 } | 872 { |
731 } | 873 int digit = s[k] - '0'; |
732 } | 874 if (digit < 0 || digit > 7) |
733 | 875 break; |
734 return fname; | 876 tmpi <<= 3; |
735 } | 877 tmpi += digit; |
736 | 878 } |
737 // See if there is an function file in the path. | 879 retval[i] = tmpi; |
738 // If so, return the full path to the file. | 880 j = k - 1; |
739 | |
740 std::string fcn_file_in_path (const std::string& name) | |
741 { | |
742 std::string retval; | |
743 | |
744 int len = name.length (); | |
745 | |
746 if (len > 0) | |
747 { | |
748 if (sys::env::absolute_pathname (name)) | |
749 { | |
750 sys::file_stat fs (name); | |
751 | |
752 if (fs.exists () && ! fs.is_dir ()) | |
753 retval = name; | |
754 } | |
755 else if (len > 2 && name[len - 2] == '.' && name[len - 1] == 'm') | |
756 { | |
757 load_path& lp = __get_load_path__ (); | |
758 | |
759 retval = lp.find_fcn_file (name.substr (0, len-2)); | |
760 } | |
761 else | |
762 { | |
763 std::string fname = name; | |
764 std::size_t pos = name.find_first_of ('>'); | |
765 if (pos != std::string::npos) | |
766 fname = name.substr (0, pos); | |
767 | |
768 load_path& lp = __get_load_path__ (); | |
769 | |
770 retval = lp.find_fcn_file (fname); | |
771 } | |
772 } | |
773 | |
774 return retval; | |
775 } | |
776 | |
777 // See if there is a directory called "name" in the path and if it | |
778 // contains a Contents.m file. If so, return the full path to this file. | |
779 | |
780 std::string contents_file_in_path (const std::string& dir) | |
781 { | |
782 std::string retval; | |
783 | |
784 if (! dir.empty ()) | |
785 { | |
786 load_path& lp = __get_load_path__ (); | |
787 | |
788 std::string tcontents | |
789 = sys::file_ops::concat (lp.find_dir (dir), "Contents.m"); | |
790 | |
791 sys::file_stat fs (tcontents); | |
792 | |
793 if (fs.exists ()) | |
794 retval = sys::env::make_absolute (tcontents); | |
795 } | |
796 | |
797 return retval; | |
798 } | |
799 | |
800 // Replace backslash escapes in a string with the real values. | |
801 | |
802 std::string do_string_escapes (const std::string& s) | |
803 { | |
804 std::string retval; | |
805 | |
806 std::size_t i = 0; | |
807 std::size_t j = 0; | |
808 std::size_t len = s.length (); | |
809 | |
810 retval.resize (len); | |
811 | |
812 while (j < len) | |
813 { | |
814 if (s[j] == '\\' && j+1 < len) | |
815 { | |
816 switch (s[++j]) | |
817 { | |
818 case 'a': // alarm | |
819 retval[i] = '\a'; | |
820 break; | |
821 | |
822 case 'b': // backspace | |
823 retval[i] = '\b'; | |
824 break; | |
825 | |
826 case 'f': // formfeed | |
827 retval[i] = '\f'; | |
828 break; | |
829 | |
830 case 'n': // newline | |
831 retval[i] = '\n'; | |
832 break; | |
833 | |
834 case 'r': // carriage return | |
835 retval[i] = '\r'; | |
836 break; | |
837 | |
838 case 't': // horizontal tab | |
839 retval[i] = '\t'; | |
840 break; | |
841 | |
842 case 'v': // vertical tab | |
843 retval[i] = '\v'; | |
844 break; | |
845 | |
846 case '\\': // backslash | |
847 retval[i] = '\\'; | |
848 break; | |
849 | |
850 case '\'': // quote | |
851 retval[i] = '\''; | |
852 break; | |
853 | |
854 case '"': // double quote | |
855 retval[i] = '"'; | |
856 break; | |
857 | |
858 case '0': | |
859 case '1': | |
860 case '2': | |
861 case '3': | |
862 case '4': | |
863 case '5': | |
864 case '6': | |
865 case '7': // octal input | |
866 { | |
867 std::size_t k; | |
868 int tmpi = s[j] - '0'; | |
869 for (k = j+1; k < std::min (j+3, len); k++) | |
870 { | |
871 int digit = s[k] - '0'; | |
872 if (digit < 0 || digit > 7) | |
873 break; | |
874 tmpi <<= 3; | |
875 tmpi += digit; | |
876 } | |
877 retval[i] = tmpi; | |
878 j = k - 1; | |
879 break; | |
880 } | |
881 | |
882 case 'x': // hex input | |
883 { | |
884 std::size_t k; | |
885 int tmpi = 0; | |
886 for (k = j+1; k < std::min (j+3, len); k++) | |
887 { | |
888 if (! isxdigit (s[k])) | |
889 break; | |
890 | |
891 tmpi <<= 4; | |
892 int digit = s[k]; | |
893 if (digit >= 'a') | |
894 tmpi += digit - 'a' + 10; | |
895 else if (digit >= 'A') | |
896 tmpi += digit - 'A' + 10; | |
897 else | |
898 tmpi += digit - '0'; | |
899 } | |
900 | |
901 if (k == j+1) | |
902 warning (R"(malformed hex escape sequence '\x' -- converting to '\0')"); | |
903 | |
904 retval[i] = tmpi; | |
905 j = k - 1; | |
906 break; | |
907 } | |
908 | |
909 default: | |
910 warning (R"(unrecognized escape sequence '\%c' -- converting to '%c')", s[j], s[j]); | |
911 retval[i] = s[j]; | |
912 break; | 881 break; |
913 } | 882 } |
914 } | 883 |
915 else | 884 case 'x': // hex input |
916 retval[i] = s[j]; | 885 { |
917 | 886 std::size_t k; |
918 i++; | 887 int tmpi = 0; |
919 j++; | 888 for (k = j+1; k < std::min (j+3, len); k++) |
920 } | 889 { |
921 | 890 if (! isxdigit (s[k])) |
922 retval.resize (i); | 891 break; |
923 | 892 |
924 return retval; | 893 tmpi <<= 4; |
925 } | 894 int digit = s[k]; |
895 if (digit >= 'a') | |
896 tmpi += digit - 'a' + 10; | |
897 else if (digit >= 'A') | |
898 tmpi += digit - 'A' + 10; | |
899 else | |
900 tmpi += digit - '0'; | |
901 } | |
902 | |
903 if (k == j+1) | |
904 warning (R"(malformed hex escape sequence '\x' -- converting to '\0')"); | |
905 | |
906 retval[i] = tmpi; | |
907 j = k - 1; | |
908 break; | |
909 } | |
910 | |
911 default: | |
912 warning (R"(unrecognized escape sequence '\%c' -- converting to '%c')", s[j], s[j]); | |
913 retval[i] = s[j]; | |
914 break; | |
915 } | |
916 } | |
917 else | |
918 retval[i] = s[j]; | |
919 | |
920 i++; | |
921 j++; | |
922 } | |
923 | |
924 retval.resize (i); | |
925 | |
926 return retval; | |
927 } | |
926 | 928 |
927 DEFUN (do_string_escapes, args, , | 929 DEFUN (do_string_escapes, args, , |
928 doc: /* -*- texinfo -*- | 930 doc: /* -*- texinfo -*- |
929 @deftypefn {} {@var{newstr} =} do_string_escapes (@var{string}) | 931 @deftypefn {} {@var{newstr} =} do_string_escapes (@var{string}) |
930 Convert escape sequences in @var{string} to the characters they represent. | 932 Convert escape sequences in @var{string} to the characters they represent. |
936 @end deftypefn */) | 938 @end deftypefn */) |
937 { | 939 { |
938 if (args.length () != 1) | 940 if (args.length () != 1) |
939 print_usage (); | 941 print_usage (); |
940 | 942 |
941 std::string str = args(0).xstring_value ("do_string_escapes: STRING argument must be of type string"); | 943 std::string str = args( |
944 0).xstring_value ("do_string_escapes: STRING argument must be of type string"); | |
942 | 945 |
943 return ovl (do_string_escapes (str)); | 946 return ovl (do_string_escapes (str)); |
944 } | 947 } |
945 | 948 |
946 /* | 949 /* |
978 %!error <STRING argument> do_string_escapes (3) | 981 %!error <STRING argument> do_string_escapes (3) |
979 %!warning <malformed hex escape sequence> do_string_escapes ('\xG'); | 982 %!warning <malformed hex escape sequence> do_string_escapes ('\xG'); |
980 %!warning <unrecognized escape sequence> do_string_escapes ('\G'); | 983 %!warning <unrecognized escape sequence> do_string_escapes ('\G'); |
981 */ | 984 */ |
982 | 985 |
983 const char * undo_string_escape (char c) | 986 const char * undo_string_escape (char c) |
984 { | 987 { |
985 if (! c) | 988 if (! c) |
986 return ""; | 989 return ""; |
987 | 990 |
988 switch (c) | 991 switch (c) |
992 { | |
993 case '\0': | |
994 return R"(\0)"; | |
995 | |
996 case '\a': | |
997 return R"(\a)"; | |
998 | |
999 case '\b': // backspace | |
1000 return R"(\b)"; | |
1001 | |
1002 case '\f': // formfeed | |
1003 return R"(\f)"; | |
1004 | |
1005 case '\n': // newline | |
1006 return R"(\n)"; | |
1007 | |
1008 case '\r': // carriage return | |
1009 return R"(\r)"; | |
1010 | |
1011 case '\t': // horizontal tab | |
1012 return R"(\t)"; | |
1013 | |
1014 case '\v': // vertical tab | |
1015 return R"(\v)"; | |
1016 | |
1017 case '\\': // backslash | |
1018 return R"(\\)"; | |
1019 | |
1020 case '"': // double quote | |
1021 return R"(\")"; | |
1022 | |
1023 default: | |
989 { | 1024 { |
990 case '\0': | 1025 static char retval[2] {'\0', '\0'}; |
991 return R"(\0)"; | 1026 |
992 | 1027 retval[0] = c; |
993 case '\a': | 1028 return retval; |
994 return R"(\a)"; | |
995 | |
996 case '\b': // backspace | |
997 return R"(\b)"; | |
998 | |
999 case '\f': // formfeed | |
1000 return R"(\f)"; | |
1001 | |
1002 case '\n': // newline | |
1003 return R"(\n)"; | |
1004 | |
1005 case '\r': // carriage return | |
1006 return R"(\r)"; | |
1007 | |
1008 case '\t': // horizontal tab | |
1009 return R"(\t)"; | |
1010 | |
1011 case '\v': // vertical tab | |
1012 return R"(\v)"; | |
1013 | |
1014 case '\\': // backslash | |
1015 return R"(\\)"; | |
1016 | |
1017 case '"': // double quote | |
1018 return R"(\")"; | |
1019 | |
1020 default: | |
1021 { | |
1022 static char retval[2] {'\0', '\0'}; | |
1023 | |
1024 retval[0] = c; | |
1025 return retval; | |
1026 } | |
1027 } | 1029 } |
1028 } | 1030 } |
1029 | 1031 } |
1030 std::string undo_string_escapes (const std::string& s) | 1032 |
1031 { | 1033 std::string undo_string_escapes (const std::string& s) |
1032 std::string retval; | 1034 { |
1033 | 1035 std::string retval; |
1034 for (std::size_t i = 0; i < s.length (); i++) | 1036 |
1035 retval.append (undo_string_escape (s[i])); | 1037 for (std::size_t i = 0; i < s.length (); i++) |
1036 | 1038 retval.append (undo_string_escape (s[i])); |
1037 return retval; | 1039 |
1038 } | 1040 return retval; |
1041 } | |
1039 | 1042 |
1040 DEFUN (undo_string_escapes, args, , | 1043 DEFUN (undo_string_escapes, args, , |
1041 doc: /* -*- texinfo -*- | 1044 doc: /* -*- texinfo -*- |
1042 @deftypefn {} {@var{newstr} =} undo_string_escapes (@var{string}) | 1045 @deftypefn {} {@var{newstr} =} undo_string_escapes (@var{string}) |
1043 Convert special characters in @var{string} back to their escaped forms. | 1046 Convert special characters in @var{string} back to their escaped forms. |
1303 %!assert (isstruct (errno_list ())) | 1306 %!assert (isstruct (errno_list ())) |
1304 | 1307 |
1305 %!error errno_list ("foo") | 1308 %!error errno_list ("foo") |
1306 */ | 1309 */ |
1307 | 1310 |
1308 static void check_dimensions (octave_idx_type& nr, octave_idx_type& nc, | 1311 static void check_dimensions (octave_idx_type& nr, octave_idx_type& nc, |
1309 const char *warnfor) | 1312 const char *warnfor) |
1310 { | 1313 { |
1311 if (nr < 0 || nc < 0) | 1314 if (nr < 0 || nc < 0) |
1312 { | 1315 { |
1313 warning_with_id ("Octave:neg-dim-as-zero", | |
1314 "%s: converting negative dimension to zero", warnfor); | |
1315 | |
1316 nr = (nr < 0) ? 0 : nr; | |
1317 nc = (nc < 0) ? 0 : nc; | |
1318 } | |
1319 } | |
1320 | |
1321 void check_dimensions (dim_vector& dim, const char *warnfor) | |
1322 { | |
1323 bool neg = false; | |
1324 | |
1325 for (int i = 0; i < dim.ndims (); i++) | |
1326 { | |
1327 if (dim(i) < 0) | |
1328 { | |
1329 dim(i) = 0; | |
1330 neg = true; | |
1331 } | |
1332 } | |
1333 | |
1334 if (neg) | |
1335 warning_with_id ("Octave:neg-dim-as-zero", | 1316 warning_with_id ("Octave:neg-dim-as-zero", |
1336 "%s: converting negative dimension to zero", warnfor); | 1317 "%s: converting negative dimension to zero", warnfor); |
1337 } | 1318 |
1338 | 1319 nr = (nr < 0) ? 0 : nr; |
1339 void get_dimensions (const octave_value& a, const char *warn_for, | 1320 nc = (nc < 0) ? 0 : nc; |
1340 dim_vector& dim) | 1321 } |
1341 { | 1322 } |
1342 // We support dimensions to be specified by a vector, even if it's empty. | 1323 |
1343 // If the vector is empty, the final dimensions end up being 0x0. | 1324 void check_dimensions (dim_vector& dim, const char *warnfor) |
1344 if (! a.dims ().isvector () && a.dims ().numel () != 0) | 1325 { |
1345 error ("%s (A): use %s (size (A)) instead", warn_for, warn_for); | 1326 bool neg = false; |
1346 | 1327 |
1347 const Array<octave_idx_type> v = a.octave_idx_type_vector_value (true); | 1328 for (int i = 0; i < dim.ndims (); i++) |
1348 const octave_idx_type n = v.numel (); | 1329 { |
1349 | 1330 if (dim(i) < 0) |
1350 dim.resize (n); // even if n < 2, resize sets it back to 2 | 1331 { |
1351 if (n == 0) | 1332 dim(i) = 0; |
1352 { | 1333 neg = true; |
1353 dim(0) = 0; | 1334 } |
1354 dim(1) = 0; | 1335 } |
1355 } | 1336 |
1356 else if (n == 1) | 1337 if (neg) |
1357 { | 1338 warning_with_id ("Octave:neg-dim-as-zero", |
1358 dim(0) = v(0); | 1339 "%s: converting negative dimension to zero", warnfor); |
1359 dim(1) = v(0); | 1340 } |
1360 } | 1341 |
1361 else | 1342 void get_dimensions (const octave_value& a, const char *warn_for, |
1343 dim_vector& dim) | |
1344 { | |
1345 // We support dimensions to be specified by a vector, even if it's empty. | |
1346 // If the vector is empty, the final dimensions end up being 0x0. | |
1347 if (! a.dims ().isvector () && a.dims ().numel () != 0) | |
1348 error ("%s (A): use %s (size (A)) instead", warn_for, warn_for); | |
1349 | |
1350 const Array<octave_idx_type> v = a.octave_idx_type_vector_value (true); | |
1351 const octave_idx_type n = v.numel (); | |
1352 | |
1353 dim.resize (n); // even if n < 2, resize sets it back to 2 | |
1354 if (n == 0) | |
1355 { | |
1356 dim(0) = 0; | |
1357 dim(1) = 0; | |
1358 } | |
1359 else if (n == 1) | |
1360 { | |
1361 dim(0) = v(0); | |
1362 dim(1) = v(0); | |
1363 } | |
1364 else | |
1365 for (octave_idx_type i = 0; i < n; i++) | |
1366 dim(i) = v(i); | |
1367 | |
1368 check_dimensions (dim, warn_for); | |
1369 } | |
1370 | |
1371 void get_dimensions (const octave_value& a, const char *warn_for, | |
1372 octave_idx_type& nr, octave_idx_type& nc) | |
1373 { | |
1374 if (a.is_scalar_type ()) | |
1375 { | |
1376 nr = nc = a.idx_type_value (true); | |
1377 } | |
1378 else | |
1379 { | |
1380 nr = a.rows (); | |
1381 nc = a.columns (); | |
1382 | |
1383 if ((nr != 1 || nc != 2) && (nr != 2 || nc != 1)) | |
1384 error ("%s (A): use %s (size (A)) instead", warn_for, warn_for); | |
1385 | |
1386 Array<octave_idx_type> v = a.octave_idx_type_vector_value (true); | |
1387 nr = v(0); | |
1388 nc = v(1); | |
1389 } | |
1390 | |
1391 check_dimensions (nr, nc, warn_for); | |
1392 } | |
1393 | |
1394 void get_dimensions (const octave_value& a, const octave_value& b, | |
1395 const char *warn_for, octave_idx_type& nr, | |
1396 octave_idx_type& nc) | |
1397 { | |
1398 nr = (a.isempty () ? 0 : a.idx_type_value (true)); | |
1399 nc = (b.isempty () ? 0 : b.idx_type_value (true)); | |
1400 | |
1401 check_dimensions (nr, nc, warn_for); | |
1402 } | |
1403 | |
1404 octave_idx_type dims_to_numel (const dim_vector& dims, | |
1405 const octave_value_list& idx_arg) | |
1406 { | |
1407 octave_idx_type retval; | |
1408 | |
1409 octave_idx_type len = idx_arg.length (); | |
1410 | |
1411 if (len == 0) | |
1412 retval = dims.numel (); | |
1413 else | |
1414 { | |
1415 const dim_vector dv = dims.redim (len); | |
1416 retval = 1; | |
1417 for (octave_idx_type i = 0; i < len; i++) | |
1418 { | |
1419 octave_value idxi = idx_arg(i); | |
1420 if (idxi.is_magic_colon ()) | |
1421 retval *= dv(i); | |
1422 else if (idxi.isnumeric ()) | |
1423 retval *= idxi.numel (); | |
1424 else | |
1425 { | |
1426 try | |
1427 { | |
1428 idx_vector jdx = idxi.index_vector (); | |
1429 | |
1430 retval *= jdx.length (dv(i)); | |
1431 } | |
1432 catch (const index_exception& ie) | |
1433 { | |
1434 error ("dims_to_numel: invalid index %s", ie.what ()); | |
1435 } | |
1436 } | |
1437 } | |
1438 } | |
1439 | |
1440 return retval; | |
1441 } | |
1442 | |
1443 Matrix identity_matrix (octave_idx_type nr, octave_idx_type nc) | |
1444 { | |
1445 Matrix m (nr, nc, 0.0); | |
1446 | |
1447 if (nr > 0 && nc > 0) | |
1448 { | |
1449 octave_idx_type n = std::min (nr, nc); | |
1450 | |
1362 for (octave_idx_type i = 0; i < n; i++) | 1451 for (octave_idx_type i = 0; i < n; i++) |
1363 dim(i) = v(i); | 1452 m (i, i) = 1.0; |
1364 | 1453 } |
1365 check_dimensions (dim, warn_for); | 1454 |
1366 } | 1455 return m; |
1367 | 1456 } |
1368 void get_dimensions (const octave_value& a, const char *warn_for, | 1457 |
1369 octave_idx_type& nr, octave_idx_type& nc) | 1458 FloatMatrix float_identity_matrix (octave_idx_type nr, octave_idx_type nc) |
1370 { | 1459 { |
1371 if (a.is_scalar_type ()) | 1460 FloatMatrix m (nr, nc, 0.0); |
1372 { | 1461 |
1373 nr = nc = a.idx_type_value (true); | 1462 if (nr > 0 && nc > 0) |
1374 } | 1463 { |
1375 else | 1464 octave_idx_type n = std::min (nr, nc); |
1376 { | 1465 |
1377 nr = a.rows (); | 1466 for (octave_idx_type i = 0; i < n; i++) |
1378 nc = a.columns (); | 1467 m (i, i) = 1.0; |
1379 | 1468 } |
1380 if ((nr != 1 || nc != 2) && (nr != 2 || nc != 1)) | 1469 |
1381 error ("%s (A): use %s (size (A)) instead", warn_for, warn_for); | 1470 return m; |
1382 | 1471 } |
1383 Array<octave_idx_type> v = a.octave_idx_type_vector_value (true); | 1472 |
1384 nr = v(0); | 1473 std::size_t format (std::ostream& os, const char *fmt, ...) |
1385 nc = v(1); | 1474 { |
1386 } | 1475 std::size_t retval; |
1387 | 1476 |
1388 check_dimensions (nr, nc, warn_for); | 1477 va_list args; |
1389 } | 1478 va_start (args, fmt); |
1390 | 1479 |
1391 void get_dimensions (const octave_value& a, const octave_value& b, | 1480 retval = vformat (os, fmt, args); |
1392 const char *warn_for, octave_idx_type& nr, | 1481 |
1393 octave_idx_type& nc) | 1482 va_end (args); |
1394 { | 1483 |
1395 nr = (a.isempty () ? 0 : a.idx_type_value (true)); | 1484 return retval; |
1396 nc = (b.isempty () ? 0 : b.idx_type_value (true)); | 1485 } |
1397 | 1486 |
1398 check_dimensions (nr, nc, warn_for); | 1487 std::size_t vformat (std::ostream& os, const char *fmt, va_list args) |
1399 } | 1488 { |
1400 | 1489 std::string s = vasprintf (fmt, args); |
1401 octave_idx_type dims_to_numel (const dim_vector& dims, | 1490 |
1402 const octave_value_list& idx_arg) | 1491 os << s; |
1403 { | 1492 |
1404 octave_idx_type retval; | 1493 return s.length (); |
1405 | 1494 } |
1406 octave_idx_type len = idx_arg.length (); | 1495 |
1407 | 1496 std::string vasprintf (const char *fmt, va_list args) |
1408 if (len == 0) | 1497 { |
1409 retval = dims.numel (); | 1498 std::string retval; |
1410 else | 1499 |
1411 { | 1500 char *result; |
1412 const dim_vector dv = dims.redim (len); | 1501 |
1413 retval = 1; | 1502 int status = octave_vasprintf_wrapper (&result, fmt, args); |
1414 for (octave_idx_type i = 0; i < len; i++) | 1503 |
1415 { | 1504 if (status >= 0) |
1416 octave_value idxi = idx_arg(i); | 1505 { |
1417 if (idxi.is_magic_colon ()) | 1506 retval = result; |
1418 retval *= dv(i); | 1507 ::free (result); |
1419 else if (idxi.isnumeric ()) | 1508 } |
1420 retval *= idxi.numel (); | 1509 |
1421 else | 1510 return retval; |
1422 { | 1511 } |
1423 try | 1512 |
1424 { | 1513 std::string asprintf (const char *fmt, ...) |
1425 idx_vector jdx = idxi.index_vector (); | 1514 { |
1426 | 1515 std::string retval; |
1427 retval *= jdx.length (dv(i)); | 1516 |
1428 } | 1517 va_list args; |
1429 catch (const index_exception& ie) | 1518 va_start (args, fmt); |
1430 { | 1519 |
1431 error ("dims_to_numel: invalid index %s", ie.what ()); | 1520 retval = vasprintf (fmt, args); |
1432 } | 1521 |
1433 } | 1522 va_end (args); |
1434 } | 1523 |
1435 } | 1524 return retval; |
1436 | 1525 } |
1437 return retval; | 1526 |
1438 } | 1527 // FIXME: sleep is complicated because we want it to be interruptible. |
1439 | 1528 // With the way this program handles signals, the sleep system call |
1440 Matrix identity_matrix (octave_idx_type nr, octave_idx_type nc) | 1529 // won't respond to SIGINT. Maybe there is a better way than |
1441 { | 1530 // breaking this up into multiple shorter intervals? |
1442 Matrix m (nr, nc, 0.0); | 1531 |
1443 | 1532 void sleep (double seconds, bool do_graphics_events) |
1444 if (nr > 0 && nc > 0) | 1533 { |
1445 { | 1534 if (seconds <= 0) |
1446 octave_idx_type n = std::min (nr, nc); | 1535 return; |
1447 | 1536 |
1448 for (octave_idx_type i = 0; i < n; i++) | 1537 // Allow free access to graphics resources while the interpreter thread |
1449 m (i, i) = 1.0; | 1538 // is asleep |
1450 } | 1539 |
1451 | 1540 gh_manager& gh_mgr = __get_gh_manager__ (); |
1452 return m; | 1541 |
1453 } | 1542 if (do_graphics_events) |
1454 | 1543 gh_mgr.unlock (); |
1455 FloatMatrix float_identity_matrix (octave_idx_type nr, octave_idx_type nc) | 1544 |
1456 { | 1545 if (math::isinf (seconds)) |
1457 FloatMatrix m (nr, nc, 0.0); | 1546 { |
1458 | 1547 // Wait for kbhit |
1459 if (nr > 0 && nc > 0) | 1548 int c = -1; |
1460 { | 1549 flush_stdout (); |
1461 octave_idx_type n = std::min (nr, nc); | 1550 |
1462 | 1551 struct timespec one_tenth = { 0, 100000000 }; |
1463 for (octave_idx_type i = 0; i < n; i++) | 1552 |
1464 m (i, i) = 1.0; | 1553 while (c < 0) |
1465 } | 1554 { |
1466 | 1555 octave_nanosleep_wrapper (&one_tenth, nullptr); |
1467 return m; | 1556 |
1468 } | 1557 octave_quit (); |
1469 | 1558 |
1470 std::size_t format (std::ostream& os, const char *fmt, ...) | 1559 if (do_graphics_events) |
1471 { | 1560 gh_mgr.process_events (); |
1472 std::size_t retval; | 1561 |
1473 | 1562 c = kbhit (false); |
1474 va_list args; | 1563 } |
1475 va_start (args, fmt); | 1564 } |
1476 | 1565 else |
1477 retval = vformat (os, fmt, args); | 1566 { |
1478 | 1567 sys::time now; |
1479 va_end (args); | 1568 double end_time = now.double_value () + seconds; |
1480 | 1569 double remaining_time = seconds; |
1481 return retval; | 1570 |
1482 } | 1571 // Split pause into 100 ms time steps to allow the execution of |
1483 | 1572 // graphics events and interrupts. |
1484 std::size_t vformat (std::ostream& os, const char *fmt, va_list args) | 1573 struct timespec nano_laps = { 0, 100000000 }; |
1485 { | 1574 |
1486 std::string s = vasprintf (fmt, args); | 1575 while (remaining_time > 0.1) |
1487 | 1576 { |
1488 os << s; | 1577 octave_quit (); |
1489 | 1578 |
1490 return s.length (); | 1579 if (do_graphics_events) |
1491 } | 1580 { |
1492 | |
1493 std::string vasprintf (const char *fmt, va_list args) | |
1494 { | |
1495 std::string retval; | |
1496 | |
1497 char *result; | |
1498 | |
1499 int status = octave_vasprintf_wrapper (&result, fmt, args); | |
1500 | |
1501 if (status >= 0) | |
1502 { | |
1503 retval = result; | |
1504 ::free (result); | |
1505 } | |
1506 | |
1507 return retval; | |
1508 } | |
1509 | |
1510 std::string asprintf (const char *fmt, ...) | |
1511 { | |
1512 std::string retval; | |
1513 | |
1514 va_list args; | |
1515 va_start (args, fmt); | |
1516 | |
1517 retval = vasprintf (fmt, args); | |
1518 | |
1519 va_end (args); | |
1520 | |
1521 return retval; | |
1522 } | |
1523 | |
1524 // FIXME: sleep is complicated because we want it to be interruptible. | |
1525 // With the way this program handles signals, the sleep system call | |
1526 // won't respond to SIGINT. Maybe there is a better way than | |
1527 // breaking this up into multiple shorter intervals? | |
1528 | |
1529 void sleep (double seconds, bool do_graphics_events) | |
1530 { | |
1531 if (seconds <= 0) | |
1532 return; | |
1533 | |
1534 // Allow free access to graphics resources while the interpreter thread | |
1535 // is asleep | |
1536 | |
1537 gh_manager& gh_mgr = __get_gh_manager__ (); | |
1538 | |
1539 if (do_graphics_events) | |
1540 gh_mgr.unlock (); | |
1541 | |
1542 if (math::isinf (seconds)) | |
1543 { | |
1544 // Wait for kbhit | |
1545 int c = -1; | |
1546 flush_stdout (); | |
1547 | |
1548 struct timespec one_tenth = { 0, 100000000 }; | |
1549 | |
1550 while (c < 0) | |
1551 { | |
1552 octave_nanosleep_wrapper (&one_tenth, nullptr); | |
1553 | |
1554 octave_quit (); | |
1555 | |
1556 if (do_graphics_events) | |
1557 gh_mgr.process_events (); | 1581 gh_mgr.process_events (); |
1558 | 1582 |
1559 c = kbhit (false); | 1583 now.stamp (); |
1560 } | 1584 remaining_time = end_time - now.double_value (); |
1561 } | 1585 |
1562 else | 1586 if (remaining_time < 0.1) |
1563 { | 1587 break; |
1564 sys::time now; | 1588 } |
1565 double end_time = now.double_value () + seconds; | 1589 |
1566 double remaining_time = seconds; | 1590 octave_nanosleep_wrapper (&nano_laps, nullptr); |
1567 | 1591 |
1568 // Split pause into 100 ms time steps to allow the execution of | 1592 now.stamp (); |
1569 // graphics events and interrupts. | 1593 remaining_time = end_time - now.double_value (); |
1570 struct timespec nano_laps = { 0, 100000000 }; | 1594 } |
1571 | 1595 |
1572 while (remaining_time > 0.1) | 1596 if (remaining_time > 0.0) |
1573 { | 1597 { |
1574 octave_quit (); | 1598 nano_laps = { 0, static_cast<int> (remaining_time * 1e9) }; |
1575 | 1599 octave_nanosleep_wrapper (&nano_laps, nullptr); |
1576 if (do_graphics_events) | 1600 } |
1577 { | 1601 } |
1578 gh_mgr.process_events (); | 1602 } |
1579 | |
1580 now.stamp (); | |
1581 remaining_time = end_time - now.double_value (); | |
1582 | |
1583 if (remaining_time < 0.1) | |
1584 break; | |
1585 } | |
1586 | |
1587 octave_nanosleep_wrapper (&nano_laps, nullptr); | |
1588 | |
1589 now.stamp (); | |
1590 remaining_time = end_time - now.double_value (); | |
1591 } | |
1592 | |
1593 if (remaining_time > 0.0) | |
1594 { | |
1595 nano_laps = { 0, static_cast<int> (remaining_time * 1e9) }; | |
1596 octave_nanosleep_wrapper (&nano_laps, nullptr); | |
1597 } | |
1598 } | |
1599 } | |
1600 | 1603 |
1601 DEFMETHOD (isindex, interp, args, , | 1604 DEFMETHOD (isindex, interp, args, , |
1602 doc: /* -*- texinfo -*- | 1605 doc: /* -*- texinfo -*- |
1603 @deftypefn {} {@var{tf} =} isindex (@var{ind}) | 1606 @deftypefn {} {@var{tf} =} isindex (@var{ind}) |
1604 @deftypefnx {} {@var{tf} =} isindex (@var{ind}, @var{n}) | 1607 @deftypefnx {} {@var{tf} =} isindex (@var{ind}, @var{n}) |
1654 | 1657 |
1655 %!error isindex () | 1658 %!error isindex () |
1656 %!error isindex (1:3, 2, 3) | 1659 %!error isindex (1:3, 2, 3) |
1657 */ | 1660 */ |
1658 | 1661 |
1659 octave_value_list | 1662 octave_value_list |
1660 do_simple_cellfun (octave_value_list (*fcn) (const octave_value_list&, int), | 1663 do_simple_cellfun (octave_value_list (*fcn) (const octave_value_list&, int), |
1661 const char *fcn_name, const octave_value_list& args, | 1664 const char *fcn_name, const octave_value_list& args, |
1662 int nargout) | 1665 int nargout) |
1663 { | 1666 { |
1664 octave_value_list new_args = args; | 1667 octave_value_list new_args = args; |
1665 octave_value_list retval; | 1668 octave_value_list retval; |
1666 int nargin = args.length (); | 1669 int nargin = args.length (); |
1667 OCTAVE_LOCAL_BUFFER (bool, iscell, nargin); | 1670 OCTAVE_LOCAL_BUFFER (bool, iscell, nargin); |
1668 OCTAVE_LOCAL_BUFFER (Cell, cells, nargin); | 1671 OCTAVE_LOCAL_BUFFER (Cell, cells, nargin); |
1669 OCTAVE_LOCAL_BUFFER (Cell, rcells, nargout); | 1672 OCTAVE_LOCAL_BUFFER (Cell, rcells, nargout); |
1670 | 1673 |
1671 const Cell *ccells = cells; | 1674 const Cell *ccells = cells; |
1672 | 1675 |
1673 octave_idx_type numel = 1; | 1676 octave_idx_type numel = 1; |
1674 dim_vector dims (1, 1); | 1677 dim_vector dims (1, 1); |
1675 | 1678 |
1676 for (int i = 0; i < nargin; i++) | 1679 for (int i = 0; i < nargin; i++) |
1677 { | 1680 { |
1678 octave_value arg = new_args(i); | 1681 octave_value arg = new_args(i); |
1679 iscell[i] = arg.iscell (); | 1682 iscell[i] = arg.iscell (); |
1683 if (iscell[i]) | |
1684 { | |
1685 cells[i] = arg.cell_value (); | |
1686 octave_idx_type n = ccells[i].numel (); | |
1687 if (n == 1) | |
1688 { | |
1689 iscell[i] = false; | |
1690 new_args(i) = ccells[i](0); | |
1691 } | |
1692 else if (numel == 1) | |
1693 { | |
1694 numel = n; | |
1695 dims = ccells[i].dims (); | |
1696 } | |
1697 else if (dims != ccells[i].dims ()) | |
1698 error ("%s: cell arguments must have matching sizes", fcn_name); | |
1699 } | |
1700 } | |
1701 | |
1702 for (int i = 0; i < nargout; i++) | |
1703 rcells[i].clear (dims); | |
1704 | |
1705 for (octave_idx_type j = 0; j < numel; j++) | |
1706 { | |
1707 for (int i = 0; i < nargin; i++) | |
1680 if (iscell[i]) | 1708 if (iscell[i]) |
1681 { | 1709 new_args(i) = ccells[i](j); |
1682 cells[i] = arg.cell_value (); | 1710 |
1683 octave_idx_type n = ccells[i].numel (); | 1711 octave_quit (); |
1684 if (n == 1) | 1712 |
1685 { | 1713 const octave_value_list tmp = fcn (new_args, nargout); |
1686 iscell[i] = false; | 1714 |
1687 new_args(i) = ccells[i](0); | 1715 if (tmp.length () < nargout) |
1688 } | 1716 error ("%s: do_simple_cellfun: internal error", fcn_name); |
1689 else if (numel == 1) | 1717 |
1690 { | 1718 for (int i = 0; i < nargout; i++) |
1691 numel = n; | 1719 rcells[i](j) = tmp(i); |
1692 dims = ccells[i].dims (); | 1720 } |
1693 } | 1721 |
1694 else if (dims != ccells[i].dims ()) | 1722 retval.resize (nargout); |
1695 error ("%s: cell arguments must have matching sizes", fcn_name); | 1723 |
1696 } | 1724 for (int i = 0; i < nargout; i++) |
1697 } | 1725 retval(i) = rcells[i]; |
1698 | 1726 |
1699 for (int i = 0; i < nargout; i++) | 1727 return retval; |
1700 rcells[i].clear (dims); | 1728 } |
1701 | 1729 |
1702 for (octave_idx_type j = 0; j < numel; j++) | 1730 octave_value |
1703 { | 1731 do_simple_cellfun (octave_value_list (*fcn) (const octave_value_list&, int), |
1704 for (int i = 0; i < nargin; i++) | 1732 const char *fcn_name, const octave_value_list& args) |
1705 if (iscell[i]) | 1733 { |
1706 new_args(i) = ccells[i](j); | 1734 octave_value retval; |
1707 | 1735 |
1708 octave_quit (); | 1736 const octave_value_list tmp = do_simple_cellfun (fcn, fcn_name, args, 1); |
1709 | 1737 |
1710 const octave_value_list tmp = fcn (new_args, nargout); | 1738 if (tmp.length () > 0) |
1711 | 1739 retval = tmp(0); |
1712 if (tmp.length () < nargout) | 1740 |
1713 error ("%s: do_simple_cellfun: internal error", fcn_name); | 1741 return retval; |
1714 | 1742 } |
1715 for (int i = 0; i < nargout; i++) | |
1716 rcells[i](j) = tmp(i); | |
1717 } | |
1718 | |
1719 retval.resize (nargout); | |
1720 | |
1721 for (int i = 0; i < nargout; i++) | |
1722 retval(i) = rcells[i]; | |
1723 | |
1724 return retval; | |
1725 } | |
1726 | |
1727 octave_value | |
1728 do_simple_cellfun (octave_value_list (*fcn) (const octave_value_list&, int), | |
1729 const char *fcn_name, const octave_value_list& args) | |
1730 { | |
1731 octave_value retval; | |
1732 | |
1733 const octave_value_list tmp = do_simple_cellfun (fcn, fcn_name, args, 1); | |
1734 | |
1735 if (tmp.length () > 0) | |
1736 retval = tmp(0); | |
1737 | |
1738 return retval; | |
1739 } | |
1740 | 1743 |
1741 DEFUN (isstudent, args, , | 1744 DEFUN (isstudent, args, , |
1742 doc: /* -*- texinfo -*- | 1745 doc: /* -*- texinfo -*- |
1743 @deftypefn {} {@var{tf} =} isstudent () | 1746 @deftypefn {} {@var{tf} =} isstudent () |
1744 Return true if running in the student edition of @sc{matlab}. | 1747 Return true if running in the student edition of @sc{matlab}. |