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}.