Mercurial > hg > octave-lojdl
changeset 14075:7efa14e5a53c gui
Merge default onto gui
author | Jordi Gutiérrez Hermoso <jordigh@octave.org> |
---|---|
date | Tue, 20 Dec 2011 16:57:55 -0500 |
parents | c72ad9f5fa2e (current diff) 88029530ffbc (diff) |
children | 43ad81bc42be |
files | NEWS configure.ac libcruft/arpack/src/dnaupe.f libcruft/arpack/src/snaupe.f liboctave/regex-match.cc liboctave/regex-match.h scripts/plot/__gnuplot_drawnow__.m scripts/plot/__go_close_all__.m src/DLD-FUNCTIONS/onCleanup.cc src/base-list.h |
diffstat | 267 files changed, 5751 insertions(+), 3473 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgsubstate +++ b/.hgsubstate @@ -1,1 +1,1 @@ -ff549c078493ea86e7bd87526db276a1b94a411a gnulib +bb052d4a7416accaad0747e84bd2a0accbfcf923 gnulib
--- a/.hgtags +++ b/.hgtags @@ -53,3 +53,4 @@ 901d466ee55ac902a875ec0ade6f1eccef0841dc release-3-4-1 3666e8e6f96e6899b8306d6ea9614aadf0500d67 release-3-4-2 b0e70a71647b671ebcfa7a79af1ae6d3c0f52065 release-3-4-3 +3781981be535e80d44c85373b8fdaa60ca5cd097 ss-3-5-90
--- a/NEWS +++ b/NEWS @@ -159,9 +159,9 @@ cut is_duplicate_entry cor polyderiv - corrcoef studentize - __error_text__ sylvester_matrix - error_text + corrcoef shell_cmd + __error_text__ studentize + error_text sylvester_matrix Summary of important user-visible changes for version 3.4.3: -----------------------------------------------------------
--- a/build-aux/bootstrap.conf +++ b/build-aux/bootstrap.conf @@ -40,6 +40,7 @@ lstat mkdir mkfifo + mkostemp mkstemp mktime nanosleep @@ -73,7 +74,7 @@ truncf unistd unlink - vsnprintf + vasprintf " # Additional xgettext options to use. Use "\\\newline" to break lines.
--- a/configure.ac +++ b/configure.ac @@ -27,13 +27,13 @@ EXTERN_CFLAGS="$CFLAGS" EXTERN_CXXFLAGS="$CXXFLAGS" -AC_INIT([GNU Octave], [3.5.0+], [http://octave.org/bugs.html], [octave]) +AC_INIT([GNU Octave], [3.5.90+], [http://octave.org/bugs.html], [octave]) dnl PACKAGE_VERSION is set by the AC_INIT VERSION arg OCTAVE_VERSION="$PACKAGE_VERSION" -OCTAVE_API_VERSION_NUMBER="45" +OCTAVE_API_VERSION_NUMBER="46" OCTAVE_API_VERSION="api-v$OCTAVE_API_VERSION_NUMBER+" -OCTAVE_RELEASE_DATE="2011-01-22" +OCTAVE_RELEASE_DATE="2011-12-11" OCTAVE_COPYRIGHT="Copyright (C) 2011 John W. Eaton and others." AC_SUBST(OCTAVE_VERSION) AC_SUBST(OCTAVE_API_VERSION_NUMBER) @@ -171,11 +171,20 @@ AC_ARG_ENABLE(octave-allocator, [AS_HELP_STRING([--enable-octave-allocator], [use the obsolete octave_allocator class for many of Octave's objects (mostly octave_value types). You probably do NOT want to enable this feature. (default is no)])], - [if test "$enableval" = yes; then USE_ALLOCATOR=true; fi], []) + [if test "$enableval" = yes; then USE_OCTAVE_ALLOCATOR=true; fi], []) if $USE_OCTAVE_ALLOCATOR; then AC_DEFINE(USE_OCTAVE_ALLOCATOR, 1, [Define to use octave_allocator class.]) fi +USE_ATOMIC_REFCOUNT=false +AC_ARG_ENABLE(atomic-refcount, + [AS_HELP_STRING([--enable-atomic-refcount], + [use atomic operations for internal reference counting. This is required for thread-safe behavior. (default is no)])], + [if test "$enableval" = yes; then USE_ATOMIC_REFCOUNT=true; fi], []) +if $USE_ATOMIC_REFCOUNT; then + AC_DEFINE(USE_ATOMIC_REFCOUNT, 1, [Define to use atomic operations for reference counting.]) +fi + ### Make it possible to disable running Make in the doc directory. ### Useful for building on systems without TeX, for example. DOCDIR=doc @@ -640,7 +649,7 @@ OCTAVE_CHECK_LIBRARY(qhull, QHull, [Qhull library not found -- this will result in loss of functionality of some geometry functions.], - [qhull/qhull_a.h], [qh_qhull], [], [], + [qhull/libqhull.h libqhull.h qhull/qhull.h qhull.h], [qh_qhull], [], [], [warn_qhull= OCTAVE_CHECK_QHULL_VERSION OCTAVE_CHECK_QHULL_OK([TEXINFO_QHULL="@set HAVE_QHULL" @@ -653,12 +662,17 @@ pcre_fail_msg="to build Octave, you must have the PCRE library and header files installed" -## NB: no need to do separate check for pcre.h header -- checking -## macros is good enough +AC_CHECK_HEADERS([pcre.h pcre/pcre.h]) + AC_CACHE_CHECK([whether pcre.h defines the macros we need], [ac_cv_pcre_h_macros_present], [AC_EGREP_CPP([PCRE_HAS_MACROS_WE_NEED], [ +#if defined (HAVE_PCRE_H) #include <pcre.h> +#elif defined (HAVE_PCRE_PCRE_H) +#include <pcre.h> +#error "NO PCRE HEADER" +#endif #if defined (PCRE_INFO_NAMECOUNT) \ && defined (PCRE_INFO_NAMEENTRYSIZE) \ && defined (PCRE_INFO_NAMETABLE) @@ -1999,7 +2013,7 @@ AC_ARG_ENABLE([no-undefined], [AS_HELP_STRING([--enable-no-undefined], - [pass -no-undefined to libtool when linking linking Octave and its shared libraries (on by default)])], + [pass -no-undefined to libtool when linking Octave and its shared libraries (on by default)])], [case "${enableval}" in yes) NO_UNDEFINED_LDFLAG="-no-undefined" ;; no) NO_UNDEFINED_LDFLAG="" ;; @@ -2603,6 +2617,9 @@ typedef OCTAVE_IDX_TYPE octave_idx_type; #include <stdint.h> + +/* Tag indicating octave config.h has been included */ +#define OCTAVE_CONFIG_INCLUDED 1 ]) ### Do the substitutions in all the Makefiles. @@ -2979,6 +2996,22 @@ warn_msg_printed=true fi +if $USE_ATOMIC_REFCOUNT; then + AC_MSG_WARN([]) + AC_MSG_WARN([Using atomic reference counting.]) + AC_MSG_WARN([This feature allows to access octave data safely from]) + AC_MSG_WARN([another thread, for instance from a GUI. However this]) + AC_MSG_WARN([results in a small performance penalty in the octave]) + AC_MSG_WARN([interpreter.]) + AC_MSG_WARN([]) + if $USE_OCTAVE_ALLOCATOR; then + AC_MSG_WARN([Thread-safe behavior is not guaranteed unless you also]) + AC_MSG_WARN([disable the use of the octave_allocator class.]) + AC_MSG_WARN([]) + fi + warn_msg_printed=true +fi + if $warn_msg_printed; then AC_MSG_NOTICE([]) AC_MSG_NOTICE([NOTE: libraries may be skipped if a library is not found OR])
--- a/doc/interpreter/basics.txi +++ b/doc/interpreter/basics.txi @@ -1059,7 +1059,7 @@ lines "@code{disp(2);}" and "@code{disp(1);}" won't be executed. The block comment markers must appear alone as the only characters on a line -(excepting whitespace) in order to to be parsed correctly. +(excepting whitespace) in order to be parsed correctly. @node Comments and the Help System @subsection Comments and the Help System
--- a/doc/interpreter/container.txi +++ b/doc/interpreter/container.txi @@ -374,7 +374,8 @@ Besides the index operator ".", Octave can use dynamic naming "(var)" or the @code{struct} function to create structures. Dynamic naming uses the string -value of a variable as the field name. For example, +value of a variable as the field name. For example: + @example @group a = "field2";
--- a/doc/interpreter/contrib.txi +++ b/doc/interpreter/contrib.txi @@ -71,7 +71,7 @@ @end example You may want to get familiar with Mercurial queues to manage your -changesets. Here is a slightly more complex example using Mercurial +changesets. Here is a slightly more complex example using Mercurial queues, where work on two unrelated changesets is done in parallel and one of the changesets is updated after discussion on the maintainers mailing list: @@ -154,7 +154,7 @@ look for methods before constructors * symtab.cc (symbol_table::fcn_info::fcn_info_rep::find): -Look for class methods before constructors, contrary to Matlab +Look for class methods before constructors, contrary to @sc{matlab} documentation. * test/ctor-vs-method: New directory of test classes.
--- a/doc/interpreter/debug.txi +++ b/doc/interpreter/debug.txi @@ -190,11 +190,11 @@ @cindex profiler @cindex code profiling -Octave supports profiling of code execution on a per-function level. If +Octave supports profiling of code execution on a per-function level. If profiling is enabled, each call to a function (supporting built-ins, operators, functions in oct- and mex-files, user-defined functions in Octave code and anonymous functions) is recorded while running Octave -code. After that, this data can aid in analyzing the code behavior, and +code. After that, this data can aid in analyzing the code behavior, and is in particular helpful for finding ``hot spots'' in the code which use up a lot of computation time and are the best targets to spend optimization efforts on. @@ -207,7 +207,7 @@ @DOCSTRING(profile) An easy way to get an overview over the collected data is -@code{profshow}. This function takes the profiler data returned by +@code{profshow}. This function takes the profiler data returned by @code{profile} as input and prints a flat profile, for instance: @example @@ -223,7 +223,7 @@ This shows that most of the run time was spent executing the function @samp{myfib}, and some minor proportion evaluating the listed binary -operators. Furthermore, it is shown how often the function was called +operators. Furthermore, it is shown how often the function was called and the profiler also records that it is recursive. @DOCSTRING(profshow) @@ -233,12 +233,11 @@ @node Profiler Example @section Profiler Example -Below, we will give a short example of a profiler session. See also +Below, we will give a short example of a profiler session. See also @ref{Profiling} for the documentation of the profiler functions in -detail. Consider the code: +detail. Consider the code: @example -@group global N A; N = 300; @@ -274,7 +273,6 @@ fib = bar (N - 1) + bar (N - 2); endif endfunction -@end group @end example If we execute the two main functions, we get: @@ -291,7 +289,7 @@ But this does not give much information about where this time is spent; for instance, whether the single call to @code{expm} is more expensive -or the recursive time-stepping itself. To get a more detailed picture, +or the recursive time-stepping itself. To get a more detailed picture, we can use the profiler. @example @@ -326,29 +324,29 @@ The entries are the individual functions which have been executed (only the 10 most important ones), together with some information for each of -them. The entries like @samp{binary *} denote operators, while other -entries are ordinary functions. They include both built-ins like -@code{expm} and our own routines (for instance @code{timesteps}). From +them. The entries like @samp{binary *} denote operators, while other +entries are ordinary functions. They include both built-ins like +@code{expm} and our own routines (for instance @code{timesteps}). From this profile, we can immediately deduce that @code{expm} uses up the largest proportion of the processing time, even though it is only called -once. The second expensive operation is the matrix-vector product in the -routine @code{timesteps}. @footnote{We only know it is the binary +once. The second expensive operation is the matrix-vector product in the +routine @code{timesteps}. @footnote{We only know it is the binary multiplication operator, but fortunately this operator appears only at one place in the code and thus we know which occurrence takes so much -time. If there were multiple places, we would have to use the +time. If there were multiple places, we would have to use the hierarchical profile to find out the exact place which uses up the time which is not covered in this example.} Timing, however, is not the only information available from the profile. The attribute column shows us that @code{timesteps} calls itself -recursively. This may not be that remarkable in this example (since it's -clear anyway), but could be helpful in a more complex setting. As to the +recursively. This may not be that remarkable in this example (since it's +clear anyway), but could be helpful in a more complex setting. As to the question of why is there a @samp{binary \} in the output, we can easily -shed some light on that too. Note that @code{data} is a structure array +shed some light on that too. Note that @code{data} is a structure array (@ref{Structure Arrays}) which contains the field @code{FunctionTable}. -This stores the raw data for the profile shown. The number in the first +This stores the raw data for the profile shown. The number in the first column of the table gives the index under which the shown function can -be found there. Looking up @code{data.FunctionTable(41)} gives: +be found there. Looking up @code{data.FunctionTable(41)} gives: @example @group @@ -364,13 +362,13 @@ @end example Here we see the information from the table again, but have additional -fields @code{Parents} and @code{Children}. Those are both arrays, which +fields @code{Parents} and @code{Children}. Those are both arrays, which contain the indices of functions which have directly called the function in question (which is entry 7, @code{expm}, in this case) or been called -by it (no functions). Hence, the backslash operator has been used +by it (no functions). Hence, the backslash operator has been used internally by @code{expm}. -Now let's take a look at @code{bar}. For this, we start a fresh +Now let's take a look at @code{bar}. For this, we start a fresh profiling session (@code{profile on} does this; the old data is removed before the profiler is restarted): @@ -387,6 +385,7 @@ This gives: @example +@group # Function Attr Time (s) Calls ------------------------------------------------------- 1 bar R 2.091 13529 @@ -398,14 +397,15 @@ 6 nargin 0.000 1 7 binary != 0.000 1 9 __profiler_enable__ 0.000 1 +@end group @end example -Unsurprisingly, @code{bar} is also recursive. It has been called 13,529 +Unsurprisingly, @code{bar} is also recursive. It has been called 13,529 times in the course of recursively calculating the Fibonacci number in a suboptimal way, and most of the time was spent in @code{bar} itself. Finally, let's say we want to profile the execution of both @code{foo} -and @code{bar} together. Since we already have the run-time data +and @code{bar} together. Since we already have the run-time data collected for @code{bar}, we can restart the profiler without clearing the existing data and collect the missing statistics about @code{foo}. This is done by:
--- a/doc/interpreter/doccheck/mk_undocumented_list +++ b/doc/interpreter/doccheck/mk_undocumented_list @@ -120,7 +120,6 @@ SEEK_END semicolon setenv -shell_cmd toc triu unimplemented
--- a/doc/interpreter/expr.txi +++ b/doc/interpreter/expr.txi @@ -55,28 +55,38 @@ Indices may be scalars, vectors, ranges, or the special operator @samp{:}, which may be used to select entire rows or columns. -Vectors are indexed using a single index expression. Matrices may be -indexed using one or two indices. When using a single index -expression, the elements of the matrix are taken in column-first order; -the dimensions of the output match those of the index expression. For -example, +Vectors are indexed using a single index expression. Matrices (2-D) +and higher multi-dimensional arrays are indexed using either one index +or @math{N} indices where @math{N} is the dimension of the array. +When using a single index expression to index 2-D or higher data the +elements of the array are taken in column-first order (like Fortran). + +The output from indexing assumes the dimensions of the index +expression. For example: @example @group -a(2) # a scalar -a(1:2) # a row vector -a([1; 2]) # a column vector +a(2) # result is a scalar +a(1:2) # result is a row vector +a([1; 2]) # result is a column vector @end group @end example As a special case, when a colon is used as a single index, the output -is a column vector containing all the elements of the vector or matrix. -For example: +is a column vector containing all the elements of the vector or +matrix. For example: @example -a(:) # a column vector +@group +a(:) # result is a column vector +a(:)' # result is a row vector +@end group @end example +The above two code idioms are often used in place of @code{reshape} +when a simple vector, rather than an arbitrarily sized array, is +needed. + Given the matrix @example @@ -84,32 +94,89 @@ @end example @noindent -all of the following expressions are equivalent +all of the following expressions are equivalent and select the first +row of the matrix. @example @group -a(1, [1, 2]) -a(1, 1:2) -a(1, :) +a(1, [1, 2]) # row 1, columns 1 and 2 +a(1, 1:2) # row 1, columns in range 1-2 +a(1, :) # row 1, all columns +@end group +@end example + +@cindex @code{end}, indexing +@cindex :end + +In index expressions the keyword @code{end} automatically refers to +the last entry for a particular dimension. This magic index can also +be used in ranges and typically eliminates the needs to call +@code{size} or @code{length} to gather array bounds before indexing. +For example: + +@example +@group +a = [1, 2, 3, 4]; + +a(1:end/2) # first half of a => [1, 2] +a(end + 1) = 5; # append element +a(end) = []; # delete element +a(1:2:end) # odd elements of a => [1, 3] +a(2:2:end) # even elements of a => [2, 4] +a(end:-1:1) # reversal of a => [4, 3, 2 , 1] @end group @end example -@noindent -and select the first row of the matrix. +@menu +* Advanced Indexing:: +@end menu + +@node Advanced Indexing +@subsection Advanced Indexing + +An array with @samp{n} dimensions can be indexed using @samp{m} +indices. More generally, the set of index tuples determining the +result is formed by the Cartesian product of the index vectors (or +ranges or scalars). + +For the ordinary and most common case, @w{@code{m == n}}, and each +index corresponds to its respective dimension. If @w{@code{m < n}} +and every index is less than the size of the array in the +@math{i^{th}} dimension, @code{m(i) < n(i)}, then the index expression +is padded with trailing singleton dimensions (@code{[ones (m-n, 1)]}). +If @w{@code{m < n}} but one of the indices @code{m(i)} is outside the +size of the current array, then the last @w{@code{n-m+1}} dimensions +are folded into a single dimension with an extent equal to the product +of extents of the original dimensions. This is easiest to understand +with an example. -In general, an array with @samp{n} dimensions can be indexed using @samp{m} -indices. If @code{n == m}, each index corresponds to its respective dimension. -The set of index tuples determining the result is formed by the Cartesian -product of the index vectors (or ranges or scalars). If @code{n < m}, then the -array is padded by trailing singleton dimensions. If @code{n > m}, the last -@code{n-m+1} dimensions are folded into a single dimension with extent equal to -product of extents of the original dimensions. +@example +a = reshape (1:8, 2, 2, 2) # Create 3-D array +a = + +ans(:,:,1) = + + 1 3 + 2 4 + +ans(:,:,2) = + + 5 7 + 6 8 -@c FIXED -- sections on variable prefer_zero_one_indexing were removed +a(2,1,2); # Case (m == n): ans = 6 +a(2,1); # Case (m < n), idx within array: + # equivalent to a(2,1,1), ans = 2 +a(2,4); # Case (m < n), idx outside array: + # Dimension 2 & 3 folded into new dimension of size 2x2 = 4 + # Select 2nd row, 4th element of [2, 4, 6, 8], ans = 8 +@end example -Indexing a scalar with a vector of ones can be used to create a -vector the same size as the index vector, with each element equal to -the value of the original scalar. For example, the following statements +One advanced use of indexing is to create arrays filled with a single +value. This can be done by using an index of ones on a scalar value. +The result is an object with the dimensions of the index expression +and every element equal to the original scalar. For example, the +following statements @example @group @@ -121,8 +188,8 @@ @noindent produce a vector whose four elements are all equal to 13. -Similarly, indexing a scalar with two vectors of ones can be used to -create a matrix. For example the following statements +Similarly, by indexing a scalar with two vectors of ones it is +possible to create a matrix. The following statements @example @group @@ -132,20 +199,35 @@ @end example @noindent -create a 2 by 3 matrix with all elements equal to 13. +create a 2x3 matrix with all elements equal to 13. The last example could also be written as @example @group -13 (ones (2, 3)) +13(ones (2, 3)) @end group @end example -It should be, noted that @code{ones (1, n)} (a row vector of ones) results in a -range (with zero increment), and is therefore more efficient when used in index -expression than other forms of @dfn{ones}. In particular, when @samp{r} is a -row vector, the expressions +It is more efficient to use indexing rather than the code construction +@code{scalar * ones (N, M, @dots{})} because it avoids the unnecessary +multiplication operation. Moreover, multiplication may not be +defined for the object to be replicated whereas indexing an array is +always defined. The following code shows how to create a 2x3 cell +array from a base unit which is not itself a scalar. + +@example +@group +@{"Hello"@}(ones (2, 3)) +@end group +@end example + +It should be, noted that @code{ones (1, n)} (a row vector of ones) +results in a range (with zero increment). A range is stored +internally as a starting value, increment, end value, and total number +of values; hence, it is more efficient for storage than a vector or +matrix of ones whenever the number of elements is greater than 4. In +particular, when @samp{r} is a row vector, the expressions @example r(ones (1, n), :) @@ -156,17 +238,22 @@ @end example @noindent -will produce identical results, but the first one will be significantly -faster, at least for @samp{r} and @samp{n} large enough. The reason is that -in the first case the index is kept in a compressed form, which allows Octave -to choose a more efficient algorithm to handle the expression. +will produce identical results, but the first one will be +significantly faster, at least for @samp{r} and @samp{n} large enough. +In the first case the index is held in compressed form as a range +which allows Octave to choose a more efficient algorithm to handle the +expression. -In general, for an user unaware of these subtleties, it is best to use -the function @dfn{repmat} for spreading arrays into bigger ones. +A general recommendation, for a user unaware of these subtleties, is +to use the function @code{repmat} for replicating smaller arrays into +bigger ones. -It is also possible to create a matrix with different values. The -following example creates a 10 dimensional row vector @math{a} containing -the values +A second use of indexing is to speed up code. Indexing is a fast +operation and judicious use of it can reduce the requirement for +looping over individual array elements which is a slow operation. + +Consider the following example which creates a 10-element row vector +@math{a} containing the values @tex $a_i = \sqrt{i}$. @end tex @@ -183,20 +270,22 @@ @end example @noindent -Note that it is quite inefficient to create a vector using a loop like -the one shown in the example above. In this particular case, it would -have been much more efficient to use the expression +It is quite inefficient to create a vector using a loop like this. In +this case, it would have been much more efficient to use the +expression @example a = sqrt (1:10); @end example @noindent -thus avoiding the loop entirely. In cases where a loop is still -required, or a number of values must be combined to form a larger -matrix, it is generally much faster to set the size of the matrix first, -and then insert elements using indexing commands. For example, given a -matrix @code{a}, +which avoids the loop entirely. + +In cases where a loop cannot be avoided, or a number of values must be +combined to form a larger matrix, it is generally faster to set the +size of the matrix first (pre-allocate storage), and then insert +elements using indexing commands. For example, given a matrix +@code{a}, @example @group @@ -221,8 +310,8 @@ @end example @noindent -particularly for large matrices because Octave does not have to -repeatedly resize the result. +because Octave does not have to repeatedly resize the intermediate +result. @DOCSTRING(sub2ind)
--- a/doc/interpreter/func.txi +++ b/doc/interpreter/func.txi @@ -290,8 +290,8 @@ values distinct names. It is possible to use the @code{nthargout} function to obtain only some -of the return values or several at once in a cell array. @ref{Cell Array -Objects} +of the return values or several at once in a cell array. +@ref{Cell Array Objects} @DOCSTRING(nthargout)
--- a/doc/interpreter/install.txi +++ b/doc/interpreter/install.txi @@ -82,7 +82,7 @@ @item --disable-docs Disable building all forms of the documentation (Info, PDF, HTML). The default is to build documentation, but your system will need functioning -Texinfo and Tex installs for this to succeed. +Texinfo and @TeX{} installs for this to succeed. @item --enable-float-truncate This option allows for truncation of intermediate floating point results @@ -747,7 +747,7 @@ these files without @option{-g}. @item -Some people have reported that calls to shell_cmd and the pager do not +Some people have reported that calls to system() and the pager do not work on SunOS systems. This is apparently due to having @w{@code{G_HAVE_SYS_WAIT}} defined to be 0 instead of 1 when compiling @code{libg++}.
--- a/doc/interpreter/intro.txi +++ b/doc/interpreter/intro.txi @@ -562,7 +562,9 @@ Here is a description of an imaginary function @code{foo}: -@deftypefn {Function} {} foo (@var{x}, @var{y}, @dots{}) +@deftypefn {Function} {} foo (@var{x}) +@deftypefnx {Function} {} foo (@var{x}, @var{y}) +@deftypefnx {Function} {} foo (@var{x}, @var{y}, @dots{}) The function @code{foo} subtracts @var{x} from @var{y}, then adds the remaining arguments to the result. If @var{y} is not supplied, then the number 19 is used by default.
--- a/doc/interpreter/io.txi +++ b/doc/interpreter/io.txi @@ -582,7 +582,7 @@ @item @samp{%x}, @samp{%X} Print an integer as an unsigned hexadecimal number. @samp{%x} uses -lower-case letters and @samp{%X} uses upper-case. @xref{Integer +lowercase letters and @samp{%X} uses uppercase. @xref{Integer Conversions}, for details. @item @samp{%f} @@ -591,13 +591,13 @@ @item @samp{%e}, @samp{%E} Print a floating-point number in exponential notation. @samp{%e} uses -lower-case letters and @samp{%E} uses upper-case. @xref{Floating-Point +lowercase letters and @samp{%E} uses uppercase. @xref{Floating-Point Conversions}, for details. @item @samp{%g}, @samp{%G} Print a floating-point number in either normal (fixed-point) or exponential notation, whichever is more appropriate for its magnitude. -@samp{%g} uses lower-case letters and @samp{%G} uses upper-case. +@samp{%g} uses lowercase letters and @samp{%G} uses uppercase. @xref{Floating-Point Conversions}, for details. @item @samp{%c}
--- a/doc/interpreter/octave.texi +++ b/doc/interpreter/octave.texi @@ -383,6 +383,10 @@ * Increment Ops:: * Operator Precedence:: +Index Expressions + +* Advanced Indexing:: + Calling Functions * Call by Value::
--- a/doc/interpreter/package.txi +++ b/doc/interpreter/package.txi @@ -206,7 +206,7 @@ @item package/NEWS This is an optional file describing all user-visible changes worth -mentioning. As this file increases on size, old entries can be moved +mentioning. As this file increases on size, old entries can be moved into @file{package/ONEWS}. @item package/ONEWS
--- a/doc/interpreter/poly.txi +++ b/doc/interpreter/poly.txi @@ -107,7 +107,7 @@ @section Derivatives / Integrals / Transforms Octave comes with functions for computing the derivative and the integral -of a polynomial. The functions @code{polyderiv} and @code{polyint} +of a polynomial. The functions @code{polyder} and @code{polyint} both return new polynomials describing the result. As an example we'll compute the definite integral of @math{p(x) = x^2 + 1} from 0 to 3. @@ -120,8 +120,6 @@ @end group @end example -@DOCSTRING(polyderiv) - @DOCSTRING(polyder) @DOCSTRING(polyint)
--- a/doc/interpreter/stats.txi +++ b/doc/interpreter/stats.txi @@ -118,8 +118,6 @@ @DOCSTRING(histc) -@DOCSTRING(cut) - @c FIXME: really want to put a reference to unique here @c @DOCSTRING(values)
--- a/doc/interpreter/testfun.txi +++ b/doc/interpreter/testfun.txi @@ -34,20 +34,20 @@ @DOCSTRING(test) -@code{test} scans the named script file looking for lines which -start with @code{%!}. The prefix is stripped off and the rest of the -line is processed through the Octave interpreter. If the code +@code{test} scans the named script file looking for lines which start +with the identifier @samp{%!}. The prefix is stripped off and the rest +of the line is processed through the Octave interpreter. If the code generates an error, then the test is said to fail. Since @code{eval()} will stop at the first error it encounters, you must divide your tests up into blocks, with anything in a separate block evaluated separately. Blocks are introduced by the keyword -@code{test} immediately following the @code{%!}. For example: +@code{test} immediately following @samp{%!}. For example: @example @group - %!test error ("this test fails!"); - %!test "test doesn't fail. it doesn't generate an error"; +%!test error ("this test fails!"); +%!test "test doesn't fail. it doesn't generate an error"; @end group @end example @@ -55,9 +55,9 @@ @example @group - ***** test error ('this test fails!') - !!!!! test failed - this test fails! + ***** test error ("this test fails!") +!!!!! test failed +this test fails! @end group @end example @@ -66,16 +66,16 @@ @example @group - %!test - %! @var{a} = [1, 2, 3; 4, 5, 6]; B = [1; 2]; - %! expect = [ @var{a} ; 2*@var{a} ]; - %! get = kron (@var{b}, @var{a}); - %! if (any(size(expect) != size(get))) - %! error ("wrong size: expected %d,%d but got %d,%d", - %! size(expect), size(get)); - %! elseif (any(any(expect!=get))) - %! error ("didn't get what was expected."); - %! endif +%!test +%! @var{a} = [1, 2, 3; 4, 5, 6]; B = [1; 2]; +%! expect = [ @var{a} ; 2*@var{a} ]; +%! get = kron (@var{b}, @var{a}); +%! if (any (size (expect) != size (get))) +%! error ("wrong size: expected %d,%d but got %d,%d", +%! size(expect), size(get)); +%! elseif (any (any (expect != get))) +%! error ("didn't get what was expected."); +%! endif @end group @end example @@ -84,9 +84,9 @@ @example @group - %!test - %! @var{a} = [1, 2, 3; 4, 5, 6]; @var{b} = [1; 2]; - %! assert (kron (@var{b}, @var{a}), [ @var{a}; 2*@var{a} ]); +%!test +%! @var{a} = [1, 2, 3; 4, 5, 6]; @var{b} = [1; 2]; +%! assert (kron (@var{b}, @var{a}), [ @var{a}; 2*@var{a} ]); @end group @end example @@ -95,8 +95,8 @@ @example @group - %!test assert (1+eps, 1, 2*eps) # absolute error - %!test assert (100+100*eps, 100, -2*eps) # relative error +%!test assert (1+eps, 1, 2*eps) # absolute error +%!test assert (100+100*eps, 100, -2*eps) # relative error @end group @end example @@ -105,8 +105,8 @@ @example @group - %!test assert (isempty([])) - %!test assert ([ 1,2; 3,4 ] > 0) +%!test assert (isempty ([])) +%!test assert ([1, 2; 3, 4] > 0) @end group @end example @@ -114,16 +114,32 @@ is a shorthand form: @example - %!assert (@dots{}) +%!assert (@dots{}) @end example @noindent which is equivalent to: @example - %!test assert (@dots{}) +%!test assert (@dots{}) @end example +Occasionally a block of tests will depend on having optional +functionality in Octave. Before testing such blocks the availability of +the required functionality must be checked. A @code{%!testif HAVE_XXX} +block will only be run if Octave was compiled with functionality +@samp{HAVE_XXX}. For example, the sparse single value decomposition, +@code{svds()}, depends on having the @sc{arpack} library. All of the tests +for @code{svds} begin with + +@example +%!testif HAVE_ARPACK +@end example + +@noindent +Review @file{config.h} or @code{octave_config_info ("DEFS")} to see some +of the possible values to check. + Sometimes during development there is a test that should work but is known to fail. You still want to leave the test in because when the final code is ready the test should pass, but you may not be able to @@ -132,45 +148,49 @@ @example @group - %!xtest assert (1==0) - %!xtest fail ('success=1','error')) +%!xtest assert (1==0) +%!xtest fail ("success=1", "error") @end group @end example -Another use of @code{xtest} is for statistical tests which should -pass most of the time but are known to fail occasionally. +@noindent +In this case, the test will run and any failure will be reported. +However, testing is not aborted and subsequent test blocks will be +processed normally. Another use of @code{xtest} is for statistical +tests which should pass most of the time but are known to fail +occasionally. Each block is evaluated in its own function environment, which means that variables defined in one block are not automatically shared with other blocks. If you do want to share variables, then you must declare them as @code{shared} before you use them. For example, the following declares the variable @var{a}, gives it an initial value (default -is empty), then uses it in several subsequent tests. +is empty), and then uses it in several subsequent tests. @example @group - %!shared @var{a} - %! @var{a} = [1, 2, 3; 4, 5, 6]; - %!assert (kron ([1; 2], @var{a}), [ @var{a}; 2*@var{a} ]); - %!assert (kron ([1, 2], @var{a}), [ @var{a}, 2*@var{a} ]); - %!assert (kron ([1,2; 3,4], @var{a}), [ @var{a},2*@var{a}; 3*@var{a},4*@var{a} ]); +%!shared @var{a} +%! @var{a} = [1, 2, 3; 4, 5, 6]; +%!assert (kron ([1; 2], @var{a}), [ @var{a}; 2*@var{a} ]); +%!assert (kron ([1, 2], @var{a}), [ @var{a}, 2*@var{a} ]); +%!assert (kron ([1,2; 3,4], @var{a}), [ @var{a},2*@var{a}; 3*@var{a},4*@var{a} ]); @end group @end example You can share several variables at the same time: @example - %!shared @var{a}, @var{b} +%!shared @var{a}, @var{b} @end example You can also share test functions: @example @group - %!function @var{a} = fn (@var{b}) - %! @var{a} = 2*@var{b}; - %!endfunction - %!assert (@var{fn}(2), 4); +%!function @var{a} = fn (@var{b}) +%! @var{a} = 2*@var{b}; +%!endfunction +%!assert (fn(2), 4); @end group @end example @@ -183,13 +203,13 @@ For example: @example - %!error <passes!> error('this test passes!'); +%!error <passes!> error ("this test passes!"); @end example If the code doesn't generate an error, the test fails. For example: @example - %!error "this is an error because it succeeds."; +%!error "this is an error because it succeeds."; @end example @noindent @@ -197,23 +217,23 @@ @example @group - ***** error "this is an error because it succeeds."; - !!!!! test failed: no error + ***** error "this is an error because it succeeds."; +!!!!! test failed: no error @end group @end example It is important to automate the tests as much as possible, however some tests require user interaction. These can be isolated into demo blocks, which if you are in batch mode, are only run when -called with @code{demo} or @code{verbose}. The code is displayed before -it is executed. For example, +called with @code{demo} or the @code{verbose} option to @code{test}. +The code is displayed before it is executed. For example, @example @group - %!demo - %! @var{t}=[0:0.01:2*pi]; @var{x}=sin(@var{t}); - %! plot(@var{t},@var{x}); - %! you should now see a sine wave in your figure window +%!demo +%! @var{t} = [0:0.01:2*pi]; @var{x} = sin (@var{t}); +%! plot (@var{t}, @var{x}); +%! # you should now see a sine wave in your figure window @end group @end example @@ -222,10 +242,12 @@ @example @group - > @var{t}=[0:0.01:2*pi]; @var{x}=sin(@var{t}); - > plot(@var{t},@var{x}); - > you should now see a sine wave in your figure window - Press <enter> to continue: +funcname example 1: + @var{t} = [0:0.01:2*pi]; @var{x} = sin (@var{t}); + plot (@var{t}, @var{x}); + # you should now see a sine wave in your figure window + +Press <enter> to continue: @end group @end example @@ -234,23 +256,29 @@ If you want to temporarily disable a test block, put @code{#} in place of the block type. This creates a comment block which is echoed -in the log file, but is not executed. For example: +in the log file but not executed. For example: @example @group - %!#demo - %! @var{t}=[0:0.01:2*pi]; @var{x}=sin(@var{t}); - %! plot(@var{t},@var{x}); - %! you should now see a sine wave in your figure window +%!#demo +%! @var{t} = [0:0.01:2*pi]; @var{x} = sin (@var{t}); +%! plot (@var{t}, @var{x}); +%! # you should now see a sine wave in your figure window @end group @end example -Block type summary: +@subsubheading Block type summary: @table @code @item %!test check that entire block is correct +@item %!testif HAVE_XXX +check block only if Octave was compiled with feature HAVE_XXX. + +@item %!xtest +check block, report a test failure but do not abort testing. + @item %!error check for correct error message @@ -277,15 +305,16 @@ @end table You can also create test scripts for builtins and your own C++ -functions. Just put a file of the function name on your path without -any extension and it will be picked up by the test procedure. You -can even embed tests directly in your C++ code: +functions. To do so put a file with the bare function name (no .m +extension) in a directory in the load path and it will be discovered by +the @code{test} function. Alternatively, you can embed tests directly in your +C++ code: @example @group - #if 0 - %!test disp('this is a test') - #endif +#if 0 +%!test disp ("this is a test") +#endif @end group @end example @@ -294,21 +323,16 @@ @example @group - /* - %!test disp('this is a test') - */ +/* +%!test disp ("this is a test") +*/ @end group @end example @noindent -but then the code will have to be on the load path and the user -will have to remember to type test('name.cc'). Conversely, you -can separate the tests from normal Octave script files by putting -them in plain files with no extension rather than in script files. -@c DO I WANT TO INCLUDE THE EDITOR SPECIFIC STATEMENT BELOW??? -@c Don't forget to tell emacs that the plain text file you are using -@c is actually octave code, using something like: -@c -*-octave-*- +However, in this case the raw source code will need to be on the load +path and the user will have to remember to type +@code{test ("funcname.cc")}. @DOCSTRING(assert) @@ -319,10 +343,10 @@ @DOCSTRING(demo) +@DOCSTRING(example) + @DOCSTRING(rundemos) @DOCSTRING(runtests) -@DOCSTRING(example) - @DOCSTRING(speed)
--- a/libcruft/arpack/module.mk +++ b/libcruft/arpack/module.mk @@ -29,7 +29,6 @@ arpack/src/dnapps.f \ arpack/src/dnaup2.f \ arpack/src/dnaupd.f \ - arpack/src/dnaupe.f \ arpack/src/dnconv.f \ arpack/src/dneigh.f \ arpack/src/dneupd.f \ @@ -54,7 +53,6 @@ arpack/src/snapps.f \ arpack/src/snaup2.f \ arpack/src/snaupd.f \ - arpack/src/snaupe.f \ arpack/src/snconv.f \ arpack/src/sneigh.f \ arpack/src/sneupd.f \
--- a/liboctave/Array.cc +++ b/liboctave/Array.cc @@ -84,7 +84,7 @@ void Array<T>::clear (void) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; rep = nil_rep (); @@ -99,7 +99,7 @@ void Array<T>::clear (const dim_vector& dv) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; rep = new ArrayRep (dv.safe_numel ());
--- a/liboctave/Array.h +++ b/liboctave/Array.h @@ -110,8 +110,12 @@ { if (rep->count > 1) { - --rep->count; - rep = new ArrayRep (slice_data, slice_len); + ArrayRep *r = new ArrayRep (slice_data, slice_len); + + if (--rep->count == 0) + delete rep; + + rep = r; slice_data = rep->data; } } @@ -152,10 +156,12 @@ typename Array<T>::ArrayRep *nil_rep (void) const { - static typename Array<T>::ArrayRep *nr - = new typename Array<T>::ArrayRep (); + // NR was originally allocated with new, but that does not seem + // to be necessary since it will never be deleted. So just use + // a static object instead. - return nr; + static typename Array<T>::ArrayRep nr; + return &nr; } public: @@ -225,7 +231,7 @@ ~Array (void) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; } @@ -233,7 +239,7 @@ { if (this != &a) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; rep = a.rep;
--- a/liboctave/Makefile.am +++ b/liboctave/Makefile.am @@ -187,6 +187,7 @@ Range.h \ base-dae.h \ base-de.h \ + base-list.h \ base-min.h \ bsxfun.h \ byte-swap.h \ @@ -243,7 +244,8 @@ randgamma.h \ randmtzig.h \ randpoisson.h \ - regex-match.h \ + regexp.h \ + singleton-cleanup.h \ sparse-sort.h \ sparse-util.h \ statdefs.h \ @@ -451,7 +453,8 @@ oct-time.cc \ oct-uname.cc \ pathsearch.cc \ - regex-match.cc \ + regexp.cc \ + singleton-cleanup.cc \ sparse-sort.cc \ sparse-util.cc \ str-vec.cc \
--- a/liboctave/Sparse.cc +++ b/liboctave/Sparse.cc @@ -667,7 +667,7 @@ template <class T> Sparse<T>::~Sparse (void) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; } @@ -677,7 +677,7 @@ { if (this != &a) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; rep = a.rep;
--- a/liboctave/Sparse.h +++ b/liboctave/Sparse.h @@ -147,8 +147,12 @@ { if (rep->count > 1) { - --rep->count; - rep = new SparseRep (*rep); + SparseRep *r = new SparseRep (*rep); + + if (--rep->count == 0) + delete rep; + + rep = r; } } @@ -165,18 +169,17 @@ typename Sparse<T>::SparseRep *nil_rep (void) const { - static typename Sparse<T>::SparseRep *nr - = new typename Sparse<T>::SparseRep (); - - nr->count++; - - return nr; + static typename Sparse<T>::SparseRep nr; + return &nr; } public: Sparse (void) - : rep (nil_rep ()), dimensions (dim_vector(0,0)) { } + : rep (nil_rep ()), dimensions (dim_vector(0,0)) + { + rep->count++; + } explicit Sparse (octave_idx_type n) : rep (new typename Sparse<T>::SparseRep (n)),
--- a/liboctave/SparseCmplxQR.h +++ b/liboctave/SparseCmplxQR.h @@ -96,7 +96,7 @@ ~SparseComplexQR (void) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; } @@ -104,7 +104,7 @@ { if (this != &a) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; rep = a.rep;
--- a/liboctave/SparseQR.h +++ b/liboctave/SparseQR.h @@ -98,7 +98,7 @@ ~SparseQR (void) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; } @@ -106,7 +106,7 @@ { if (this != &a) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; rep = a.rep;
rename from src/base-list.h rename to liboctave/base-list.h --- a/src/base-list.h +++ b/liboctave/base-list.h @@ -36,7 +36,8 @@ bool empty (void) const { return lst.empty (); } - size_t length (void) const { return lst.size (); } + size_t size (void) const { return lst.size (); } + size_t length (void) const { return size (); } iterator erase (iterator pos) { return lst.erase (pos); } @@ -90,6 +91,8 @@ octave_base_list (void) : lst () { } + octave_base_list (const std::list<elt_type>& l) : lst (l) { } + octave_base_list (const octave_base_list& bl) : lst (bl.lst) { } octave_base_list& operator = (const octave_base_list& bl)
--- a/liboctave/bsxfun.h +++ b/liboctave/bsxfun.h @@ -26,10 +26,12 @@ #include "Array.h" #include "dim-vector.h" +#include "lo-error.h" inline bool -is_valid_bsxfun (const dim_vector& dx, const dim_vector& dy) +is_valid_bsxfun (const std::string& name, const dim_vector& dx, + const dim_vector& dy) { for (int i = 0; i < std::min (dx.length (), dy.length ()); i++) { @@ -38,6 +40,10 @@ if (! ( (xk == yk) || (xk == 1 && yk > 1) || (xk > 1 && yk == 1))) return false; } + + (*current_liboctave_warning_with_id_handler) + ("Octave:auto-bsxfun", "%s: automatic broadcasting operation applied", name.c_str ()); + return true; } @@ -46,7 +52,8 @@ // different here. inline bool -is_valid_inplace_bsxfun (const dim_vector& dr, const dim_vector& dx) +is_valid_inplace_bsxfun (const std::string& name, const dim_vector& dr, + const dim_vector& dx) { octave_idx_type drl = dr.length (), dxl = dx.length (); if (drl < dxl) @@ -60,6 +67,10 @@ if (! ( (rk == xk) || (rk > 1 && xk == 1))) return false; } + + (*current_liboctave_warning_with_id_handler) + ("Octave:auto-bsxfun", "%s: automatic broadcasting operation applied", name.c_str ()); + return true; }
--- a/liboctave/chMatrix.cc +++ b/liboctave/chMatrix.cc @@ -137,7 +137,7 @@ octave_idx_type nr = rows (); octave_idx_type nc = cols (); - if (r == 0 && nr == 0 && nc == 0) + if (r == 0 && (nr == 0 || nc == 0)) return retval; if (r < 0 || r >= nr)
--- a/liboctave/cmd-edit.cc +++ b/liboctave/cmd-edit.cc @@ -42,6 +42,7 @@ #include "oct-env.h" #include "oct-mutex.h" #include "oct-time.h" +#include "singleton-cleanup.h" command_editor *command_editor::instance = 0; @@ -831,7 +832,12 @@ bool retval = true; if (! instance) - make_command_editor (); + { + make_command_editor (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) {
--- a/liboctave/cmd-edit.h +++ b/liboctave/cmd-edit.h @@ -184,6 +184,8 @@ // The real thing. static command_editor *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + protected: // To use something other than the GNU readline library, derive a new
--- a/liboctave/cmd-hist.cc +++ b/liboctave/cmd-hist.cc @@ -49,6 +49,7 @@ #include "oct-rl-hist.h" #include "file-stat.h" +#include "singleton-cleanup.h" class gnu_history : public command_history @@ -467,7 +468,12 @@ bool retval = true; if (! instance) - make_command_history (); + { + make_command_history (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) {
--- a/liboctave/cmd-hist.h +++ b/liboctave/cmd-hist.h @@ -126,6 +126,8 @@ // The real thing. static command_history *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + protected: // To use something other than the GNU history library, derive a new
--- a/liboctave/dim-vector.h +++ b/liboctave/dim-vector.h @@ -32,6 +32,7 @@ #include "lo-error.h" #include "lo-macros.h" +#include "oct-refcount.h" // Rationale: This implementation is more tricky than Array, but the // big plus is that dim_vector requires only one allocation instead of @@ -128,8 +129,12 @@ { if (count () > 1) { - --count(); - rep = clonerep (); + octave_idx_type *new_rep = clonerep (); + + if (OCTREFCOUNT_ATOMIC_DECREMENT(&(count())) == 0) + freerep (); + + rep = new_rep; } } @@ -222,9 +227,11 @@ static octave_idx_type dim_max (void); - explicit dim_vector (void) : rep (nil_rep ()) { count()++; } + explicit dim_vector (void) : rep (nil_rep ()) + { OCTREFCOUNT_ATOMIC_INCREMENT (&(count())); } - dim_vector (const dim_vector& dv) : rep (dv.rep) { count()++; } + dim_vector (const dim_vector& dv) : rep (dv.rep) + { OCTREFCOUNT_ATOMIC_INCREMENT (&(count())); } static dim_vector alloc (int n) { @@ -235,11 +242,11 @@ { if (&dv != this) { - if (--count() <= 0) + if (OCTREFCOUNT_ATOMIC_DECREMENT (&(count())) == 0) freerep (); rep = dv.rep; - count()++; + OCTREFCOUNT_ATOMIC_INCREMENT (&(count())); } return *this; @@ -247,7 +254,7 @@ ~dim_vector (void) { - if (--count() <= 0) + if (OCTREFCOUNT_ATOMIC_DECREMENT (&(count())) == 0) freerep (); } @@ -265,7 +272,7 @@ { octave_idx_type *r = resizerep (n, fill_value); - if (--count() <= 0) + if (OCTREFCOUNT_ATOMIC_DECREMENT (&(count())) == 0) freerep (); rep = r;
--- a/liboctave/file-ops.cc +++ b/liboctave/file-ops.cc @@ -42,11 +42,12 @@ #include "file-ops.h" #include "file-stat.h" #include "oct-env.h" +#include "oct-locbuf.h" #include "oct-passwd.h" #include "pathlen.h" #include "quit.h" +#include "singleton-cleanup.h" #include "str-vec.h" -#include "oct-locbuf.h" file_ops *file_ops::instance = 0; @@ -73,13 +74,16 @@ instance = new file_ops (system_dir_sep_char, system_dir_sep_str, system_dir_sep_chars); - if (! instance) - { - (*current_liboctave_error_handler) - ("unable to create file_ops object!"); + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } - retval = false; - } + if (! instance) + { + (*current_liboctave_error_handler) + ("unable to create file_ops object!"); + + retval = false; } return retval;
--- a/liboctave/file-ops.h +++ b/liboctave/file-ops.h @@ -99,6 +99,8 @@ static file_ops *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + // No copying! file_ops (const file_ops&);
--- a/liboctave/mach-info.cc +++ b/liboctave/mach-info.cc @@ -27,6 +27,7 @@ #include "f77-fcn.h" #include "lo-error.h" #include "mach-info.h" +#include "singleton-cleanup.h" extern "C" { @@ -163,7 +164,12 @@ bool retval = true; if (! instance) - instance = new oct_mach_info (); + { + instance = new oct_mach_info (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) {
--- a/liboctave/mach-info.h +++ b/liboctave/mach-info.h @@ -61,6 +61,8 @@ static oct_mach_info *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + // The floating point format for the current machine. mutable float_format native_float_fmt;
--- a/liboctave/mx-inlines.cc +++ b/liboctave/mx-inlines.cc @@ -372,7 +372,7 @@ op (r.length (), r.fortran_vec (), x.data (), y.data ()); return r; } - else if (is_valid_bsxfun (dx, dy)) + else if (is_valid_bsxfun (opname, dx, dy)) { return do_bsxfun_op (x, y, op, op1, op2); } @@ -415,7 +415,7 @@ { op (r.length (), r.fortran_vec (), x.data ()); } - else if (is_valid_inplace_bsxfun (dr, dx)) + else if (is_valid_inplace_bsxfun (opname, dr, dx)) { do_inplace_bsxfun_op (r, x, op, op1); }
--- a/liboctave/oct-binmap.h +++ b/liboctave/oct-binmap.h @@ -174,7 +174,7 @@ return binmap<U, T, R, F> (xa, ya(0), fcn); else if (xad != yad) { - if (is_valid_bsxfun (xad, yad)) + if (is_valid_bsxfun (name, xad, yad)) { bsxfun_wrapper<U, T, R, F>::set_f(fcn); return do_bsxfun_op (xa, ya,
--- a/liboctave/oct-env.cc +++ b/liboctave/oct-env.cc @@ -58,6 +58,7 @@ #include "oct-env.h" #include "oct-passwd.h" #include "oct-syscalls.h" +#include "singleton-cleanup.h" octave_env::octave_env (void) : follow_symbolic_links (true), verbatim_pwd (true), @@ -81,7 +82,12 @@ bool retval = true; if (! instance) - instance = new octave_env (); + { + instance = new octave_env (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) {
--- a/liboctave/oct-env.h +++ b/liboctave/oct-env.h @@ -115,6 +115,9 @@ // The real thing. static octave_env *instance; + + static void cleanup_instance (void) { delete instance; instance = 0; } + // TRUE means follow symbolic links that point to directories just // as if they are real directories. bool follow_symbolic_links;
--- a/liboctave/oct-fftw.cc +++ b/liboctave/oct-fftw.cc @@ -33,6 +33,7 @@ #include "oct-fftw.h" #include "quit.h" #include "oct-locbuf.h" +#include "singleton-cleanup.h" octave_fftw_planner *octave_fftw_planner::instance = 0; @@ -75,7 +76,12 @@ bool retval = true; if (! instance) - instance = new octave_fftw_planner (); + { + instance = new octave_fftw_planner (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) { @@ -383,7 +389,12 @@ bool retval = true; if (! instance) - instance = new octave_float_fftw_planner (); + { + instance = new octave_float_fftw_planner (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) {
--- a/liboctave/oct-fftw.h +++ b/liboctave/oct-fftw.h @@ -108,6 +108,8 @@ static octave_fftw_planner *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + fftw_plan do_create_plan (int dir, const int rank, const dim_vector dims, octave_idx_type howmany, octave_idx_type stride, @@ -243,6 +245,8 @@ static octave_float_fftw_planner *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + fftwf_plan do_create_plan (int dir, const int rank, const dim_vector dims, octave_idx_type howmany, octave_idx_type stride,
--- a/liboctave/oct-locbuf.cc +++ b/liboctave/oct-locbuf.cc @@ -25,44 +25,55 @@ #endif #include <iostream> + +#include "lo-error.h" #include "oct-locbuf.h" -// Query for configured chunk size, and if not defined, set it to 32 MB. -// FIXME: 32MB is hard-coded. Maybe we could use something better, like -// querying for available physical memory. +// FIXME -- Maybe we should querying for available physical memory? + #ifndef OCTAVE_LOCBUF_CHUNKSIZE_MB #define OCTAVE_LOCBUF_CHUNKSIZE_MB 32 #endif // Each chunk will be at least this big. + const size_t octave_chunk_buffer::chunk_size = static_cast<size_t> (OCTAVE_LOCBUF_CHUNKSIZE_MB) << 20; -char *octave_chunk_buffer::top = 0, *octave_chunk_buffer::chunk = 0; +char *octave_chunk_buffer::top = 0; +char *octave_chunk_buffer::chunk = 0; size_t octave_chunk_buffer::left = 0; +size_t octave_chunk_buffer::active = 0; octave_chunk_buffer::octave_chunk_buffer (size_t size) : cnk (0), dat (0) { - // Alignment mask. The size of double or long int, whichever is greater. - // All data will be aligned to this size. If it's not enough for a type, - // that type should not be declared as POD. + // Alignment mask. The size of double or long int, whichever is + // greater. All data will be aligned to this size. If it's not + // enough for a type, that type should not be declared as POD. + static const size_t align_mask = (sizeof (long) < sizeof (double) ? sizeof (double) : sizeof (long)) - 1; - if (! size) return; + active++; + + if (! size) + return; + // Align size. Note that size_t is unsigned, so size-1 must correctly // wrap around. + size = ((size - 1) | align_mask) + 1; if (size > left) { // Big buffers (> 1/8 chunk) will be allocated as stand-alone and // won't disrupt the chain. + if (size > chunk_size >> 3) { - // Use new [] to get std::bad_alloc if out of memory. Could as - // well be std::malloc and handle that ourselves. + // Use new [] to get std::bad_alloc if out of memory. + dat = new char [size]; return; } @@ -73,6 +84,7 @@ } // Now allocate memory from the chunk and update state. + cnk = chunk; dat = top; left -= size; @@ -81,24 +93,55 @@ octave_chunk_buffer::~octave_chunk_buffer (void) { + active--; + if (cnk == chunk) { - // Our chunk is still the active one. Just restore the state. + // Our chunk is still the active one. Just restore the state. + left += top - dat; top = dat; } - else if (! cnk) + else { - // We were a stand-alone buffer. - delete [] dat; + if (cnk) + { + // Responsible for deletion. + + delete [] chunk; + chunk = cnk; + top = dat; + + // FIXME -- the following calcuation of remaining data will + // only work if each chunk has the same chunk_size. + + left = chunk_size - (dat - cnk); + } + else + { + // We were a stand-alone buffer. + + delete [] dat; + } + } +} + +// Clear the final chunk of allocated memory. + +void +octave_chunk_buffer::clear (void) +{ + if (active == 0) + { + delete [] chunk; + chunk = 0; + top = 0; + left = 0; } else { - // Responsible for deletion. - delete [] chunk; - chunk = cnk; - top = dat; - // FIXME: This will only work if chunk_size is constant. - left = chunk_size - (dat - cnk); + (*current_liboctave_warning_handler) + ("octave_chunk_buffer::clear: %d active allocations remain!", + active); } }
--- a/liboctave/oct-locbuf.h +++ b/liboctave/oct-locbuf.h @@ -26,8 +26,9 @@ #include <cstddef> #include "oct-cmplx.h" -// The default local buffer simply encapsulates an *array* pointer that gets -// delete[]d automatically. For common POD types, we provide specializations. +// The default local buffer simply encapsulates an *array* pointer +// that gets deleted automatically. For common POD types, we provide +// specializations. template <class T> class octave_local_buffer @@ -50,16 +51,17 @@ octave_local_buffer& operator = (const octave_local_buffer&); }; -// For buffers of POD types, we'll be more smart. There is one thing that -// differentiates a local buffer from a dynamic array - the local buffers, if -// not manipulated improperly, have a FIFO semantics, meaning that if buffer B -// is allocated after buffer A, B *must* be deallocated before A. This is -// *guaranteed* if you use local buffer exclusively through the -// OCTAVE_LOCAL_BUFFER macro, because the C++ standard *mandates* explicit -// local objects be destroyed in reverse order of declaration. -// Therefore, we can avoid memory fragmentation by allocating fairly large -// chunks of memory and serving local buffers from them in a stack-like manner. -// The first returning buffer in previous chunk will be responsible for +// For buffers of POD types, we'll be smarter. There is one thing +// that differentiates a local buffer from a dynamic array - the local +// buffers, if not manipulated improperly, have a FIFO semantics, +// meaning that if buffer B is allocated after buffer A, B *must* be +// deallocated before A. This is *guaranteed* if you use local buffer +// exclusively through the OCTAVE_LOCAL_BUFFER macro, because the C++ +// standard requires that explicit local objects be destroyed in +// reverse order of declaration. Therefore, we can avoid memory +// fragmentation by allocating fairly large chunks of memory and +// serving local buffers from them in a stack-like manner. The first +// returning buffer in previous chunk will be responsible for // deallocating the chunk. class octave_chunk_buffer @@ -72,13 +74,30 @@ char *data (void) const { return dat; } + static OCTAVE_API void clear (void); + private: + + // The number of bytes we allocate for each large chunk of memory we + // manage. static const size_t chunk_size; - static char *top, *chunk; + // Pointer to the end end of the last allocation. + static char *top; + + // Pointer to the current active chunk. + static char *chunk; + + // The number of bytes remaining in the active chunk. static size_t left; + // The number of active allocations. + static size_t active; + + // Pointer to the current chunk. char *cnk; + + // Pointer to the beginning of the most recent allocation. char *dat; // No copying! @@ -86,8 +105,8 @@ octave_chunk_buffer& operator = (const octave_chunk_buffer&); }; -// This specializes octave_local_buffer to use the chunked buffer mechanism -// for POD types. +// This specializes octave_local_buffer to use the chunked buffer +// mechanism for POD types. #define SPECIALIZE_POD_BUFFER(TYPE) \ template <> \ class octave_local_buffer<TYPE> : private octave_chunk_buffer \ @@ -143,32 +162,37 @@ } }; -// If the compiler supports dynamic stack arrays, we can use the attached hack -// to place small buffer arrays on the stack. It may be even faster than our -// obstack-like optimization, but is dangerous because stack is a very limited -// resource, so we disable it. -#if 0 //defined (HAVE_DYNAMIC_AUTO_ARRAYS) +// If the compiler supports dynamic stack arrays, we can use the +// attached hack to place small buffer arrays on the stack. It may be +// even faster than our obstack-like optimization, but is dangerous +// because stack is a very limited resource, so we disable it. + +#if 0 // defined (HAVE_DYNAMIC_AUTO_ARRAYS) // Maximum buffer size (in bytes) to be placed on the stack. #define OCTAVE_LOCAL_BUFFER_MAX_STACK_SIZE 8192 -// If we have automatic arrays, we use an automatic array if the size is small -// enough. To avoid possibly evaluating `size' multiple times, we first cache -// it. Note that we always construct both the stack array and the -// octave_local_buffer object, but only one of them will be nonempty. +// If we have automatic arrays, we use an automatic array if the size +// is small enough. To avoid possibly evaluating `size' multiple +// times, we first cache it. Note that we always construct both the +// stack array and the octave_local_buffer object, but only one of +// them will be nonempty. #define OCTAVE_LOCAL_BUFFER(T, buf, size) \ const size_t _bufsize_ ## buf = size; \ const bool _lbufaut_ ## buf = _bufsize_ ## buf * sizeof (T) \ <= OCTAVE_LOCAL_BUFFER_MAX_STACK_SIZE; \ T _bufaut_ ## buf [_lbufaut_ ## buf ? _bufsize_ ## buf : 0]; \ - octave_local_buffer<T> _bufheap_ ## buf (!_lbufaut_ ## buf ? _bufsize_ ## buf : 0); \ - T *buf = _lbufaut_ ## buf ? _bufaut_ ## buf : static_cast<T *> (_bufheap_ ## buf) + octave_local_buffer<T> _bufheap_ ## buf \ + (!_lbufaut_ ## buf ? _bufsize_ ## buf : 0); \ + T *buf = _lbufaut_ ## buf \ + ? _bufaut_ ## buf : static_cast<T *> (_bufheap_ ## buf) #else -// If we don't have automatic arrays, we simply always use octave_local_buffer. +// If we don't have automatic arrays, we simply always use +// octave_local_buffer. #define OCTAVE_LOCAL_BUFFER(T, buf, size) \ octave_local_buffer<T> _buffer_ ## buf (size); \ @@ -176,13 +200,14 @@ #endif -// Yeah overloading macros would be nice. -// Note: we use weird variables in the for loop to avoid warnings about -// shadowed parameters. +// Note: we use weird variables in the for loop to avoid warnings +// about shadowed parameters. + #define OCTAVE_LOCAL_BUFFER_INIT(T, buf, size, value) \ OCTAVE_LOCAL_BUFFER(T, buf, size); \ for (size_t _buf_iter = 0, _buf_size = size; \ - _buf_iter < _buf_size; _buf_iter++) buf[_buf_iter] = value + _buf_iter < _buf_size; _buf_iter++) \ + buf[_buf_iter] = value #endif
--- a/liboctave/oct-mutex.h +++ b/liboctave/oct-mutex.h @@ -23,6 +23,8 @@ #if !defined (octave_octave_mutex_h) #define octave_octave_mutex_h 1 +#include "oct-refcount.h" + class octave_mutex; class @@ -42,7 +44,7 @@ virtual bool try_lock (void); private: - int count; + octave_refcount<int> count; }; class
--- a/liboctave/oct-rand.cc +++ b/liboctave/oct-rand.cc @@ -29,18 +29,19 @@ #include <stdint.h> +#include "data-conv.h" #include "f77-fcn.h" +#include "lo-error.h" #include "lo-ieee.h" -#include "lo-error.h" #include "lo-mappers.h" +#include "mach-info.h" +#include "oct-locbuf.h" #include "oct-rand.h" #include "oct-time.h" -#include "data-conv.h" +#include "randgamma.h" #include "randmtzig.h" #include "randpoisson.h" -#include "randgamma.h" -#include "mach-info.h" -#include "oct-locbuf.h" +#include "singleton-cleanup.h" extern "C" { @@ -89,7 +90,12 @@ bool retval = true; if (! instance) - instance = new octave_rand (); + { + instance = new octave_rand (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) {
--- a/liboctave/oct-rand.h +++ b/liboctave/oct-rand.h @@ -160,6 +160,8 @@ static octave_rand *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + enum { unknown_dist,
--- a/liboctave/oct-refcount.h +++ b/liboctave/oct-refcount.h @@ -23,6 +23,30 @@ #if !defined (octave_refcount_h) #define octave_refcount_h 1 +#ifndef OCTAVE_CONFIG_INCLUDED +# error "The file <octave/config.h> must be included before oct-refcount.h." +#endif + +#if defined (USE_ATOMIC_REFCOUNT) && (defined (_MSC_VER) || defined (__GNUC__)) +# if defined (_MSC_VER) +# include <intrin.h> +# define OCTREFCOUNT_ATOMIC_INCREMENT(x) _InterlockedIncrement((long*)x) +# define OCTREFCOUNT_ATOMIC_DECREMENT(x) _InterlockedDecrement((long*)x) +# define OCTREFCOUNT_ATOMIC_INCREMENT_POST(x) _InterlockedExchangeAdd((long*)x, 1) +# define OCTREFCOUNT_ATOMIC_DECREMENT_POST(x) _InterlockedExchangeAdd((long*)x, -1) +# elif defined (__GNUC__) +# define OCTREFCOUNT_ATOMIC_INCREMENT(x) __sync_add_and_fetch(x, 1) +# define OCTREFCOUNT_ATOMIC_DECREMENT(x) __sync_add_and_fetch(x, -1) +# define OCTREFCOUNT_ATOMIC_INCREMENT_POST(x) __sync_fetch_and_add(x, 1) +# define OCTREFCOUNT_ATOMIC_DECREMENT_POST(x) __sync_fetch_and_add(x, -1) +# endif +#else // Generic non-locking versions +# define OCTREFCOUNT_ATOMIC_INCREMENT(x) ++(*(x)) +# define OCTREFCOUNT_ATOMIC_DECREMENT(x) --(*(x)) +# define OCTREFCOUNT_ATOMIC_INCREMENT_POST(x) (*(x))++ +# define OCTREFCOUNT_ATOMIC_DECREMENT_POST(x) (*(x))-- +#endif + // Encapsulates a reference counter. template <class T> class octave_refcount @@ -35,28 +59,28 @@ // Increment/Decrement. int is postfix. count_type operator++(void) { - return ++count; + return OCTREFCOUNT_ATOMIC_INCREMENT (&count); } count_type operator++(int) { - return count++; + return OCTREFCOUNT_ATOMIC_INCREMENT_POST (&count); } count_type operator--(void) { - return --count; + return OCTREFCOUNT_ATOMIC_DECREMENT (&count); } count_type operator--(int) { - return count--; + return OCTREFCOUNT_ATOMIC_DECREMENT_POST (&count); } - operator count_type (void) const { return count; } - - // For low-level optimizations only. - count_type& direct (void) const { return count; } + operator count_type (void) const + { + return static_cast<count_type const volatile&> (count); + } private: count_type count;
--- a/liboctave/oct-spparms.cc +++ b/liboctave/oct-spparms.cc @@ -29,6 +29,7 @@ #include "lo-ieee.h" #include "oct-spparms.h" +#include "singleton-cleanup.h" octave_sparse_params *octave_sparse_params::instance = 0; @@ -38,7 +39,12 @@ bool retval = true; if (! instance) - instance = new octave_sparse_params (); + { + instance = new octave_sparse_params (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) {
--- a/liboctave/oct-spparms.h +++ b/liboctave/oct-spparms.h @@ -95,6 +95,8 @@ static octave_sparse_params *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + void do_defaults (void); void do_tight (void);
--- a/liboctave/oct-time.cc +++ b/liboctave/oct-time.cc @@ -36,6 +36,7 @@ #include "lo-error.h" #include "lo-math.h" #include "lo-utils.h" +#include "oct-locbuf.h" #include "oct-time.h" octave_time::octave_time (const octave_base_tm& tm) @@ -53,6 +54,10 @@ t.tm_yday = tm.yday (); t.tm_isdst = tm.isdst (); +#if defined (HAVE_STRUCT_TM_GMTOFF) + t.tm_gmtoff = tm.gmtoff (); +#endif + #if defined (HAVE_STRUCT_TM_TM_ZONE) std::string s = tm.zone (); char *ps = strsave (s.c_str ()); @@ -98,29 +103,17 @@ // // So, we no longer check limits here. -#if 0 -#define DEFINE_SET_INT_FIELD_FCN(f, lo, hi) \ +#define DEFINE_SET_FIELD_FCN(type, f, lo, hi) \ octave_base_tm& \ - octave_base_tm::f (int v) \ - { \ - if (v < lo || v > hi) \ - (*current_liboctave_error_handler) \ - ("invalid value specified for " #f); \ - \ - tm_ ## f = v; \ - \ - return *this; \ - } -#else -#define DEFINE_SET_INT_FIELD_FCN(f, lo, hi) \ - octave_base_tm& \ - octave_base_tm::f (int v) \ + octave_base_tm::f (type v) \ { \ tm_ ## f = v; \ \ return *this; \ } -#endif + +#define DEFINE_SET_INT_FIELD_FCN(f, lo, hi) \ + DEFINE_SET_FIELD_FCN (int, f, lo, hi) DEFINE_SET_INT_FIELD_FCN (usec, 0, 1000000) DEFINE_SET_INT_FIELD_FCN (sec, 0, 61) @@ -132,6 +125,7 @@ DEFINE_SET_INT_FIELD_FCN (wday, 0, 6) DEFINE_SET_INT_FIELD_FCN (yday, 0, 365) DEFINE_SET_INT_FIELD_FCN (isdst, 0, 1) +DEFINE_SET_FIELD_FCN (long, gmtoff, -86400, 0) octave_base_tm& octave_base_tm::zone (const std::string& s) @@ -163,6 +157,10 @@ t.tm_yday = tm_yday; t.tm_isdst = tm_isdst; +#if defined (HAVE_STRUCT_TM_GMTOFF) + t.tm_gmtoff = tm_gmtoff; +#endif + #if defined (HAVE_STRUCT_TM_TM_ZONE) char *ps = strsave (tm_zone.c_str ()); t.tm_zone = ps; @@ -215,6 +213,10 @@ tm_yday = t->tm_yday; tm_isdst = t->tm_isdst; +#if defined (HAVE_STRUCT_TM_GMTOFF) + tm_gmtoff = t->tm_gmtoff; +#endif + #if defined (HAVE_STRUCT_TM_TM_ZONE) if (t->tm_zone) tm_zone = t->tm_zone; @@ -259,12 +261,16 @@ t.tm_yday = 0; t.tm_isdst = 0; +#if defined (HAVE_STRUCT_TM_GMTOFF) + t.tm_gmtoff = 0; +#endif + #if defined (HAVE_STRUCT_TM_TM_ZONE) char *ps = strsave (""); t.tm_zone = ps; #endif - char *p = strsave (str.c_str ()); + const char *p = str.c_str (); char *q = gnulib::strptime (p, fmt.c_str (), &t); @@ -287,8 +293,6 @@ else nchars = 0; - delete [] p; - octave_base_tm::init (&t); #if defined (HAVE_STRUCT_TM_TM_ZONE)
--- a/liboctave/oct-time.h +++ b/liboctave/oct-time.h @@ -174,14 +174,14 @@ octave_base_tm (void) : tm_usec (0), tm_sec (0), tm_min (0), tm_hour (0), tm_mday (0), tm_mon (0), tm_year (0), tm_wday (0), - tm_yday (0), tm_isdst (0), tm_zone ("unknown") + tm_yday (0), tm_isdst (0), tm_gmtoff (0), tm_zone ("unknown") { } octave_base_tm (const octave_base_tm& tm) : tm_usec (tm.tm_usec), tm_sec (tm.tm_sec), tm_min (tm.tm_min), tm_hour (tm.tm_hour), tm_mday (tm.tm_mday), tm_mon (tm.tm_mon), tm_year (tm.tm_year), tm_wday (tm.tm_wday), tm_yday (tm.tm_yday), - tm_isdst (tm.tm_isdst), tm_zone (tm.tm_zone) + tm_isdst (tm.tm_isdst), tm_gmtoff (tm.tm_gmtoff), tm_zone (tm.tm_zone) { } octave_base_tm& operator = (const octave_base_tm& tm) @@ -198,6 +198,7 @@ tm_wday = tm.tm_wday; tm_yday = tm.tm_yday; tm_isdst = tm.tm_isdst; + tm_gmtoff = tm.tm_gmtoff; tm_zone = tm.tm_zone; } @@ -216,6 +217,7 @@ int wday (void) const { return tm_wday; } int yday (void) const { return tm_yday; } int isdst (void) const { return tm_isdst; } + long gmtoff (void) const { return tm_gmtoff; } std::string zone (void) const { return tm_zone; } octave_base_tm& usec (int v); @@ -228,6 +230,7 @@ octave_base_tm& wday (int v); octave_base_tm& yday (int v); octave_base_tm& isdst (int v); + octave_base_tm& gmtoff (long v); octave_base_tm& zone (const std::string& s); std::string strftime (const std::string& fmt) const; @@ -268,6 +271,9 @@ int tm_isdst; // Time zone. + long tm_gmtoff; + + // Time zone. std::string tm_zone; void init (void *p);
--- a/liboctave/pathsearch.cc +++ b/liboctave/pathsearch.cc @@ -31,7 +31,7 @@ #include "lo-utils.h" #include "oct-env.h" #include "pathsearch.h" -#include "str-vec.h" +#include "singleton-cleanup.h" #include "str-vec.h" #include "kpse.cc" @@ -47,7 +47,12 @@ bool retval = true; if (! instance) - instance = new static_members (); + { + instance = new static_members (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) {
--- a/liboctave/pathsearch.h +++ b/liboctave/pathsearch.h @@ -153,6 +153,8 @@ static static_members *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + static bool instance_ok (void); // No copying!
rename from liboctave/regex-match.cc rename to liboctave/regexp.cc --- a/liboctave/regex-match.cc +++ b/liboctave/regexp.cc @@ -1,6 +1,8 @@ /* -Copyright (C) 2008-2011 David Bateman +Copyright (C) 2011 John W. Eaton +Copyright (C) 2005-2011 David Bateman +Copyright (C) 2002-2005 Paul Kienzle This file is part of Octave. @@ -24,126 +26,554 @@ #include <config.h> #endif +#include <list> +#include <sstream> +#include <string> #include <vector> -#include <iostream> -#include <string> -#include "regex-match.h" -#include "str-vec.h" -#include "oct-locbuf.h" +#if defined (HAVE_PCRE_H) +#include <pcre.h> +#elif defined (HAVE_PCRE_PCRE_H) +#include <pcre/pcre.h> +#endif -regex_match& -regex_match::operator = (const regex_match& gm) -{ - if (this != &gm) - { -#if HAVE_REGEX - for (int i = 0; i < pat.length (); i++) - regfree (compiled +i); - delete [] compiled; -#endif - pat = gm.pat; - case_insen = gm.case_insen; - init (); - } - return *this; -} +#include "Matrix.h" +#include "base-list.h" +#include "lo-error.h" +#include "oct-locbuf.h" +#include "quit.h" +#include "regexp.h" +#include "str-vec.h" -regex_match::~regex_match (void) -{ -#if HAVE_REGEX - for (int i = 0; i < pat.length (); i++) - regfree (compiled +i); - delete [] compiled; -#endif -} +// Define the maximum number of retries for a pattern that possibly +// results in an infinite recursion. +#define PCRE_MATCHLIMIT_MAX 10 +// FIXME -- should this be configurable? +#define MAXLOOKBEHIND 10 + +static bool lookbehind_warned = false; + +// FIXME -- don't bother collecting and composing return values the user +// doesn't want. void -regex_match::set_pattern (const std::string& p) +regexp::free (void) { -#if HAVE_REGEX - for (int i = 0; i < pat.length (); i++) - regfree (compiled +i); - delete [] compiled; -#endif - pat = p; - init (); -} - -void -regex_match::set_pattern (const string_vector& p) -{ -#if HAVE_REGEX - for (int i = 0; i < pat.length (); i++) - regfree (compiled +i); - delete [] compiled; -#endif - pat = p; - init (); + if (data) + pcre_free (static_cast<pcre *> (data)); } void -regex_match::init (void) +regexp::compile_internal (void) { -#ifdef HAVE_REGEX - int npat = pat.length (); - int err = 0; - int i; + // If we had a previously compiled pattern, release it. + free (); + + size_t max_length = MAXLOOKBEHIND; + + size_t pos = 0; + size_t new_pos; + int inames = 0; + std::ostringstream buf; + + while ((new_pos = pattern.find ("(?", pos)) != std::string::npos) + { + if (pattern.at (new_pos + 2) == '<' + && !(pattern.at (new_pos + 3) == '=' + || pattern.at (new_pos + 3) == '!')) + { + // The syntax of named tokens in pcre is "(?P<name>...)" while + // we need a syntax "(?<name>...)", so fix that here. Also an + // expression like + // "(?<first>\w+)\s+(?<last>\w+)|(?<last>\w+),\s+(?<first>\w+)" + // should be perfectly legal, while pcre does not allow the same + // named token name on both sides of the alternative. Also fix + // that here by replacing name tokens by dummy names, and dealing + // with the dummy names later. + + size_t tmp_pos = pattern.find_first_of ('>', new_pos); + + if (tmp_pos == std::string::npos) + { + (*current_liboctave_error_handler) + ("regexp: syntax error in pattern"); + return; + } + + std::string tmp_name = + pattern.substr (new_pos+3, tmp_pos-new_pos-3); + + bool found = false; + + for (int i = 0; i < nnames; i++) + { + if (named_pats(i) == tmp_name) + { + named_idx.resize (dim_vector (inames+1, 1)); + named_idx(inames) = i; + found = true; + break; + } + } + + if (! found) + { + named_idx.resize (dim_vector (inames+1, 1)); + named_idx(inames) = nnames; + named_pats.append (tmp_name); + nnames++; + } + + if (new_pos - pos > 0) + buf << pattern.substr (pos, new_pos-pos); + if (inames < 10) + buf << "(?P<n00" << inames++; + else if (inames < 100) + buf << "(?P<n0" << inames++; + else + buf << "(?P<n" << inames++; - compiled = new regex_t [npat]; + pos = tmp_pos; + } + else if (pattern.at (new_pos + 2) == '<') + { + // Find lookbehind operators of arbitrary length (ie like + // "(?<=[a-z]*)") and replace with a maximum length operator + // as PCRE can not yet handle arbitrary length lookahead + // operators. Use the string length as the maximum length to + // avoid issues. + + int brackets = 1; + size_t tmp_pos1 = new_pos + 2; + size_t tmp_pos2 = tmp_pos1; + + while (tmp_pos1 <= pattern.length () && brackets > 0) + { + char ch = pattern.at (tmp_pos1); + + if (ch == '(') + brackets++; + else if (ch == ')') + { + if (brackets > 1) + tmp_pos2 = tmp_pos1; + + brackets--; + } + + tmp_pos1++; + } + + if (brackets != 0) + { + buf << pattern.substr (pos, new_pos - pos) << "(?"; + pos = new_pos + 2; + } + else + { + size_t tmp_pos3 = pattern.find_first_of ("*+", tmp_pos2); - for (i = 0; i < npat; i++) - { - err = regcomp (compiled + i, pat(i).c_str (), - (REG_NOSUB | REG_EXTENDED | - (case_insen ? REG_ICASE : 0))); - if (err) - break; + if (tmp_pos3 != std::string::npos && tmp_pos3 < tmp_pos1) + { + if (!lookbehind_warned) + { + lookbehind_warned = true; + (*current_liboctave_warning_handler) + ("%s: arbitrary length lookbehind patterns are only supported up to length %d", + who.c_str (), MAXLOOKBEHIND); + } + + buf << pattern.substr (pos, new_pos - pos) << "("; + + size_t i; + + if (pattern.at (tmp_pos3) == '*') + i = 0; + else + i = 1; + + for (; i < max_length + 1; i++) + { + buf << pattern.substr (new_pos, tmp_pos3 - new_pos) + << "{" << i << "}"; + buf << pattern.substr (tmp_pos3 + 1, + tmp_pos1 - tmp_pos3 - 1); + if (i != max_length) + buf << "|"; + } + buf << ")"; + } + else + buf << pattern.substr (pos, tmp_pos1 - pos); + + pos = tmp_pos1; + } + } + else + { + buf << pattern.substr (pos, new_pos - pos) << "(?"; + pos = new_pos + 2; + } + } - if (err) + buf << pattern.substr (pos); + + const char *err; + int erroffset; + std::string buf_str = buf.str (); + + int pcre_options + = ((options.case_insensitive () ? PCRE_CASELESS : 0) + | (options.dotexceptnewline () ? 0 : PCRE_DOTALL) + | (options.lineanchors () ? PCRE_MULTILINE : 0) + | (options.freespacing () ? PCRE_EXTENDED : 0)); + + data = pcre_compile (buf_str.c_str (), pcre_options, &err, &erroffset, 0); + + if (! data) + (*current_liboctave_error_handler) + ("%s: %s at position %d of expression", who.c_str (), + err, erroffset); +} + +regexp::match_data +regexp::match (const std::string& buffer) +{ + regexp::match_data retval; + + std::list<regexp::match_element> lst; + + int subpatterns; + int namecount; + int nameentrysize; + char *nametable; + size_t idx = 0; + + pcre *re = static_cast <pcre *> (data); + + pcre_fullinfo (re, 0, PCRE_INFO_CAPTURECOUNT, &subpatterns); + pcre_fullinfo (re, 0, PCRE_INFO_NAMECOUNT, &namecount); + pcre_fullinfo (re, 0, PCRE_INFO_NAMEENTRYSIZE, &nameentrysize); + pcre_fullinfo (re, 0, PCRE_INFO_NAMETABLE, &nametable); + + OCTAVE_LOCAL_BUFFER (int, ovector, (subpatterns+1)*3); + OCTAVE_LOCAL_BUFFER (int, nidx, namecount); + + for (int i = 0; i < namecount; i++) { - int len = regerror (err, compiled + i, 0, 0); - OCTAVE_LOCAL_BUFFER (char, errmsg, len); - regerror(err, compiled + i, errmsg, len); - (*current_liboctave_error_handler) ("%s in pattern (%s)", errmsg, - pat(i).c_str()); + // Index of subpattern in first two bytes MSB first of name. + // Extract index. + nidx[i] = (static_cast<int> (nametable[i*nameentrysize])) << 8 + | static_cast<int> (nametable[i*nameentrysize+1]); + } + + while (true) + { + OCTAVE_QUIT; + + int matches = pcre_exec (re, 0, buffer.c_str (), + buffer.length (), idx, + (idx ? PCRE_NOTBOL : 0), + ovector, (subpatterns+1)*3); + + if (matches == PCRE_ERROR_MATCHLIMIT) + { + // Try harder; start with default value for MATCH_LIMIT + // and increase it. + (*current_liboctave_warning_handler) + ("your pattern caused PCRE to hit its MATCH_LIMIT; trying harder now, but this will be slow"); + + pcre_extra pe; + + pcre_config (PCRE_CONFIG_MATCH_LIMIT, + static_cast <void *> (&pe.match_limit)); + + pe.flags = PCRE_EXTRA_MATCH_LIMIT; + + int i = 0; + while (matches == PCRE_ERROR_MATCHLIMIT + && i++ < PCRE_MATCHLIMIT_MAX) + { + OCTAVE_QUIT; + + pe.match_limit *= 10; + matches = pcre_exec (re, &pe, buffer.c_str (), + buffer.length (), idx, + (idx ? PCRE_NOTBOL : 0), + ovector, (subpatterns+1)*3); + } + } - for (int j = 0; j < i + 1; j++) - regfree (compiled + j); + if (matches < 0 && matches != PCRE_ERROR_NOMATCH) + { + (*current_liboctave_error_handler) + ("%s: internal error calling pcre_exec; error code from pcre_exec is %i", + who.c_str (), matches); + return retval; + } + else if (matches == PCRE_ERROR_NOMATCH) + break; + else if (ovector[1] <= ovector[0]) + { + // Zero sized match. Skip to next char. + idx = ovector[0] + 1; + if (idx < buffer.length ()) + continue; + else + break; + } + else + { + int pos_match = 0; + Matrix token_extents (matches-1, 2); + + for (int i = 1; i < matches; i++) + { + if (ovector[2*i] >= 0 && ovector[2*i+1] > 0 + && (i == 1 || ovector[2*i] != ovector[2*i-2] + || ovector[2*i-1] != ovector[2*i+1]) + && ovector[2*i] >= 0 && ovector[2*i+1] > 0) + { + token_extents(pos_match,0) = double (ovector[2*i]+1); + token_extents(pos_match++,1) = double (ovector[2*i+1]); + } + } + + token_extents.resize (pos_match, 2); + + double start = double (ovector[0]+1); + double end = double (ovector[1]); + + const char **listptr; + int status = pcre_get_substring_list (buffer.c_str (), ovector, + matches, &listptr); + + if (status == PCRE_ERROR_NOMEMORY) + { + (*current_liboctave_error_handler) + ("%s: cannot allocate memory in pcre_get_substring_list", + who.c_str ()); + return retval; + } + + string_vector tokens (pos_match); + string_vector named_tokens (nnames); + int pos_offset = 0; + pos_match = 0; + + for (int i = 1; i < matches; i++) + { + if (ovector[2*i] >= 0 && ovector[2*i+1] > 0) + { + if (i == 1 || ovector[2*i] != ovector[2*i-2] + || ovector[2*i-1] != ovector[2*i+1]) + { + if (namecount > 0) + named_tokens(named_idx(i-pos_offset-1)) = + std::string (*(listptr+nidx[i-pos_offset-1])); + + tokens(pos_match++) = std::string (*(listptr+i)); + } + else + pos_offset++; + } + } + + std::string match_string = std::string (*listptr); + + pcre_free_substring_list (listptr); + + regexp::match_element new_elem (named_tokens, tokens, match_string, + token_extents, start, end); + lst.push_back (new_elem); + idx = ovector[1]; + + if (options.once () || idx >= buffer.length ()) + break; + } } -#else - (*current_liboctave_error_handler) - ("regex not available in this version of Octave"); -#endif + + retval = regexp::match_data (lst, named_pats); + + return retval; } bool -regex_match::match (const std::string& s) +regexp::is_match (const std::string& buffer) { -#if HAVE_REGEX - int npat = pat.length (); - - const char *str = s.c_str (); + regexp::match_data rx_lst = match (buffer); - for (int i = 0; i < npat; i++) - if (regexec (compiled + i, str, 0, 0, 0) == 0) - return true; -#endif + regexp::match_data::const_iterator p = rx_lst.begin (); - return false; + std::string match_string = p->match_string (); + + return ! match_string.empty (); } Array<bool> -regex_match::match (const string_vector& s) +regexp::is_match (const string_vector& buffer) { - int n = s.length (); + octave_idx_type len = buffer.length (); - Array<bool> retval (dim_vector (n, 1)); + Array<bool> retval (dim_vector (len, 1)); - for (int i = 0; i < n; i++) - retval(i) = match (s[i]); + for (octave_idx_type i = 0; i < buffer.length (); i++) + retval(i) = is_match (buffer(i)); return retval; } + +std::string +regexp::replace (const std::string& buffer, const std::string& replacement) +{ + std::string retval; + + // Identify replacement tokens; build a vector of group numbers in + // the replacement string so that we can quickly calculate the size + // of the replacement. + + int tokens = 0; + for (size_t i=1; i < replacement.size (); i++) + { + if (replacement[i-1]=='$' && isdigit (replacement[i])) + { + tokens++; + i++; + } + } + std::vector<int> token (tokens); + + int kk = 0; + for (size_t i = 1; i < replacement.size (); i++) + { + if (replacement[i-1]=='$' && isdigit (replacement[i])) + { + token[kk++] = replacement[i]-'0'; + i++; + } + } + + regexp::match_data rx_lst = match (buffer); + + size_t sz = rx_lst.size (); + + if (sz == 0) + { + retval = buffer; + return retval; + } + + std::string rep; + + if (tokens > 0) + { + // Determine replacement length + const size_t replen = replacement.size () - 2*tokens; + int delta = 0; + regexp::match_data::const_iterator p = rx_lst.begin (); + for (size_t i = 0; i < sz; i++) + { + OCTAVE_QUIT; + + double start = p->start (); + double end = p->end (); + + const Matrix pairs (p->token_extents ()); + size_t pairlen = 0; + for (int j = 0; j < tokens; j++) + { + if (token[j] == 0) + pairlen += static_cast<size_t> (end - start) + 1; + else if (token[j] <= pairs.rows ()) + pairlen += static_cast<size_t> (pairs(token[j]-1,1) + - pairs(token[j]-1,0)) + 1; + } + delta += (static_cast<int> (replen + pairlen) + - static_cast<int> (end - start + 1)); + p++; + } + + // Build replacement string + rep.reserve (buffer.size () + delta); + size_t from = 0; + p = rx_lst.begin (); + for (size_t i = 0; i < sz; i++) + { + OCTAVE_QUIT; + + double start = p->start (); + double end = p->end (); + + const Matrix pairs (p->token_extents ()); + rep.append (&buffer[from], static_cast<size_t> (start - 1) - from); + from = static_cast<size_t> (end - 1) + 1; + + for (size_t j = 1; j < replacement.size (); j++) + { + if (replacement[j-1]=='$' && isdigit (replacement[j])) + { + int k = replacement[j]-'0'; + if (k == 0) + { + // replace with entire match + rep.append (&buffer[static_cast<size_t> (end - 1)], + static_cast<size_t> (end - start) + 1); + } + else if (k <= pairs.rows ()) + { + // replace with group capture + rep.append (&buffer[static_cast<size_t> (pairs(k-1,0)-1)], + static_cast<size_t> (pairs(k-1,1) + - pairs(k-1,0)) + 1); + } + else + { + // replace with nothing + } + j++; + } + else + rep.append (1, replacement[j-1]); + + if (j+1 == replacement.size ()) + rep.append (1, replacement[j]); + } + p++; + } + rep.append (&buffer[from], buffer.size () - from); + } + else + { + // Determine replacement length + const size_t replen = replacement.size (); + int delta = 0; + regexp::match_data::const_iterator p = rx_lst.begin (); + for (size_t i = 0; i < sz; i++) + { + OCTAVE_QUIT; + delta += static_cast<int> (replen) + - static_cast<int> (p->end () - p->start () + 1); + p++; + } + + // Build replacement string + rep.reserve (buffer.size () + delta); + size_t from = 0; + p = rx_lst.begin (); + for (size_t i = 0; i < sz; i++) + { + OCTAVE_QUIT; + rep.append (&buffer[from], + static_cast<size_t> (p->start () - 1) - from); + from = static_cast<size_t> (p->end () - 1) + 1; + rep.append (replacement); + p++; + } + rep.append (&buffer[from], buffer.size () - from); + } + + retval = rep; + return retval; +}
rename from liboctave/regex-match.h rename to liboctave/regexp.h --- a/liboctave/regex-match.h +++ b/liboctave/regexp.h @@ -1,6 +1,7 @@ /* -Copyright (C) 2008-2011 David Bateman +Copyright (C) 2011 John W. Eaton +Copyright (C) 2005-2011 David Bateman This file is part of Octave. @@ -20,80 +21,261 @@ */ -#if !defined (octave_regex_match_h) -#define octave_regex_match_h 1 +#if !defined (octave_regexp_match_h) +#define octave_regexp_match_h 1 +#include <list> +#include <sstream> #include <string> -#if defined (HAVE_REGEX) -#if defined (__MINGW32__) -#define __restrict -#endif -#include <sys/types.h> -#include <regex.h> -#endif - #include "Array.h" +#include "Matrix.h" +#include "base-list.h" #include "str-vec.h" -class -OCTAVE_API -regex_match +class regexp { public: - regex_match (const std::string& p, bool insen = false) - : pat (p), case_insen (insen) -#if HAVE_REGEX - , compiled (0) -#endif + class opts; + class match_data; + + regexp (const std::string& pat = "", + const regexp::opts& opt = regexp::opts (), + const std::string& w = "regexp") + : pattern (pat), options (opt), data (0), named_pats (), + nnames (0), named_idx (), who (w) + { + compile_internal (); + } + + regexp (const regexp& rx) + : pattern (rx.pattern), data (rx.data), named_pats (rx.named_pats), + nnames (rx.nnames), named_idx (rx.named_idx) + { } + + regexp& operator = (const regexp& rx) + { + if (this != &rx) + { + pattern = rx.pattern; + data = rx.data; + named_pats = rx.named_pats; + nnames = rx.nnames; + named_idx = rx.named_idx; + } + + return *this; + } + + ~regexp (void) { free (); } + + void compile (const std::string& pat, + const regexp::opts& opt = regexp::opts ()) + { + pattern = pat; + options = opt; + compile_internal (); + } + + match_data match (const std::string& buffer); + + bool is_match (const std::string& buffer); + + Array<bool> is_match (const string_vector& buffer); + + std::string replace (const std::string& buffer, + const std::string& replacement); + + struct opts + { + public: + + opts (void) + : x_case_insensitive (false), x_dotexceptnewline (false), + x_freespacing (false), x_lineanchors (false), x_once (false) { } + + opts (const opts& o) + : x_case_insensitive (o.x_case_insensitive), + x_dotexceptnewline (o.x_dotexceptnewline), + x_freespacing (o.x_freespacing), + x_lineanchors (o.x_lineanchors), + x_once (o.x_once) + { } + + opts& operator = (const opts& o) { - init (); - } + if (this != &o) + { + x_case_insensitive = o.x_case_insensitive; + x_dotexceptnewline = o.x_dotexceptnewline; + x_freespacing = o.x_freespacing; + x_lineanchors = o.x_lineanchors; + x_once = o.x_once; + } - regex_match (const string_vector& p = string_vector (), bool insen = false) - : pat (p), case_insen (insen) -#if HAVE_REGEX - , compiled (0) -#endif - { - init (); + return *this; } - regex_match (const regex_match& gm) - : pat (gm.pat), case_insen (gm.case_insen) -#if HAVE_REGEX - , compiled (0) -#endif + ~opts (void) { } + + void case_insensitive (bool val) { x_case_insensitive = val; } + void dotexceptnewline (bool val) { x_dotexceptnewline = val; } + void freespacing (bool val) { x_freespacing = val; } + void lineanchors (bool val) { x_lineanchors = val; } + void once (bool val) { x_once = val; } + + bool case_insensitive (void) const { return x_case_insensitive; } + bool dotexceptnewline (void) const { return x_dotexceptnewline; } + bool freespacing (void) const { return x_freespacing; } + bool lineanchors (void) const { return x_lineanchors; } + bool once (void) const { return x_once; } + + private: + + bool x_case_insensitive; + bool x_dotexceptnewline; + bool x_freespacing; + bool x_lineanchors; + bool x_once; + }; + + class match_element + { + public: + + match_element (const string_vector& nt, const string_vector& t, + const std::string& ms, const Matrix& te, + double s, double e) + : x_match_string (ms), x_named_tokens (nt), x_tokens (t), + x_token_extents (te), x_start (s), x_end (e) + { } + + match_element (const match_element &a) + : x_match_string (a.x_match_string), + x_named_tokens (a.x_named_tokens), x_tokens (a.x_tokens), + x_token_extents (a.x_token_extents), + x_start (a.x_start), x_end (a.x_end) + { } + + std::string match_string (void) const { return x_match_string; } + string_vector named_tokens (void) const { return x_named_tokens; } + string_vector tokens (void) const { return x_tokens; } + Matrix token_extents (void) const { return x_token_extents; } + double start (void) const { return x_start; } + double end (void) const { return x_end; } + + private: + + std::string x_match_string; + string_vector x_named_tokens; + string_vector x_tokens; + Matrix x_token_extents; + double x_start; + double x_end; + }; + + class match_data : public octave_base_list<match_element> + { + public: + + match_data (void) + : octave_base_list<match_element> (), named_pats () + { } + + match_data (const std::list<match_element>& l, const string_vector& np) + : octave_base_list<match_element> (l), named_pats (np) + { } + + match_data (const match_data& rx_lst) + : octave_base_list<match_element> (rx_lst), + named_pats (rx_lst.named_pats) + { } + + match_data& operator = (const match_data& rx_lst) { - init (); + if (this != &rx_lst) + { + octave_base_list<match_element>::operator = (rx_lst); + named_pats = rx_lst.named_pats; + } + + return *this; } - regex_match& operator = (const regex_match& gm); + ~match_data (void) { } - ~regex_match (void); - - void set_pattern (const std::string& p); + string_vector named_patterns (void) { return named_pats; } - void set_pattern (const string_vector& p); + private: - bool match (const std::string&); - - Array<bool> match (const string_vector&); + string_vector named_pats; + }; private: - void init (void); + // The pattern we've been asked to match. + std::string pattern; - // Regex pattern(s). - string_vector pat; + opts options; + + // Internal data describing the regular expression. + void *data; - // Should match be case insensitive - bool case_insen; + std::string m; + string_vector named_pats; + int nnames; + Array<int> named_idx; + std::string who; -#if HAVE_REGEX - regex_t *compiled; -#endif + void free (void); + + void compile_internal (void); }; +inline regexp::match_data +regexp_match (const std::string& pat, + const std::string& buffer, + const regexp::opts& opt = regexp::opts (), + const std::string& who = "regexp") +{ + regexp rx (pat, opt, who); + + return rx.match (buffer); +} + +inline bool +is_regexp_match (const std::string& pat, + const std::string& buffer, + const regexp::opts& opt = regexp::opts (), + const std::string& who = "regexp") +{ + regexp rx (pat, opt, who); + + return rx.is_match (buffer); +} + +inline Array<bool> +is_regexp_match (const std::string& pat, + const string_vector& buffer, + const regexp::opts& opt = regexp::opts (), + const std::string& who = "regexp") +{ + regexp rx (pat, opt, who); + + return rx.is_match (buffer); +} + +inline std::string +regexp_replace (const std::string& pat, + const std::string& buffer, + const std::string& replacement, + const regexp::opts& opt = regexp::opts (), + const std::string& who = "regexp") +{ + regexp rx (pat, opt, who); + + return rx.replace (buffer, replacement); +} + #endif
new file mode 100644 --- /dev/null +++ b/liboctave/singleton-cleanup.cc @@ -0,0 +1,60 @@ +/* + +Copyright (C) 2011 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <lo-error.h> +#include <singleton-cleanup.h> + +singleton_cleanup_list *singleton_cleanup_list::instance = 0; + +singleton_cleanup_list::~singleton_cleanup_list (void) +{ + for (std::set<fptr>::iterator p = fcn_list.begin (); + p != fcn_list.end (); p++) + { + fptr fcn = *p; + + fcn (); + } +} + +bool +singleton_cleanup_list::instance_ok (void) +{ + bool retval = true; + + if (! instance) + instance = new singleton_cleanup_list (); + + if (! instance) + { + current_liboctave_error_handler + ("unable to create singleton_cleanup_list object!"); + + retval = false; + } + + return retval; +}
new file mode 100644 --- /dev/null +++ b/liboctave/singleton-cleanup.h @@ -0,0 +1,50 @@ +#if !defined (octave_singleton_cleanup_h) +#define octave_singleton_cleanup_h 1 + +#include <set> + +class +OCTAVE_API +singleton_cleanup_list +{ +protected: + + singleton_cleanup_list (void) : fcn_list () { } + +public: + + typedef void (*fptr) (void); + + ~singleton_cleanup_list (void); + + static void add (fptr f) + { + if (instance_ok ()) + instance->do_add (f); + } + + static void cleanup (void) { delete instance; instance = 0; } + +private: + + static singleton_cleanup_list *instance; + + static bool instance_ok (void); + + static void cleanup_instance (void) { delete instance; instance = 0; } + + std::set<fptr> fcn_list; + + void do_add (fptr f) + { + fcn_list.insert (f); + } + + // No copying! + + singleton_cleanup_list (const singleton_cleanup_list&); + + singleton_cleanup_list& operator = (const singleton_cleanup_list&); +}; + +#endif
--- a/liboctave/sparse-base-chol.h +++ b/liboctave/sparse-base-chol.h @@ -178,7 +178,7 @@ virtual ~sparse_base_chol (void) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; } @@ -186,7 +186,7 @@ { if (this != &a) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; rep = a.rep;
--- a/m4/acinclude.m4 +++ b/m4/acinclude.m4 @@ -370,7 +370,8 @@ assert (in[0] == out[0] && in[1] == out[1]); ]])], [octave_cv_fortran_integer_size=yes], - [octave_cv_fortran_integer_size=no]) + [octave_cv_fortran_integer_size=no], + [octave_cv_fortran_integer_size=yes]) AC_LANG_POP(C)dnl LIBS="$octave_fintsize_save_LIBS" rm -f conftest.$ac_objext fintsize.$ac_objext @@ -818,7 +819,7 @@ }]])], octave_cv_ieee754_data_format=yes, octave_cv_ieee754_data_format=no, - octave_cv_ieee754_data_format=no)]) + octave_cv_ieee754_data_format=yes)]) if test "$cross_compiling" = yes; then AC_MSG_RESULT([$octave_cv_ieee754_data_format assumed for cross compilation]) else @@ -881,7 +882,7 @@ ]])], octave_cv_umfpack_seperate_split=yes, octave_cv_umfpack_seperate_split=no, - octave_cv_umfpack_seperate_split=no)]) + octave_cv_umfpack_seperate_split=yes)]) if test "$cross_compiling" = yes; then AC_MSG_RESULT([$octave_cv_umfpack_seperate_split assumed for cross compilation]) else @@ -935,7 +936,28 @@ [AC_CACHE_CHECK([for qh_version in $QHULL_LIBS], octave_cv_lib_qhull_version, [ AC_LINK_IFELSE([AC_LANG_PROGRAM([[ -#include <qhull/qhull_a.h> +#include <stdio.h> +#if defined (HAVE_QHULL_LIBQHULL_H) || defined (HAVE_QHULL_QHULL_H) +# if defined (HAVE_QHULL_LIBQHULL_H) +# include <qhull/libqhull.h> +# else +# include <qhull/qhull.h> +# endif +# include <qhull/qset.h> +# include <qhull/geom.h> +# include <qhull/poly.h> +# include <qhull/io.h> +#elif defined (HAVE_LIBQHULL_H) || defined (HAVE_QHULL_H) +# if defined (HAVE_LIBQHULL_H) +# include <libqhull.h> +# else +# include <qhull.h> +# endif +# include <qset.h> +# include <geom.h> +# include <poly.h> +# include <io.h> +#endif ]], [[ const char *tmp = qh_version; ]])], [octave_cv_lib_qhull_version=yes], [octave_cv_lib_qhull_version=no])]) @@ -952,7 +974,27 @@ octave_cv_lib_qhull_ok, [ AC_RUN_IFELSE([AC_LANG_PROGRAM([[ #include <stdio.h> -#include <qhull/qhull.h> +#if defined (HAVE_QHULL_LIBQHULL_H) || defined (HAVE_QHULL_QHULL_H) +# if defined (HAVE_QHULL_LIBQHULL_H) +# include <qhull/libqhull.h> +# else +# include <qhull/qhull.h> +# endif +# include <qhull/qset.h> +# include <qhull/geom.h> +# include <qhull/poly.h> +# include <qhull/io.h> +#elif defined (HAVE_LIBQHULL_H) || defined (HAVE_QHULL_H) +# if defined (HAVE_LIBQHULL_H) +# include <libqhull.h> +# else +# include <qhull.h> +# endif +# include <qset.h> +# include <geom.h> +# include <poly.h> +# include <io.h> +#endif #ifdef NEED_QHULL_VERSION char *qh_version = "version"; #endif @@ -962,7 +1004,10 @@ coordT points[8] = { -0.5, -0.5, -0.5, 0.5, 0.5, -0.5, 0.5, 0.5 }; boolT ismalloc = 0; return qh_new_qhull (dim, n, points, ismalloc, "qhull ", 0, stderr); -]])], [octave_cv_lib_qhull_ok=yes], [octave_cv_lib_qhull_ok=no])]) +]])], + [octave_cv_lib_qhull_ok=yes], + [octave_cv_lib_qhull_ok=no], + [octave_cv_lib_qhull_ok=yes])]) if test "$octave_cv_lib_qhull_ok" = "yes"; then $1 else @@ -1337,9 +1382,10 @@ dnl 4. Bit operations on signed integers work like on unsigned integers, dnl except for the shifts. Shifts are arithmetic. dnl -AC_DEFUN([OCTAVE_FAST_INT_OPS],[ -AC_MSG_CHECKING([whether fast integer arithmetics is usable]) -AC_LANG_PUSH(C++) +AC_DEFUN([OCTAVE_FAST_INT_OPS], +[AC_CACHE_CHECK([whether fast integer arithmetics is usable], +octave_cv_fast_int_ops, +[AC_LANG_PUSH(C++) AC_RUN_IFELSE([AC_LANG_PROGRAM([[ #include <limits> template<class UT, class ST> @@ -1383,10 +1429,15 @@ DO_TEST(long long) #endif ]])], -[AC_MSG_RESULT([yes]) - AC_DEFINE(HAVE_FAST_INT_OPS,1,[Define if signed integers use two's complement])], -[AC_MSG_RESULT([no])]) + [octave_cv_fast_int_ops=yes], + [octave_cv_fast_int_ops=no], + [octave_cv_fast_int_ops=yes]) AC_LANG_POP(C++)]) +if test $octave_cv_fast_int_ops = yes; then + AC_DEFINE(HAVE_FAST_INT_OPS, 1, + [Define if signed integers use two's complement]) +fi +]) dnl dnl Check to see if the compiler and the linker can handle the flags dnl "-framework $1" for the given prologue $2 and the given body $3 of
--- a/scripts/deprecated/module.mk +++ b/scripts/deprecated/module.mk @@ -24,6 +24,7 @@ deprecated/replot.m \ deprecated/saveimage.m \ deprecated/setstr.m \ + deprecated/shell_cmd.m \ deprecated/sphcat.m \ deprecated/spvcat.m \ deprecated/strerror.m \
new file mode 100644 --- /dev/null +++ b/scripts/deprecated/shell_cmd.m @@ -0,0 +1,68 @@ +## Copyright (C) 2011 Rik Wehbring +## +## This file is part of Octave. +## +## Octave is free software; you can redistribute it and/or modify it +## under the terms of the GNU General Public License as published by +## the Free Software Foundation; either version 3 of the License, or (at +## your option) any later version. +## +## Octave is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +## General Public License for more details. +## +## You should have received a copy of the GNU General Public License +## along with Octave; see the file COPYING. If not, see +## <http://www.gnu.org/licenses/>. + +## "-*- texinfo -*- +## @deftypefn {Built-in Function} {} shell_cmd (@var{string}) +## @deftypefnx {Built-in Function} {} shell_cmd (@var{string}, @var{return_output}) +## @deftypefnx {Built-in Function} {} shell_cmd (@var{string}, @var{return_output}, @var{type}) +## @deftypefnx {Built-in Function} {[@var{status}, @var{output}] =} shell_cmd (@dots{}) +## @deftypefnx {Built-in Function} {[@var{status}, @var{output}] =} shell_cmd (@var{string}, @var{return_output}, @var{type}) +## Execute a shell command specified by @var{string}. +## If the optional argument @var{type} is "async", the process +## is started in the background and the process id of the child process +## is returned immediately. Otherwise, the process is started and +## Octave waits until it exits. If the @var{type} argument is omitted, it +## defaults to a value of "sync". +## +## If the optional argument @var{return_output} is true and the subprocess +## is started synchronously, or if @var{shell_cmd} is called with one input +## argument and one or more output arguments, then the output from the command +## is returned. Otherwise, if the subprocess is executed synchronously, its +## output is sent to the standard output. +## +## The @code{shell_cmd} function can return two values. The first is the +## exit status of the command and the second is any output from the +## command that was written to the standard output stream. For example, +## +## @example +## [status, output] = shell_cmd ("echo foo; exit 2"); +## @end example +## +## @noindent +## will set the variable @code{output} to the string @samp{foo}, and the +## variable @code{status} to the integer @samp{2}. +## +## For commands run asynchronously, @var{status} is the process id of the +## command shell that is started to run the command. +## @seealso{system, unix, dos} +## @end deftypefn + +## Deprecated in version 3.6 + +function [status, output] = shell_cmd (varargin) + persistent warned = false; + if (! warned) + warned = true; + warning ("Octave:deprecated-function", + "shell_cmd is obsolete and will be removed from a future version of Octave; please use system instead"); + endif + + [status, output] = system (varargin{:}); + +endfunction +
--- a/scripts/general/accumarray.m +++ b/scripts/general/accumarray.m @@ -264,7 +264,7 @@ elseif (islogical (vals)) zero = true; elseif (fillval == 0 && all (vals(:) <= 0)) - ## This is a common case - fillval is zero, all numbers nonpositive. + ## This is a common case - fillval is zero, all numbers non-positive. zero = 0; else zero = NaN; # Neutral value.
--- a/scripts/general/iscolumn.m +++ b/scripts/general/iscolumn.m @@ -35,26 +35,22 @@ endfunction -%!assert(iscolumn ([1, 2, 3]), false); -%!assert(iscolumn ([1; 2; 3])); -%!assert(iscolumn (1)); -%!assert(iscolumn ([]), false); -%!assert(iscolumn ([1, 2; 3, 4]), false); -%!test -%! warning ("off", "Octave:str-to-num"); -%! assert((iscolumn ("t"))); -%!test -%! warning ("off", "Octave:str-to-num"); -%! assert(!(iscolumn ("test"))); +%!assert (iscolumn ([1, 2, 3]), false) +%!assert (iscolumn ([1; 2; 3])) +%!assert (iscolumn (1)) +%!assert (iscolumn ([]), false) +%!assert (iscolumn ([1, 2; 3, 4]), false) -%!assert(!(iscolumn (["test"; "ing"]))); +%!assert (iscolumn ("t")) +%!assert (iscolumn ("test"), false) +%!assert (iscolumn (["test"; "ing"]), false) %!test %! s.a = 1; -%! assert((iscolumn (s))); +%! assert (iscolumn (s)); %% Test input validation -%!error iscolumn (); -%!error iscolumn ([1, 2], 2); +%!error iscolumn () +%!error iscolumn ([1, 2], 2)
--- a/scripts/general/isrow.m +++ b/scripts/general/isrow.m @@ -35,26 +35,22 @@ endfunction -%!assert(isrow ([1, 2, 3])); -%!assert(isrow ([1; 2; 3]), false); -%!assert(isrow (1)); -%!assert(isrow ([]), false); -%!assert(isrow ([1, 2; 3, 4]), false); -%!test -%! warning ("off", "Octave:str-to-num"); -%! assert((isrow ("t"))); -%!test -%! warning ("off", "Octave:str-to-num"); -%! assert((isrow ("test"))); +%!assert (isrow ([1, 2, 3])) +%!assert (isrow ([1; 2; 3]), false) +%!assert (isrow (1)) +%!assert (isrow ([]), false) +%!assert (isrow ([1, 2; 3, 4]), false) -%!assert(!(isrow (["test"; "ing"]))); +%!assert (isrow ("t")) +%!assert (isrow ("test")) +%!assert (isrow (["test"; "ing"]), false) %!test %! s.a = 1; -%! assert((isrow (s))); +%! assert (isrow (s)); %% Test input validation -%!error isrow (); -%!error isrow ([1, 2], 2); +%!error isrow () +%!error isrow ([1, 2], 2)
--- a/scripts/general/isscalar.m +++ b/scripts/general/isscalar.m @@ -34,23 +34,21 @@ endfunction -%!assert(isscalar (1)); -%!assert(!(isscalar ([1, 2]))); -%!assert(!(isscalar ([]))); -%!assert(!(isscalar ([1, 2; 3, 4]))); -%!test -%! warning ("off", "Octave:str-to-num"); -%! assert((isscalar ("t"))); +%!assert (isscalar (1)) +%!assert (isscalar ([1, 2]), false) +%!assert (isscalar ([]), false) +%!assert (isscalar ([1, 2; 3, 4]), false) -%!assert(!(isscalar ("test"))); -%!assert(!(isscalar (["test"; "ing"]))); +%!assert (isscalar ("t")) +%!assert (isscalar ("test"), false) +%!assert (isscalar (["test"; "ing"]), false) %!test %! s.a = 1; -%! assert((isscalar (s))); +%! assert (isscalar (s)); %% Test input validation -%!error isscalar (); -%!error isscalar (1, 2); +%!error isscalar () +%!error isscalar (1, 2)
--- a/scripts/general/isvector.m +++ b/scripts/general/isvector.m @@ -37,26 +37,21 @@ endfunction -%!assert(isvector (1)); -%!assert(isvector ([1; 2; 3])); -%!assert(!(isvector ([]))); -%!assert(!(isvector ([1, 2; 3, 4]))); -%!test -%! warning ("off", "Octave:str-to-num"); -%! assert((isvector ("t"))); +%!assert (isvector (1)) +%!assert (isvector ([1; 2; 3])) +%!assert (isvector ([]), false) +%!assert (isvector ([1, 2; 3, 4]), false) -%!test -%! warning ("off", "Octave:str-to-num"); -%! assert((isvector ("test"))); - -%!assert(!(isvector (["test"; "ing"]))); +%!assert (isvector ("t")) +%!assert (isvector ("test")) +%!assert (isvector (["test"; "ing"]), false) %!test %! s.a = 1; -%! assert((isvector (s))); +%! assert (isvector (s)); %% Test input validation -%!error isvector (); -%!error isvector ([1, 2], 2); +%!error isvector () +%!error isvector ([1, 2], 2)
--- a/scripts/general/polyarea.m +++ b/scripts/general/polyarea.m @@ -20,7 +20,7 @@ ## @deftypefn {Function File} {} polyarea (@var{x}, @var{y}) ## @deftypefnx {Function File} {} polyarea (@var{x}, @var{y}, @var{dim}) ## -## Determines area of a polygon by triangle method. The variables +## Determine area of a polygon by triangle method. The variables ## @var{x} and @var{y} define the vertex pairs, and must therefore have ## the same shape. They can be either vectors or arrays. If they are ## arrays then the columns of @var{x} and @var{y} are treated separately
--- a/scripts/general/quadl.m +++ b/scripts/general/quadl.m @@ -203,11 +203,11 @@ ## the values here are very high so it may be unavoidable that this fails %!assert (quadl (@(x) sin (3*x).*cosh (x).*sinh (x),10,15), -%! 2.588424538641647e+10, -9e-15) +%! 2.588424538641647e+10, -1.1e-14) ## extra parameters %!assert (quadl (@(x,a,b) sin (a + b*x), 0, 1, [], [], 2, 3), -%! cos(2)/3 - cos(5)/3, - 3e-16) +%! cos(2)/3 - cos(5)/3, -3e-16) ## test different tolerances. %!assert (quadl (@(x) sin (2 + 3*x).^2, 0, 10, 0.3, []),
--- a/scripts/geometry/voronoi.m +++ b/scripts/geometry/voronoi.m @@ -36,7 +36,7 @@ ## @url{http://www.qhull.org/html/qh-quick.htm#options}. ## ## If a single output argument is requested then the Voronoi diagram will be -## plotted and a graphics handle to the plot is returned. +## plotted and a graphics handle @var{h} to the plot is returned. ## [@var{vx}, @var{vy}] = voronoi(@dots{}) returns the Voronoi vertices ## instead of plotting the diagram. ##
--- a/scripts/gethelp.cc +++ b/scripts/gethelp.cc @@ -31,7 +31,7 @@ // Perhaps someday we will want to do more here, so leave this as a // separate function. - return (s.substr (0, 9) == "Copyright"); + return (s.substr (0, 9) == "Copyright" || s.substr (0, 6) == "Author"); } // Eat whitespace and comments from FFILE, returning the text of the
--- a/scripts/image/image.m +++ b/scripts/image/image.m @@ -19,6 +19,7 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} image (@var{img}) ## @deftypefnx {Function File} {} image (@var{x}, @var{y}, @var{img}) +## @deftypefnx {Function File} {@var{h} =} image (@dots{}) ## Display a matrix as a color image. The elements of @var{img} are indices ## into the current colormap, and the colormap will be scaled so that the ## extremes of @var{img} are mapped to the extremes of the colormap. @@ -35,6 +36,8 @@ ## an image and an ordinary plot need to be overlaid. The recommended ## solution is to display the image and then plot the reversed ydata ## using, for example, @code{flipud (ydata,1)}. +## +## The optional return value @var{h} is a graphics handle to the image. ## @seealso{imshow, imagesc, colormap} ## @end deftypefn @@ -95,7 +98,7 @@ ## Adapted-By: jwe function h = __img__ (x, y, img, varargin) - + newplot (); if (isempty (img)) @@ -113,6 +116,15 @@ xdata = [x(1), x(end)]; ydata = [y(1), y(end)]; + dx = diff (x); + dy = diff (y); + dx = std (dx) / mean (abs (dx)); + dy = std (dy) / mean (abs (dy)); + tol = 100*eps; + if (any (dx > tol) || any (dy > tol)) + warning ("Image does not map to non-linearly spaced coordinates") + endif + ca = gca (); tmp = __go_image__ (ca, "cdata", img, "xdata", xdata, "ydata", ydata,
--- a/scripts/image/imagesc.m +++ b/scripts/image/imagesc.m @@ -32,6 +32,7 @@ ## values for the respective axes, or as values for each row and column ## of the matrix @var{A}. ## +## The optional return value @var{h} is a graphics handle to the image. ## @seealso{image, imshow, caxis} ## @end deftypefn
--- a/scripts/image/imshow.m +++ b/scripts/image/imshow.m @@ -23,6 +23,7 @@ ## @deftypefnx {Function File} {} imshow (@var{rgb}, @dots{}) ## @deftypefnx {Function File} {} imshow (@var{filename}) ## @deftypefnx {Function File} {} imshow (@dots{}, @var{string_param1}, @var{value1}, @dots{}) +## @deftypefnx {Function File} {@var{h} =} imshow (@dots{}) ## Display the image @var{im}, where @var{im} can be a 2-dimensional ## (gray-scale image) or a 3-dimensional (RGB image) matrix. ## @@ -44,6 +45,8 @@ ## @item "displayrange" ## @var{value1} is the display range as described above. ## @end table +## +## The optional return value @var{h} is a graphics handle to the image. ## @seealso{image, imagesc, colormap, gray2ind, rgb2ind} ## @end deftypefn
--- a/scripts/linear-algebra/isdefinite.m +++ b/scripts/linear-algebra/isdefinite.m @@ -37,16 +37,16 @@ print_usage (); endif - if (! ishermitian (x)) - error ("isdefinite: X must be a hermitian matrix"); - endif - if (! isfloat (x)) x = double (x); endif if (nargin == 1) - tol = 100 * eps(class (x)) * norm (x, "fro"); + tol = 100 * eps (class (x)) * norm (x, "fro"); + endif + + if (! ishermitian (x, tol)) + error ("isdefinite: X must be a Hermitian matrix"); endif e = tol * eye (rows (x)); @@ -64,6 +64,7 @@ endfunction + %!test %! A = [-1 0; 0 -1]; %! assert (isdefinite (A), -1) @@ -81,4 +82,6 @@ %! assert (isdefinite (A), 0) %!error isdefinite () -%!error isdefinite ([1 2; 3 4]) \ No newline at end of file +%!error isdefinite (1,2,3) +%!error <X must be a Hermitian matrix> isdefinite ([1 2; 3 4]) +
--- a/scripts/miscellaneous/debug.m +++ b/scripts/miscellaneous/debug.m @@ -18,13 +18,12 @@ ## -*- texinfo -*- ## @deftypefn {Function File} {} debug () -## Summary of the debugging commands. The debugging commands that are -## available in Octave are +## Summary of debugging commands. For more information on each command +## and available options use @code{help CMD}. +## +## The debugging commands available in Octave are ## ## @table @code -## @item keyboard -## Force entry into debug mode. -## ## @item dbstop ## Add a breakpoint. ## @@ -34,51 +33,59 @@ ## @item dbstatus ## List all breakpoints. ## +## @item dbwhere +## Report the current file and line number where execution is stopped. +## +## @item dbtype +## List the function where execution is currently stopped, enumerating +## the line numbers. +## +## @item dbstep +## @itemx dbnext +## Execute (step) one or more lines, follow execution into (step into) a +## function call, or execute until the end of a function (step out), and +## re-enter debug mode. +## ## @item dbcont -## Continue execution from the debug prompt. +## Continue normal code execution from the debug prompt. +## +## @item dbquit +## Quit debugging mode immediately and return to the main prompt. ## ## @item dbstack ## Print a backtrace of the execution stack. ## -## @item dbstep -## Execute one or more lines and re-enter debug mode -## -## @item dbtype -## List the function where execution is currently stopped, enumerating -## the lines. -## ## @item dbup -## The workspace up the execution stack. +## Move up the execution stack. ## ## @item dbdown -## The workspace down the execution stack. +## Move down the execution stack. ## -## @item dbquit -## Quit debugging mode and return to the main prompt. +## @item keyboard +## Force entry into debug mode from an m-file. ## ## @item debug_on_error -## Function to query or set whether to enter debug mode in case Octave -## encounters an error. +## Configure whether Octave enters debug mode when it encounters an error. ## ## @item debug_on_warning -## Function to query or set whether to enter debug mode in case Octave -## encounters a warning. +## Configure whether Octave enters debug mode when it encounters a warning. ## ## @item debug_on_interrupt -## Function to query or set whether to enter debug mode in case Octave -## encounters an interupt. +## Configure whether Octave enters debug mode when it encounters an interrupt. ## +## @item isdebugmode +## Return true if in debug mode. ## @end table ## ## @noindent -## when Octave encounters a breakpoint or other reason to enter debug +## When Octave encounters a breakpoint, or other reason to enter debug ## mode, the prompt changes to @code{"debug>"}. The workspace of the function ## where the breakpoint was encountered becomes available and any Octave -## command that works within that workspace may be executed. +## command that is valid in that workspace context may be executed. ## -## @seealso{dbstop, dbclear, dbstatus, dbcont, dbstack, dbstep, dbtype, -## dbup, dbdown, dbquit, debug_on_error, debug_on_warning, -## debug_on_interrupt} +## @seealso{dbstop, dbclear, dbstatus, dbwhere, dbtype, dbcont, dbquit, +## dbstack, dbup, dbdown, keyboard, debug_on_error, debug_on_warning, +## debug_on_interrupt, isdebugmode} ## @end deftypefn function debug ()
--- a/scripts/miscellaneous/dos.m +++ b/scripts/miscellaneous/dos.m @@ -17,14 +17,16 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {[@var{status}, @var{text}] =} dos (@var{command}) -## @deftypefnx {Function File} {[@var{status}, @var{text}] =} dos (@var{command}, "-echo") +## @deftypefn {Function File} {} dos ("@var{command}") +## @deftypefnx {Function File} {@var{status} =} dos ("@var{command}") +## @deftypefnx {Function File} {[@var{status}, @var{text}] =} dos ("@var{command"}) +## @deftypefnx {Function File} {[@dots{}] =} dos ("@var{command}", "-echo") ## Execute a system command if running under a Windows-like operating ## system, otherwise do nothing. Return the exit status of the program -## in @var{status} and any output sent to the standard output in -## @var{text}. If the optional second argument @code{"-echo"} is given, -## then also send the output from the command to the standard output. -## @seealso{unix, isunix, ispc, system} +## in @var{status} and any output from the command in @var{text}. +## When called with no output argument, or the "-echo" argument is +## given, then @var{text} is also sent to standard output. +## @seealso{unix, system, isunix, ispc} ## @end deftypefn ## Author: octave-forge ??? @@ -42,3 +44,28 @@ endif endfunction + + +%!test +%! cmd = ls_command (); +%! old_wstate = warning ("query"); +%! warning ("off", "Octave:undefined-return-values"); +%! unwind_protect +%! [status, output] = dos (cmd); +%! unwind_protect_cleanup +%! warning (old_wstate); +%! end_unwind_protect +%! +%! if (ispc () && ! isunix ()) +%! [status, output] = dos (cmd); +%! assert (status, 0); +%! assert (ischar (output)); +%! assert (! isempty (output)); +%! else +%! assert (status, []); +%! assert (output, []); +%! endif + +%!error dos () +%!error dos (1, 2, 3) +
--- a/scripts/miscellaneous/fileattrib.m +++ b/scripts/miscellaneous/fileattrib.m @@ -17,7 +17,7 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {[@var{status}, @var{msg}, @var{msgid}] =} fileattrib (@var{file}) +## @deftypefn {Function File} {[@var{status}, @var{result}, @var{msgid}] =} fileattrib (@var{file}) ## Return information about @var{file}. ## ## If successful, @var{status} is 1, with @var{result} containing a
--- a/scripts/miscellaneous/ls.m +++ b/scripts/miscellaneous/ls.m @@ -46,46 +46,49 @@ ls_command (); endif - if (iscellstr (varargin)) - - args = tilde_expand (varargin); + if (! iscellstr (varargin)) + error ("ls: all arguments must be character strings"); + endif - if (nargin > 0) - ## FIXME -- this will fail for filenames that contain single quote - ## characters... - cmd = sprintf (" '%s'", args{:}); + if (nargin > 0) + args = tilde_expand (varargin); + if (ispc () && ! isunix ()) + ## shell (cmd.exe) on MinGW uses '^' as escape character + args = regexprep (args, '([^\w.*? -])', '^$1'); else - cmd = ""; + args = regexprep (args, '([^\w.*? -])', '\$1'); endif - - cmd = sprintf ("%s%s", __ls_command__, cmd); - - if (page_screen_output () || nargout > 0) - - [status, output] = system (cmd); + args = sprintf ("%s ", args{:}); + else + args = ""; + endif - if (status == 0) - if (nargout == 0) - puts (output); - else - retval = strvcat (regexp (output, '\S+', 'match'){:}); - endif - else - error ("ls: command exited abnormally with status %d\n", status); - endif + cmd = sprintf ("%s %s", __ls_command__, args); + + if (page_screen_output () || nargout > 0) + [status, output] = system (cmd); + if (status != 0) + error ("ls: command exited abnormally with status %d\n", status); + elseif (nargout == 0) + puts (output); else - ## Just let the output flow if the pager is off. That way the - ## output from things like "ls -R /" will show up immediately and - ## we won't have to buffer all the output. - system (cmd); + retval = strvcat (regexp (output, '\S+', 'match'){:}); endif - else - error ("ls: expecting all arguments to be character strings"); + ## Just let the output flow if the pager is off. That way the + ## output from things like "ls -R /" will show up immediately and + ## we won't have to buffer all the output. + system (cmd); endif endfunction + +%!test +%! list = ls (); +%! assert (ischar (list)); +%! assert (! isempty (list)); + %!error ls (1);
--- a/scripts/miscellaneous/ls_command.m +++ b/scripts/miscellaneous/ls_command.m @@ -30,10 +30,10 @@ global __ls_command__; if (isempty (__ls_command__)) - ## FIXME -- ispc and isunix both return true for Cygwin. Should they? + ## MinGW uses different ls_command if (ispc () && ! isunix () && isempty (file_in_path (getenv ("PATH"), "ls"))) - __ls_command__ = "cmd /C dir /D"; + __ls_command__ = "dir /D"; else __ls_command__ = "ls -C"; endif @@ -54,3 +54,14 @@ endif endfunction + + +%!test +%! cmd = ls_command (); +%! assert (ischar (cmd)); +%! if (ispc () && ! isunix ()) +%! assert (cmd(1:3), "dir"); +%! else +%! assert (cmd(1:2), "ls"); +%! endif +
--- a/scripts/miscellaneous/menu.m +++ b/scripts/miscellaneous/menu.m @@ -42,38 +42,29 @@ ## Don't send the menu through the pager since doing that can cause ## major confusion. - save_page_screen_output = page_screen_output (); - - unwind_protect - - page_screen_output (0); + page_screen_output (0, "local"); - if (! isempty (title)) - disp (title); - printf ("\n"); - endif + if (! isempty (title)) + disp (title); + printf ("\n"); + endif - nopt = nargin - 1; + nopt = nargin - 1; - while (1) - for i = 1:nopt - printf (" [%2d] ", i); - disp (varargin{i}); - endfor - printf ("\n"); - s = input ("pick a number, any number: ", "s"); - num = sscanf (s, "%d"); - if (! isscalar (num) || num < 1 || num > nopt) - printf ("\nerror: input invalid or out of range\n\n"); - else - break; - endif - endwhile - - unwind_protect_cleanup - - page_screen_output (save_page_screen_output); - - end_unwind_protect + while (1) + for i = 1:nopt + printf (" [%2d] ", i); + disp (varargin{i}); + endfor + printf ("\n"); + s = input ("pick a number, any number: ", "s"); + num = sscanf (s, "%d"); + if (! isscalar (num) || num < 1 || num > nopt) + printf ("\nerror: input invalid or out of range\n\n"); + else + break; + endif + endwhile endfunction +
--- a/scripts/miscellaneous/private/__xzip__.m +++ b/scripts/miscellaneous/private/__xzip__.m @@ -99,13 +99,8 @@ unwind_protect_cleanup cd (cwd); if (nargin == 4) - crr = confirm_recursive_rmdir (); - unwind_protect - confirm_recursive_rmdir (false); - rmdir (outdir, "s"); - unwind_protect_cleanup - confirm_recursive_rmdir (crr); - end_unwind_protect + confirm_recursive_rmdir (false, "local"); + rmdir (outdir, "s"); endif end_unwind_protect
--- a/scripts/miscellaneous/unix.m +++ b/scripts/miscellaneous/unix.m @@ -17,14 +17,16 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {[@var{status}, @var{text}] =} unix (@var{command}) -## @deftypefnx {Function File} {[@var{status}, @var{text}] =} unix (@var{command}, "-echo") +## @deftypefn {Function File} {} unix ("@var{command}") +## @deftypefnx {Function File} {@var{status} =} unix ("@var{command}") +## @deftypefnx {Function File} {[@var{status}, @var{text}] =} unix ("@var{command}") +## @deftypefnx {Function File} {[@dots{}] =} unix ("@var{command}", "-echo") ## Execute a system command if running under a Unix-like operating ## system, otherwise do nothing. Return the exit status of the program -## in @var{status} and any output sent to the standard output in -## @var{text}. If the optional second argument @code{"-echo"} is given, -## then also send the output from the command to the standard output. -## @seealso{isunix, ispc, system} +## in @var{status} and any output from the command in @var{text}. +## When called with no output argument, or the "-echo" argument is +## given, then @var{text} is also sent to standard output. +## @seealso{dos, system, isunix, ispc} ## @end deftypefn ## Author: octave-forge ??? @@ -42,3 +44,27 @@ endif endfunction + + +%!test +%! cmd = ls_command (); +%! old_wstate = warning ("query"); +%! warning ("off", "Octave:undefined-return-values"); +%! unwind_protect +%! [status, output] = unix (cmd); +%! unwind_protect_cleanup +%! warning (old_wstate); +%! end_unwind_protect +%! +%! if (isunix ()) +%! assert (status, 0); +%! assert (ischar (output)); +%! assert (! isempty (output)); +%! else +%! assert (status, []); +%! assert (output, []); +%! endif + +%!error unix () +%!error unix (1, 2, 3) +
--- a/scripts/pkg/pkg.m +++ b/scripts/pkg/pkg.m @@ -946,6 +946,15 @@ load_packages_and_dependencies (idx, handle_deps, installed_pkgs_lst, global_install); endif + + ## If there's a NEWS file, mention it + ## we are checking if desc exists too because it's possible to ge to this point + ## without creating it such as giving an invalid filename for the package + if (exist ("desc", "var") && exist (fullfile (desc.dir, "packinfo", "NEWS"), "file")) + printf ("For information about changes from previous versions of the %s package, run 'news (\"%s\")'.\n", + desc.name, desc.name); + endif + endfunction function uninstall (pkgnames, handle_deps, verbose, local_list, @@ -2190,13 +2199,8 @@ function [status_out, msg_out] = rm_rf (dir) if (exist (dir)) - crr = confirm_recursive_rmdir (); - unwind_protect - confirm_recursive_rmdir (false); - [status, msg] = rmdir (dir, "s"); - unwind_protect_cleanup - confirm_recursive_rmdir (crr); - end_unwind_protect + crr = confirm_recursive_rmdir (false, "local"); + [status, msg] = rmdir (dir, "s"); else status = 1; msg = "";
deleted file mode 100644 --- a/scripts/plot/__go_close_all__.m +++ /dev/null @@ -1,32 +0,0 @@ -## Copyright (C) 2007-2011 John W. Eaton -## -## This file is part of Octave. -## -## Octave is free software; you can redistribute it and/or modify it -## under the terms of the GNU General Public License as published by -## the Free Software Foundation; either version 3 of the License, or (at -## your option) any later version. -## -## Octave is distributed in the hope that it will be useful, but -## WITHOUT ANY WARRANTY; without even the implied warranty of -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -## General Public License for more details. -## -## You should have received a copy of the GNU General Public License -## along with Octave; see the file COPYING. If not, see -## <http://www.gnu.org/licenses/>. - -## -*- texinfo -*- -## @deftypefn {Function File} {} __go_close_all__ () -## Undocumented internal function. -## @end deftypefn - -## Author: jwe - -function __go_close_all__ () - close ("all", "hidden"); -endfunction - - -## No test needed for internal helper function. -%!assert (1)
--- a/scripts/plot/allchild.m +++ b/scripts/plot/allchild.m @@ -35,25 +35,23 @@ shh = get (0, "showhiddenhandles"); unwind_protect set (0, "showhiddenhandles", "on"); - if (isscalar (handles)) - h = get (handles, "children"); - else - h = cell (size (handles)); - for i = 1:numel (handles) - h{i} = get (handles, "children"); - endfor - endif + h = get (handles, "children"); unwind_protect_cleanup set (0, "showhiddenhandles", shh); end_unwind_protect endfunction -%!test + +%!testif HAVE_FLTK +%! toolkit = graphics_toolkit (); +%! graphics_toolkit ("fltk"); %! hf = figure ("visible", "off"); %! unwind_protect %! l = line; -%! assert(get(allchild(hf),'type'),{'axes'; 'uimenu'; 'uimenu'; 'uimenu'}) +%! assert(get (allchild (hf),"type"),{"axes"; "uimenu"; "uimenu"; "uimenu"}); %! unwind_protect_cleanup %! close (hf); +%! graphics_toolkit (toolkit); %! end_unwind_protect +
--- a/scripts/plot/area.m +++ b/scripts/plot/area.m @@ -33,9 +33,11 @@ ## @code{1 : rows (@var{y})}. A value @var{lvl} can be defined that determines ## where the base level of the shading under the curve should be defined. ## -## Additional arguments to the @code{area} function are passed to the -## @code{patch}. The optional return value @var{h} provides a handle to -## area series object representing the patches of the areas. +## Additional arguments to the @code{area} function are passed to +## @code{patch}. +## +## The optional return value @var{h} is a graphics handle to the hggroup +## object representing the area patch objects. ## @seealso{plot, patch} ## @end deftypefn
--- a/scripts/plot/axis.m +++ b/scripts/plot/axis.m @@ -309,9 +309,9 @@ ## Get the limits for axis ("tight"). ## AX should be one of "x", "y", or "z". kids = findobj (ca, "-property", strcat (ax, "data")); - ## Since contours set the cdata for the patches to the hggroup zdata property, exclude - ## hgroups when determining the tight limits. - hg_kids = findobj (ca, "-property", strcat (ax, "data"), "type", "hggroup"); + ## The data properties for hggroups mirror their children. + ## Exclude the redundant hgroup values. + hg_kids = findobj (kids, "type", "hggroup"); kids = setdiff (kids, hg_kids); if (isempty (kids)) ## Return the current limits. @@ -319,20 +319,23 @@ else data = get (kids, strcat (ax, "data")); scale = get (ca, strcat (ax, "scale")); - if (strcmp (scale, "log") && any (data > 0)) - data(data<=0) = NaN; + if (! iscell (data)) + data = {data}; + end + if (strcmp (scale, "log")) + tmp = data; + data = cellfun (@(x) x(x>0), tmp, "uniformoutput", false); + n = cellfun (@isempty, data); + data(n) = cellfun (@(x) x(x<0), tmp(n), "uniformoutput", false); endif - if (iscell (data)) - data = data (find (! cellfun ("isempty", data))); - if (! isempty (data)) - lims_min = min (cellfun ("min", cellfun ("min", data, 'uniformoutput', false)(:))); - lims_max = max (cellfun ("max", cellfun ("max", data, 'uniformoutput', false)(:))); - lims = [lims_min, lims_max]; - else - lims = [0, 1]; - endif + data = cellfun (@(x) x(isfinite(x)), data, "uniformoutput", false); + data = data(! cellfun ("isempty", data)); + if (! isempty (data)) + lims_min = min (cellfun (@(x) min (x(:)), data(:))); + lims_max = max (cellfun (@(x) max (x(:)), data(:))); + lims = [lims_min, lims_max]; else - lims = [min(data(:)), max(data(:))]; + lims = [0, 1]; endif endif @@ -547,3 +550,26 @@ %! set (gca, "yaxislocation", "zero") %! box off +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! plot (11:20, [21:24, NaN, -Inf, 27:30]); +%! hold all; +%! plot (11:20, 25.5 + rand (10)); +%! axis tight; +%! assert (axis (), [11 20 21 30]); +%! unwind_protect_cleanup +%! close (hf); +%! end_unwind_protect + +%!test +%! hf = figure ("visible", "off"); +%! unwind_protect +%! a = logspace (-5, 1, 10); +%! loglog (a, -a) +%! axis tight; +%! assert (axis (), [1e-5, 10, -10, -1e-5]) +%! unwind_protect_cleanup +%! close (hf); +%! end_unwind_protect +
--- a/scripts/plot/bar.m +++ b/scripts/plot/bar.m @@ -36,7 +36,7 @@ ## argument, which can take the values @code{"grouped"} (the default), ## or @code{"stacked"}. ## -## The optional return value @var{h} provides a handle to the "bar series" +## The optional return value @var{h} is a handle to the created "bar series" ## object with one handle per column of the variable @var{y}. This ## series allows common elements of the group of bar series objects to ## be changed in a single bar series and the same properties are changed @@ -93,3 +93,7 @@ varargout = cell (nargout, 1); [varargout{:}] = __bar__ (true, "bar", varargin{:}); endfunction + + +%% FIXME: Need demo or test for function +
--- a/scripts/plot/barh.m +++ b/scripts/plot/barh.m @@ -36,13 +36,13 @@ ## argument, which can take the values @code{"grouped"} (the default), ## or @code{"stacked"}. ## -## The optional return value @var{h} provides a handle to the bar series -## object. See @code{bar} for a description of the use of the bar series. -## ## The optional input handle @var{h} allows an axis handle to be passed. ## Properties of the patch graphics object can be changed using ## @var{prop}, @var{val} pairs. ## +## The optional return value @var{h} is a graphics handle to the created +## bar series object. See @code{bar} for a description of the use of the +## bar series. ## @seealso{bar, plot} ## @end deftypefn @@ -52,3 +52,7 @@ varargout = cell (nargout, 1); [varargout{:}] = __bar__ (false, "barh", varargin{:}); endfunction + + +%% FIXME: Need demo or test for function +
--- a/scripts/plot/clabel.m +++ b/scripts/plot/clabel.m @@ -39,9 +39,10 @@ ## on a contour (in points) to be specified. The default is 144 points, or 2 ## inches. ## -## The returned value @var{h} is the set of text object that represent the -## contour labels. The "userdata" property of the text objects contains the -## numerical value of the contour label. +## The optional return value @var{h} is a vector of graphics handles to +## the text objects representing each label. +## The "userdata" property of the text objects contains the numerical value of +## the contour label. ## ## An example of the use of @code{clabel} is ## @@ -128,12 +129,14 @@ endif endfunction -%!demo -%! clf -%! [c, h] = contour (peaks(), -4 : 6); -%! clabel (c, h, -4 : 2 : 6, 'fontsize', 12); %!demo %! clf -%! [c, h] = contourf (peaks(), -7 : 6); -%! clabel (c, h, -6 : 2 : 6, 'fontsize', 12); +%! [c, h] = contour (peaks(), -4:6); +%! clabel (c, h, -4:2:6, "fontsize", 12); + +%!demo +%! clf +%! [c, h] = contourf (peaks(), -7:6); +%! clabel (c, h, -6:2:6, "fontsize", 12); +
--- a/scripts/plot/clf.m +++ b/scripts/plot/clf.m @@ -26,8 +26,10 @@ ## graphics objects with visible handles (@code{handlevisibility} = on). ## If @var{hfig} is specified operate on it instead of the current figure. ## If the optional argument @code{"reset"} is specified, all objects including -## those with hidden handles are deleted. If an output value is -## requested, return the handle of the figure window that was cleared. +## those with hidden handles are deleted. +## +## The optional return value @var{h} is the graphics handle of the figure +## window that was cleared. ## @seealso{cla, close, delete} ## @end deftypefn @@ -82,6 +84,7 @@ endfunction + %!test %! hf = figure ("visible", "off"); %! unwind_protect @@ -99,3 +102,4 @@ %! unwind_protect_cleanup %! close (hf); %! end_unwind_protect +
--- a/scripts/plot/compass.m +++ b/scripts/plot/compass.m @@ -31,17 +31,17 @@ ## The style to use for the plot can be defined with a line style @var{style} ## in a similar manner to the line styles used with the @code{plot} command. ## -## The optional return value @var{h} provides a list of handles to the -## the parts of the vector field (body, arrow and marker). +## The optional return value @var{h} is a vector of graphics handles to the +## line objects representing the drawn vectors. ## ## @example ## @group -## a = toeplitz([1;randn(9,1)],[1,randn(1,9)]); +## a = toeplitz ([1;randn(9,1)], [1,randn(1,9)]); ## compass (eig (a)) ## @end group ## @end example ## -## @seealso{plot, polar, quiver, feather} +## @seealso{polar, quiver, feather, plot} ## @end deftypefn function retval = compass (varargin)
--- a/scripts/plot/ezcontour.m +++ b/scripts/plot/ezcontour.m @@ -23,7 +23,7 @@ ## @deftypefnx {Function File} {} ezcontour (@var{h}, @dots{}) ## @deftypefnx {Function File} {@var{h} =} ezcontour (@dots{}) ## -## Plots the contour lines of a function. @var{f} is a string, inline function +## Plot the contour lines of a function. @var{f} is a string, inline function ## or function handle with two arguments defining the function. By default the ## plot is over the domain @code{-2*pi < @var{x} < 2*pi} and @code{-2*pi < ## @var{y} < 2*pi} with 60 points in each dimension. @@ -35,8 +35,7 @@ ## ## @var{n} is a scalar defining the number of points to use in each dimension. ## -## The optional return value @var{h} provides a list of handles to the -## the parts of the vector field (body, arrow and marker). +## The optional return value @var{h} is a graphics handle to the created plot. ## ## @example ## @group @@ -61,6 +60,8 @@ endif endfunction + %!demo %! f = @(x,y) sqrt(abs(x .* y)) ./ (1 + x.^2 + y.^2); %! ezcontour (f, [-3, 3]); +
--- a/scripts/plot/ezcontourf.m +++ b/scripts/plot/ezcontourf.m @@ -23,7 +23,7 @@ ## @deftypefnx {Function File} {} ezcontourf (@var{h}, @dots{}) ## @deftypefnx {Function File} {@var{h} =} ezcontourf (@dots{}) ## -## Plots the filled contour lines of a function. @var{f} is a string, inline +## Plot the filled contour lines of a function. @var{f} is a string, inline ## function or function handle with two arguments defining the function. By ## default the plot is over the domain @code{-2*pi < @var{x} < 2*pi} and ## @code{-2*pi < @var{y} < 2*pi} with 60 points in each dimension. @@ -35,8 +35,7 @@ ## ## @var{n} is a scalar defining the number of points to use in each dimension. ## -## The optional return value @var{h} provides a list of handles to the -## the parts of the vector field (body, arrow and marker). +## The optional return value @var{h} is a graphics handle to the created plot. ## ## @example ## @group @@ -61,6 +60,7 @@ endif endfunction + %!demo %! f = @(x,y) sqrt(abs(x .* y)) ./ (1 + x.^2 + y.^2); %! ezcontourf (f, [-3, 3]);
--- a/scripts/plot/ezmesh.m +++ b/scripts/plot/ezmesh.m @@ -25,7 +25,7 @@ ## @deftypefnx {Function File} {} ezmesh (@var{h}, @dots{}) ## @deftypefnx {Function File} {@var{h} =} ezmesh (@dots{}) ## -## Plots the mesh defined by a function. @var{f} is a string, inline +## Plot the mesh defined by a function. @var{f} is a string, inline ## function or function handle with two arguments defining the function. By ## default the plot is over the domain @code{-2*pi < @var{x} < 2*pi} and ## @code{-2*pi < @var{y} < 2*pi} with 60 points in each dimension. @@ -44,8 +44,8 @@ ## If the argument 'circ' is given, then the function is plotted over a disk ## centered on the middle of the domain @var{dom}. ## -## The optional return value @var{h} provides a list of handles to the -## the parts of the vector field (body, arrow and marker). +## The optional return value @var{h} is a graphics handle to the created +## surface object. ## ## @example ## @group @@ -65,7 +65,7 @@ ## @end group ## @end example ## -## @seealso{ezplot, ezsurf, ezsurfc, ezmeshc} +## @seealso{ezplot, ezmeshc, ezsurf, ezsurfc} ## @end deftypefn function retval = ezmesh (varargin) @@ -81,6 +81,7 @@ endif endfunction + %!demo %! f = @(x,y) sqrt(abs(x .* y)) ./ (1 + x.^2 + y.^2); %! ezmesh (f, [-3, 3]); @@ -90,3 +91,4 @@ %! fy = @(s,t) sin (s) .* cos(t); %! fz = @(s,t) sin (t); %! ezmesh (fx, fy, fz, [-pi,pi,-pi/2,pi/2], 20); +
--- a/scripts/plot/ezmeshc.m +++ b/scripts/plot/ezmeshc.m @@ -25,7 +25,7 @@ ## @deftypefnx {Function File} {} ezmeshc (@var{h}, @dots{}) ## @deftypefnx {Function File} {@var{h} =} ezmeshc (@dots{}) ## -## Plots the mesh and contour lines defined by a function. @var{f} is a string, +## Plot the mesh and contour lines defined by a function. @var{f} is a string, ## inline function or function handle with two arguments defining the function. ## By default the plot is over the domain @code{-2*pi < @var{x} < 2*pi} and ## @code{-2*pi < @var{y} < 2*pi} with 60 points in each dimension. @@ -44,8 +44,9 @@ ## If the argument 'circ' is given, then the function is plotted over a disk ## centered on the middle of the domain @var{dom}. ## -## The optional return value @var{h} provides a list of handles to the -## the parts of the vector field (body, arrow and marker). +## The optional return value @var{h} is a 2-element vector with a graphics +## handle for the created mesh plot and a second handle for the created contour +## plot. ## ## @example ## @group @@ -70,6 +71,8 @@ endif endfunction + %!demo %! f = @(x,y) sqrt(abs(x .* y)) ./ (1 + x.^2 + y.^2); %! ezmeshc (f, [-3, 3]); +
--- a/scripts/plot/ezplot.m +++ b/scripts/plot/ezplot.m @@ -24,7 +24,7 @@ ## @deftypefnx {Function File} {} ezplot (@var{h}, @dots{}) ## @deftypefnx {Function File} {@var{h} =} ezplot (@dots{}) ## -## Plots in two-dimensions the curve defined by @var{f}. The function +## Plot the curve defined by @var{f} in two dimensions. The function ## @var{f} may be a string, inline function or function handle and can ## have either one or two variables. If @var{f} has one variable, then ## the function is plotted over the domain @code{-2*pi < @var{x} < 2*pi} @@ -61,8 +61,7 @@ ## @var{n} is a scalar defining the number of points to use in plotting ## the function. ## -## The optional return value @var{h} provides a list of handles to the -## the line objects plotted. +## The optional return value @var{h} is a graphics handle to the created plot. ## ## @seealso{plot, ezplot3} ## @end deftypefn @@ -80,6 +79,7 @@ endif endfunction + %!demo %! ezplot (@cos, @sin) @@ -87,4 +87,5 @@ %! ezplot ("1/x") %!demo -%! ezplot (inline("x^2 - y^2 = 1")) +%! ezplot (inline ("x^2 - y^2 = 1")) +
--- a/scripts/plot/ezplot3.m +++ b/scripts/plot/ezplot3.m @@ -23,7 +23,7 @@ ## @deftypefnx {Function File} {} ezplot3 (@var{h}, @dots{}) ## @deftypefnx {Function File} {@var{h} =} ezplot3 (@dots{}) ## -## Plots in three-dimensions the curve defined parametrically. +## Plot a parametrically defined curve in three dimensions. ## @var{fx}, @var{fy}, and @var{fz} are strings, inline functions ## or function handles with one arguments defining the function. By ## default the plot is over the domain @code{-2*pi < @var{x} < 2*pi} @@ -32,8 +32,7 @@ ## If @var{dom} is a two element vector, it represents the minimum and maximum ## value of @var{t}. @var{n} is a scalar defining the number of points to use. ## -## The optional return value @var{h} provides a list of handles to the -## the parts of the vector field (body, arrow and marker). +## The optional return value @var{h} is a graphics handle to the created plot. ## ## @example ## @group @@ -60,8 +59,10 @@ endif endfunction + %!demo %! fx = @(t) cos (t); %! fy = @(t) sin (t); %! fz = @(t) t; %! ezplot3 (fx, fy, fz, [0, 10*pi], 100); +
--- a/scripts/plot/ezpolar.m +++ b/scripts/plot/ezpolar.m @@ -23,7 +23,7 @@ ## @deftypefnx {Function File} {} ezpolar (@var{h}, @dots{}) ## @deftypefnx {Function File} {@var{h} =} ezpolar (@dots{}) ## -## Plots in polar plot defined by a function. The function @var{f} is either +## Plot a function in polar coordinates. The function @var{f} is either ## a string, inline function or function handle with one arguments defining ## the function. By default the plot is over the domain @code{0 < @var{x} < ## 2*pi} with 60 points. @@ -32,8 +32,7 @@ ## value of both @var{t}. @var{n} is a scalar defining the number of points to ## use. ## -## The optional return value @var{h} provides a list of handles to the -## the parts of the vector field (body, arrow and marker). +## The optional return value @var{h} is a graphics handle to the created plot. ## ## @example ## ezpolar (@@(t) 1 + sin (t)); @@ -55,5 +54,7 @@ endif endfunction + %!demo %! ezpolar (@(t) 1 + sin (t)); +
--- a/scripts/plot/ezsurf.m +++ b/scripts/plot/ezsurf.m @@ -25,7 +25,7 @@ ## @deftypefnx {Function File} {} ezsurf (@var{h}, @dots{}) ## @deftypefnx {Function File} {@var{h} =} ezsurf (@dots{}) ## -## Plots the surface defined by a function. @var{f} is a string, inline +## Plot the surface defined by a function. @var{f} is a string, inline ## function or function handle with two arguments defining the function. By ## default the plot is over the domain @code{-2*pi < @var{x} < 2*pi} and ## @code{-2*pi < @var{y} < 2*pi} with 60 points in each dimension. @@ -44,8 +44,8 @@ ## If the argument 'circ' is given, then the function is plotted over a disk ## centered on the middle of the domain @var{dom}. ## -## The optional return value @var{h} provides a list of handles to the -## the parts of the vector field (body, arrow and marker). +## The optional return value @var{h} is a graphics handle to the created +## surface object. ## ## @example ## @group @@ -81,6 +81,7 @@ endif endfunction + %!demo %! f = @(x,y) sqrt(abs(x .* y)) ./ (1 + x.^2 + y.^2); %! ezsurf (f, [-3, 3]); @@ -90,3 +91,4 @@ %! fy = @(s,t) sin (s) .* cos(t); %! fz = @(s,t) sin (t); %! ezsurf (fx, fy, fz, [-pi,pi,-pi/2,pi/2], 20); +
--- a/scripts/plot/ezsurfc.m +++ b/scripts/plot/ezsurfc.m @@ -25,7 +25,7 @@ ## @deftypefnx {Function File} {} ezsurfc (@var{h}, @dots{}) ## @deftypefnx {Function File} {@var{h} =} ezsurfc (@dots{}) ## -## Plots the surface and contour lines defined by a function. @var{f} is a +## Plot the surface and contour lines defined by a function. @var{f} is a ## string, inline function or function handle with two arguments defining the ## function. By default the plot is over the domain @code{-2*pi < @var{x} < ## 2*pi} and @code{-2*pi < @var{y} < 2*pi} with 60 points in each dimension. @@ -44,8 +44,9 @@ ## If the argument 'circ' is given, then the function is plotted over a disk ## centered on the middle of the domain @var{dom}. ## -## The optional return value @var{h} provides a list of handles to the -## the parts of the vector field (body, arrow and marker). +## The optional return value @var{h} is a 2-element vector with a graphics +## for the created surface plot and a second handle for the created contour +## plot. ## ## @example ## @group @@ -70,6 +71,8 @@ endif endfunction + %!demo %! f = @(x,y) sqrt(abs(x .* y)) ./ (1 + x.^2 + y.^2); %! ezsurfc (f, [-3, 3]); +
--- a/scripts/plot/feather.m +++ b/scripts/plot/feather.m @@ -31,8 +31,8 @@ ## The style to use for the plot can be defined with a line style @var{style} ## in a similar manner to the line styles used with the @code{plot} command. ## -## The optional return value @var{h} provides a list of handles to the -## the parts of the vector field (body, arrow and marker). +## The optional return value @var{h} is a vector of graphics handles to the +## line objects representing the drawn vectors. ## ## @example ## @group @@ -109,6 +109,8 @@ endfunction + %!demo %! phi = [0 : 15 : 360] * pi / 180; %! feather (sin (phi), cos (phi)) +
--- a/scripts/plot/fill.m +++ b/scripts/plot/fill.m @@ -22,7 +22,11 @@ ## @deftypefnx {Function File} {} fill (@dots{}, @var{prop}, @var{val}) ## @deftypefnx {Function File} {} fill (@var{h}, @dots{}) ## @deftypefnx {Function File} {@var{h} =} fill (@dots{}) -## Create one or more filled patch objects, returning a patch object for each. +## Create one or more filled patch objects. +## +## The optional return value @var{h} is an array of graphics handles to +## the created patch objects. +## @seealso{patch} ## @end deftypefn function retval = fill (varargin) @@ -114,12 +118,14 @@ endwhile endfunction + %!demo %! clf -%! t1 = (1/16:1/8:1)'*2*pi; -%! t2 = ((1/16:1/8:1)' + 1/32)*2*pi; -%! x1 = sin(t1) - 0.8; -%! y1 = cos(t1); -%! x2 = sin(t2) + 0.8; -%! y2 = cos(t2); -%! h = fill(x1,y1,'r',x2,y2,'g'); +%! t1 = (1/16:1/8:1)*2*pi; +%! t2 = ((1/16:1/8:1) + 1/32)*2*pi; +%! x1 = sin (t1) - 0.8; +%! y1 = cos (t1); +%! x2 = sin (t2) + 0.8; +%! y2 = cos (t2); +%! h = fill (x1,y1,'r', x2,y2,'g'); +
--- a/scripts/plot/findall.m +++ b/scripts/plot/findall.m @@ -21,7 +21,7 @@ ## @deftypefnx {Function File} {@var{h} =} findall (@var{prop_name}, @var{prop_value}) ## @deftypefnx {Function File} {@var{h} =} findall (@var{h}, @dots{}) ## @deftypefnx {Function File} {@var{h} =} findall (@var{h}, "-depth", @var{d}, @dots{}) -## Find object with specified property values including hidden handles. +## Find graphics object with specified property values including hidden handles. ## ## This function performs the same function as @code{findobj}, but it ## includes hidden objects in its search. For full documentation, see @@ -43,12 +43,18 @@ endfunction -%!test + +%!testif HAVE_FLTK +%! toolkit = graphics_toolkit (); +%! graphics_toolkit ("fltk"); %! hf = figure ("visible", "off"); %! unwind_protect %! h = findall (hf); -%! all_handles = {"uimenu"; "uimenu"; "uimenu"; "uimenu"; "uimenu"; "uimenu"; "uimenu"; "uimenu"; "uimenu"; "uimenu"; "uimenu"; "uimenu"; "uimenu"; "figure"}; -%! assert (get (h, 'type'), all_handles) +%! all_handles(1:13,1) = {"uimenu"}; +%! all_handles(14) = {"figure"}; +%! assert (get (h, "type"), all_handles); %! unwind_protect_cleanup %! close (hf); +%! graphics_toolkit (toolkit); %! end_unwind_protect +
--- a/scripts/plot/findobj.m +++ b/scripts/plot/findobj.m @@ -24,7 +24,7 @@ ## @deftypefnx {Function File} {@var{h} =} findobj ('flat', @dots{}) ## @deftypefnx {Function File} {@var{h} =} findobj (@var{h}, @dots{}) ## @deftypefnx {Function File} {@var{h} =} findobj (@var{h}, '-depth', @var{d}, @dots{}) -## Find object with specified property values. The simplest form is +## Find graphics object with specified property values. The simplest form is ## ## @example ## findobj (@var{prop_name}, @var{prop_Value}) @@ -243,6 +243,7 @@ h = reshape (h, [numel(h), 1]); endfunction + %!test %! hf = figure ("visible", "off"); %! unwind_protect @@ -255,3 +256,4 @@ %! unwind_protect_cleanup %! close (hf); %! end_unwind_protect +
--- a/scripts/plot/graphics_toolkit.m +++ b/scripts/plot/graphics_toolkit.m @@ -17,9 +17,10 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {} graphics_toolkit (@var{name}) +## @deftypefn {Function File} {@var{name} =} graphics_toolkit () +## @deftypefnx {Function File} {@var{old_name} =} graphics_toolkit (@var{name}) ## @deftypefnx {Function File} {} graphics_toolkit (@var{hlist}, @var{name}) -## Change the default graphics toolkit to @var{name}. If the +## Query or set the default graphics toolkit to @var{name}. If the ## toolkit is not already loaded, it is first initialized by calling the ## function @code{__init_@var{name}__}. ## @@ -28,44 +29,67 @@ ## @seealso{available_graphics_toolkits} ## @end deftypefn -function graphics_toolkit (varargin) +function retval = graphics_toolkit (name, hlist = []) - name = ""; - hlist = []; + if (nargin > 2) + print_usage (); + endif - if (nargin == 1) - if (ischar (varargin{1})) - name = varargin{1}; - else + if (nargout > 0 || nargin == 0) + retval = get (0, "defaultfigure__graphics_toolkit__"); + endif + + if (nargin == 0) + return; + elseif (nargin == 1) + if (! ischar (name)) error ("graphics_toolkit: invalid graphics toolkit NAME"); endif elseif (nargin == 2) - if (isnumeric (varargin{1}) && ischar (varargin{2})) - hlist = varargin{1}; - name = varargin{2}; - elseif (ischar (varargin{2})) - error ("graphics_toolkit: invalid handle list"); - else + ## Swap input arguments + [hlist, name] = deal (name, hlist); + if (! all (isfigure (hlist))) + error ("graphics_toolkit: invalid figure handle list HLIST"); + elseif (! ischar (name)) error ("graphics_toolkit: invalid graphics toolkit NAME"); endif - else - print_usage (); endif - if (! any (strcmp (available_graphics_toolkits (), name))) + if (! any (strcmp (loaded_graphics_toolkits (), name))) feval (["__init_", name, "__"]); - if (! any (strcmp (available_graphics_toolkits (), name))) - error ("graphics_toolkit: %s toolkit was not correctly registered", - name); + if (! any (strcmp (loaded_graphics_toolkits (), name))) + error ("graphics_toolkit: %s toolkit was not correctly loaded", name); endif endif if (isempty (hlist)) set (0, "defaultfigure__graphics_toolkit__", name); else - for h = hlist(:)' - set (h, "__graphics_toolkit__", name); - endfor + set (hlist, "__graphics_toolkit__", name); endif endfunction + + +%!testif HAVE_FLTK +%! unwind_protect +%! hf = figure ("visible", "off"); +%! toolkit = graphics_toolkit (); +%! assert (get (0, "defaultfigure__graphics_toolkit__"), toolkit); +%! graphics_toolkit (hf, "fltk"); +%! assert (get (hf, "__graphics_toolkit__"), "fltk"); +%! unwind_protect_cleanup +%! close (hf); +%! end_unwind_protect + +%!testif HAVE_FLTK +%! old_toolkit = graphics_toolkit (); +%! switch old_toolkit +%! case {"gnuplot"} +%! new_toolkit = "fltk"; +%! otherwise +%! new_toolkit = "gnuplot"; +%! endswitch +%! assert (graphics_toolkit (new_toolkit), old_toolkit) +%! assert (graphics_toolkit (old_toolkit), new_toolkit) +
--- a/scripts/plot/legend.m +++ b/scripts/plot/legend.m @@ -378,13 +378,15 @@ break; endif elseif (! warned) - warned = true; - warning ("legend: ignoring extra labels"); + break; endif else error ("legend: expecting argument to be a character string"); endif endfor + if (i < nargs && ! warned) + warning ("legend: ignoring extra labels"); + endif else k = nkids; while (k > 0) @@ -816,22 +818,14 @@ endfunction function updatelegendtext (h, d) + hax = get (h, "userdata").handle; kids = get (h, "children"); - k = numel (kids); - in = get (h, "interpreter"); - tc = get (h, "textcolor"); - while (k > 0) - typ = get (kids(k), "type"); - while (k > 0 && ! strcmp (typ, "text")) - typ = get (kids(--k), "type"); - endwhile - if (k > 0) - set (kids (k), "interpreter", in, "color", tc); - if (--k == 0) - break; - endif - endif - endwhile + text_kids = findobj (kids, "-property", "interpreter", "type", "text"); + interpreter = get (h, "interpreter"); + textcolor = get (h, "textcolor"); + set (kids, "interpreter", interpreter, "color", textcolor); + hobj = cell2mat (get (kids, "userdata")); + set (hobj, "interpreter", interpreter); endfunction function hideshowlegend (h, d, ca, pos1, pos2) @@ -1134,21 +1128,34 @@ %!demo %! clf -%! x = 0:4; +%! x = 1:5; %! subplot (2, 2, 1) %! plot (x, rand (numel (x))); -%! legend (cellstr (num2str ((1:10)')), "location", "northwestoutside") +%! legend (cellstr (num2str (x')), "location", "northwestoutside") %! legend boxon %! subplot (2, 2, 2) %! plot (x, rand (numel (x))); -%! legend (cellstr (num2str ((1:10)')), "location", "northeastoutside") +%! legend (cellstr (num2str (x')), "location", "northeastoutside") %! legend boxon %! subplot (2, 2, 3); %! plot (x, rand (numel (x))); -%! legend (cellstr (num2str ((1:10)')), "location", "southwestoutside") +%! legend (cellstr (num2str (x')), "location", "southwestoutside") %! legend boxon %! subplot (2, 2, 4) %! plot (x, rand (numel (x))); -%! legend (cellstr (num2str ((1:10)')), "location", "southeastoutside") +%! legend (cellstr (num2str (x')), "location", "southeastoutside") %! legend boxon +%!demo +%! clf +%! plot (rand (2)) +%! title ("Warn of extra labels") +%! legend ("Hello", "World", "interpreter", "foobar") + +%!demo +%! clf +%! plot (rand (2)) +%! title ("Turn off TeX interpreter") +%! h = legend ("Hello_World", "foo^bar"); +%! set (h, "interpreter", "none") +
--- a/scripts/plot/loglog.m +++ b/scripts/plot/loglog.m @@ -26,6 +26,8 @@ ## Produce a two-dimensional plot using log scales for both axes. See ## the documentation of @code{plot} for a description of the arguments ## that @code{loglog} will accept. +## +## The optional return value @var{h} is a graphics handle to the created plot. ## @seealso{plot, semilogx, semilogy} ## @end deftypefn
--- a/scripts/plot/mesh.m +++ b/scripts/plot/mesh.m @@ -32,6 +32,9 @@ ## The color of the mesh is derived from the @code{colormap} ## and the value of @var{z}. Optionally the color of the mesh can be ## specified independent of @var{z}, by adding a fourth matrix, @var{c}. +## +## The optional return value @var{h} is a graphics handle to the created +## surface object. ## @seealso{colormap, contour, meshgrid, surf} ## @end deftypefn @@ -58,3 +61,7 @@ endif endfunction + + +%% FIXME: Need demo or test for function +
--- a/scripts/plot/module.mk +++ b/scripts/plot/module.mk @@ -56,7 +56,6 @@ plot_FCN_FILES = \ plot/__gnuplot_drawnow__.m \ - plot/__go_close_all__.m \ plot/__plt_get_axis_arg__.m \ plot/allchild.m \ plot/ancestor.m \
--- a/scripts/plot/pareto.m +++ b/scripts/plot/pareto.m @@ -41,6 +41,10 @@ ## @var{y} can be a string array, a cell array of strings or a numerical ## vector. ## +## The optional return value @var{h} is a 2-element vector with a graphics +## handle for the created bar plot and a second handle for the created line +## plot. +## ## An example of the use of @code{pareto} is ## ## @example @@ -48,7 +52,7 @@ ## Cheese = @{"Cheddar", "Swiss", "Camembert", ... ## "Munster", "Stilton", "Blue"@}; ## Sold = [105, 30, 70, 10, 15, 20]; -## pareto(Sold, Cheese); +## pareto (Sold, Cheese); ## @end group ## @end example ## @end deftypefn @@ -99,12 +103,13 @@ endfunction + %!demo %! clf -%! colormap (jet (64)) +%! colormap (jet (64)); %! Cheese = {"Cheddar", "Swiss", "Camembert", "Munster", "Stilton", "Blue"}; %! Sold = [105, 30, 70, 10, 15, 20]; -%! pareto(Sold, Cheese); +%! pareto (Sold, Cheese); %!demo %! clf @@ -114,3 +119,4 @@ %! SoldUnits = [54723 41114 16939 1576091 168000 687197 120222 168195, ... %! 1084118 55576]'; %! pareto (Value.*SoldUnits, Codes); +
--- a/scripts/plot/patch.m +++ b/scripts/plot/patch.m @@ -35,6 +35,10 @@ ## If passed a structure @var{fv} contain the fields "vertices", "faces" ## and optionally "facevertexcdata", create the patch based on these ## properties. +## +## The optional return value @var{h} is a graphics handle to the created patch +## object. +## @seealso{fill} ## @end deftypefn ## Author: jwe @@ -60,10 +64,10 @@ %! clf %! t1 = (1/16:1/8:1)'*2*pi; %! t2 = ((1/16:1/8:1)' + 1/32)*2*pi; -%! x1 = sin(t1) - 0.8; -%! y1 = cos(t1); -%! x2 = sin(t2) + 0.8; -%! y2 = cos(t2); +%! x1 = sin (t1) - 0.8; +%! y1 = cos (t1); +%! x2 = sin (t2) + 0.8; +%! y2 = cos (t2); %! patch([x1,x2],[y1,y2],'r'); %!demo @@ -71,10 +75,10 @@ %! clf %! t1 = (1/16:1/8:1)'*2*pi; %! t2 = ((1/16:1/16:1)' + 1/32)*2*pi; -%! x1 = sin(t1) - 0.8; -%! y1 = cos(t1); -%! x2 = sin(t2) + 0.8; -%! y2 = cos(t2); +%! x1 = sin (t1) - 0.8; +%! y1 = cos (t1); +%! x2 = sin (t2) + 0.8; +%! y2 = cos (t2); %! patch([[x1;NaN(8,1)],x2],[[y1;NaN(8,1)],y2],'r'); %!demo @@ -82,10 +86,10 @@ %! clf %! t1 = (1/16:1/8:1)'*2*pi; %! t2 = ((1/16:1/16:1)' + 1/32)*2*pi; -%! x1 = sin(t1) - 0.8; -%! y1 = cos(t1); -%! x2 = sin(t2) + 0.8; -%! y2 = cos(t2); +%! x1 = sin (t1) - 0.8; +%! y1 = cos (t1); +%! x2 = sin (t2) + 0.8; +%! y2 = cos (t2); %! vert = [x1, y1; x2, y2]; %! fac = [1:8,NaN(1,8);9:24]; %! patch('Faces',fac,'Vertices',vert,'FaceColor','r'); @@ -95,10 +99,10 @@ %! clf %! t1 = (1/16:1/8:1)'*2*pi; %! t2 = ((1/16:1/16:1)' + 1/32)*2*pi; -%! x1 = sin(t1) - 0.8; -%! y1 = cos(t1); -%! x2 = sin(t2) + 0.8; -%! y2 = cos(t2); +%! x1 = sin (t1) - 0.8; +%! y1 = cos (t1); +%! x2 = sin (t2) + 0.8; +%! y2 = cos (t2); %! vert = [x1, y1; x2, y2]; %! fac = [1:8,NaN(1,8);9:24]; %! patch('Faces',fac,'Vertices',vert,'FaceVertexCData', [0, 1, 0; 0, 0, 1]); @@ -108,10 +112,10 @@ %! clf %! t1 = (1/16:1/8:1)'*2*pi; %! t2 = ((1/16:1/8:1)' + 1/32)*2*pi; -%! x1 = sin(t1) - 0.8; -%! y1 = cos(t1); -%! x2 = sin(t2) + 0.8; -%! y2 = cos(t2); +%! x1 = sin (t1) - 0.8; +%! y1 = cos (t1); +%! x2 = sin (t2) + 0.8; +%! y2 = cos (t2); %! h = patch([x1,x2],[y1,y2],cat (3,[0,0],[1,0],[0,1])); %! pause (1); %! set (h, 'FaceColor', 'r'); @@ -127,9 +131,9 @@ %! 2, 3, 5; %! 3, 4, 5; %! 4, 1, 5]; -%! patch('Vertices', vertices, 'Faces', faces, ... -%! 'FaceVertexCData', jet(4), 'FaceColor', 'flat') -%! view (-37.5, 30) +%! patch ('Vertices', vertices, 'Faces', faces, ... +%! 'FaceVertexCData', jet(4), 'FaceColor', 'flat'); +%! view (-37.5, 30); %!demo %! clf @@ -142,37 +146,37 @@ %! 2, 3, 5; %! 3, 4, 5; %! 4, 1, 5]; -%! patch('Vertices', vertices, 'Faces', faces, ... -%! 'FaceVertexCData', jet(5), 'FaceColor', 'interp') -%! view (-37.5, 30) +%! patch ('Vertices', vertices, 'Faces', faces, ... +%! 'FaceVertexCData', jet(5), 'FaceColor', 'interp'); +%! view (-37.5, 30); %!demo %! clf -%! colormap (jet) +%! colormap (jet); %! x = [0 1 1 0]; %! y = [0 0 1 1]; -%! subplot (2, 1, 1) -%! title ("Blue, Light-Green, and Red Horizontal Bars") +%! subplot (2, 1, 1); +%! title ("Blue, Light-Green, and Red Horizontal Bars"); %! patch (x, y + 0, 1); %! patch (x, y + 1, 2); %! patch (x, y + 2, 3); -%! subplot (2, 1, 2) -%! title ("Blue, Light-Green, and Red Vertical Bars") +%! subplot (2, 1, 2); +%! title ("Blue, Light-Green, and Red Vertical Bars"); %! patch (x + 0, y, 1 * ones (size (x))); %! patch (x + 1, y, 2 * ones (size (x))); %! patch (x + 2, y, 3 * ones (size (x))); %!demo %! clf -%! colormap (jet) +%! colormap (jet); %! x = [0 1 1 0]; %! y = [0 0 1 1]; -%! subplot (2, 1, 1) -%! title ("Blue horizontal bars: Dark to Light") +%! subplot (2, 1, 1); +%! title ("Blue horizontal bars: Dark to Light"); %! patch (x, y + 0, 1, "cdatamapping", "direct"); %! patch (x, y + 1, 9, "cdatamapping", "direct"); %! patch (x, y + 2, 17, "cdatamapping", "direct"); -%! subplot (2, 1, 2) +%! subplot (2, 1, 2); %! title ("Blue vertical bars: Dark to Light") %! patch (x + 0, y, 1 * ones (size (x)), "cdatamapping", "direct"); %! patch (x + 1, y, 9 * ones (size (x)), "cdatamapping", "direct"); @@ -184,9 +188,9 @@ %! x = [ 0 0; 1 1; 1 0 ]; %! y = [ 0 0; 0 1; 1 1 ]; %! p = patch (x, y, "facecolor", "b"); -%! title ("Two blue triangles") -%! set (p, "cdatamapping", "direct", "facecolor", "flat", "cdata", [1 32]) -%! title ("Direct mapping of colors: Light-Green UL and Blue LR triangles") +%! title ("Two blue triangles"); +%! set (p, "cdatamapping", "direct", "facecolor", "flat", "cdata", [1 32]); +%! title ("Direct mapping of colors: Light-Green UL and Blue LR triangles"); %!demo %! clf; @@ -194,7 +198,7 @@ %! x = [ 0 0; 1 1; 1 0 ]; %! y = [ 0 0; 0 1; 1 1 ]; %! p = patch (x, y, [1 32]); -%! title ("Autoscaling of colors: Red UL and Blue LR triangles") +%! title ("Autoscaling of colors: Red UL and Blue LR triangles"); %!test %! hf = figure ("visible", "off"); @@ -203,8 +207,8 @@ %! assert (findobj (hf, "type", "patch"), h); %! assert (get (h, "xdata"), [0; 1; 0], eps); %! assert (get (h, "ydata"), [1; 1; 0], eps); -%! assert (isempty(get (h, "zdata"))); -%! assert (isempty(get (h, "cdata"))); +%! assert (isempty (get (h, "zdata"))); +%! assert (isempty (get (h, "cdata"))); %! assert (get (h, "faces"), [1, 2, 3], eps); %! assert (get (h, "vertices"), [0 1; 1 1; 0 0], eps); %! assert (get (h, "type"), "patch"); @@ -228,3 +232,4 @@ %! unwind_protect_cleanup %! close (hf); %! end_unwind_protect +
--- a/scripts/plot/pie.m +++ b/scripts/plot/pie.m @@ -22,7 +22,7 @@ ## @deftypefnx {Function File} {} pie (@dots{}, @var{labels}) ## @deftypefnx {Function File} {} pie (@var{h}, @dots{}); ## @deftypefnx {Function File} {@var{h} =} pie (@dots{}); -## Produce a pie chart. +## Produce a 2-D pie chart. ## ## Called with a single vector argument, produces a pie chart of the ## elements in @var{x}, with the size of the slice determined by percentage @@ -34,7 +34,8 @@ ## If given @var{labels} is a cell array of strings of the same length as ## @var{x}, giving the labels of each of the slices of the pie chart. ## -## The optional return value @var{h} provides a handle to the patch object. +## The optional return value @var{h} is a list of handles to the patch +## and text objects generating the plot. ## ## @seealso{pie3, bar, stem} ## @end deftypefn @@ -65,17 +66,19 @@ endfunction + %!demo %! pie ([3, 2, 1], [0, 0, 1]); -%! colormap([1,0,0;0,1,0;0,0,1;1,1,0;1,0,1;0,1,1]); +%! colormap ([1,0,0;0,1,0;0,0,1;1,1,0;1,0,1;0,1,1]); %!demo %! pie ([3, 2, 1], [0, 0, 1], {"Cheddar", "Swiss", "Camembert"}); -%! colormap([1,0,0;0,1,0;0,0,1;1,1,0;1,0,1;0,1,1]); +%! colormap ([1,0,0;0,1,0;0,0,1;1,1,0;1,0,1;0,1,1]); %! axis ([-2,2,-2,2]); %!demo %! pie ([0.17, 0.34, 0.41], {"Cheddar", "Swiss", "Camembert"}); -%! colormap([1,0,0;0,1,0;0,0,1;1,1,0;1,0,1;0,1,1]); +%! colormap ([1,0,0;0,1,0;0,0,1;1,1,0;1,0,1;0,1,1]); %! axis ([-2,2,-2,2]); -%! title ("missing slice"); \ No newline at end of file +%! title ("missing slice"); +
--- a/scripts/plot/pie3.m +++ b/scripts/plot/pie3.m @@ -35,8 +35,8 @@ ## If given @var{labels} is a cell array of strings of the same length as ## @var{x}, giving the labels of each of the slices of the pie chart. ## -## The optional return value @var{h} provides a handle list to patch, surface -## and text objects generating this plot. +## The optional return value @var{h} is a list of graphics handles to the patch, +## surface, and text objects generating the plot. ## ## @seealso{pie, bar, stem} ## @end deftypefn @@ -67,17 +67,19 @@ endfunction + %!demo %! pie3 ([5:-1:1], [0, 0, 1, 0, 0]); -%! colormap([1,0,0;0,1,0;0,0,1;1,1,0;1,0,1;0,1,1]); +%! colormap ([1,0,0;0,1,0;0,0,1;1,1,0;1,0,1;0,1,1]); %!demo %! pie3 ([3, 2, 1], [0, 0, 1], {"Cheddar", "Swiss", "Camembert"}); -%! colormap([1,0,0;0,1,0;0,0,1;1,1,0;1,0,1;0,1,1]); +%! colormap ([1,0,0;0,1,0;0,0,1;1,1,0;1,0,1;0,1,1]); %! axis ([-2,2,-2,2]); %!demo %! pie3 ([0.17, 0.34, 0.41], {"Cheddar", "Swiss", "Camembert"}); -%! colormap([1,0,0;0,1,0;0,0,1;1,1,0;1,0,1;0,1,1]); +%! colormap ([1,0,0;0,1,0;0,0,1;1,1,0;1,0,1;0,1,1]); %! axis ([-2,2,-2,2]); %! title ("missing slice"); +
--- a/scripts/plot/plot.m +++ b/scripts/plot/plot.m @@ -173,6 +173,8 @@ ## If the first argument is an axis handle, then plot into these axes, ## rather than the current axis handle returned by @code{gca}. ## +## The optional return value @var{h} is a graphics handle to the created plot. +## ## @seealso{semilogx, semilogy, loglog, polar, mesh, contour, bar, ## stairs, errorbar, xlabel, ylabel, title, print} ## @end deftypefn @@ -201,3 +203,7 @@ endif endfunction + + +%% FIXME: Need demo or test for function +
--- a/scripts/plot/polar.m +++ b/scripts/plot/polar.m @@ -21,10 +21,13 @@ ## @deftypefnx {Function File} {} polar (@var{theta}, @var{rho}, @var{fmt}) ## @deftypefnx {Function File} {} polar (@var{h}, @dots{}) ## @deftypefnx {Function File} {@var{h} =} polar (@dots{}) -## Make a two-dimensional plot given the polar coordinates @var{theta} and +## Create a two-dimensional plot from polar coordinates @var{theta} and ## @var{rho}. ## -## The optional third argument specifies the line type. +## The optional argument @var{fmt} specifies the line format. +## +## The optional return value @var{h} is a graphics handle to the created plot. +## ## @seealso{plot} ## @end deftypefn
--- a/scripts/plot/private/__go_draw_axes__.m +++ b/scripts/plot/private/__go_draw_axes__.m @@ -441,6 +441,7 @@ while (! isempty (kids)) obj = get (kids(end)); + if (isfield (obj, "units")) units = obj.units; unwind_protect @@ -2302,10 +2303,38 @@ warning ("latex markup not supported for text objects"); warned_latex = true; endif + elseif (enhanced) + str = no_super_sub_scripts (str); endif endif endfunction +function str = no_super_sub_scripts (str) + if (iscellstr (str)) + labels = str; + else + labels = cellstr (str); + endif + for marker = "_^" + for m = 1 : numel(labels) + n1 = strfind (labels{m}, sprintf ("\\%s", marker)); + n2 = strfind (labels{m}, marker); + if (! isempty (n1)) + n1 = n1 + 1; + n2 = setdiff (n2, n1); + end + for n = numel(n2):-1:1 + labels{m} = [labels{m}(1:n2(n)-1), "\\", labels{m}(n2(n):end)] + endfor + endfor + endfor + if (iscellstr (str)) + str = labels; + else + str = char (labels); + endif +endfunction + function str = __tex2enhanced__ (str, fnt, it, bld) persistent sym = __setup_sym_table__ (); persistent flds = fieldnames (sym);
--- a/scripts/plot/private/__patch__.m +++ b/scripts/plot/private/__patch__.m @@ -29,6 +29,7 @@ function [h, failed] = __patch__ (p, varargin) + h = NaN; failed = false; is_numeric_arg = cellfun (@isnumeric, varargin); @@ -128,11 +129,29 @@ else error ("patch: color value not valid"); endif - elseif (size (c, ndims (c)) == 3) + elseif (isvector (c) && numel (c) == 3) args{7} = "facecolor"; args{8} = c; args{9} = "cdata"; args{10} = []; + elseif (ndims (c) == 3 && size (c, 3) == 3) + ## CDATA is specified as RGB data + if ((size (c, 1) == 1 && size (c, 2) == 1) ... + || (size (c, 1) == 1 && size (c, 2) == columns (x))) + ## Single patch color or per-face color + args{7} = "facecolor"; + args{8} = "flat"; + args{9} = "cdata"; + args{10} = c; + elseif (size (c, 1) == rows (x) && size (c, 2) == columns (x)) + ## Per-vertex color + args{7} = "facecolor"; + args{8} = "interp"; + args{9} = "cdata"; + agrs{10} = c; + else + error ("patch: color value not valid"); + endif else ## Color Vectors if (isempty (c)) @@ -231,11 +250,8 @@ fc = [0, 1, 0]; endif args = {"facecolor", fc, args{:}}; - else - fc = args {idx}; endif - nr = size (faces, 2); nc = size (faces, 1); idx = faces .'; t1 = isnan (idx); @@ -302,17 +318,19 @@ fc = [0, 1, 0]; endif args = {"facecolor", fc, args{:}}; - else - fc = args {idx}; endif [nr, nc] = size (x); + if (nr == 1 && nc > 1) + nr = nc; + nc = 1; + end if (!isempty (z)) vert = [x(:), y(:), z(:)]; else vert = [x(:), y(:)]; endif - faces = reshape (1:numel(x), rows (x), columns (x)); + faces = reshape (1:numel(x), nr, nc); faces = faces'; if (ndims (c) == 3)
--- a/scripts/plot/private/__scatter__.m +++ b/scripts/plot/private/__scatter__.m @@ -133,6 +133,8 @@ addlistener (hg, "cdata", @update_data); addlistener (hg, "sizedata", @update_data); + one_explicit_color = ischar (c) || isequal (size (c), [1, 3]); + if (numel (x) <= 100) ## For small number of points, we'll construct an object for each point. @@ -141,7 +143,7 @@ s = repmat (s, numel(x), 1); endif - if (ischar (c) || rows(c) == 1) + if (one_explicit_color) for i = 1 : numel (x) if (filled) h = __go_patch__ (hg, "xdata", x(i), "ydata", y(i), "zdata", z(i,:), @@ -160,6 +162,9 @@ endif endfor else + if (rows (c) == 1) + c = ones (rows (x), 1) * c; + endif for i = 1 : numel (x) if (filled) h = __go_patch__ (hg, "xdata", x(i), "ydata", y(i), "zdata", z(i,:), @@ -189,24 +194,28 @@ ## For larger numbers of points, we split the points by common color. vert = [x, y, z]; - - if (ischar (c) || rows (c) == 1) - h = render_size_color (hg, vert, s, c, marker, filled, false); - elseif (columns (c) == 1) + if (one_explicit_color) h = render_size_color (hg, vert, s, c, marker, filled, true); else - [cc, idx] = unique_idx (c, "rows"); - if (isscalar (s)) - for i = 1:rows (x) - h = render_size_color (hg, vert(idx{i},:), s, cc(i,:), + if (rows (c) == 1) + c = ones (rows (x), 1) * c; + endif + ## We want to group points by colour. So first get all the unique colours + [cc, ~, c_to_cc] = unique (c, "rows"); + + for i = 1:rows (cc) + ## Now for each possible unique colour, get the logical index of + ## points that correspond to that colour + idx = (i == c_to_cc); + if (isscalar (s)) + h = render_size_color (hg, vert(idx, :), s, c(idx,:), marker, filled, true); - endfor - else - for i = 1:rows (x) - h = render_size_color (hg, vert(idx{i},:), s(idx{i}), cc(i,:), + else + h = render_size_color (hg, vert(idx, :), s(idx), c(idx,:), marker, filled, true); - endfor - endif + endif + endfor + endif endif @@ -226,14 +235,14 @@ addproperty ("marker", hg, "patchmarker", marker); if (filled) addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", "none"); - if (ischar (c) || rows (c) == 1) + if (one_explicit_color) addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", c); else addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", "flat"); endif else addproperty ("markerfacecolor", hg, "patchmarkerfacecolor", "none"); - if (ischar (c) || rows (c) == 1) + if (one_explicit_color) addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", c); else addproperty ("markeredgecolor", hg, "patchmarkeredgecolor", "flat"); @@ -250,48 +259,31 @@ endfunction -function [y, idx] = unique_idx (x, byrows) - if (nargin == 2) - [xx, idx] = sortrows (x); - n = rows (x); - jdx = find (any (xx(1:n-1,:) != xx(2:n,:), 2)); - jdx(end+1) = n; - y = xx(jdx,:); - else - [xx, idx] = sort (x); - n = length (x); - jdx = find (xx(1:n-1,:) != xx(2:n,:)); - jdx(end+1) = n; - y = xx(jdx); - endif - - if (nargin == 2 || columns (x) == 1) - idx = mat2cell (idx, diff ([0; jdx]), 1); - else - idx = mat2cell (idx, 1, diff ([0, jdx])); - endif -endfunction - function h = render_size_color(hg, vert, s, c, marker, filled, isflat) if (isscalar (s)) x = vert(:,1); y = vert(:,2); z = vert(:,3:end); - if (ischar (c) || !isflat) + toolkit = get (ancestor (hg, "figure"), "__graphics_toolkit__"); + ## Does gnuplot only support triangles with different vertex colors ? + ## TODO - Verify gnuplot can only support one color. If RGB triplets + ## can be assigned to each vertex, then fix __go_draw_axe__.m + gnuplot_hack = numel (x) > 1 && strcmp (toolkit, "gnuplot"); + if (ischar (c) || ! isflat || gnuplot_hack) if (filled) h = __go_patch__ (hg, "xdata", x, "ydata", y, "zdata", z, "faces", 1:numel(x), "vertices", vert, "facecolor", "none", "edgecolor", "none", "marker", marker, "markeredgecolor", "none", - "markerfacecolor", c, + "markerfacecolor", c(1,:), "markersize", s, "linestyle", "none"); else h = __go_patch__ (hg, "xdata", x, "ydata", y, "zdata", z, "faces", 1:numel(x), "vertices", vert, "facecolor", "none", "edgecolor", "none", "marker", marker, - "markeredgecolor", c, + "markeredgecolor", c(1,:), "markerfacecolor", "none", "markersize", s, "linestyle", "none"); endif @@ -303,7 +295,7 @@ "marker", marker, "markersize", s, "markeredgecolor", "none", "markerfacecolor", "flat", - "cdata", c, "facevertexcdata", c(:), + "cdata", c, "facevertexcdata", c, "linestyle", "none"); else h = __go_patch__ (hg, "xdata", x, "ydata", y, "zdata", z, @@ -312,15 +304,16 @@ "marker", marker, "markersize", s, "markeredgecolor", "flat", "markerfacecolor", "none", - "cdata", c, "facevertexcdata", c(:), + "cdata", c, "facevertexcdata", c, "linestyle", "none"); endif endif else ## FIXME: round the size to one decimal place. It's not quite right, though. - [ss, idx] = unique_idx (ceil (s*10) / 10); + [ss, ~, s_to_ss] = unique (ceil (s*10) / 10); for i = 1:rows (ss) - h = render_size_color (hg, vert(idx{i},:), ss(i), c, + idx = (i == s_to_ss); + h = render_size_color (hg, vert(idx,:), ss(i), c, marker, filled, isflat); endfor endif
--- a/scripts/plot/quiver.m +++ b/scripts/plot/quiver.m @@ -34,7 +34,7 @@ ## size(@var{u})}. ## ## The variable @var{s} is a scalar defining a scaling factor to use for -## the arrows of the field relative to the mesh spacing. A value of 0 +## the arrows of the field relative to the mesh spacing. A value of 0 ## disables all scaling. The default value is 1. ## ## The style to use for the plot can be defined with a line style @var{style} @@ -43,9 +43,9 @@ ## printed rather than arrows. If the argument 'filled' is given then the ## markers as filled. ## -## The optional return value @var{h} provides a quiver group that -## regroups the components of the quiver plot (body, arrow and marker), -## and allows them to be changed together +## The optional return value @var{h} is a graphics handle to a quiver object. +## A quiver object regroups the components of the quiver plot (body, arrow, +## and marker), and allows them to be changed together. ## ## @example ## @group @@ -81,14 +81,18 @@ endfunction + %!demo %! clf -%! [x,y] = meshgrid(1:2:20); -%! h = quiver(x,y,sin(2*pi*x/10),sin(2*pi*y/10)); +%! [x,y] = meshgrid (1:2:20); +%! h = quiver (x,y, sin (2*pi*x/10), sin (2*pi*y/10)); %! set (h, "maxheadsize", 0.33); %!demo -%! axis("equal"); -%! x=linspace(0,3,80); y=sin(2*pi*x); theta=2*pi*x+pi/2; -%! quiver(x,y,sin(theta)/10,cos(theta)/10); +%! axis ("equal"); +%! x = linspace (0,3,80); +%! y = sin (2*pi*x); +%! theta = 2*pi*x + pi/2; +%! quiver (x, y, sin (theta)/10, cos (theta)/10); %! hold on; plot(x,y,"r"); hold off; +
--- a/scripts/plot/quiver3.m +++ b/scripts/plot/quiver3.m @@ -43,9 +43,9 @@ ## printed rather than arrows. If the argument 'filled' is given then the ## markers as filled. ## -## The optional return value @var{h} provides a quiver group that -## regroups the components of the quiver plot (body, arrow and marker), -## and allows them to be changed together +## The optional return value @var{h} is a graphics handle to a quiver object. +## A quiver object regroups the components of the quiver plot (body, arrow, +## and marker), and allows them to be changed together. ## ## @example ## @group @@ -86,13 +86,13 @@ %!demo %! clf -%! colormap (jet (64)) -%! [x,y]=meshgrid (-1:0.1:1); -%! z=sin(2*pi*sqrt(x.^2+y.^2)); -%! theta=2*pi*sqrt(x.^2+y.^2)+pi/2; -%! quiver3(x,y,z,sin(theta),cos(theta),ones(size(z))); +%! colormap (jet (64)); +%! [x,y] = meshgrid (-1:0.1:1); +%! z = sin (2*pi * sqrt (x.^2+y.^2)); +%! theta = 2*pi * sqrt (x.^2+y.^2) + pi/2; +%! quiver3 (x, y, z, sin (theta), cos (theta), ones (size (z))); %! hold on; -%! mesh(x,y,z); +%! mesh (x,y,z); %! hold off; %!demo
--- a/scripts/plot/rectangle.m +++ b/scripts/plot/rectangle.m @@ -44,9 +44,10 @@ ## min (pos (1:2)) / max (pos (1:2)) * curv ## @end example ## -## Other properties are passed to the underlying patch command. If called -## with an output argument, @code{rectangle} returns the handle to the -## rectangle. +## Other properties are passed to the underlying patch command. +## +## The optional return value @var{h} is a graphics handle to the created +## rectangle object. ## @end deftypefn ## @seealso{patch} @@ -204,17 +205,17 @@ %!demo -%! close all +%! clf %! axis equal %! rectangle ("Position", [0.05, 0.05, 0.9, 0.9], "Curvature", [0.5, 0.5]); %!demo -%! close all +%! clf %! axis equal %! rectangle ("Position", [0.05, 0.05, 0.9, 0.4], "Curvature", 1.0); %!demo -%! close all +%! clf %! axis equal %! h = rectangle ("Position", [0.05, 0.05, 0.9, 0.4], "Curvature", 1.0); %! set (h, "FaceColor", [0, 1, 0]);
--- a/scripts/plot/ribbon.m +++ b/scripts/plot/ribbon.m @@ -23,9 +23,10 @@ ## Plot a ribbon plot for the columns of @var{y} vs. @var{x}. The ## optional parameter @var{width} specifies the width of a single ribbon ## (default is 0.75). If @var{x} is omitted, a vector containing the -## row numbers is assumed (1:rows(Y)). If requested, return a vector -## @var{h} of the handles to the surface objects. -## @seealso{gca, colorbar} +## row numbers is assumed (1:rows(Y)). +## +## The optional return value @var{h} is a vector of graphics handles to +## the surface objects representing each ribbon. ## @end deftypefn ## Author: Kai Habel <kai.habel at gmx.de> @@ -85,7 +86,9 @@ endfunction + %!demo %! [x, y, z] = sombrero (); %! [x, y] = meshgrid (x, y); %! ribbon (y, z); +
--- a/scripts/plot/rose.m +++ b/scripts/plot/rose.m @@ -30,10 +30,10 @@ ## @var{r} bins. If @var{r} is a vector, then the center of each bin are ## defined by the values of @var{r}. ## -## The optional return value @var{h} provides a list of handles to the -## the parts of the vector field (body, arrow and marker). +## The optional return value @var{h} is a vector of graphics handles to the +## line objects representing each histogram. ## -## If two output arguments are requested, then rather than plotting the +## If two output arguments are requested then, rather than plotting the ## histogram, the polar vectors necessary to plot the histogram are ## returned. ## @@ -44,8 +44,7 @@ ## @end group ## @end example ## -## -## @seealso{plot, compass, polar, hist} +## @seealso{polar, compass, hist} ## @end deftypefn function [thout, rout] = rose (varargin)
--- a/scripts/plot/scatter.m +++ b/scripts/plot/scatter.m @@ -82,16 +82,19 @@ %!demo +%! clf %! x = randn (100, 1); %! y = randn (100, 1); %! scatter (x, y, "r"); %!demo +%! clf %! x = randn (100, 1); %! y = randn (100, 1); -%! scatter (x, y, [], sqrt(x.^2 + y.^2)); +%! scatter (x, y, [], sqrt (x.^2 + y.^2)); %!demo +%! clf %! rand_10x1_data1 = [0.171577, 0.404796, 0.025469, 0.335309, 0.047814, 0.898480, 0.639599, 0.700247, 0.497798, 0.737940]; %! rand_10x1_data2 = [0.75495, 0.83991, 0.80850, 0.73603, 0.19360, 0.72573, 0.69371, 0.74388, 0.13837, 0.54143]; %! x = rand_10x1_data1; @@ -100,6 +103,7 @@ %! h = scatter (x, y, s, s, "s", "filled"); %!demo +%! clf %! rand_10x1_data3 = [0.42262, 0.51623, 0.65992, 0.14999, 0.68385, 0.55929, 0.52251, 0.92204, 0.19762, 0.93726]; %! rand_10x1_data4 = [0.020207, 0.527193, 0.443472, 0.061683, 0.370277, 0.947349, 0.249591, 0.666304, 0.134247, 0.920356]; %! x = rand_10x1_data3; @@ -108,6 +112,7 @@ %! h = scatter (x, y, [], "r", "s", "filled"); %!demo +%! clf %! rand_10x1_data5 = [0.777753, 0.093848, 0.183162, 0.399499, 0.337997, 0.686724, 0.073906, 0.651808, 0.869273, 0.137949]; %! rand_10x1_data6 = [0.37460, 0.25027, 0.19510, 0.51182, 0.54704, 0.56087, 0.24853, 0.75443, 0.42712, 0.44273]; %! x = rand_10x1_data5; @@ -115,3 +120,64 @@ %! s = 10 - 10*log (x.^2 + y.^2); %! h = scatter (x, y, [], "r", "s"); +%!demo +%! k = 1; +%! clf +%! for m = [1, 3] +%! for n = [101, 50, 1] +%! x = rand (n, 1); +%! y = rand (n, 1); +%! if (m > 1) +%! str = "Three Colors"; +%! idx = ceil (rand (n, 1) * 3); +%! colors = eye(3); +%! colors = colors(idx, :); +%! else +%! str = "Random Colors"; +%! colors = rand (n, m); +%! endif +%! if (n == 1) +%! str = sprintf ("%s: 1 point", str); +%! elseif (n < 100) +%! str = sprintf ("%s: < 100 points", str); +%! else +%! str = sprintf ("%s: > 100 points", str); +%! endif +%! subplot (2, 3, k) +%! k = k + 1; +%! scatter (x, y, 15, colors, "filled") +%! axis ([0 1 0 1]) +%! title (str) +%! endfor +%! endfor + +%!demo +%! k = 1; +%! clf +%! for m = [1, 3] +%! for n = [101, 50, 1] +%! x = rand (n, 1); +%! y = rand (n, 1); +%! if (m > 1) +%! str = "Three Colors"; +%! idx = ceil (rand (n, 1) * 3); +%! colors = eye(3); +%! colors = colors(idx, :); +%! else +%! str = "Random Colors"; +%! colors = rand (n, m); +%! endif +%! if (n == 1) +%! str = sprintf ("%s: 1 point", str); +%! elseif (n < 100) +%! str = sprintf ("%s: < 100 points", str); +%! else +%! str = sprintf ("%s: > 100 points", str); +%! endif +%! subplot (2, 3, k) +%! k = k + 1; +%! scatter (x, y, 15, colors) +%! axis ([0 1 0 1]) +%! title (str) +%! endfor +%! endfor
--- a/scripts/plot/scatter3.m +++ b/scripts/plot/scatter3.m @@ -41,7 +41,8 @@ ## If the argument 'filled' is given then the markers as filled. All ## additional arguments are passed to the underlying patch command. ## -## The optional return value @var{h} provides a handle to the patch object +## The optional return value @var{h} is a graphics handle to the hggroup +## object representing the points. ## ## @example ## @group
--- a/scripts/plot/semilogx.m +++ b/scripts/plot/semilogx.m @@ -26,6 +26,8 @@ ## Produce a two-dimensional plot using a logarithmic scale for the @var{x} ## axis. See the documentation of @code{plot} for a description of the ## arguments that @code{semilogx} will accept. +## +## The optional return value @var{h} is a graphics handle to the created plot. ## @seealso{plot, semilogy, loglog} ## @end deftypefn @@ -60,6 +62,7 @@ endfunction + %!demo %! x = 1:0.01:10; %! y = (x .* (1 + rand (size (x)))) .^ 2; @@ -70,28 +73,28 @@ %! x = logspace (-5, 1, 10); %! y = logspace (-5, 1, 10); %! -%! subplot (1, 2, 1) -%! semilogx (x, y) -%! xlabel ('semilogx (x, y)') +%! subplot (1, 2, 1); +%! semilogx (x, y); +%! xlabel ("semilogx (x, y)"); %! -%! subplot (1, 2, 2) -%! semilogx (-x, y) -%! xlabel ('semilogx (-x, y)') +%! subplot (1, 2, 2); +%! semilogx (-x, y); +%! xlabel ("semilogx (-x, y)"); %!demo %! clf (); %! x = logspace (-5, 1, 10); %! y = logspace (-5, 1, 10); %! -%! subplot (1, 2, 1) -%! semilogx (x, y) +%! subplot (1, 2, 1); +%! semilogx (x, y); %! set (gca, "xdir", "reverse", "activepositionproperty", "outerposition") %! xlabel ({"semilogx (x, y)", "xdir = reversed"}) %! -%! subplot (1, 2, 2) -%! semilogx (-x, y) -%! set (gca, "xdir", "reverse", "activepositionproperty", "outerposition") -%! xlabel ({"semilogx (-x, y)","xdir = reversed"}) +%! subplot (1, 2, 2); +%! semilogx (-x, y); +%! set (gca, "xdir", "reverse", "activepositionproperty", "outerposition"); +%! xlabel ({"semilogx (-x, y)", "xdir = reversed"}); %!test %! hf = figure ("visible", "off"); @@ -102,7 +105,7 @@ %! assert (get (gca, "xscale"), "log"); %! assert (get (gca, "yscale"), "linear"); %! unwind_protect_cleanup -%! close (hf); +%! close (hf); %! end_unwind_protect %!test @@ -110,9 +113,10 @@ %! unwind_protect %! a = logspace (-5, 1, 10); %! b =-logspace (-5, 1, 10); -%! semilogx (a, b) -%! axis tight +%! semilogx (a, b); +%! axis tight; %! assert (all (get (gca, "ytick") < 0)); %! unwind_protect_cleanup -%! close (hf); +%! close (hf); %! end_unwind_protect +
--- a/scripts/plot/semilogy.m +++ b/scripts/plot/semilogy.m @@ -26,6 +26,8 @@ ## Produce a two-dimensional plot using a logarithmic scale for the @var{y} ## axis. See the documentation of @code{plot} for a description of the ## arguments that @code{semilogy} will accept. +## +## The optional return value @var{h} is a graphics handle to the created plot. ## @seealso{plot, semilogx, loglog} ## @end deftypefn @@ -71,39 +73,39 @@ %! x = logspace (-5, 1, 10); %! y = logspace (-5, 1, 10); %! -%! subplot (2, 1, 1) -%! semilogy (x, y) -%! ylabel ('semilogy (x, y)') +%! subplot (2, 1, 1); +%! semilogy (x, y); +%! ylabel ("semilogy (x, y)"); %! -%! subplot (2, 1, 2) -%! semilogy (x, -y) -%! ylabel ('semilogy (x, -y)') +%! subplot (2, 1, 2); +%! semilogy (x, -y); +%! ylabel ("semilogy (x, -y)"); %!demo %! clf (); %! x = logspace (-5, 1, 10); %! y = logspace (-5, 1, 10); %! -%! subplot (2, 1, 1) -%! semilogy (x, y) -%! set (gca, "ydir", "reverse", "activepositionproperty", "outerposition") -%! ylabel ({"semilogy (x, y)", "ydir = reversed"}) +%! subplot (2, 1, 1); +%! semilogy (x, y); +%! set (gca, "ydir", "reverse", "activepositionproperty", "outerposition"); +%! ylabel ({"semilogy (x, y)", "ydir = reversed"}); %! -%! subplot (2, 1, 2) -%! semilogy (x, -y) -%! set (gca, "ydir", "reverse", "activepositionproperty", "outerposition") -%! ylabel ({"semilogy (x, -y)", "ydir = reversed"}) +%! subplot (2, 1, 2); +%! semilogy (x, -y); +%! set (gca, "ydir", "reverse", "activepositionproperty", "outerposition"); +%! ylabel ({"semilogy (x, -y)", "ydir = reversed"}); %!test %! hf = figure ("visible", "off"); %! unwind_protect %! a = logspace (-5, 1, 10); %! b = logspace (-5, 1, 10); -%! semilogy (a, b) +%! semilogy (a, b); %! assert (get (gca, "yscale"), "log"); %! assert (get (gca, "xscale"), "linear"); %! unwind_protect_cleanup -%! close (hf); +%! close (hf); %! end_unwind_protect %!test @@ -111,11 +113,10 @@ %! unwind_protect %! a = logspace (-5, 1, 10); %! b =-logspace (-5, 1, 10); -%! semilogy (a, b) -%! axis tight +%! semilogy (a, b); +%! axis tight; %! assert (all (get (gca, "ytick") < 0)); %! unwind_protect_cleanup -%! close (hf); +%! close (hf); %! end_unwind_protect -
--- a/scripts/plot/shading.m +++ b/scripts/plot/shading.m @@ -73,24 +73,36 @@ endfunction + %!demo %! clf %! colormap (jet) %! sombrero %! shading faceted -%! title("shading ""faceted""") +%! title ('shading "faceted"') + +%!demo +%! sombrero +%! shading flat +%! title ('shading "flat"') %!demo %! sombrero %! shading interp -%! title("shading ""interp""") +%! title ('shading "interp"') %!demo %! pcolor (peaks ()) %! shading faceted -%! title("shading ""faceted""") +%! title ('shading "faceted"') + +%!demo +%! pcolor (peaks ()) +%! shading flat +%! title ('shading "flat"') %!demo %! pcolor (peaks ()) %! shading interp -%! title("shading ""interp""") +%! title ('shading "interp"') +
--- a/scripts/plot/slice.m +++ b/scripts/plot/slice.m @@ -55,8 +55,9 @@ ## @end table ## ## The default method is @code{"linear"}. -## The optional return value @var{h} is a vector of handles to the -## surface graphic objects. +## +## The optional return value @var{h} is a graphics handle to the created +## surface object. ## ## Examples: ## @@ -179,10 +180,14 @@ endfunction + %!demo %! [x, y, z] = meshgrid (linspace (-8, 8, 32)); %! v = sin (sqrt (x.^2 + y.^2 + z.^2)) ./ (sqrt (x.^2 + y.^2 + z.^2)); %! slice (x, y, z, v, [], 0, []); + +%!demo %! [xi, yi] = meshgrid (linspace (-7, 7)); %! zi = xi + yi; %! slice (x, y, z, v, xi, yi, zi); +
--- a/scripts/plot/stem.m +++ b/scripts/plot/stem.m @@ -47,8 +47,8 @@ ## @noindent ## plots 10 stems with heights from 2 to 20 in red; ## -## The return value of @code{stem} is a vector of "stem series" graphics -## handles, with one handle per column of the variable @var{y}. This +## The optional return value @var{h} is a vector of "stem series" graphics +## handles with one handle per column of the variable @var{y}. The ## handle regroups the elements of the stem graph together as the ## children of the "stem series" handle, allowing them to be altered ## together. For example, @@ -86,33 +86,34 @@ endfunction + %!demo %! x = 1:10; %! stem (x); %!demo %! x = 1:10; -%! y = ones (1, length (x))*2.*x; +%! y = 2*x; %! stem (x, y); %!demo %! x = 1:10; -%! y = ones (size (x))*2.*x; +%! y = 2*x; %! h = stem (x, y, "r"); %!demo %! x = 1:10; -%! y = ones (size (x))*2.*x; +%! y = 2*x; %! h = stem (x, y, "-.k"); %!demo %! x = 1:10; -%! y = ones (size (x))*2.*x; +%! y = 2*x; %! h = stem (x, y, "-.k."); %!demo %! x = 1:10; -%! y = ones (size (x))*2.*x; +%! y = 2*x; %! h = stem (x, y, "filled"); %!demo @@ -121,3 +122,4 @@ %! h = stem (x, y); %! set (h(2), "color", "g"); %! set (h(1), "basevalue", -1) +
--- a/scripts/plot/surf.m +++ b/scripts/plot/surf.m @@ -32,6 +32,9 @@ ## The color of the surface is derived from the @code{colormap} and ## the value of @var{z}. Optionally the color of the surface can be ## specified independent of @var{z}, by adding a fourth matrix, @var{c}. +## +## The optional return value @var{h} is a graphics handle to the created +## surface object. ## @seealso{colormap, contour, meshgrid, mesh} ## @end deftypefn @@ -61,19 +64,21 @@ endfunction + %!demo %! clf -%! [~,~,Z]=peaks; -%! surf(Z); +%! [~,~,Z] = peaks; +%! surf (Z); %!demo -%! [~,~,Z]=sombrero; -%! [Fx,Fy] = gradient(Z); -%! surf(Z,Fx+Fy); +%! [~,~,Z] = sombrero; +%! [Fx,Fy] = gradient (Z); +%! surf (Z, Fx+Fy); %! shading interp; %!demo -%! [X,Y,Z]=sombrero; -%! [~,Fy] = gradient(Z); -%! surf(X,Y,Z,Fy); +%! [X,Y,Z] = sombrero; +%! [~,Fy] = gradient (Z); +%! surf (X, Y, Z, Fy); %! shading interp; +
--- a/scripts/plot/surface.m +++ b/scripts/plot/surface.m @@ -33,6 +33,9 @@ ## are missing, they are constructed from size of the matrix @var{z}. ## ## Any additional properties passed are assigned to the surface. +## +## The optional return value @var{h} is a graphics handle to the created +## surface object. ## @seealso{surf, mesh, patch, line} ## @end deftypefn @@ -163,8 +166,7 @@ endfunction -## Mark file as being tested. Tests for surface are in -## surf.m, surfc.m, surfl.m, and pcolor.m +## Functional tests for surface() are in surf.m, surfc.m, surfl.m, and pcolor.m %!test %! hf = figure ("visible", "off"); @@ -183,3 +185,4 @@ %! unwind_protect_cleanup %! close (hf); %! end_unwind_protect +
--- a/scripts/plot/text.m +++ b/scripts/plot/text.m @@ -17,13 +17,17 @@ ## <http://www.gnu.org/licenses/>. ## -*- texinfo -*- -## @deftypefn {Function File} {@var{h} =} text (@var{x}, @var{y}, @var{label}) -## @deftypefnx {Function File} {@var{h} =} text (@var{x}, @var{y}, @var{z}, @var{label}) -## @deftypefnx {Function File} {@var{h} =} text (@var{x}, @var{y}, @var{label}, @var{p1}, @var{v1}, @dots{}) -## @deftypefnx {Function File} {@var{h} =} text (@var{x}, @var{y}, @var{z}, @var{label}, @var{p1}, @var{v1}, @dots{}) +## @deftypefn {Function File} {} text (@var{x}, @var{y}, @var{label}) +## @deftypefnx {Function File} {} text (@var{x}, @var{y}, @var{z}, @var{label}) +## @deftypefnx {Function File} {} text (@var{x}, @var{y}, @var{label}, @var{p1}, @var{v1}, @dots{}) +## @deftypefnx {Function File} {} text (@var{x}, @var{y}, @var{z}, @var{label}, @var{p1}, @var{v1}, @dots{}) +## @deftypefnx {Function File} {@var{h} =} text (@dots{}) ## Create a text object with text @var{label} at position @var{x}, ## @var{y}, @var{z} on the current axes. Property-value pairs following ## @var{label} may be used to specify the appearance of the text. +## +## The optional return value @var{h} is a graphics handle to the created text +## object. ## @end deftypefn ## Author: jwe @@ -134,17 +138,17 @@ %! text (x(nh), y(nv), "Hello World", ... %! "rotation", t, ... %! "horizontalalignment", ha{nh}, ... -%! "verticalalignment", va{nv}) +%! "verticalalignment", va{nv}); %! endfor %! endfor %! endfor %! set (gca, "xtick", [0.25, 0.5, 0.75], ... %! "xticklabel", ha, ... %! "ytick", [0.25, 0.5, 0.75], ... -%! "yticklabel", va) -%! axis ([0 1 0 1]) -%! xlabel ("horizontal alignment") -%! ylabel ("vertical alignment") +%! "yticklabel", va); +%! axis ([0 1 0 1]); +%! xlabel ("horizontal alignment"); +%! ylabel ("vertical alignment"); %! title ("text alignment and rotation (0:30:360 degrees)") %!demo @@ -156,20 +160,20 @@ %! text (25, 25, 0, "Vertical Alignment = Bottom", ... %! "rotation", t, ... %! "horizontalalignment", "left", ... -%! "verticalalignment", "bottom") +%! "verticalalignment", "bottom"); %! endfor -%! caxis ([-100 100]) -%! title ("Vertically Aligned at Bottom") +%! caxis ([-100 100]); +%! title ("Vertically Aligned at Bottom"); %!demo %! clf -%! axis ([0 8 0 8]) -%! title (["1st title";"2nd title"]) -%! xlabel (["1st xlabel";"2nd xlabel"]) -%! ylabel (["1st ylabel";"2nd ylabel"]) +%! axis ([0 8 0 8]); +%! title (["1st title";"2nd title"]); +%! xlabel (["1st xlabel";"2nd xlabel"]); +%! ylabel (["1st ylabel";"2nd ylabel"]); %! text (4, 4, {"Hello", "World"}, ... %! "horizontalalignment", "center", ... -%! "verticalalignment", "middle") +%! "verticalalignment", "middle"); %! grid on %!demo @@ -177,74 +181,74 @@ %! h = mesh (peaks, "edgecolor", 0.7 * [1 1 1], ... %! "facecolor", "none", ... %! "facealpha", 0); -%! title (["1st title";"2nd title"]) -%! xlabel (["1st xlabel";"2nd xlabel"]) -%! ylabel (["1st ylabel";"2nd ylabel"]) -%! zlabel (["1st zlabel";"2nd zlabel"]) +%! title (["1st title";"2nd title"]); +%! xlabel (["1st xlabel";"2nd xlabel"]); +%! ylabel (["1st ylabel";"2nd ylabel"]); +%! zlabel (["1st zlabel";"2nd zlabel"]); %! text (0, 0, 5, {"Hello", "World"}, ... %! "horizontalalignment", "center", ... -%! "verticalalignment", "middle") -%! hold on -%! plot3 (0, 0, 5, "+k") -%! +%! "verticalalignment", "middle"); +%! hold on; +%! plot3 (0, 0, 5, "+k"); %!demo %! clf %! h = text (0.5, 0.3, "char"); -%! assert ("char", class (get (h, "string"))) +%! assert ("char", class (get (h, "string"))); %! h = text (0.5, 0.4, ["char row 1"; "char row 2"]); -%! assert ("char", class (get (h, "string"))) +%! assert ("char", class (get (h, "string"))); %! h = text (0.5, 0.6, {"cell2str (1,1)", "cell2str (1,2)"; "cell2str (2,1)", "cell2str (2,2)"}); -%! assert ("cell", class (get (h, "string"))) +%! assert ("cell", class (get (h, "string"))); %! h = text (0.5, 0.8, "foobar"); -%! set (h, "string", 1:3) +%! set (h, "string", 1:3); %! h = text ([0.1, 0.1], [0.3, 0.4], "one string & two objects"); -%! assert ("char", class (get (h(1), "string"))) -%! assert ("char", class (get (h(2), "string"))) +%! assert ("char", class (get (h(1), "string"))); +%! assert ("char", class (get (h(2), "string"))); %! h = text ([0.1, 0.1], [0.5, 0.6], {"one cellstr & two objects"}); -%! assert ("cell", class (get (h(1), "string"))) -%! assert ("cell", class (get (h(2), "string"))) +%! assert ("cell", class (get (h(1), "string"))); +%! assert ("cell", class (get (h(2), "string"))); %! h = text ([0.1, 0.1], [0.7, 0.8], {"cellstr 1 object 1", "cellstr 2 object 2"}); -%! assert ("char", class (get (h(1), "string"))) -%! assert ("char", class (get (h(2), "string"))) +%! assert ("char", class (get (h(1), "string"))); +%! assert ("char", class (get (h(2), "string"))); %! h = text ([0.1, 0.1], [0.1, 0.2], ["1st string & 1st object"; "2nd string & 2nd object"]); -%! assert ("char", class (get (h(1), "string"))) -%! assert ("char", class (get (h(2), "string"))) +%! assert ("char", class (get (h(1), "string"))); +%! assert ("char", class (get (h(2), "string"))); %! h = text (0.7, 0.6, "single string"); -%! assert ("char", class (get (h, "string"))) +%! assert ("char", class (get (h, "string"))); %! h = text (0.7, 0.5, {"single cell-string"}); -%! assert ("cell", class (get (h, "string"))) -%! xlabel (1:2) -%! ylabel (1:2) -%! title (1:2) +%! assert ("cell", class (get (h, "string"))); +%! xlabel (1:2); +%! ylabel (1:2); +%! title (1:2); %!test %! hf = figure ("visible", "off"); %! unwind_protect %! h = text (0.5, 0.3, "char"); -%! assert ("char", class (get (h, "string"))) +%! assert ("char", class (get (h, "string"))); %! h = text (0.5, 0.4, ["char row 1"; "char row 2"]); -%! assert ("char", class (get (h, "string"))) +%! assert ("char", class (get (h, "string"))); %! h = text (0.5, 0.6, {"cell2str (1,1)", "cell2str (1,2)"; "cell2str (2,1)", "cell2str (2,2)"}); -%! assert ("cell", class (get (h, "string"))) +%! assert ("cell", class (get (h, "string"))); %! h = text (0.5, 0.8, "foobar"); -%! set (h, "string", 1:3) +%! set (h, "string", 1:3); %! h = text ([0.1, 0.1], [0.3, 0.4], "one string & two objects"); -%! assert ("char", class (get (h(1), "string"))) -%! assert ("char", class (get (h(2), "string"))) +%! assert ("char", class (get (h(1), "string"))); +%! assert ("char", class (get (h(2), "string"))); %! h = text ([0.1, 0.1], [0.5, 0.6], {"one cellstr & two objects"}); -%! assert ("cell", class (get (h(1), "string"))) -%! assert ("cell", class (get (h(2), "string"))) +%! assert ("cell", class (get (h(1), "string"))); +%! assert ("cell", class (get (h(2), "string"))); %! h = text ([0.1, 0.1], [0.7, 0.8], {"cellstr 1 object 1", "cellstr 2 object 2"}); -%! assert ("char", class (get (h(1), "string"))) -%! assert ("char", class (get (h(2), "string"))) +%! assert ("char", class (get (h(1), "string"))); +%! assert ("char", class (get (h(2), "string"))); %! h = text ([0.1, 0.1], [0.1, 0.2], ["1st string & 1st object"; "2nd string & 2nd object"]); -%! assert ("char", class (get (h(1), "string"))) -%! assert ("char", class (get (h(2), "string"))) +%! assert ("char", class (get (h(1), "string"))); +%! assert ("char", class (get (h(2), "string"))); %! h = text (0.7, 0.6, "single string"); -%! assert ("char", class (get (h, "string"))) +%! assert ("char", class (get (h, "string"))); %! h = text (0.7, 0.5, {"single cell-string"}); -%! assert ("cell", class (get (h, "string"))) +%! assert ("cell", class (get (h, "string"))); %! unwind_protect_cleanup %! close (hf); %! end_unwind_protect +
--- a/scripts/plot/title.m +++ b/scripts/plot/title.m @@ -21,7 +21,9 @@ ## @deftypefnx {Function File} {} title (@var{string}, @var{p1}, @var{v1}, @dots{}) ## @deftypefnx {Function File} {} title (@var{h}, @dots{}) ## @deftypefnx {Function File} {@var{h} =} title (@dots{}) -## Create a title object and return a handle to it. +## Create a title object for a plot. +## +## The optional return value @var{h} is a graphics handle to the created object. ## @end deftypefn ## Author: jwe @@ -42,27 +44,28 @@ endfunction + %!demo %! clf (); -%! ax=axes(); -%! xl = get(ax,"title"); -%! title("Testing title") -%! assert(get(xl,"string"),"Testing title") +%! ax = axes(); +%! xl = get (ax,"title"); +%! title ("Testing title"); +%! assert (get (xl,"string"), "Testing title"); %!demo %! clf (); %! plot3 ([0,1], [0,1], [0,1]); %! xl = get(gca (), "title"); -%! title("Testing title") -%! assert(get(xl,"string"),"Testing title") +%! title ("Testing title"); +%! assert (get (xl,"string"),"Testing title"); %!test %! hf = figure ("visible", "off"); %! unwind_protect -%! ax=axes(); -%! xl = get(ax,"title"); -%! title("Testing title") -%! assert(get(xl,"string"),"Testing title") +%! ax = axes(); +%! xl = get (ax,"title"); +%! title ("Testing title"); +%! assert (get (xl,"string"), "Testing title"); %! unwind_protect_cleanup %! close (hf); %! end_unwind_protect @@ -71,9 +74,10 @@ %! hf = figure ("visible", "off"); %! unwind_protect %! plot3 ([0,1], [0,1], [0,1]); -%! xl = get(gca (), "title"); -%! title("Testing title") -%! assert(get(xl,"string"),"Testing title") +%! xl = get (gca (), "title"); +%! title("Testing title"); +%! assert (get (xl,"string"), "Testing title"); %! unwind_protect_cleanup %! close (hf); %! end_unwind_protect +
--- a/scripts/plot/trimesh.m +++ b/scripts/plot/trimesh.m @@ -22,8 +22,9 @@ ## Plot a triangular mesh in 3D@. The variable @var{tri} is the triangular ## meshing of the points @code{(@var{x}, @var{y})} which is returned ## from @code{delaunay}. The variable @var{z} is value at the point -## @code{(@var{x}, @var{y})}. The output argument @var{h} is the graphic -## handle of the plot. +## @code{(@var{x}, @var{y})}. +## +## The optional return value @var{h} is a graphics handle to the created plot. ## @seealso{triplot, trisurf, delaunay3} ## @end deftypefn
--- a/scripts/plot/triplot.m +++ b/scripts/plot/triplot.m @@ -23,8 +23,9 @@ ## Plot a triangular mesh in 2D@. The variable @var{tri} is the triangular ## meshing of the points @code{(@var{x}, @var{y})} which is returned from ## @code{delaunay}. If given, @var{linespec} determines the properties -## to use for the lines. The output argument @var{h} is the graphic handle -## of the plot. +## to use for the lines. +## +## The optional return value @var{h} is a graphics handle to the created plot. ## @seealso{plot, trimesh, trisurf, delaunay} ## @end deftypefn
--- a/scripts/plot/trisurf.m +++ b/scripts/plot/trisurf.m @@ -22,8 +22,9 @@ ## Plot a triangular surface in 3D@. The variable @var{tri} is the triangular ## meshing of the points @code{(@var{x}, @var{y})} which is returned ## from @code{delaunay}. The variable @var{z} is value at the point -## @code{(@var{x}, @var{y})}. The output argument @var{h} is the graphic -## handle of the plot. +## @code{(@var{x}, @var{y})}. +## +## The optional return value @var{h} is a graphics handle to the created plot. ## @seealso{triplot, trimesh, delaunay3} ## @end deftypefn @@ -87,19 +88,19 @@ %! y = rand (100, 1); %! z = x.^2 + y.^2; %! tri = delaunay (x, y); -%! trisurf (tri, x, y, z) +%! trisurf (tri, x, y, z); %!demo %! x = rand (100, 1); %! y = rand (100, 1); %! z = x.^2 + y.^2; %! tri = delaunay (x, y); -%! trisurf (tri, x, y, z, "facecolor", "interp") +%! trisurf (tri, x, y, z, "facecolor", "interp"); %!demo %! x = rand (100, 1); %! y = rand (100, 1); %! z = x.^2 + y.^2; %! tri = delaunay (x, y); -%! trisurf (tri, x, y, z, "facecolor", "interp", "edgecolor", "k") +%! trisurf (tri, x, y, z, "facecolor", "interp", "edgecolor", "k");
--- a/scripts/plot/uimenu.m +++ b/scripts/plot/uimenu.m @@ -89,16 +89,19 @@ endfunction + %!demo -%! surfl(peaks); -%! colormap(copper); -%! shading("interp"); -%! f = uimenu("label", "&File", "accelerator", "f"); -%! e = uimenu("label", "&Edit", "accelerator", "e"); -%! uimenu(f, "label", "Close", "accelerator", "q", "callback", "close (gcf)"); -%! uimenu(e, "label", "Toggle &Grid", "accelerator", "g", "callback", "grid (gca)"); +%! surfl (peaks); +%! colormap (copper); +%! shading ("interp"); +%! f = uimenu ("label", "&File", "accelerator", "f"); +%! e = uimenu ("label", "&Edit", "accelerator", "e"); +%! uimenu (f, "label", "Close", "accelerator", "q", "callback", "close (gcf)"); +%! uimenu (e, "label", "Toggle &Grid", "accelerator", "g", "callback", "grid (gca)"); -%!test +%!testif HAVE_FLTK +%! toolkit = graphics_toolkit (); +%! graphics_toolkit ("fltk"); %! hf = figure ("visible", "off"); %! unwind_protect %! ui = uimenu ("label", "mylabel"); @@ -110,10 +113,13 @@ %! assert (get (ui, "position"), 9); %! unwind_protect_cleanup %! close (hf); +%! graphics_toolkit (toolkit); %! end_unwind_protect %% check for top level menus file, edit, and help -%!test +%!testif HAVE_FLTK +%! toolkit = graphics_toolkit (); +%! graphics_toolkit ("fltk"); %! hf = figure ("visible", "off"); %! unwind_protect %! uif = findall (hf, "label", "&file"); @@ -124,9 +130,12 @@ %! assert (ishghandle (uih)) %! unwind_protect_cleanup %! close (hf); +%! graphics_toolkit (toolkit); %! end_unwind_protect -%!test +%!testif HAVE_FLTK +%! toolkit = graphics_toolkit (); +%! graphics_toolkit ("fltk"); %! hf = figure ("visible", "off"); %! unwind_protect %! uie = findall (hf, "label", "&edit"); @@ -134,4 +143,6 @@ %! assert (ancestor (myui, "uimenu", "toplevel"), uie) %! unwind_protect_cleanup %! close (hf); +%! graphics_toolkit (toolkit); %! end_unwind_protect +
--- a/scripts/plot/xlabel.m +++ b/scripts/plot/xlabel.m @@ -23,10 +23,10 @@ ## @deftypefnx {Function File} {} ylabel (@dots{}) ## @deftypefnx {Function File} {} zlabel (@dots{}) ## Specify x-, y-, or z-axis labels for the current axis. If @var{h} is -## specified then label the axis defined by @var{h}. The optional return -## value @var{h} provides a handle to the created label. -## @seealso{plot, semilogx, semilogy, loglog, polar, mesh, contour, -## bar, stairs, title} +## specified then label the axis defined by @var{h}. +## +## The optional return value @var{h} is a graphics handle to the created object. +## @seealso{title, text} ## @end deftypefn ## Author: jwe @@ -48,14 +48,16 @@ endfunction + %!test %! hf = figure ("visible", "off"); %! unwind_protect %! x = xlabel ("xlabel_string"); -%! assert (get(gca, "xlabel"), x); -%! assert (get(x, "type"), "text"); -%! assert (get(x, "visible"), "on"); -%! assert (get(x, "string"), "xlabel_string"); +%! assert (get (gca, "xlabel"), x); +%! assert (get (x, "type"), "text"); +%! assert (get (x, "visible"), "on"); +%! assert (get (x, "string"), "xlabel_string"); %! unwind_protect_cleanup %! close (hf); %! end_unwind_protect +
--- a/scripts/plot/ylabel.m +++ b/scripts/plot/ylabel.m @@ -42,14 +42,16 @@ endfunction + %!test %! hf = figure ("visible", "off"); %! unwind_protect %! y = ylabel ("ylabel_string"); -%! assert (get(gca, "ylabel"), y); -%! assert (get(y, "type"), "text"); -%! assert (get(y, "visible"), "on"); -%! assert (get(y, "string"), "ylabel_string"); +%! assert (get (gca, "ylabel"), y); +%! assert (get (y, "type"), "text"); +%! assert (get (y, "visible"), "on"); +%! assert (get (y, "string"), "ylabel_string"); %! unwind_protect_cleanup %! close (hf); %! end_unwind_protect +
--- a/scripts/plot/zlabel.m +++ b/scripts/plot/zlabel.m @@ -42,14 +42,15 @@ endfunction + %!test %! hf = figure ("visible", "off"); %! unwind_protect %! z = zlabel ("zlabel_string"); -%! assert (get(gca, "zlabel"), z); -%! assert (get(z, "type"), "text"); -%! assert (get(z, "visible"), "off"); -%! assert (get(z, "string"), "zlabel_string"); +%! assert (get (gca, "zlabel"), z); +%! assert (get (z, "type"), "text"); +%! assert (get (z, "visible"), "off"); +%! assert (get (z, "string"), "zlabel_string"); %! unwind_protect_cleanup %! close (hf); %! end_unwind_protect @@ -59,10 +60,11 @@ %! plot3 (0, 0, 0); %! unwind_protect %! z = zlabel ("zlabel_string"); -%! assert (get(gca, "zlabel"), z); -%! assert (get(z, "type"), "text"); -%! assert (get(z, "visible"), "off"); -%! assert (get(z, "string"), "zlabel_string"); +%! assert (get (gca, "zlabel"), z); +%! assert (get (z, "type"), "text"); +%! assert (get (z, "visible"), "off"); +%! assert (get (z, "string"), "zlabel_string"); %! unwind_protect_cleanup %! close (hf); %! end_unwind_protect +
--- a/scripts/polynomial/compan.m +++ b/scripts/polynomial/compan.m @@ -51,7 +51,7 @@ ## @end ifnottex ## The eigenvalues of the companion matrix are equal to the roots of the ## polynomial. -## @seealso{poly, roots, residue, conv, deconv, polyval, polyderiv, +## @seealso{poly, roots, residue, conv, deconv, polyval, polyder, ## polyint} ## @end deftypefn
--- a/scripts/polynomial/deconv.m +++ b/scripts/polynomial/deconv.m @@ -26,7 +26,7 @@ ## If @var{y} and @var{a} are polynomial coefficient vectors, @var{b} will ## contain the coefficients of the polynomial quotient and @var{r} will be ## a remainder polynomial of lowest order. -## @seealso{conv, poly, roots, residue, polyval, polyderiv, polyint} +## @seealso{conv, poly, roots, residue, polyval, polyder, polyint} ## @end deftypefn ## Author: Tony Richardson <arichard@stark.cc.oh.us>
--- a/scripts/polynomial/mpoles.m +++ b/scripts/polynomial/mpoles.m @@ -44,7 +44,7 @@ ## @end group ## @end example ## -## @seealso{poly, roots, conv, deconv, polyval, polyderiv, polyint, residue} +## @seealso{poly, roots, conv, deconv, polyval, polyder, polyint, residue} ## @end deftypefn ## Author: Ben Abbott <bpabbott@mac.com>
--- a/scripts/polynomial/polyfit.m +++ b/scripts/polynomial/polyfit.m @@ -77,7 +77,7 @@ endif if (! (isscalar (n) && n >= 0 && ! isinf (n) && n == fix (n))) - error ("polyfit: N must be a nonnegative integer"); + error ("polyfit: N must be a non-negative integer"); endif y_is_row_vector = (rows (y) == 1);
--- a/scripts/polynomial/polygcd.m +++ b/scripts/polynomial/polygcd.m @@ -39,7 +39,7 @@ ## @result{} [ 0, 0, 0 ] ## @end group ## @end example -## @seealso{poly, polyint, polyderiv, polyreduce, roots, conv, deconv, +## @seealso{poly, polyint, polyder, polyreduce, roots, conv, deconv, ## residue, filter, polyval, polyvalm} ## @end deftypefn
--- a/scripts/polynomial/polyint.m +++ b/scripts/polynomial/polyint.m @@ -22,7 +22,7 @@ ## Return the coefficients of the integral of the polynomial whose ## coefficients are represented by the vector @var{p}. The variable ## @var{k} is the constant of integration, which by default is set to zero. -## @seealso{poly, polyderiv, polyreduce, roots, conv, deconv, residue, +## @seealso{poly, polyder, polyreduce, roots, conv, deconv, residue, ## filter, polyval, polyvalm} ## @end deftypefn
--- a/scripts/polynomial/polyout.m +++ b/scripts/polynomial/polyout.m @@ -35,7 +35,7 @@ ## @var{nargout} is zero). ## @var{x} defaults to the string @code{"s"}. ## @seealso{polyval, polyvalm, poly, roots, conv, deconv, residue, -## filter, polyderiv, polyint} +## filter, polyder, polyint} ## @end deftypefn ## Author: A. S. Hodel <a.s.hodel@eng.auburn.edu>
--- a/scripts/polynomial/polyreduce.m +++ b/scripts/polynomial/polyreduce.m @@ -21,7 +21,7 @@ ## Reduce a polynomial coefficient vector to a minimum number of terms by ## stripping off any leading zeros. ## @seealso{poly, roots, conv, deconv, residue, filter, polyval, -## polyvalm, polyderiv, polyint} +## polyvalm, polyder, polyint} ## @end deftypefn ## Author: Tony Richardson <arichard@stark.cc.oh.us>
--- a/scripts/polynomial/polyval.m +++ b/scripts/polynomial/polyval.m @@ -32,7 +32,7 @@ ## prediction interval, the structured variable @var{s}, originating ## form `polyfit', must be present. ## @seealso{polyfit, polyvalm, poly, roots, conv, deconv, residue, filter, -## polyderiv, polyint} +## polyder, polyint} ## @end deftypefn ## Author: Tony Richardson <arichard@stark.cc.oh.us>
--- a/scripts/polynomial/polyvalm.m +++ b/scripts/polynomial/polyvalm.m @@ -27,7 +27,7 @@ ## ## The argument @var{x} must be a square matrix. ## @seealso{polyval, poly, roots, conv, deconv, residue, filter, -## polyderiv, polyint} +## polyder, polyint} ## @end deftypefn ## Author: Tony Richardson <arichard@stark.cc.oh.us>
--- a/scripts/polynomial/residue.m +++ b/scripts/polynomial/residue.m @@ -136,7 +136,7 @@ ## @end example ## ## @end ifnottex -## @seealso{poly, roots, conv, deconv, mpoles, polyval, polyderiv, polyint} +## @seealso{poly, roots, conv, deconv, mpoles, polyval, polyder, polyint} ## @end deftypefn ## Author: Tony Richardson <arichard@stark.cc.oh.us>
--- a/scripts/sparse/svds.m +++ b/scripts/sparse/svds.m @@ -241,46 +241,56 @@ endfunction -%!shared n, k, A, u, s, v, opts +%!shared n, k, A, u, s, v, opts, rand_state, randn_state %! n = 100; %! k = 7; -%! A = sparse([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),0.4*n*ones(1,n),ones(1,n-2)]); -%! [u,s,v] = svd(full(A)); -%! s = diag(s); -%! [~, idx] = sort(abs(s)); +%! A = sparse ([3:n,1:n,1:(n-2)],[1:(n-2),1:n,3:n],[ones(1,n-2),0.4*n*ones(1,n),ones(1,n-2)]); +%! [u,s,v] = svd (full (A)); +%! s = diag (s); +%! [~, idx] = sort (abs(s)); %! s = s(idx); -%! u = u(:,idx); -%! v = v(:,idx); -%! old_state1 = randn ("state"); -%! restore_state1 = onCleanup (@() randn ("state", old_state1)); -%! old_state2 = rand ("state"); -%! restore_state2 = onCleanup (@() rand ("state", old_state2)); -%! randn ('state', 42); % Initialize to make normest function reproducible -%! rand ('state', 42); +%! u = u(:, idx); +%! v = v(:, idx); +%! randn_state = randn ("state"); +%! rand_state = rand ("state"); +%! randn ("state", 42); % Initialize to make normest function reproducible +%! rand ("state", 42); %! opts.v0 = rand (2*n,1); % Initialize eigs ARPACK starting vector %! % to guarantee reproducible results +%! %!test -%! [u2,s2,v2,flag] = svds(A,k); -%! s2 = diag(s2); -%! assert(flag,!1); -%! assert(s2, s(end:-1:end-k+1), 1e-10); +%! [u2,s2,v2,flag] = svds (A,k); +%! s2 = diag (s2); +%! assert (flag, !1); +%! assert (s2, s(end:-1:end-k+1), 1e-10); +%! %!testif HAVE_UMFPACK -%! [u2,s2,v2,flag] = svds(A,k,0,opts); -%! s2 = diag(s2); -%! assert(flag,!1); -%! assert(s2, s(k:-1:1), 1e-10); +%! [u2,s2,v2,flag] = svds (A,k,0,opts); +%! s2 = diag (s2); +%! assert (flag, !1); +%! assert (s2, s(k:-1:1), 1e-10); +%! %!testif HAVE_UMFPACK %! idx = floor(n/2); %! % Don't put sigma right on a singular value or there are convergence issues %! sigma = 0.99*s(idx) + 0.01*s(idx+1); -%! [u2,s2,v2,flag] = svds(A,k,sigma,opts); -%! s2 = diag(s2); -%! assert(flag,!1); -%! assert(s2, s((idx+floor(k/2)):-1:(idx-floor(k/2))), 1e-10); +%! [u2,s2,v2,flag] = svds (A,k,sigma,opts); +%! s2 = diag (s2); +%! assert (flag, !1); +%! assert (s2, s((idx+floor(k/2)):-1:(idx-floor(k/2))), 1e-10); +%! %!test -%! [u2,s2,v2,flag] = svds(zeros (10), k); -%! assert (isequal(u2, eye (10, k)) && isequal (s2, zeros(k)) && isequal (v2, eye(10, 7))); +%! [u2,s2,v2,flag] = svds (zeros (10), k); +%! assert (u2, eye (10, k)); +%! assert (s2, zeros (k)); +%! assert (v2, eye (10, 7)); +%! %!test %! s = svds (speye (10)); %! assert (s, ones (6, 1), 2*eps); +%!test +%! ## Restore random number generator seeds at end of tests +%! rand ("state", rand_state); +%! randn ("state", randn_state); +
--- a/scripts/specfun/factorial.m +++ b/scripts/specfun/factorial.m @@ -30,7 +30,7 @@ if (nargin != 1) print_usage (); elseif (any (n(:) < 0 | n(:) != fix (n(:)))) - error ("factorial: N must all be nonnegative integers"); + error ("factorial: N must all be non-negative integers"); endif x = round (gamma (n+1)); endfunction @@ -38,5 +38,5 @@ %!assert (factorial(5), prod(1:5)) %!assert (factorial([1,2;3,4]), [1,2;6,24]) %!assert (factorial(70), exp(sum(log(1:70))), -128*eps) -%!fail ('factorial(5.5)', "must all be nonnegative integers") -%!fail ('factorial(-3)', "must all be nonnegative integers") +%!fail ('factorial(5.5)', "must all be non-negative integers") +%!fail ('factorial(-3)', "must all be non-negative integers")
--- a/scripts/specfun/nchoosek.m +++ b/scripts/specfun/nchoosek.m @@ -68,7 +68,7 @@ endif if ((isscalar(v) && v < k) || k < 0 || k != round(k) || any (v < 0 || v != round(v))) - error ("nchoosek: args are nonnegative integers with V not less than K"); + error ("nchoosek: args are non-negative integers with V not less than K"); endif n = length (v);
--- a/scripts/statistics/tests/mcnemar_test.m +++ b/scripts/statistics/tests/mcnemar_test.m @@ -43,7 +43,7 @@ if (! (min (size (x)) > 1) && issquare (x)) error ("mcnemar_test: X must be a square matrix of size > 1"); elseif (! (all (all (x >= 0)) && all (all (x == fix (x))))) - error ("mcnemar_test: all entries of X must be nonnegative integers"); + error ("mcnemar_test: all entries of X must be non-negative integers"); endif r = rows (x);
--- a/scripts/testfun/assert.m +++ b/scripts/testfun/assert.m @@ -23,7 +23,7 @@ ## @deftypefnx {Function File} {} assert (@var{observed}, @var{expected}) ## @deftypefnx {Function File} {} assert (@var{observed}, @var{expected}, @var{tol}) ## -## Produces an error if the condition is not met. @code{assert} can be +## Produce an error if the condition is not met. @code{assert} can be ## called in three different ways. ## ## @table @code
--- a/scripts/testfun/demo.m +++ b/scripts/testfun/demo.m @@ -122,11 +122,19 @@ ## Process each demo without failing try block = code(idx(doidx(i)):idx(doidx(i)+1)-1); - ## Use an environment without variables - eval (cstrcat ("function __demo__()\n", block, "\nendfunction")); - ## Display the code that will be executed before executing it - printf ("%s example %d:%s\n\n", name, doidx(i), block); - __demo__; + ## FIXME: need to check for embedded test functions, which cause + ## segfaults, until issues with subfunctions in functions are resolved. + embed_func = regexp (block, '^\s*function ', 'once', 'lineanchors'); + if (isempty (embed_func)) + ## Use an environment without variables + eval (cstrcat ("function __demo__()\n", block, "\nendfunction")); + ## Display the code that will be executed before executing it + printf ("%s example %d:%s\n\n", name, doidx(i), block); + __demo__; + else + error (["Functions embedded in %!demo blocks are not allowed.\n", ... + "Use the %!function/%!endfunction syntax instead to define shared functions for testing.\n"]); + endif catch ## Let the programmer know which demo failed. printf ("%s example %d: failed\n%s\n", name, doidx(i), lasterr ());
--- a/scripts/testfun/example.m +++ b/scripts/testfun/example.m @@ -83,6 +83,7 @@ endfunction + %!## warning: don't modify the demos without modifying the tests! %!demo %! example ('example'); @@ -98,5 +99,6 @@ %! assert (idx, [1, 23, 63]); %% Test input validation -%!error example; -%!error example('example', 3, 5) +%!error example +%!error example ('example', 3, 5) +
--- a/scripts/testfun/test.m +++ b/scripts/testfun/test.m @@ -491,9 +491,17 @@ ## evaluate code for test, shared, and assert. if (! isempty(__code)) try - eval (sprintf ("function %s__test__(%s)\n%s\nendfunction", - __shared_r,__shared, __code)); - eval (sprintf ("%s__test__(%s);", __shared_r, __shared)); + ## FIXME: need to check for embedded test functions, which cause + ## segfaults, until issues with subfunctions in functions are resolved. + embed_func = regexp (__code, '^\s*function ', 'once', 'lineanchors'); + if (isempty (embed_func)) + eval (sprintf ("function %s__test__(%s)\n%s\nendfunction", + __shared_r,__shared, __code)); + eval (sprintf ("%s__test__(%s);", __shared_r, __shared)); + else + error (["Functions embedded in %!test blocks are not allowed.\n", ... + "Use the %!function/%!endfunction syntax instead to define shared functions for testing.\n"]); + endif catch if (strcmp (__type, "xtest")) __msg = sprintf ("%sknown failure\n%s", __signal_fail, lasterr ());
--- a/src/DLD-FUNCTIONS/__delaunayn__.cc +++ b/src/DLD-FUNCTIONS/__delaunayn__.cc @@ -50,14 +50,11 @@ #include "error.h" #include "oct-obj.h" -#ifdef HAVE_QHULL -extern "C" { -#include <qhull/qhull_a.h> -} - -#ifdef NEED_QHULL_VERSION +#if defined (HAVE_QHULL) +# include "oct-qhull.h" +# if defined (NEED_QHULL_VERSION) char qh_version[] = "__delaunayn__.oct 2007-08-21"; -#endif +# endif #endif DEFUN_DLD (__delaunayn__, args, , @@ -70,7 +67,7 @@ { octave_value_list retval; -#ifdef HAVE_QHULL +#if defined (HAVE_QHULL) retval(0) = 0.0;
--- a/src/DLD-FUNCTIONS/__init_fltk__.cc +++ b/src/DLD-FUNCTIONS/__init_fltk__.cc @@ -29,6 +29,8 @@ */ +// PKG_ADD: register_graphics_toolkit ("fltk"); + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -659,7 +661,8 @@ plot_window (int xx, int yy, int ww, int hh, figure::properties& xfp) : Fl_Window (xx, yy, ww, hh, "octave"), window_label (), shift (0), ndim (2), fp (xfp), canvas (0), autoscale (0), togglegrid (0), - panzoom (0), rotate (0), help (0), status (0) + panzoom (0), rotate (0), help (0), status (0), + ax_obj (), pos_x (0), pos_y (0) { callback (window_close, static_cast<void*> (this)); size_range (4*status_h, 2*status_h); @@ -749,9 +752,6 @@ status->hide (); uimenu->hide (); this->hide (); - delete canvas; - delete status; - delete uimenu; } double number (void) { return fp.get___myhandle__ ().value (); } @@ -971,6 +971,9 @@ Fl_Button* rotate; Fl_Button* help; Fl_Output* status; + graphics_object ax_obj; + int pos_x; + int pos_y; void axis_auto (void) { @@ -1177,9 +1180,6 @@ int handle (int event) { - static int px0,py0; - static graphics_object ax0; - graphics_handle gh; graphics_object fig = gh_manager::get_object (fp.get___myhandle__ ()); @@ -1255,17 +1255,17 @@ break; case FL_PUSH: - px0 = Fl::event_x (); - py0 = Fl::event_y (); + pos_x = Fl::event_x (); + pos_y = Fl::event_y (); set_currentpoint (Fl::event_x (), Fl::event_y ()); - gh = pixel2axes_or_ca (px0, py0); + gh = pixel2axes_or_ca (pos_x, pos_y); if (gh.ok ()) { - ax0 = gh_manager::get_object (gh); - set_axes_currentpoint (ax0, px0, py0); + ax_obj = gh_manager::get_object (gh); + set_axes_currentpoint (ax_obj, pos_x, pos_y); } fp.execute_windowbuttondownfcn (); @@ -1284,42 +1284,44 @@ if (Fl::event_button () == 1) { - if (ax0 && ax0.isa ("axes")) + if (ax_obj && ax_obj.isa ("axes")) { if (gui_mode == pan_zoom) - pixel2status (ax0, px0, py0, Fl::event_x (), Fl::event_y ()); + pixel2status (ax_obj, pos_x, pos_y, + Fl::event_x (), Fl::event_y ()); else - view2status (ax0); + view2status (ax_obj); axes::properties& ap = - dynamic_cast<axes::properties&> (ax0.get_properties ()); + dynamic_cast<axes::properties&> (ax_obj.get_properties ()); double x0, y0, x1, y1; Matrix pos = fp.get_position ().matrix_value (); - pixel2pos (ax0, px0, py0, x0, y0); - pixel2pos (ax0, Fl::event_x (), Fl::event_y (), x1, y1); + pixel2pos (ax_obj, pos_x, pos_y, x0, y0); + pixel2pos (ax_obj, Fl::event_x (), Fl::event_y (), x1, y1); if (gui_mode == pan_zoom) ap.translate_view (x0 - x1, y0 - y1); else if (gui_mode == rotate_zoom) { double daz, del; - daz = (Fl::event_x () - px0) / pos(2) * 360; - del = (Fl::event_y () - py0) / pos(3) * 360; + daz = (Fl::event_x () - pos_x) / pos(2) * 360; + del = (Fl::event_y () - pos_y) / pos(3) * 360; ap.rotate_view (del, daz); } - px0 = Fl::event_x (); - py0 = Fl::event_y (); + pos_x = Fl::event_x (); + pos_y = Fl::event_y (); mark_modified (); } return 1; } else if (Fl::event_button () == 3) { - pixel2status (ax0, px0, py0, Fl::event_x (), Fl::event_y ()); + pixel2status (ax_obj, pos_x, pos_y, + Fl::event_x (), Fl::event_y ()); Matrix zoom_box (1,4,0); - zoom_box (0) = px0; - zoom_box (1) = py0; + zoom_box (0) = pos_x; + zoom_box (1) = pos_y; zoom_box (2) = Fl::event_x (); zoom_box (3) = Fl::event_y (); canvas->set_zoom_box (zoom_box); @@ -1364,10 +1366,10 @@ { if ( Fl::event_clicks () == 1) { - if (ax0 && ax0.isa ("axes")) + if (ax_obj && ax_obj.isa ("axes")) { axes::properties& ap = - dynamic_cast<axes::properties&> (ax0.get_properties ()); + dynamic_cast<axes::properties&> (ax_obj.get_properties ()); ap.set_xlimmode ("auto"); ap.set_ylimmode ("auto"); ap.set_zlimmode ("auto"); @@ -1382,12 +1384,13 @@ { canvas->zoom (false); double x0,y0,x1,y1; - if (ax0 && ax0.isa ("axes")) + if (ax_obj && ax_obj.isa ("axes")) { axes::properties& ap = - dynamic_cast<axes::properties&> (ax0.get_properties ()); - pixel2pos (ax0, px0, py0, x0, y0); - pixel2pos (ax0, Fl::event_x (), Fl::event_y (), x1, y1); + dynamic_cast<axes::properties&> (ax_obj.get_properties ()); + pixel2pos (ax_obj, pos_x, pos_y, x0, y0); + pixel2pos (ax_obj, Fl::event_x (), Fl::event_y (), + x1, y1); Matrix xl (1,2,0); Matrix yl (1,2,0); if (x0 < x1) @@ -1768,12 +1771,12 @@ std::string figure_manager::fltk_idx_header="fltk index="; int figure_manager::curr_index = 1; -static bool toolkit_registered = false; +static bool toolkit_loaded = false; static int __fltk_redraw__ (void) { - if (toolkit_registered) + if (toolkit_loaded) { // We scan all figures and add those which use FLTK. graphics_object obj = gh_manager::get_object (0); @@ -1937,31 +1940,42 @@ sz(1) = Fl::h (); return sz; } + + void close (void) + { + if (toolkit_loaded) + { + munlock ("__init_fltk__"); + + figure_manager::close_all (); + gtk_manager::unload_toolkit (FLTK_GRAPHICS_TOOLKIT_NAME); + toolkit_loaded = false; + + octave_value_list args; + args(0) = "__fltk_redraw__"; + feval ("remove_input_event_hook", args, 0); + + // FIXME ??? + Fl::wait (fltk_maxtime); + } + } }; // Initialize the fltk graphics toolkit. DEFUN_DLD (__init_fltk__, , , "") { - static bool remove_fltk_registered = false; - - if (! toolkit_registered) + if (! toolkit_loaded) { mlock (); - graphics_toolkit::register_toolkit (new fltk_graphics_toolkit); - toolkit_registered = true; + graphics_toolkit tk (new fltk_graphics_toolkit ()); + gtk_manager::load_toolkit (tk); + toolkit_loaded = true; octave_value_list args; args(0) = "__fltk_redraw__"; feval ("add_input_event_hook", args, 0); - - if (! remove_fltk_registered) - { - octave_add_atexit_function ("__remove_fltk__"); - - remove_fltk_registered = true; - } } octave_value retval; @@ -1975,29 +1989,6 @@ return octave_value (); } -// Delete the fltk graphics toolkit. - -DEFUN_DLD (__remove_fltk__, , , "") -{ - if (toolkit_registered) - { - munlock ("__init_fltk__"); - - figure_manager::close_all (); - graphics_toolkit::unregister_toolkit (FLTK_GRAPHICS_TOOLKIT_NAME); - toolkit_registered = false; - - octave_value_list args; - args(0) = "__fltk_redraw__"; - feval ("remove_input_event_hook", args, 0); - - // FIXME ??? - Fl::wait (fltk_maxtime); - } - - return octave_value (); -} - DEFUN_DLD (__fltk_maxtime__, args, ,"") { octave_value retval = fltk_maxtime;
new file mode 100644 --- /dev/null +++ b/src/DLD-FUNCTIONS/__init_gnuplot__.cc @@ -0,0 +1,193 @@ +/* + +Copyright (C) 2007-2011 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +/* + +To initialize: + + graphics_toolkit ("gnuplot"); + plot (randn (1e3, 1)); + +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "defun-dld.h" +#include "error.h" +#include "graphics.h" +#include "parse.h" +#include "variables.h" + +// PKG_ADD: register_graphics_toolkit ("gnuplot"); + +static bool toolkit_loaded = false; + +class gnuplot_graphics_toolkit : public base_graphics_toolkit +{ +public: + gnuplot_graphics_toolkit (void) + : base_graphics_toolkit ("gnuplot") { } + + ~gnuplot_graphics_toolkit (void) { } + + bool is_valid (void) const { return true; } + + bool initialize (const graphics_object& go) + { + return go.isa ("figure"); + } + + void finalize (const graphics_object& go) + { + if (go.isa ("figure")) + { + const figure::properties& props = + dynamic_cast<const figure::properties&> (go.get_properties ()); + + send_quit (props.get___plot_stream__ ()); + } + } + + void update (const graphics_object& go, int id) + { + if (go.isa ("figure")) + { + graphics_object obj (go); + + figure::properties& props = + dynamic_cast<figure::properties&> (obj.get_properties ()); + + switch (id) + { + case base_properties::ID_VISIBLE: + if (! props.is_visible ()) + { + send_quit (props.get___plot_stream__ ()); + props.set___plot_stream__ (Matrix ()); + props.set___enhanced__ (false); + } + break; + } + } + } + + void redraw_figure (const graphics_object& go) const + { + octave_value_list args; + args(0) = go.get_handle ().as_octave_value (); + feval ("__gnuplot_drawnow__", args); + } + + void print_figure (const graphics_object& go, const std::string& term, + const std::string& file, bool mono, + const std::string& debug_file) const + { + octave_value_list args; + if (! debug_file.empty ()) + args(4) = debug_file; + args(3) = mono; + args(2) = file; + args(1) = term; + args(0) = go.get_handle ().as_octave_value (); + feval ("__gnuplot_drawnow__", args); + } + + Matrix get_canvas_size (const graphics_handle&) const + { + Matrix sz (1, 2, 0.0); + return sz; + } + + double get_screen_resolution (void) const + { return 72.0; } + + Matrix get_screen_size (void) const + { return Matrix (1, 2, 0.0); } + + void close (void) + { + if (toolkit_loaded) + { + munlock ("__init_gnuplot__"); + + gtk_manager::unload_toolkit ("gnuplot"); + + toolkit_loaded = false; + } + } + +private: + + void send_quit (const octave_value& pstream) const + { + if (! pstream.is_empty ()) + { + octave_value_list args; + Matrix fids = pstream.matrix_value (); + + if (! error_state) + { + args(1) = "\nquit;\n"; + args(0) = fids(0); + feval ("fputs", args); + + args.resize (1); + feval ("fflush", args); + feval ("pclose", args); + + if (fids.numel () > 1) + { + args(0) = fids(1); + feval ("pclose", args); + + if (fids.numel () > 2) + { + args(0) = fids(2); + feval ("waitpid", args); + } + } + } + } + } +}; + +// Initialize the fltk graphics toolkit. + +DEFUN_DLD (__init_gnuplot__, , , "") +{ + octave_value retval; + + if (! toolkit_loaded) + { + mlock (); + + graphics_toolkit tk (new gnuplot_graphics_toolkit ()); + gtk_manager::load_toolkit (tk); + + toolkit_loaded = true; + } + + return retval; +} +
--- a/src/DLD-FUNCTIONS/__voronoi__.cc +++ b/src/DLD-FUNCTIONS/__voronoi__.cc @@ -45,14 +45,11 @@ #include "error.h" #include "oct-obj.h" -#ifdef HAVE_QHULL -extern "C" { -#include <qhull/qhull_a.h> -} - -#ifdef NEED_QHULL_VERSION +#if defined (HAVE_QHULL) +# include "oct-qhull.h" +# if defined (NEED_QHULL_VERSION) char qh_version[] = "__voronoi__.oct 2007-07-24"; -#endif +# endif #endif DEFUN_DLD (__voronoi__, args, , @@ -67,7 +64,7 @@ std::string caller = args(0).string_value (); -#ifdef HAVE_QHULL +#if defined (HAVE_QHULL) retval(0) = 0.0;
--- a/src/DLD-FUNCTIONS/amd.cc +++ b/src/DLD-FUNCTIONS/amd.cc @@ -55,7 +55,7 @@ @deftypefn {Loadable Function} {@var{p} =} amd (@var{S})\n\ @deftypefnx {Loadable Function} {@var{p} =} amd (@var{S}, @var{opts})\n\ \n\ -Returns the approximate minimum degree permutation of a matrix. This\n\ +Return the approximate minimum degree permutation of a matrix. This\n\ permutation such that the Cholesky@tie{}factorization of @code{@var{S}\n\ (@var{p}, @var{p})} tends to be sparser than the Cholesky@tie{}factorization\n\ of @var{S} itself. @code{amd} is typically faster than @code{symamd} but\n\
--- a/src/DLD-FUNCTIONS/balance.cc +++ b/src/DLD-FUNCTIONS/balance.cc @@ -169,8 +169,8 @@ else { retval(2) = result.balanced_matrix (); + retval(1) = result.permuting_vector (); retval(0) = result.scaling_vector (); - retval(1) = result.permuting_vector (); } } @@ -188,8 +188,8 @@ else { retval(2) = result.balanced_matrix (); + retval(1) = result.permuting_vector (); retval(0) = result.scaling_vector (); - retval(1) = result.permuting_vector (); } } } @@ -209,8 +209,8 @@ else { retval(2) = result.balanced_matrix (); + retval(1) = result.permuting_vector (); retval(0) = result.scaling_vector (); - retval(1) = result.permuting_vector (); } } else @@ -227,8 +227,8 @@ else { retval(2) = result.balanced_matrix (); + retval(1) = result.permuting_vector (); retval(0) = result.scaling_vector (); - retval(1) = result.permuting_vector (); } } }
--- a/src/DLD-FUNCTIONS/cellfun.cc +++ b/src/DLD-FUNCTIONS/cellfun.cc @@ -380,7 +380,6 @@ } octave_value func = args(0); - bool symbol_table_lookup = false; if (! args(1).is_cell ()) { @@ -418,8 +417,6 @@ if (func.is_undefined ()) error ("cellfun: invalid function NAME: %s", name.c_str ()); - - symbol_table_lookup = true; } if (error_state || ! retval.empty ()) @@ -429,35 +426,50 @@ if (func.is_function_handle () || func.is_inline_function () || func.is_function ()) { + // The following is an optimisation because the symbol table can // give a more specific function class, so this can result in // fewer polymorphic function calls as the function gets called // for each value of the array. + { + if (func.is_function_handle ()) + { + octave_fcn_handle* f = func.fcn_handle_value (); - if (! symbol_table_lookup ) - { - if (func.is_function_handle ()) - { - octave_fcn_handle* f = func.fcn_handle_value (); + // Overloaded function handles need to check the type of the + // arguments for each element of the array, so they cannot + // be optimised this way. + if (f -> is_overloaded ()) + goto nevermind; + } + + std::string name = func.function_value () -> name (); + octave_value f = symbol_table::find_function (name); - // Overloaded function handles need to check the type of - // the arguments for each element of the array, so they - // cannot be optimised this way. + if (f.is_defined ()) + { + //Except for these two which are special cases... + if (name != "size" && name != "class") + { + //Try first the optimised code path for built-in functions + octave_value_list tmp_args = args; + tmp_args(0) = name; + retval = try_cellfun_internal_ops (tmp_args, nargin); + if (error_state || ! retval.empty ()) + return retval; + } - if (f -> is_overloaded ()) - goto nevermind; - } - octave_value f = symbol_table::find_function (func.function_value () - -> name ()); - if (f.is_defined ()) + //Okay, we tried, doesn't work, let's do the best we can + //instead and avoid polymorphic calls for each element of + //the array. func = f; - } - + } + } nevermind: bool uniform_output = true; octave_value error_handler; - + get_mapper_fun_options (args, nargin, uniform_output, error_handler); if (error_state)
--- a/src/DLD-FUNCTIONS/chol.cc +++ b/src/DLD-FUNCTIONS/chol.cc @@ -61,12 +61,13 @@ } DEFUN_DLD (chol, args, nargout, - "-*- texinfo -*-\n\ +"-*- texinfo -*-\n\ @deftypefn {Loadable Function} {@var{R} =} chol (@var{A})\n\ @deftypefnx {Loadable Function} {[@var{R}, @var{p}] =} chol (@var{A})\n\ @deftypefnx {Loadable Function} {[@var{R}, @var{p}, @var{Q}] =} chol (@var{S})\n\ @deftypefnx {Loadable Function} {[@var{R}, @var{p}, @var{Q}] =} chol (@var{S}, 'vector')\n\ @deftypefnx {Loadable Function} {[@var{L}, @dots{}] =} chol (@dots{}, 'lower')\n\ +@deftypefnx {Loadable Function} {[@var{L}, @dots{}] =} chol (@dots{}, 'upper')\n\ @cindex Cholesky factorization\n\ Compute the Cholesky@tie{}factor, @var{R}, of the symmetric positive definite\n\ matrix @var{A}, where\n\ @@ -128,6 +129,10 @@ \n\ @end ifnottex\n\ \n\ +For full matrices, if the 'lower' flag is set only the lower triangular part\n\ +of the matrix is used for the factorization, otherwise the upper triangular\n\ +part is used.\n\ +\n\ In general the lower triangular factorization is significantly faster for\n\ sparse matrices.\n\ @seealso{cholinv, chol2inv}\n\ @@ -155,6 +160,10 @@ if (tmp.compare ("vector") == 0) vecout = true; else if (tmp.compare ("lower") == 0) + // FIXME currently the option "lower" is handled by transposing the + // matrix, factorizing it with the lapack function DPOTRF ('U', ...) + // and finally transposing the factor. It would be more efficient to use + // DPOTRF ('L', ...) in this case. LLt = true; else if (tmp.compare ("upper") == 0) LLt = false; @@ -251,7 +260,13 @@ if (! error_state) { octave_idx_type info; - FloatCHOL fact (m, info); + + FloatCHOL fact; + if (LLt) + fact = FloatCHOL (m.transpose (), info); + else + fact = FloatCHOL (m, info); + if (nargout == 2 || info == 0) { retval(1) = info; @@ -271,7 +286,13 @@ if (! error_state) { octave_idx_type info; - FloatComplexCHOL fact (m, info); + + FloatComplexCHOL fact; + if (LLt) + fact = FloatComplexCHOL (m.transpose (), info); + else + fact = FloatComplexCHOL (m, info); + if (nargout == 2 || info == 0) { retval(1) = info; @@ -296,7 +317,13 @@ if (! error_state) { octave_idx_type info; - CHOL fact (m, info); + + CHOL fact; + if (LLt) + fact = CHOL (m.transpose (), info); + else + fact = CHOL (m, info); + if (nargout == 2 || info == 0) { retval(1) = info; @@ -316,7 +343,13 @@ if (! error_state) { octave_idx_type info; - ComplexCHOL fact (m, info); + + ComplexCHOL fact; + if (LLt) + fact = ComplexCHOL (m.transpose (), info); + else + fact = ComplexCHOL (m, info); + if (nargout == 2 || info == 0) { retval(1) = info; @@ -993,6 +1026,78 @@ %! assert(norm(triu(R1)-R1,Inf) == 0) %! assert(norm(A1(p,p) - single(Ac),Inf) < 2e1*eps('single')) %! + +%!test +%! cu = chol (triu (A), 'upper'); +%! cl = chol (tril (A), 'lower'); +%! assert (cu, cl', eps) +%! +%!test +%! cca = chol (Ac); +%! +%! ccal = chol (Ac, 'lower'); +%! ccal2 = chol (tril (Ac), 'lower'); +%! +%! ccau = chol (Ac, 'upper'); +%! ccau2 = chol (triu (Ac), 'upper'); +%! +%! assert (cca'*cca, Ac, eps) +%! assert (ccau'*ccau, Ac, eps) +%! assert (ccau2'*ccau2, Ac, eps) +%! +%! assert (cca, ccal', eps) +%! assert (cca, ccau, eps) +%! assert (cca, ccal2', eps) +%! assert (cca, ccau2, eps) +%! +%!test +%! cca = chol (single (Ac)); +%! +%! ccal = chol (single (Ac), 'lower'); +%! ccal2 = chol (tril (single (Ac)), 'lower'); +%! +%! ccau = chol (single (Ac), 'upper'); +%! ccau2 = chol (triu (single (Ac)), 'upper'); +%! +%! assert (cca'*cca, single (Ac), eps ('single')) +%! assert (ccau'*ccau, single (Ac), eps ('single')) +%! assert (ccau2'*ccau2, single (Ac), eps ('single')) +%! +%! assert (cca, ccal', eps ('single')) +%! assert (cca, ccau, eps ('single')) +%! assert (cca, ccal2', eps ('single')) +%! assert (cca, ccau2, eps ('single')) + +%!test +%! a = [12, 2, 3, 4; +%! 2, 14, 5, 3; +%! 3, 5, 16, 6; +%! 4, 3, 6, 16]; +%! +%! b = [0, 1, 2, 3; +%! -1, 0, 1, 2; +%! -2, -1, 0, 1; +%! -3, -2, -1, 0]; +%! +%! ca = a + i*b; +%! +%! cca = chol (ca); +%! +%! ccal = chol (ca, 'lower'); +%! ccal2 = chol (tril (ca), 'lower'); +%! +%! ccau = chol (ca, 'upper'); +%! ccau2 = chol (triu (ca), 'upper'); +%! +%! assert (cca'*cca, ca, 16*eps) +%! assert (ccau'*ccau, ca, 16*eps) +%! assert (ccau2'*ccau2, ca, 16*eps) +%! +%! assert (cca, ccal', 16*eps) +%! assert (cca, ccau, 16*eps) +%! assert (cca, ccal2', 16*eps) +%! assert (cca, ccau2, 16*eps) + */ DEFUN_DLD (choldelete, args, ,
--- a/src/DLD-FUNCTIONS/colamd.cc +++ b/src/DLD-FUNCTIONS/colamd.cc @@ -647,7 +647,7 @@ @deftypefnx {Loadable Function} {@var{p} =} etree (@var{S}, @var{typ})\n\ @deftypefnx {Loadable Function} {[@var{p}, @var{q}] =} etree (@var{S}, @var{typ})\n\ \n\ -Returns the elimination tree for the matrix @var{S}. By default @var{S}\n\ +Return the elimination tree for the matrix @var{S}. By default @var{S}\n\ is assumed to be symmetric and the symmetric elimination tree is\n\ returned. The argument @var{typ} controls whether a symmetric or\n\ column elimination tree is returned. Valid values of @var{typ} are\n\
--- a/src/DLD-FUNCTIONS/config-module.awk +++ b/src/DLD-FUNCTIONS/config-module.awk @@ -7,7 +7,8 @@ print "EXTRA_DIST += \\" print " DLD-FUNCTIONS/config-module.sh \\" print " DLD-FUNCTIONS/config-module.awk \\" - print " DLD-FUNCTIONS/module-files" + print " DLD-FUNCTIONS/module-files \\" + print " DLD-FUNCTIONS/oct-qhull.h" print "" } /^#.*/ { next; }
--- a/src/DLD-FUNCTIONS/convhulln.cc +++ b/src/DLD-FUNCTIONS/convhulln.cc @@ -41,15 +41,12 @@ #include "oct-obj.h" #include "parse.h" -#ifdef HAVE_QHULL -extern "C" { -#include <qhull/qhull_a.h> -} - -# ifdef NEED_QHULL_VERSION +#if defined (HAVE_QHULL) +# include "oct-qhull.h" +# if defined (NEED_QHULL_VERSION) char qh_version[] = "convhulln.oct 2007-07-24"; # endif -#endif /* HAVE_QHULL */ +#endif DEFUN_DLD (convhulln, args, nargout, "-*- texinfo -*-\n\ @@ -85,7 +82,7 @@ { octave_value_list retval; -#ifdef HAVE_QHULL +#if defined (HAVE_QHULL) int nargin = args.length (); if (nargin < 1 || nargin > 2)
--- a/src/DLD-FUNCTIONS/find.cc +++ b/src/DLD-FUNCTIONS/find.cc @@ -413,7 +413,7 @@ if (error_state || (val < 0 || (! xisinf (val) && val != xround (val)))) { - error ("find: N must be a nonnegative integer"); + error ("find: N must be a non-negative integer"); return retval; } else if (! xisinf (val))
--- a/src/DLD-FUNCTIONS/getgrent.cc +++ b/src/DLD-FUNCTIONS/getgrent.cc @@ -80,8 +80,8 @@ { std::string msg; + retval(1) = msg; retval(0) = mk_gr_map (octave_group::getgrent (msg)); - retval(1) = msg; } else print_usage (); @@ -116,8 +116,8 @@ std::string msg; + retval(1) = msg; retval(0) = mk_gr_map (octave_group::getgrgid (gid, msg)); - retval(1) = msg; } else error ("getgrgid: GID must be an integer"); @@ -152,8 +152,8 @@ { std::string msg; + retval(1) = msg; retval(0) = mk_gr_map (octave_group::getgrnam (s.c_str (), msg)); - retval(1) = msg; } } else @@ -179,8 +179,8 @@ { std::string msg; + retval(1) = msg; retval(0) = static_cast<double> (octave_group::setgrent (msg)); - retval(1) = msg; } else print_usage (); @@ -205,8 +205,8 @@ { std::string msg; + retval(1) = msg; retval(0) = static_cast<double> (octave_group::endgrent (msg)); - retval(1) = msg; } else print_usage ();
--- a/src/DLD-FUNCTIONS/getpwent.cc +++ b/src/DLD-FUNCTIONS/getpwent.cc @@ -84,8 +84,8 @@ { std::string msg; + retval(1) = msg; retval(0) = mk_pw_map (octave_passwd::getpwent (msg)); - retval(1) = msg; } else print_usage (); @@ -120,8 +120,8 @@ std::string msg; + retval(1) = msg; retval(0) = mk_pw_map (octave_passwd::getpwuid (uid, msg)); - retval(1) = msg; } else error ("getpwuid: UID must be an integer"); @@ -156,8 +156,8 @@ { std::string msg; + retval(1) = msg; retval(0) = mk_pw_map (octave_passwd::getpwnam (s, msg)); - retval(1) = msg; } } else @@ -183,8 +183,8 @@ { std::string msg; + retval(1) = msg; retval(0) = static_cast<double> (octave_passwd::setpwent (msg)); - retval(1) = msg; } else print_usage (); @@ -209,8 +209,8 @@ { std::string msg; + retval(1) = msg; retval(0) = static_cast<double> (octave_passwd::endpwent (msg)); - retval(1) = msg; } else print_usage ();
--- a/src/DLD-FUNCTIONS/module-files +++ b/src/DLD-FUNCTIONS/module-files @@ -6,6 +6,7 @@ __fltk_uigetfile__.cc|$(GRAPHICS_CFLAGS) $(FT2_CPPFLAGS)|$(GRAPHICS_LDFLAGS) $(FT2_LDFLAGS)|$(GRAPHICS_LIBS) $(FT2_LIBS) __glpk__.cc|$(GLPK_CPPFLAGS)|$(GLPK_LDFLAGS)|$(GLPK_LIBS) __init_fltk__.cc|$(GRAPHICS_CFLAGS) $(FT2_CPPFLAGS)|$(GRAPHICS_LDFLAGS) $(FT2_LDFLAGS)|$(GRAPHICS_LIBS) $(FT2_LIBS) +__init_gnuplot__.cc __lin_interpn__.cc __magick_read__.cc|$(MAGICK_CPPFLAGS)|$(MAGICK_LDFLAGS)|$(MAGICK_LIBS) __pchip_deriv__.cc @@ -57,7 +58,6 @@ md5sum.cc mgorth.cc nproc.cc -onCleanup.cc pinv.cc qr.cc|$(QRUPDATE_CPPFLAGS) $(SPARSE_XCPPFLAGS)|$(QRUPDATE_LDFLAGS) $(SPARSE_XLDFLAGS)|$(QRUPDATE_LIBS) $(SPARSE_XLIBS) quad.cc
new file mode 100644 --- /dev/null +++ b/src/DLD-FUNCTIONS/oct-qhull.h @@ -0,0 +1,54 @@ +/* + +Copyright (C) 2011 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +#if !defined (octave_oct_qhull_h) +#define octave_oct_qhull_h 1 + +#include <cstdio> + +extern "C" { + +#if defined (HAVE_QHULL_LIBQHULL_H) || defined (HAVE_QHULL_QHULL_H) +# if defined (HAVE_QHULL_LIBQHULL_H) +# include <qhull/libqhull.h> +# else +# include <qhull/qhull.h> +# endif +# include <qhull/qset.h> +# include <qhull/geom.h> +# include <qhull/poly.h> +# include <qhull/io.h> +#elif defined (HAVE_LIBQHULL_H) || defined (HAVE_QHULL_H) +# if defined (HAVE_LIBQHULL_H) +# include <libqhull.h> +# else +# include <qhull.h> +# endif +# include <qset.h> +# include <geom.h> +# include <poly.h> +# include <io.h> +#endif + +} + +#endif
deleted file mode 100644 --- a/src/DLD-FUNCTIONS/onCleanup.cc +++ /dev/null @@ -1,292 +0,0 @@ -/* - -Copyright (C) 2010-2011 VZLU Prague - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -<http://www.gnu.org/licenses/>. - -*/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "defun-dld.h" -#include "ov-base.h" -#include "ov.h" -#include "ov-fcn.h" -#include "ov-usr-fcn.h" -#include "pt-misc.h" -#include "toplev.h" - -static void gripe_internal (void) -{ - error ("onCleanup: internal error: cloning nonempty object"); -} - -class octave_oncleanup : public octave_base_value, octave_auto_shlib -{ -public: - octave_oncleanup (void) : fcn () { } - octave_oncleanup (const octave_value& fcn); - - octave_base_value *clone (void) const - { - if (fcn.is_defined ()) - gripe_internal (); - return empty_clone (); - } - - octave_base_value *empty_clone (void) const { return new octave_oncleanup (); } - - ~octave_oncleanup (void); - - bool is_defined (void) const { return true; } - - bool is_object (void) const { return true; } // do we want this? - - octave_map map_value (void) const - { return scalar_map_value (); } - - octave_scalar_map scalar_map_value (void) const; - - dim_vector dims (void) const { static dim_vector dv (1, 1); return dv; } - - bool save_ascii (std::ostream& os); - - bool load_ascii (std::istream& is); - - bool save_binary (std::ostream& os, bool& save_as_floats); - - bool load_binary (std::istream& is, bool swap, - oct_mach_info::float_format fmt); - -#if defined (HAVE_HDF5) - bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats); - - bool load_hdf5 (hid_t loc_id, const char *name); -#endif - - void print (std::ostream& os, bool pr_as_read_syntax = false) const; - - void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; - -private: - - DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA - -protected: - - octave_value fcn; - -}; - -DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_oncleanup, "onCleanup", "onCleanup"); - -octave_oncleanup::octave_oncleanup (const octave_value& f) - : fcn (f) -{ - if (f.is_function_handle ()) - { - octave_function *fptr = f.function_value (true); - if (fptr) - { - octave_user_function *uptr = dynamic_cast<octave_user_function *> (fptr); - if (uptr != 0) - { - tree_parameter_list *pl = uptr->parameter_list (); - if (pl != 0 && pl->length () > 0) - warning ("onCleanup: cleanup action takes parameters"); - } - } - else - error ("onCleanup: no default dispatch for function handle"); - } - else - { - fcn = octave_value (); - error ("onCleanup: argument must be a function handle"); - } -} - -octave_oncleanup::~octave_oncleanup (void) -{ - if (fcn.is_undefined ()) - return; - - unwind_protect frame; - - // Clear interrupts. - frame.protect_var (octave_interrupt_state); - octave_interrupt_state = 0; - - // Disallow quit(). - frame.protect_var (quit_allowed); - quit_allowed = false; - - // Clear errors. - frame.protect_var (error_state); - error_state = 0; - - try - { - // Run the actual code. - fcn.do_multi_index_op (0, octave_value_list ()); - } - catch (octave_interrupt_exception) - { - // Swallow the interrupt. - warning ("onCleanup: interrupt occured in cleanup action"); - } - catch (std::bad_alloc) - { - // Swallow the exception. - warning ("onCleanup: out of memory occured in cleanup action"); - } - catch (...) // Yes, the black hole. We're in a d-tor. - { - // This shouldn't happen, in theory. - error ("onCleanup: internal error: unhandled exception in cleanup action"); - } - - // We don't want to ignore errors that occur in the cleanup code, so - // if an error is encountered there, leave error_state alone. - // Otherwise, set it back to what it was before. - if (error_state) - { - frame.discard_top (); - octave_call_stack::backtrace_error_message (); - } -} - -octave_scalar_map -octave_oncleanup::scalar_map_value (void) const -{ - octave_scalar_map retval; - retval.setfield ("task", fcn); - return retval; -} - -static void -warn_save_load (void) -{ - warning ("onCleanup: load and save not supported"); -} - -bool -octave_oncleanup::save_ascii (std::ostream& /* os */) -{ - warn_save_load (); - return true; -} - -bool -octave_oncleanup::load_ascii (std::istream& /* is */) -{ - warn_save_load (); - return true; -} - -bool -octave_oncleanup::save_binary (std::ostream& /* os */, bool& /* save_as_floats */) -{ - warn_save_load (); - return true; -} - - -bool -octave_oncleanup::load_binary (std::istream& /* is */, bool /* swap */, - oct_mach_info::float_format /* fmt */) -{ - warn_save_load (); - return true; -} - -#if defined (HAVE_HDF5) -bool -octave_oncleanup::save_hdf5 (hid_t /* loc_id */, const char * /* name */, - bool /* save_as_floats */) -{ - warn_save_load (); - return true; -} - -bool -octave_oncleanup::load_hdf5 (hid_t /* loc_id */, const char * /* name */) -{ - warn_save_load (); - return true; -} -#endif - -void -octave_oncleanup::print (std::ostream& os, bool pr_as_read_syntax) const -{ - print_raw (os, pr_as_read_syntax); - newline (os); -} - -void -octave_oncleanup::print_raw (std::ostream& os, bool pr_as_read_syntax) const -{ - os << "onCleanup ("; - if (fcn.is_defined ()) - fcn.print_raw (os, pr_as_read_syntax); - os << ")"; -} - -DEFUN_DLD (onCleanup, args, , - "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{c} =} onCleanup (@var{action})\n\ -Create a special object that executes a given function upon destruction.\n\ -If the object is copied to multiple variables (or cell or struct array\n\ -elements) or returned from a function, @var{action} will be executed after\n\ -clearing the last copy of the object. Note that if multiple local onCleanup\n\ -variables are created, the order in which they are called is unspecified.\n\ -For similar functionality @xref{The @code{unwind_protect} Statement}.\n\ -@end deftypefn") -{ - octave_value retval; - - if (args.length () == 1) - { - if (octave_oncleanup::static_type_id () < 0) - octave_oncleanup::register_type (); - - retval = new octave_oncleanup (args(0)); - } - else - print_usage (); - - return retval; -} - -/* - -%!test -%! old_wstate = warning ("query"); -%! unwind_protect -%! trigger = onCleanup (@() warning ("on", "__MY_WARNING__")); -%! warning ("off", "__MY_WARNING__"); -%! assert ((warning ("query", "__MY_WARNING__")).state, "off"); -%! clear trigger -%! assert ((warning ("query", "__MY_WARNING__")).state, "on"); -%! unwind_protect_cleanup -%! warning (old_wstate); -%! end_unwind_protect - -*/
--- a/src/DLD-FUNCTIONS/qr.cc +++ b/src/DLD-FUNCTIONS/qr.cc @@ -1174,7 +1174,7 @@ @var{R}@tie{}upper trapezoidal, return the QR@tie{}factorization of\n\ @w{[A(:,1:j-1) A(:,j+1:n)]}, i.e., @var{A} with one column deleted\n\ (if @var{orient} is \"col\"), or the QR@tie{}factorization of\n\ -@w{[A(1:j-1,:);A(:,j+1:n)]}, i.e., @var{A} with one row deleted (if\n\ +@w{[A(1:j-1,:);A(j+1:n,:)]}, i.e., @var{A} with one row deleted (if\n \ @var{orient} is \"row\").\n\ \n\ The default value of @var{orient} is \"col\".\n\
--- a/src/DLD-FUNCTIONS/rand.cc +++ b/src/DLD-FUNCTIONS/rand.cc @@ -1024,9 +1024,9 @@ @deftypefnx {Loadable Function} {} randperm (@var{n}, @var{m})\n\ Return a row vector containing a random permutation of @code{1:@var{n}}.\n\ If @var{m} is supplied, return @var{m} unique entries, sampled without\n\ -replacement from @code{1:@var{n}}. The complexity is O(@var{n}) in\n\ +replacement from @code{1:@var{n}}. The complexity is O(@var{n}) in\n\ memory and O(@var{m}) in time, unless @var{m} < @var{n}/5, in which case\n\ -O(@var{m}) memory is used as well. The randomization is performed using\n\ +O(@var{m}) memory is used as well. The randomization is performed using\n\ rand(). All permutations are equally likely.\n\ @seealso{perms}\n\ @end deftypefn")
--- a/src/DLD-FUNCTIONS/regexp.cc +++ b/src/DLD-FUNCTIONS/regexp.cc @@ -25,501 +25,106 @@ #include <config.h> #endif -#include <algorithm> +#include <list> #include <sstream> -#include "defun-dld.h" -#include "error.h" -#include "gripes.h" -#include "oct-obj.h" -#include "utils.h" - -#include "Cell.h" -#include "oct-map.h" -#include "str-vec.h" -#include "quit.h" -#include "parse.h" -#include "oct-locbuf.h" - #include <pcre.h> -// Define the maximum number of retries for a pattern that -// possibly results in an infinite recursion. -#define PCRE_MATCHLIMIT_MAX 10 - -// The regexp is constructed as a linked list to avoid resizing the -// return values in arrays at each new match. - -// FIXME don't bother collecting and composing return values the user -// doesn't want. - -class regexp_elem -{ -public: - regexp_elem (const string_vector& _named_token, const Cell& _t, - const std::string& _m, const Matrix& _te, double _s, - double _e) : - named_token (_named_token), t (_t), m (_m), te (_te), s (_s), e (_e) { } - - regexp_elem (const regexp_elem &a) : named_token (a.named_token), t (a.t), - m (a.m), te (a.te), s (a.s), e (a.e) - { } - - string_vector named_token; - Cell t; - std::string m; - Matrix te; - double s; - double e; -}; - -typedef std::list<regexp_elem>::const_iterator const_iterator; - -#define MAXLOOKBEHIND 10 -static bool lookbehind_warned = false; +#include "base-list.h" +#include "oct-locbuf.h" +#include "quit.h" +#include "regexp.h" +#include "str-vec.h" -static int -octregexp_list (const octave_value_list &args, const std::string &nm, - bool case_insensitive, std::list<regexp_elem> &lst, - string_vector &named, int &nopts, bool &once) -{ - int sz = 0; - - int nargin = args.length (); - bool lineanchors = false; - bool dotexceptnewline = false; - bool freespacing = false; - - nopts = nargin - 2; - once = false; +#include "defun-dld.h" +#include "Cell.h" +#include "error.h" +#include "gripes.h" +#include "oct-map.h" +#include "oct-obj.h" +#include "utils.h" - std::string buffer = args(0).string_value (); - size_t max_length = (buffer.length () > MAXLOOKBEHIND ? - MAXLOOKBEHIND: buffer.length ()); - - if (error_state) - { - gripe_wrong_type_arg (nm.c_str (), args(0)); - return 0; - } +static void +parse_options (regexp::opts& options, const octave_value_list& args, + const std::string& who, int skip, bool& extra_args) +{ + int nargin = args.length (); - std::string pattern = args(1).string_value (); + extra_args = false; - if (error_state) - { - gripe_wrong_type_arg (nm.c_str (), args(1)); - return 0; - } - - for (int i = 2; i < nargin; i++) + for (int i = skip; i < nargin; i++) { std::string str = args(i).string_value (); if (error_state) { - error ("%s: optional arguments must be strings", nm.c_str ()); + error ("%s: optional arguments must be character strings", + who.c_str ()); break; } std::transform (str.begin (), str.end (), str.begin (), tolower); if (str.find ("once", 0) == 0) - { - once = true; - nopts--; - } + options.once (true); else if (str.find ("matchcase", 0) == 0) - { - case_insensitive = false; - nopts--; - } + options.case_insensitive (false); else if (str.find ("ignorecase", 0) == 0) - { - case_insensitive = true; - nopts--; - } + options.case_insensitive (true); else if (str.find ("dotall", 0) == 0) - { - dotexceptnewline = false; - nopts--; - } + options.dotexceptnewline (false); else if (str.find ("stringanchors", 0) == 0) - { - lineanchors = false; - nopts--; - } + options.lineanchors (false); else if (str.find ("literalspacing", 0) == 0) - { - freespacing = false; - nopts--; - } + options.freespacing (false); else if (str.find ("dotexceptnewline", 0) == 0) - { - dotexceptnewline = true; - nopts--; - } + options.dotexceptnewline (true); else if (str.find ("lineanchors", 0) == 0) - { - lineanchors = true; - nopts--; - } + options.lineanchors (true); else if (str.find ("freespacing", 0) == 0) - { - freespacing = true; - nopts--; - } - else if (str.find ("start", 0) && str.find ("end", 0) - && str.find ("tokenextents", 0) && str.find ("match", 0) - && str.find ("tokens", 0) && str.find ("names", 0) - && str.find ("split", 0)) - error ("%s: unrecognized option", nm.c_str ()); + options.freespacing (true); + else if (str.find ("start", 0) == 0 + || str.find ("end", 0) == 0 + || str.find ("tokenextents", 0) == 0 + || str.find ("match", 0) == 0 + || str.find ("tokens", 0) == 0 + || str.find ("names", 0) == 0 + || str.find ("split", 0) == 0) + extra_args = true; + else + error ("%s: unrecognized option", who.c_str ()); } - - if (!error_state) - { - Cell t; - std::string m; - double s, e; - - // named tokens "(?<name>...)" are only treated with PCRE not regex. - - size_t pos = 0; - size_t new_pos; - int nnames = 0; - int inames = 0; - std::ostringstream buf; - Array<int> named_idx; - - while ((new_pos = pattern.find ("(?", pos)) != std::string::npos) - { - if (pattern.at (new_pos + 2) == '<' - && !(pattern.at (new_pos + 3) == '=' - || pattern.at (new_pos + 3) == '!')) - { - // The syntax of named tokens in pcre is "(?P<name>...)" while - // we need a syntax "(?<name>...)", so fix that here. Also an - // expression like - // "(?<first>\w+)\s+(?<last>\w+)|(?<last>\w+),\s+(?<first>\w+)" - // should be perfectly legal, while pcre does not allow the same - // named token name on both sides of the alternative. Also fix - // that here by replacing name tokens by dummy names, and dealing - // with the dummy names later. - - size_t tmp_pos = pattern.find_first_of ('>', new_pos); - - if (tmp_pos == std::string::npos) - { - error ("regexp: syntax error in pattern"); - break; - } - - std::string tmp_name = - pattern.substr (new_pos+3, tmp_pos-new_pos-3); - - bool found = false; - - for (int i = 0; i < nnames; i++) - { - if (named(i) == tmp_name) - { - named_idx.resize (dim_vector (inames+1, 1)); - named_idx(inames) = i; - found = true; - break; - } - } - - if (! found) - { - named_idx.resize (dim_vector (inames+1, 1)); - named_idx(inames) = nnames; - named.append (tmp_name); - nnames++; - } - - if (new_pos - pos > 0) - buf << pattern.substr (pos, new_pos-pos); - if (inames < 10) - buf << "(?P<n00" << inames++; - else if (inames < 100) - buf << "(?P<n0" << inames++; - else - buf << "(?P<n" << inames++; - - pos = tmp_pos; - } - else if (pattern.at (new_pos + 2) == '<') - { - // Find lookbehind operators of arbitrary length (ie like - // "(?<=[a-z]*)") and replace with a maximum length operator - // as PCRE can not yet handle arbitrary length lookahead - // operators. Use the string length as the maximum length to - // avoid issues. - - int brackets = 1; - size_t tmp_pos1 = new_pos + 2; - size_t tmp_pos2 = tmp_pos1; - - while (tmp_pos1 <= pattern.length () && brackets > 0) - { - char ch = pattern.at (tmp_pos1); - - if (ch == '(') - brackets++; - else if (ch == ')') - { - if (brackets > 1) - tmp_pos2 = tmp_pos1; - - brackets--; - } - - tmp_pos1++; - } - - if (brackets != 0) - { - buf << pattern.substr (pos, new_pos - pos) << "(?"; - pos = new_pos + 2; - } - else - { - size_t tmp_pos3 = pattern.find_first_of ("*+", tmp_pos2); - - if (tmp_pos3 != std::string::npos && tmp_pos3 < tmp_pos1) - { - if (!lookbehind_warned) - { - lookbehind_warned = true; - warning ("%s: arbitrary length lookbehind patterns are only supported up to length %d", - nm.c_str (), MAXLOOKBEHIND); - } - - buf << pattern.substr (pos, new_pos - pos) << "("; - - size_t i; - - if (pattern.at (tmp_pos3) == '*') - i = 0; - else - i = 1; - - for (; i < max_length + 1; i++) - { - buf << pattern.substr (new_pos, tmp_pos3 - new_pos) - << "{" << i << "}"; - buf << pattern.substr (tmp_pos3 + 1, - tmp_pos1 - tmp_pos3 - 1); - if (i != max_length) - buf << "|"; - } - buf << ")"; - } - else - buf << pattern.substr (pos, tmp_pos1 - pos); - - pos = tmp_pos1; - } - } - else - { - buf << pattern.substr (pos, new_pos - pos) << "(?"; - pos = new_pos + 2; - } - - } - - buf << pattern.substr (pos); - - if (error_state) - return 0; - - // Compile expression - const char *err; - int erroffset; - std::string buf_str = buf.str (); - - pcre *re = pcre_compile (buf_str.c_str (), - ((case_insensitive ? PCRE_CASELESS : 0) - | (dotexceptnewline ? 0 : PCRE_DOTALL) - | (lineanchors ? PCRE_MULTILINE : 0) - | (freespacing ? PCRE_EXTENDED : 0)), - &err, &erroffset, 0); - - if (re == 0) - { - error ("%s: %s at position %d of expression", nm.c_str (), - err, erroffset); - return 0; - } - - int subpatterns; - int namecount; - int nameentrysize; - char *nametable; - int idx = 0; - - pcre_fullinfo (re, 0, PCRE_INFO_CAPTURECOUNT, &subpatterns); - pcre_fullinfo (re, 0, PCRE_INFO_NAMECOUNT, &namecount); - pcre_fullinfo (re, 0, PCRE_INFO_NAMEENTRYSIZE, &nameentrysize); - pcre_fullinfo (re, 0, PCRE_INFO_NAMETABLE, &nametable); - - OCTAVE_LOCAL_BUFFER (int, ovector, (subpatterns+1)*3); - OCTAVE_LOCAL_BUFFER (int, nidx, namecount); - - for (int i = 0; i < namecount; i++) - { - // Index of subpattern in first two bytes MSB first of name. - // Extract index. - nidx[i] = (static_cast<int> (nametable[i*nameentrysize])) << 8 - | static_cast<int> (nametable[i*nameentrysize+1]); - } - - while (true) - { - OCTAVE_QUIT; - - int matches = pcre_exec (re, 0, buffer.c_str (), - buffer.length (), idx, - (idx ? PCRE_NOTBOL : 0), - ovector, (subpatterns+1)*3); - - if (matches == PCRE_ERROR_MATCHLIMIT) - { - // Try harder; start with default value for MATCH_LIMIT - // and increase it. - warning ("your pattern caused PCRE to hit its MATCH_LIMIT; trying harder now, but this will be slow"); - - pcre_extra pe; - - pcre_config (PCRE_CONFIG_MATCH_LIMIT, - static_cast <void *> (&pe.match_limit)); - - pe.flags = PCRE_EXTRA_MATCH_LIMIT; - - int i = 0; - while (matches == PCRE_ERROR_MATCHLIMIT - && i++ < PCRE_MATCHLIMIT_MAX) - { - OCTAVE_QUIT; - - pe.match_limit *= 10; - matches = pcre_exec (re, &pe, buffer.c_str (), - buffer.length (), idx, - (idx ? PCRE_NOTBOL : 0), - ovector, (subpatterns+1)*3); - } - } - - if (matches < 0 && matches != PCRE_ERROR_NOMATCH) - { - error ("%s: internal error calling pcre_exec; error code from pcre_exec is %i", - nm.c_str (), matches); - pcre_free (re); - return 0; - } - else if (matches == PCRE_ERROR_NOMATCH) - break; - else if (ovector[1] <= ovector[0]) - { - // Zero sized match. Skip to next char. - idx = ovector[0] + 1; - if (idx < buffer.length ()) - continue; - else - break; - } - else - { - int pos_match = 0; - Matrix te (matches-1, 2); - - for (int i = 1; i < matches; i++) - { - if (ovector[2*i] >= 0 && ovector[2*i+1] > 0 - && (i == 1 || ovector[2*i] != ovector[2*i-2] - || ovector[2*i-1] != ovector[2*i+1]) - && ovector[2*i] >= 0 && ovector[2*i+1] > 0) - { - te(pos_match,0) = double (ovector[2*i]+1); - te(pos_match++,1) = double (ovector[2*i+1]); - } - } - - te.resize (pos_match, 2); - - s = double (ovector[0]+1); - e = double (ovector[1]); - - const char **listptr; - int status = pcre_get_substring_list (buffer.c_str (), ovector, - matches, &listptr); - - if (status == PCRE_ERROR_NOMEMORY) - { - error ("%s: cannot allocate memory in pcre_get_substring_list", - nm.c_str ()); - pcre_free (re); - return 0; - } - - Cell cell_t (dim_vector (1, pos_match)); - string_vector named_tokens (nnames); - int pos_offset = 0; - pos_match = 0; - - for (int i = 1; i < matches; i++) - { - if (ovector[2*i] >= 0 && ovector[2*i+1] > 0) - { - if (i == 1 || ovector[2*i] != ovector[2*i-2] - || ovector[2*i-1] != ovector[2*i+1]) - { - if (namecount > 0) - named_tokens(named_idx(i-pos_offset-1)) = - std::string (*(listptr+nidx[i-pos_offset-1])); - cell_t(pos_match++) = - std::string (*(listptr+i)); - } - else - pos_offset++; - } - } - - m = std::string (*listptr); - t = cell_t; - - pcre_free_substring_list (listptr); - - regexp_elem new_elem (named_tokens, t, m, te, s, e); - lst.push_back (new_elem); - idx = ovector[1]; - sz++; - - if (once || idx >= buffer.length ()) - break; - - } - } - - pcre_free (re); - } - - return sz; } static octave_value_list -octregexp (const octave_value_list &args, int nargout, const std::string &nm, - bool case_insensitive) +octregexp (const octave_value_list &args, int nargout, + const std::string &who, bool case_insensitive = false) { octave_value_list retval; + int nargin = args.length (); - std::list<regexp_elem> lst; - string_vector named; - int nopts; - bool once; + + // Make sure we have string, pattern + const std::string buffer = args(0).string_value (); + if (error_state) + return retval; + + const std::string pattern = args(1).string_value (); + if (error_state) + return retval; - int sz = octregexp_list (args, nm, case_insensitive, lst, named, nopts, once); + regexp::opts options; + options.case_insensitive (case_insensitive); + bool extra_options = false; + parse_options (options, args, who, 2, extra_options); + if (error_state) + return retval; + + regexp::match_data rx_lst = regexp_match (pattern, buffer, options, who); + + string_vector named_pats = rx_lst.named_patterns (); + + size_t sz = rx_lst.size (); if (! error_state) { @@ -532,47 +137,54 @@ if (sz == 1) { - for (int j = 0; j < named.length (); j++) - nmap.assign (named(j), lst.begin()->named_token (j)); + string_vector named_tokens = rx_lst.begin()->named_tokens (); + + for (int j = 0; j < named_pats.length (); j++) + nmap.assign (named_pats(j), named_tokens(j)); retval(5) = nmap; } else { - for (int j = 0; j < named.length (); j++) + for (int j = 0; j < named_pats.length (); j++) { Cell tmp (dim_vector (1, sz)); i = 0; - for (const_iterator p = lst.begin (); p != lst.end (); p++) - tmp(i++) = p->named_token (j); + for (regexp::match_data::const_iterator p = rx_lst.begin (); + p != rx_lst.end (); p++) + { + string_vector named_tokens = p->named_tokens (); - nmap.assign (named(j), octave_value (tmp)); + tmp(i++) = named_tokens(j); + } + + nmap.assign (named_pats(j), octave_value (tmp)); } retval(5) = nmap; } - std::string buffer = args(0).string_value (); - - if (once) + if (options.once ()) { - retval(4) = sz ? lst.front ().t : Cell (); - retval(3) = sz ? lst.front ().m : std::string (); - retval(2) = sz ? lst.front ().te : Matrix (); + regexp::match_data::const_iterator p = rx_lst.begin (); + + retval(4) = sz ? p->tokens () : Cell (); + retval(3) = sz ? p->match_string () : std::string (); + retval(2) = sz ? p->token_extents () : Matrix (); if (sz) { - double e = lst.front ().e; - double s = lst.front ().s; + double start = p->start (); + double end = p->end (); - Cell sp (dim_vector (1, 2)); - sp(0) = buffer.substr (0, s-1); - sp(1) = buffer.substr (e); + Cell split (dim_vector (1, 2)); + split(0) = buffer.substr (0, start-1); + split(1) = buffer.substr (end); - retval(6) = sp; - retval(1) = e; - retval(0) = s; + retval(6) = split; + retval(1) = end; + retval(0) = start; } else { @@ -583,39 +195,45 @@ } else { - Cell t (dim_vector (1, sz)); - Cell m (dim_vector (1, sz)); - Cell te (dim_vector (1, sz)); - NDArray e (dim_vector (1, sz)); - NDArray s (dim_vector (1, sz)); - Cell sp (dim_vector (1, sz+1)); + Cell tokens (dim_vector (1, sz)); + Cell match_string (dim_vector (1, sz)); + Cell token_extents (dim_vector (1, sz)); + NDArray end (dim_vector (1, sz)); + NDArray start (dim_vector (1, sz)); + Cell split (dim_vector (1, sz+1)); size_t sp_start = 0; i = 0; - for (const_iterator p = lst.begin (); p != lst.end (); p++) + for (regexp::match_data::const_iterator p = rx_lst.begin (); + p != rx_lst.end (); p++) { - t(i) = p->t; - m(i) = p->m; - te(i) = p->te; - e(i) = p->e; - s(i) = p->s; - sp(i) = buffer.substr (sp_start, p->s-sp_start-1); - sp_start = p->e; + double s = p->start (); + double e = p->end (); + + string_vector tmp = p->tokens (); + tokens(i) = Cell (dim_vector (1, tmp.length ()), tmp); + match_string(i) = p->match_string (); + token_extents(i) = p->token_extents (); + end(i) = e; + start(i) = s; + split(i) = buffer.substr (sp_start, s-sp_start-1); + sp_start = e; i++; } - sp(i) = buffer.substr (sp_start); + split(i) = buffer.substr (sp_start); - retval(6) = sp; - retval(4) = t; - retval(3) = m; - retval(2) = te; - retval(1) = e; - retval(0) = s; + retval(6) = split; + retval(4) = tokens; + retval(3) = match_string; + retval(2) = token_extents; + retval(1) = end; + retval(0) = start; } // Alter the order of the output arguments - if (nopts > 0) + + if (extra_options) { int n = 0; octave_value_list new_retval; @@ -682,7 +300,7 @@ static octave_value_list octcellregexp (const octave_value_list &args, int nargout, - const std::string &nm, bool case_insensitive) + const std::string &who, bool case_insensitive = false) { octave_value_list retval; @@ -705,7 +323,7 @@ for (octave_idx_type i = 0; i < cellstr.numel (); i++) { new_args(0) = cellstr(i); - octave_value_list tmp = octregexp (new_args, nargout, nm, + octave_value_list tmp = octregexp (new_args, nargout, who, case_insensitive); if (error_state) @@ -725,7 +343,7 @@ for (octave_idx_type i = 0; i < cellpat.numel (); i++) { new_args(1) = cellpat(i); - octave_value_list tmp = octregexp (new_args, nargout, nm, + octave_value_list tmp = octregexp (new_args, nargout, who, case_insensitive); if (error_state) @@ -739,7 +357,7 @@ { if (cellstr.dims () != cellpat.dims ()) - error ("%s: Inconsistent cell array dimensions", nm.c_str ()); + error ("%s: inconsistent cell array dimensions", who.c_str ()); else { for (int j = 0; j < nargout; j++) @@ -750,7 +368,7 @@ new_args(0) = cellstr(i); new_args(1) = cellpat(i); - octave_value_list tmp = octregexp (new_args, nargout, nm, + octave_value_list tmp = octregexp (new_args, nargout, who, case_insensitive); if (error_state) @@ -772,7 +390,7 @@ for (octave_idx_type i = 0; i < cellstr.numel (); i++) { new_args(0) = cellstr(i); - octave_value_list tmp = octregexp (new_args, nargout, nm, + octave_value_list tmp = octregexp (new_args, nargout, who, case_insensitive); if (error_state) @@ -799,7 +417,7 @@ for (octave_idx_type i = 0; i < cellpat.numel (); i++) { new_args(1) = cellpat(i); - octave_value_list tmp = octregexp (new_args, nargout, nm, + octave_value_list tmp = octregexp (new_args, nargout, who, case_insensitive); if (error_state) @@ -816,7 +434,7 @@ } } else - retval = octregexp (args, nargout, nm, case_insensitive); + retval = octregexp (args, nargout, who, case_insensitive); return retval; @@ -1022,9 +640,9 @@ if (nargin < 2) print_usage (); else if (args(0).is_cell () || args(1).is_cell ()) - retval = octcellregexp (args, nargout, "regexp", false); + retval = octcellregexp (args, nargout, "regexp"); else - retval = octregexp (args, nargout, "regexp", false); + retval = octregexp (args, nargout, "regexp"); return retval; } @@ -1402,7 +1020,7 @@ static octave_value -octregexprep (const octave_value_list &args, const std::string &nm) +octregexprep (const octave_value_list &args, const std::string &who) { octave_value retval; @@ -1423,12 +1041,9 @@ // Pack options excluding 'tokenize' and various output // reordering strings into regexp arg list - octave_value_list regexpargs (nargin-1, octave_value ()); + octave_value_list regexpargs (nargin-3, octave_value ()); - regexpargs(0) = args (0); - regexpargs(1) = args (1); - - int len = 2; + int len = 0; for (int i = 3; i < nargin; i++) { const std::string opt = args(i).string_value (); @@ -1441,165 +1056,13 @@ } regexpargs.resize (len); - // Identify replacement tokens; build a vector of group numbers in - // the replacement string so that we can quickly calculate the size - // of the replacement. - int tokens = 0; - for (size_t i=1; i < replacement.size (); i++) - { - if (replacement[i-1]=='$' && isdigit (replacement[i])) - { - tokens++; - i++; - } - } - std::vector<int> token (tokens); - - int kk = 0; - for (size_t i = 1; i < replacement.size (); i++) - { - if (replacement[i-1]=='$' && isdigit (replacement[i])) - { - token[kk++] = replacement[i]-'0'; - i++; - } - } - - // Perform replacement - std::string rep; - - if (tokens > 0) - { - std::list<regexp_elem> lst; - string_vector named; - int nopts; - bool once; - int sz = octregexp_list (regexpargs, nm , false, lst, named, nopts, once); - - if (error_state) - return retval; - if (sz == 0) - { - retval = args(0); - return retval; - } - - // Determine replacement length - const size_t replen = replacement.size () - 2*tokens; - int delta = 0; - const_iterator p = lst.begin (); - for (int i = 0; i < sz; i++) - { - OCTAVE_QUIT; - - const Matrix pairs (p->te); - size_t pairlen = 0; - for (int j = 0; j < tokens; j++) - { - if (token[j] == 0) - pairlen += static_cast<size_t> (p->e - p->s) + 1; - else if (token[j] <= pairs.rows ()) - pairlen += static_cast<size_t> (pairs(token[j]-1,1) - - pairs(token[j]-1,0)) + 1; - } - delta += static_cast<int> (replen + pairlen) - - static_cast<int> (p->e - p->s + 1); - p++; - } - - // Build replacement string - rep.reserve (buffer.size () + delta); - size_t from = 0; - p = lst.begin (); - for (int i = 0; i < sz; i++) - { - OCTAVE_QUIT; + regexp::opts options; + bool extra_args = false; + parse_options (options, regexpargs, who, 0, extra_args); + if (error_state) + return retval; - const Matrix pairs (p->te); - rep.append (&buffer[from], static_cast<size_t> (p->s - 1) - from); - from = static_cast<size_t> (p->e - 1) + 1; - for (size_t j = 1; j < replacement.size (); j++) - { - if (replacement[j-1]=='$' && isdigit (replacement[j])) - { - int k = replacement[j]-'0'; - if (k == 0) - { - // replace with entire match - rep.append (&buffer[static_cast<size_t> (p->e - 1)], - static_cast<size_t> (p->e - p->s) + 1); - } - else if (k <= pairs.rows ()) - { - // replace with group capture - rep.append (&buffer[static_cast<size_t> (pairs(k-1,0)-1)], - static_cast<size_t> (pairs(k-1,1) - - pairs(k-1,0)) + 1); - } - else - { - // replace with nothing - } - j++; - } - else - { - rep.append (1, replacement[j-1]); - } - if (j+1 == replacement.size ()) - { - rep.append (1, replacement[j]); - } - } - p++; - } - rep.append (&buffer[from], buffer.size () - from); - } - else - { - std::list<regexp_elem> lst; - string_vector named; - int nopts; - bool once; - int sz = octregexp_list (regexpargs, nm, false, lst, named, nopts, once); - - if (error_state) - return retval; - if (sz == 0) - { - retval = args (0); - return retval; - } - - // Determine replacement length - const size_t replen = replacement.size (); - int delta = 0; - const_iterator p = lst.begin (); - for (int i = 0; i < sz; i++) - { - OCTAVE_QUIT; - delta += static_cast<int> (replen) - - static_cast<int> (p->e - p->s + 1); - p++; - } - - // Build replacement string - rep.reserve (buffer.size () + delta); - size_t from = 0; - p = lst.begin (); - for (int i = 0; i < sz; i++) - { - OCTAVE_QUIT; - rep.append (&buffer[from], static_cast<size_t> (p->s - 1) - from); - from = static_cast<size_t> (p->e - 1) + 1; - rep.append (replacement); - p++; - } - rep.append (&buffer[from], buffer.size () - from); - } - - retval = rep; - return retval; + return regexp_replace (pattern, buffer, replacement, options, who); } DEFUN_DLD (regexprep, args, , @@ -1672,7 +1135,7 @@ { dv1 = pat.dims (); if (rep.numel () != 1 && dv1 != rep.dims ()) - error ("regexprep: Inconsistent cell array dimensions"); + error ("regexprep: inconsistent cell array dimensions"); } else if (rep.numel () != 1) dv1 = rep.dims ();
--- a/src/DLD-FUNCTIONS/spparms.cc +++ b/src/DLD-FUNCTIONS/spparms.cc @@ -113,8 +113,8 @@ retval(0) = octave_sparse_params::get_vals (); else if (nargout == 2) { + retval (1) = octave_sparse_params::get_vals (); retval (0) = octave_sparse_params::get_keys (); - retval (1) = octave_sparse_params::get_vals (); } else error ("spparms: too many output arguments");
--- a/src/DLD-FUNCTIONS/sqrtm.cc +++ b/src/DLD-FUNCTIONS/sqrtm.cc @@ -232,6 +232,12 @@ return retval; } + if (nargout > 1) + { + retval.resize (1, 2); + retval(2) = -1.0; + } + if (arg.is_diag_matrix ()) // sqrtm of a diagonal matrix is just sqrt. retval(0) = arg.sqrt ();
--- a/src/DLD-FUNCTIONS/svd.cc +++ b/src/DLD-FUNCTIONS/svd.cc @@ -408,9 +408,14 @@ "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {@var{val} =} svd_driver ()\n\ @deftypefnx {Loadable Function} {@var{old_val} =} svd_driver (@var{new_val})\n\ +@deftypefnx {Loadable Function} {} svd_driver (@var{new_val}, \"local\")\n\ Query or set the underlying @sc{lapack} driver used by @code{svd}.\n\ Currently recognized values are \"gesvd\" and \"gesdd\". The default\n\ is \"gesvd\".\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{svd}\n\ @end deftypefn") {
--- a/src/DLD-FUNCTIONS/urlwrite.cc +++ b/src/DLD-FUNCTIONS/urlwrite.cc @@ -46,6 +46,7 @@ #include "ov-cell.h" #include "pager.h" #include "oct-map.h" +#include "oct-refcount.h" #include "unwind-prot.h" #ifdef HAVE_CURL @@ -141,7 +142,7 @@ return !ascii; } - size_t count; + octave_refcount<size_t> count; std::string host; bool valid; bool ascii; @@ -805,8 +806,8 @@ frame.add_fcn (cleanup_urlwrite, filename); - bool res; - curl_handle curl = curl_handle (url, method, param, ofile, res); + bool ok; + curl_handle curl = curl_handle (url, method, param, ofile, ok); ofile.close (); @@ -817,7 +818,7 @@ if (nargout > 0) { - if (res) + if (ok) { retval(2) = std::string (); retval(1) = true; @@ -831,7 +832,7 @@ } } - if (nargout < 2 && res) + if (nargout < 2 && ! ok) error ("urlwrite: curl: %s", curl.lasterror ().c_str ()); #else @@ -939,18 +940,18 @@ std::ostringstream buf; - bool res; - curl_handle curl = curl_handle (url, method, param, buf, res); + bool ok; + curl_handle curl = curl_handle (url, method, param, buf, ok); if (nargout > 0) { + // Return empty string if no error occured. + retval(2) = ok ? "" : curl.lasterror (); + retval(1) = ok; retval(0) = buf.str (); - retval(1) = res; - // Return empty string if no error occured. - retval(2) = res ? "" : curl.lasterror (); } - if (nargout < 2 && !res) + if (nargout < 2 && ! ok) error ("urlread: curl: %s", curl.lasterror().c_str()); #else
--- a/src/Makefile.am +++ b/src/Makefile.am @@ -179,6 +179,7 @@ ov-lazy-idx.h \ ov-mex-fcn.h \ ov-null-mat.h \ + ov-oncleanup.h \ ov-perm.h \ ov-range.h \ ov-re-diag.h \ @@ -230,7 +231,6 @@ octinclude_HEADERS = \ Cell.h \ - base-list.h \ builtins.h \ c-file-ptr-stream.h \ comment-list.h \ @@ -357,6 +357,7 @@ ov-lazy-idx.cc \ ov-mex-fcn.cc \ ov-null-mat.cc \ + ov-oncleanup.cc \ ov-perm.cc \ ov-range.cc \ ov-re-diag.cc \
--- a/src/OPERATORS/op-int.h +++ b/src/OPERATORS/op-int.h @@ -704,7 +704,7 @@ dim_vector b_dims = b.dims (); \ if (a_dims != b_dims) \ { \ - if (is_valid_bsxfun (a_dims, b_dims)) \ + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) \ { \ return bsxfun_pow (a, b); \ } \ @@ -730,7 +730,7 @@ dim_vector b_dims = b.dims (); \ if (a_dims != b_dims) \ { \ - if (is_valid_bsxfun (a_dims, b_dims)) \ + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) \ { \ return bsxfun_pow (a, b); \ } \ @@ -756,7 +756,7 @@ dim_vector b_dims = b.dims (); \ if (a_dims != b_dims) \ { \ - if (is_valid_bsxfun (a_dims, b_dims)) \ + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) \ { \ return bsxfun_pow (a, b); \ } \ @@ -782,7 +782,7 @@ dim_vector b_dims = b.dims (); \ if (a_dims != b_dims) \ { \ - if (is_valid_bsxfun (a_dims, b_dims)) \ + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) \ { \ return bsxfun_pow (a, b); \ } \ @@ -808,7 +808,7 @@ dim_vector b_dims = b.dims (); \ if (a_dims != b_dims) \ { \ - if (is_valid_bsxfun (a_dims, b_dims)) \ + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) \ { \ return bsxfun_pow (a, b); \ } \
--- a/src/comment-list.cc +++ b/src/comment-list.cc @@ -25,6 +25,7 @@ #endif #include "lo-utils.h" +#include "singleton-cleanup.h" #include "comment-list.h" #include "error.h" @@ -52,7 +53,12 @@ bool retval = true; if (! instance) - instance = new octave_comment_buffer (); + { + instance = new octave_comment_buffer (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) {
--- a/src/comment-list.h +++ b/src/comment-list.h @@ -105,6 +105,8 @@ octave_comment_buffer (void) : comment_list (new octave_comment_list ()) { } + ~octave_comment_buffer (void) { delete comment_list; } + static bool instance_ok (void); static void append @@ -122,6 +124,8 @@ octave_comment_list *comment_list; static octave_comment_buffer *instance; + + static void cleanup_instance (void) { delete instance; instance = 0; } }; #endif
--- a/src/data.cc +++ b/src/data.cc @@ -5974,6 +5974,8 @@ if (return_idx) { + retval.resize (2); + Array<octave_idx_type> sidx; retval (0) = arg.sort (sidx, dim, smode);
--- a/src/debug.cc +++ b/src/debug.cc @@ -32,6 +32,7 @@ #include <string> #include "file-stat.h" +#include "singleton-cleanup.h" #include "defun.h" #include "error.h" @@ -250,6 +251,28 @@ } } +bool +bp_table::instance_ok (void) +{ + bool retval = true; + + if (! instance) + { + instance = new bp_table (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } + + if (! instance) + { + ::error ("unable to create breakpoint table!"); + retval = false; + } + + return retval; +} + bp_table::intmap bp_table::do_add_breakpoint (const std::string& fname, const bp_table::intmap& line) @@ -285,7 +308,7 @@ } } else - error ("add_breakpoint: unable to find the function requested\n"); + error ("add_breakpoint: unable to find the requested function\n"); tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging; @@ -340,7 +363,7 @@ } } else - error ("remove_breakpoint: unable to find the function requested\n"); + error ("remove_breakpoint: unable to find the requested function\n"); } tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging; @@ -380,7 +403,7 @@ } else if (! silent) error ("remove_all_breakpoint_in_file: " - "unable to find the function requested\n"); + "unable to find the requested function\n"); tree_evaluator::debug_mode = bp_table::have_breakpoints () || Vdebugging; @@ -481,20 +504,31 @@ DEFUN (dbstop, args, , "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {@var{rline} =} dbstop (@var{func}, @var{line}, @dots{})\n\ -Set a breakpoint in a function\n\ -@table @code\n\ +@deftypefn {Loadable Function} {@var{rline} =} dbstop (\"@var{func}\")\n\ +@deftypefnx {Loadable Function} {@var{rline} =} dbstop (\"@var{func}\", @var{line}, @dots{})\n\ +Set a breakpoint in function @var{func}.\n\ +\n\ +Arguments are\n\ +\n\ +@table @var\n\ @item func\n\ -String representing the function name. When already in debug\n\ +Function name as a string variable. When already in debug\n\ mode this should be left out and only the line should be given.\n\ \n\ @item line\n\ -Line number you would like the breakpoint to be set on. Multiple\n\ -lines might be given as separate arguments or as a vector.\n\ +Line number where the breakpoint should be set. Multiple\n\ +lines may be given as separate arguments or as a vector.\n\ @end table\n\ \n\ -The rline returned is the real line that the breakpoint was set at.\n\ -@seealso{dbclear, dbstatus, dbstep}\n\ +When called with a single argument @var{func}, the breakpoint\n\ +is set at the first executable line in the named function.\n\ +\n\ +The optional output @var{rline} is the real line number where the\n\ +breakpoint was set. This can differ from specified line if\n\ +the line is not executable. For example, if a breakpoint attempted on a\n\ +blank line then Octave will set the real breakpoint at the\n\ +next executable line.\n\ +@seealso{dbclear, dbstatus, dbstep, debug_on_error, debug_on_warning, debug_on_interrupt}\n\ @end deftypefn") { bp_table::intmap retval; @@ -514,19 +548,26 @@ DEFUN (dbclear, args, , "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} dbclear (@var{func}, @var{line}, @dots{})\n\ -Delete a breakpoint in a function\n\ -@table @code\n\ +@deftypefn {Loadable Function} {} dbclear (\"@var{func}\")\n\ +@deftypefnx {Loadable Function} {} dbclear (\"@var{func}\", @var{line}, @dots{})\n\ +Delete a breakpoint in the function @var{func}.\n\ +\n\ +Arguments are\n\ +\n\ +@table @var\n\ @item func\n\ -String representing the function name. When already in debug\n\ +Function name as a string variable. When already in debug\n\ mode this should be left out and only the line should be given.\n\ \n\ @item line\n\ -Line number where you would like to remove the breakpoint. Multiple\n\ -lines might be given as separate arguments or as a vector.\n\ +Line number from which to remove a breakpoint. Multiple\n\ +lines may be given as separate arguments or as a vector.\n\ @end table\n\ -No checking is done to make sure that the line you requested is really\n\ -a breakpoint. If you get the wrong line nothing will happen.\n\ +\n\ +When called without a line number specification all breakpoints\n\ +in the named function are cleared.\n\ +\n\ +If the requested line is not a breakpoint no action is performed.\n\ @seealso{dbstop, dbstatus, dbwhere}\n\ @end deftypefn") { @@ -544,14 +585,31 @@ DEFUN (dbstatus, args, nargout, "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {lst =} dbstatus (@var{func})\n\ -Return a vector containing the lines on which a function has\n\ -breakpoints set.\n\ -@table @code\n\ -@item func\n\ -String representing the function name. When already in debug\n\ -mode this should be left out.\n\ +@deftypefn {Loadable Function} {} dbstatus ()\n\ +@deftypefnx {Loadable Function} {@var{brk_list} =} dbstatus ()\n\ +@deftypefnx {Loadable Function} {@var{brk_list} =} dbstatus (\"@var{func}\")\n\ +Report the location of active breakpoints.\n\ +\n\ +When called with no input or output arguments, print the list of\n\ +all functions with breakpoints and the line numbers where those\n\ +breakpoints are set.\n\ +If a function name @var{func} is specified then only report breakpoints\n\ +for the named function.\n\ +\n\ +The optional return argument @var{brk_list} is a struct array with the\n\ +following fields.\n\ +\n\ +@table @asis\n\ +@item name\n\ +The name of the function with a breakpoint.\n\ +\n\ +@item file\n\ +The name of the m-file where the function code is located.\n\ +\n\ +@item line\n\ +A line number, or vector of line numbers, with a breakpoint.\n\ @end table\n\ +\n\ @seealso{dbclear, dbwhere}\n\ @end deftypefn") { @@ -563,7 +621,7 @@ if (nargin != 0 && nargin != 1) { - error ("dbstatus: only zero or one arguements accepted\n"); + error ("dbstatus: only zero or one arguments accepted\n"); return octave_value (); } @@ -640,8 +698,9 @@ DEFUN (dbwhere, , , "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {} dbwhere ()\n\ -Show where we are in the code\n\ -@seealso{dbclear, dbstatus, dbstop}\n\ +In debugging mode, report the current file and line number where\n\ +execution is stopped.\n\ +@seealso{dbstatus, dbcont, dbstep, dbup}\n\ @end deftypefn") { octave_value retval; @@ -681,7 +740,7 @@ octave_stdout << " <unknown line>" << std::endl; } else - error ("dbwhere: must be inside of a user function to use dbwhere\n"); + error ("dbwhere: must be inside a user function to use dbwhere\n"); return retval; } @@ -731,9 +790,17 @@ DEFUN (dbtype, args, , "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {} dbtype ()\n\ -List script file with line numbers.\n\ -@seealso{dbclear, dbstatus, dbstop}\n\ +@deftypefn {Loadable Function} {} dbtype ()\n\ +@deftypefnx {Loadable Function} {} dbtype (\"startl:endl\")\n\ +@deftypefnx {Loadable Function} {} dbtype (\"@var{func}\")\n\ +@deftypefnx {Loadable Function} {} dbtype (\"@var{func}\", \"startl:endl\")\n\ +When in debugging mode and called with no arguments, list the script file\n\ +being debugged with line numbers. An optional range specification,\n\ +specified as a string, can be used to list only a portion of the file.\n\ +\n\ +When called with the name of a function, list that script file\n\ +with line numbers.\n\ +@seealso{dbstatus, dbstop}\n\ @end deftypefn") { octave_value retval; @@ -752,7 +819,7 @@ if (dbg_fcn) do_dbtype (octave_stdout, dbg_fcn->name (), 0, INT_MAX); else - error ("dbtype: must be in a user function to give no arguments to dbtype\n"); + error ("dbtype: must be inside a user function to give no arguments to dbtype\n"); break; case 1: // (dbtype func) || (dbtype start:end) @@ -864,7 +931,7 @@ if (n > 0) nskip = n; else - error ("dbstack: expecting N to be a nonnegative integer"); + error ("dbstack: N must be a non-negative integer"); } if (! error_state) @@ -937,10 +1004,38 @@ DEFUN (dbstack, args, nargout, "-*- texinfo -*-\n\ -@deftypefn {Loadable Function} {[@var{stack}, @var{idx}]} dbstack (@var{n})\n\ -Print or return current stack information. With optional argument\n\ -@var{n}, omit the @var{n} innermost stack frames.\n\ -@seealso{dbclear, dbstatus, dbstop}\n\ +@deftypefn {Loadable Function} {} dbstack ()\n\ +@deftypefnx {Loadable Function} {} dbstack (@var{n})\n\ +@deftypefnx {Loadable Function} {[@var{stack}, @var{idx}] =} dbstack (@dots{})\n\ +Display or return current debugging function stack information.\n\ +With optional argument @var{n}, omit the @var{n} innermost stack frames.\n\ +\n\ +The optional return argument @var{stack} is a struct array with the\n\ +following fields:\n\ +\n\ +@table @asis\n\ +@item file\n\ +The name of the m-file where the function code is located.\n\ +\n\ +@item name\n\ +The name of the function with a breakpoint.\n\ +\n\ +@item line\n\ +The line number of an active breakpoint.\n\ +\n\ +@item column\n\ +The column number of the line where the breakpoint begins.\n\ +\n\ +@item scope\n\ +Undocumented.\n\ +\n\ +@item context\n\ +Undocumented.\n\ +@end table\n\ +\n\ +The return argument @var{idx} specifies which element of the @var{stack}\n\ +struct array is currently active.\n\ +@seealso{dbup, dbdown, dbwhere, dbstatus}\n\ @end deftypefn") { return do_dbstack (args, nargout, octave_stdout); @@ -981,7 +1076,7 @@ @deftypefnx {Loadable Function} {} dbup (@var{n})\n\ In debugging mode, move up the execution stack @var{n} frames.\n\ If @var{n} is omitted, move up one frame.\n\ -@seealso{dbstack}\n\ +@seealso{dbstack, dbdown}\n\ @end deftypefn") { octave_value retval; @@ -997,7 +1092,7 @@ @deftypefnx {Loadable Function} {} dbdown (@var{n})\n\ In debugging mode, move down the execution stack @var{n} frames.\n\ If @var{n} is omitted, move down one frame.\n\ -@seealso{dbstack}\n\ +@seealso{dbstack, dbup}\n\ @end deftypefn") { octave_value retval; @@ -1013,14 +1108,17 @@ @deftypefnx {Command} {} dbstep @var{n}\n\ @deftypefnx {Command} {} dbstep in\n\ @deftypefnx {Command} {} dbstep out\n\ +@deftypefnx {Command} {} dbnext @dots{}\n\ In debugging mode, execute the next @var{n} lines of code.\n\ -If @var{n} is omitted , execute the next single line of code.\n\ -If the next line of code is itself\n\ -defined in terms of an m-file remain in the existing function.\n\ +If @var{n} is omitted, execute the next single line of code.\n\ +If the next line of code is itself defined in terms of an m-file remain in\n\ +the existing function.\n\ \n\ Using @code{dbstep in} will cause execution of the next line to step into\n\ any m-files defined on the next line. Using @code{dbstep out} will cause\n\ execution to continue until the current function returns.\n\ +\n\ +@code{dbnext} is an alias for @code{dbstep}.\n\ @seealso{dbcont, dbquit}\n\ @end deftypefn") { @@ -1066,7 +1164,7 @@ } } else - error ("dbstep: expecting character string as argument"); + error ("dbstep: input argument must be a character string"); } else { @@ -1086,7 +1184,7 @@ DEFUN (dbcont, args, , "-*- texinfo -*-\n\ @deftypefn {Command} {} dbcont\n\ -In debugging mode, quit debugging mode and continue execution.\n\ +Leave command-line debugging mode and continue code execution normally.\n\ @seealso{dbstep, dbquit}\n\ @end deftypefn") { @@ -1110,8 +1208,9 @@ DEFUN (dbquit, args, , "-*- texinfo -*-\n\ @deftypefn {Command} {} dbquit\n\ -In debugging mode, quit debugging mode and return to the top level.\n\ -@seealso{dbstep, dbcont}\n\ +Quit debugging mode immediately without further code execution and\n\ +return to the Octave prompt.\n\ +@seealso{dbcont, dbstep}\n\ @end deftypefn") { if (Vdebugging) @@ -1136,8 +1235,8 @@ DEFUN (isdebugmode, args, , "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {} isdebugmode ()\n\ -Return true if debug mode is on, otherwise false.\n\ -@seealso{dbstack, dbclear, dbstop, dbstatus}\n\ +Return true if in debugging mode, otherwise false.\n\ +@seealso{dbwhere, dbstack, dbstatus}\n\ @end deftypefn") { octave_value retval;
--- a/src/debug.h +++ b/src/debug.h @@ -55,21 +55,7 @@ typedef fname_line_map::const_iterator const_fname_line_map_iterator; typedef fname_line_map::iterator fname_line_map_iterator; - static bool instance_ok (void) - { - bool retval = true; - - if (! instance) - instance = new bp_table (); - - if (! instance) - { - ::error ("unable to create breakpoint table!"); - retval = false; - } - - return retval; - } + static bool instance_ok (void); // Add a breakpoint at the nearest executable line. static intmap add_breakpoint (const std::string& fname = "", @@ -127,6 +113,8 @@ static bp_table *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + intmap do_add_breakpoint (const std::string& fname, const intmap& lines); int do_remove_breakpoint (const std::string&, const intmap& lines);
--- a/src/defaults.cc +++ b/src/defaults.cc @@ -408,11 +408,16 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} EDITOR ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} EDITOR (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} EDITOR (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the editor to\n\ use with the @code{edit_history} command. The default value is taken from\n\ the environment variable @w{@env{EDITOR}} when Octave starts. If the\n\ environment variable is not initialized, @w{@env{EDITOR}} will be set to\n\ @code{\"emacs\"}.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{edit_history}\n\ @end deftypefn") { @@ -434,11 +439,16 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} EXEC_PATH ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} EXEC_PATH (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} EXEC_PATH (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies a colon separated\n\ list of directories to append to the shell PATH when executing external\n\ programs. The initial value of is taken from the environment variable\n\ @w{@env{OCTAVE_EXEC_PATH}}, but that value can be overridden by\n\ the command line argument @option{--exec-path PATH}.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { octave_value retval = SET_NONEMPTY_INTERNAL_STRING_VARIABLE (EXEC_PATH); @@ -464,8 +474,13 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} IMAGE_PATH ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} IMAGE_PATH (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} IMAGE_PATH (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies a colon separated\n\ list of directories in which to search for image files.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_NONEMPTY_INTERNAL_STRING_VARIABLE (IMAGE_PATH);
--- a/src/dirfns.cc +++ b/src/dirfns.cc @@ -187,8 +187,8 @@ if (dir) { string_vector dirlist = dir.read (); + retval(1) = 0.0; retval(0) = Cell (dirlist.sort ()); - retval(1) = 0.0; } else { @@ -487,12 +487,10 @@ int status = octave_readlink (symlink, result, msg); - retval(0) = result; - - retval(1) = status; - if (status < 0) retval(2) = msg; + retval(1) = status; + retval(0) = result; } } else @@ -772,8 +770,13 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} confirm_recursive_rmdir ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} confirm_recursive_rmdir (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} confirm_recursive_rmdir (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether Octave\n\ will ask for confirmation before recursively removing a directory tree.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (confirm_recursive_rmdir);
--- a/src/display.cc +++ b/src/display.cc @@ -27,13 +27,15 @@ #include <cstdlib> #if defined (OCTAVE_USE_WINDOWS_API) -#include <Windows.h> +#include <windows.h> #elif defined (HAVE_FRAMEWORK_CARBON) #include <Carbon/Carbon.h> #elif defined (HAVE_X_WINDOWS) #include <X11/Xlib.h> #endif +#include "singleton-cleanup.h" + #include "display.h" #include "error.h" @@ -118,6 +120,8 @@ } else warning ("X11 display has no default screen"); + + XCloseDisplay (display); } else warning ("unable to open X11 DISPLAY"); @@ -138,7 +142,12 @@ bool retval = true; if (! instance) - instance = new display_info (query); + { + instance = new display_info (query); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) {
--- a/src/display.h +++ b/src/display.h @@ -73,6 +73,8 @@ static display_info *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + // Height, width, and depth of the display. int ht; int wd;
--- a/src/dynamic-ld.cc +++ b/src/dynamic-ld.cc @@ -27,9 +27,10 @@ #include <iostream> #include <list> +#include "file-stat.h" #include "oct-env.h" #include "oct-time.h" -#include "file-stat.h" +#include "singleton-cleanup.h" #include <defaults.h> @@ -78,6 +79,8 @@ static octave_shlib_list *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + static bool instance_ok (void); // List of libraries we have loaded. @@ -148,7 +151,12 @@ bool retval = true; if (! instance) - instance = new octave_shlib_list (); + { + instance = new octave_shlib_list (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) { @@ -213,6 +221,8 @@ static octave_mex_file_list *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + static bool instance_ok (void); // List of libraries we have loaded. @@ -258,7 +268,12 @@ bool retval = true; if (! instance) - instance = new octave_mex_file_list (); + { + instance = new octave_mex_file_list (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) { @@ -295,7 +310,12 @@ bool retval = true; if (! instance) - instance = new octave_dynamic_loader (); + { + instance = new octave_dynamic_loader (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) {
--- a/src/dynamic-ld.h +++ b/src/dynamic-ld.h @@ -64,6 +64,8 @@ static octave_dynamic_loader *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + static bool instance_ok (void); octave_function *
--- a/src/error.cc +++ b/src/error.cc @@ -119,9 +119,6 @@ // TRUE means warning messages are turned off. bool discard_warning_messages = false; -// The message buffer. -static std::ostringstream *error_message_buffer = 0; - void reset_error_handler (void) { @@ -263,16 +260,7 @@ Vlast_error_stack = initialize_last_error_stack (); } - if (buffer_error_messages) - { - if (error_message_buffer) - msg_string = "error: " + msg_string; - else - error_message_buffer = new std::ostringstream (); - - *error_message_buffer << msg_string; - } - else + if (! buffer_error_messages) { octave_diary << msg_string; os << msg_string; @@ -564,7 +552,8 @@ } // For given warning ID, return 0 if warnings are disabled, 1 if -// enabled, and 2 if this ID should be an error instead of a warning. +// enabled, and 2 if the given ID should be an error instead of a +// warning. int warning_enabled (const std::string& id) @@ -610,8 +599,9 @@ } } + // If "all" is not present, assume warnings are enabled. if (all_state == -1) - panic_impossible (); + all_state = 1; if (all_state == 0) { @@ -1587,7 +1577,7 @@ if (! error_state && new_err.contains ("stack")) { octave_scalar_map new_err_stack = - new_err.getfield("identifier").scalar_map_value (); + new_err.getfield("stack").scalar_map_value (); if (! error_state && new_err_stack.contains ("file")) { @@ -1774,8 +1764,13 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} beep_on_error ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} beep_on_error (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} beep_on_error (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether Octave will try\n\ to ring the terminal bell before printing an error message.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (beep_on_error); @@ -1785,10 +1780,15 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} debug_on_error ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} debug_on_error (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} debug_on_error (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether Octave will try\n\ to enter the debugger when an error is encountered. This will also\n\ inhibit printing of the normal traceback message (you will only see\n\ the top-level error message).\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (debug_on_error); @@ -1798,8 +1798,13 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} debug_on_warning ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} debug_on_warning (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} debug_on_warning (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether Octave will try\n\ to enter the debugger when a warning is encountered.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (debug_on_warning);
--- a/src/file-io.cc +++ b/src/file-io.cc @@ -46,6 +46,7 @@ #include <stack> #include <vector> +#include <fcntl.h> #include <sys/types.h> #include <unistd.h> @@ -1981,7 +1982,7 @@ filename unique. The file is then created with mode read/write and\n\ permissions that are system dependent (on GNU/Linux systems, the permissions\n\ will be 0600 for versions of glibc 2.0.7 and later). The file is opened\n\ -with the @w{@code{O_EXCL}} flag.\n\ +in binary mode and with the @w{@code{O_EXCL}} flag.\n\ \n\ If the optional argument @var{delete} is supplied and is true,\n\ the file will be deleted automatically when Octave exits, or when\n\ @@ -2011,7 +2012,7 @@ OCTAVE_LOCAL_BUFFER (char, tmp, tmpl8.size () + 1); strcpy (tmp, tmpl8.c_str ()); - int fd = gnulib::mkstemp (tmp); + int fd = gnulib::mkostemp (tmp, O_BINARY); if (fd < 0) { @@ -2020,7 +2021,7 @@ } else { - const char *fopen_mode = "w+"; + const char *fopen_mode = "w+b"; FILE *fid = fdopen (fd, fopen_mode);
--- a/src/gl-render.cc +++ b/src/gl-render.cc @@ -30,6 +30,7 @@ #include <lo-mappers.h> #include "oct-locbuf.h" +#include "oct-refcount.h" #include "gl-render.h" #include "txt-eng.h" #include "txt-eng-ft.h" @@ -2460,7 +2461,7 @@ if (props.get_string ().is_empty ()) return; - const Matrix pos = xform.scale (props.get_data_position ()); + Matrix pos = xform.scale (props.get_data_position ()); const Matrix bbox = props.get_extent_matrix (); // FIXME: handle margin and surrounding box @@ -2468,7 +2469,7 @@ glEnable (GL_BLEND); glEnable (GL_ALPHA_TEST); - glRasterPos3d (pos(0), pos(1), pos(2)); + glRasterPos3d (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0); glBitmap(0, 0, 0, 0, bbox(0), bbox(1), 0); glDrawPixels (bbox(2), bbox(3), GL_RGBA, GL_UNSIGNED_BYTE, props.get_pixels ().data ());
old mode 100755 new mode 100644 --- a/src/graphics.cc +++ b/src/graphics.cc @@ -36,10 +36,12 @@ #include <string> #include <sstream> +#include "cmd-edit.h" #include "file-ops.h" #include "file-stat.h" - -#include "cmd-edit.h" +#include "oct-locbuf.h" +#include "singleton-cleanup.h" + #include "cutils.h" #include "defun.h" #include "display.h" @@ -47,7 +49,6 @@ #include "graphics.h" #include "input.h" #include "ov.h" -#include "oct-locbuf.h" #include "oct-obj.h" #include "oct-map.h" #include "ov-fcn-handle.h" @@ -283,7 +284,8 @@ static Matrix default_axes_ticklength (void) { - Matrix m (1, 2, 0.01); + Matrix m (1, 2, 0.0); + m(0) = 0.01; m(1) = 0.025; return m; } @@ -350,7 +352,8 @@ retval(0) = 0; retval(1) = 0; - retval(2) = retval(3) = 0.5; + retval(2) = 0.5; + retval(3) = 0.5; return retval; } @@ -2322,6 +2325,114 @@ } static void +delete_graphics_object (const graphics_handle& h) +{ + if (h.ok ()) + { + graphics_object obj = gh_manager::get_object (h); + + // Don't do recursive deleting, due to callbacks + if (! obj.get_properties ().is_beingdeleted ()) + { + graphics_handle parent_h = obj.get_parent (); + + graphics_object parent_obj = + gh_manager::get_object (parent_h); + + // NOTE: free the handle before removing it from its + // parent's children, such that the object's + // state is correct when the deletefcn callback + // is executed + + gh_manager::free (h); + + // A callback function might have already deleted + // the parent + if (parent_obj.valid_object ()) + parent_obj.remove_child (h); + + Vdrawnow_requested = true; + } + } +} + +static void +delete_graphics_object (double val) +{ + delete_graphics_object (gh_manager::lookup (val)); +} + +static void +delete_graphics_objects (const NDArray vals) +{ + for (octave_idx_type i = 0; i < vals.numel (); i++) + delete_graphics_object (vals.elem (i)); +} + +static void +close_figure (const graphics_handle& handle) +{ + octave_value closerequestfcn = xget (handle, "closerequestfcn"); + + OCTAVE_SAFE_CALL (gh_manager::execute_callback, (handle, closerequestfcn)); +} + +static void +force_close_figure (const graphics_handle& handle) +{ + // Remove the deletefcn and closerequestfcn callbacks and delete the + // object directly. + + xset (handle, "deletefcn", Matrix ()); + xset (handle, "closerequestfcn", Matrix ()); + + delete_graphics_object (handle); +} + +void +gh_manager::do_close_all_figures (void) +{ + // FIXME -- should we process or discard pending events? + + event_queue.clear (); + + // Don't use figure_list_iterator because we'll be removing elements + // from the list elsewhere. + + Matrix hlist = do_figure_handle_list (true); + + for (octave_idx_type i = 0; i < hlist.numel (); i++) + { + graphics_handle h = gh_manager::lookup (hlist(i)); + + if (h.ok ()) + close_figure (h); + } + + // They should all be closed now. If not, force them to close. + + hlist = do_figure_handle_list (true); + + for (octave_idx_type i = 0; i < hlist.numel (); i++) + { + graphics_handle h = gh_manager::lookup (hlist(i)); + + if (h.ok ()) + force_close_figure (h); + } + + // None left now, right? + + hlist = do_figure_handle_list (true); + + assert (hlist.numel () == 0); + + // Clear all callback objects from our list. + + callback_objects.clear (); +} + +static void adopt (const graphics_handle& p, const graphics_handle& h) { graphics_object parent_obj = gh_manager::get_object (p); @@ -2416,6 +2527,7 @@ finalize (go); } + // --------------------------------------------------------------------- void @@ -2653,135 +2765,6 @@ // --------------------------------------------------------------------- -class gnuplot_toolkit : public base_graphics_toolkit -{ -public: - gnuplot_toolkit (void) - : base_graphics_toolkit ("gnuplot") { } - - ~gnuplot_toolkit (void) { } - - bool is_valid (void) const { return true; } - - bool initialize (const graphics_object& go) - { - return go.isa ("figure"); - } - - void finalize (const graphics_object& go) - { - if (go.isa ("figure")) - { - const figure::properties& props = - dynamic_cast<const figure::properties&> (go.get_properties ()); - - send_quit (props.get___plot_stream__ ()); - } - } - - void update (const graphics_object& go, int id) - { - if (go.isa ("figure")) - { - graphics_object obj (go); - - figure::properties& props = - dynamic_cast<figure::properties&> (obj.get_properties ()); - - switch (id) - { - case base_properties::ID_VISIBLE: - if (! props.is_visible ()) - { - send_quit (props.get___plot_stream__ ()); - props.set___plot_stream__ (Matrix ()); - props.set___enhanced__ (false); - } - break; - } - } - } - - void redraw_figure (const graphics_object& go) const - { - octave_value_list args; - args(0) = go.get_handle ().as_octave_value (); - feval ("__gnuplot_drawnow__", args); - } - - void print_figure (const graphics_object& go, const std::string& term, - const std::string& file, bool mono, - const std::string& debug_file) const - { - octave_value_list args; - if (! debug_file.empty ()) - args(4) = debug_file; - args(3) = mono; - args(2) = file; - args(1) = term; - args(0) = go.get_handle ().as_octave_value (); - feval ("__gnuplot_drawnow__", args); - } - - Matrix get_canvas_size (const graphics_handle&) const - { - Matrix sz (1, 2, 0.0); - return sz; - } - - double get_screen_resolution (void) const - { return 72.0; } - - Matrix get_screen_size (void) const - { return Matrix (1, 2, 0.0); } - -private: - void send_quit (const octave_value& pstream) const - { - if (! pstream.is_empty ()) - { - octave_value_list args; - Matrix fids = pstream.matrix_value (); - - if (! error_state) - { - args(1) = "\nquit;\n"; - args(0) = fids(0); - feval ("fputs", args); - - args.resize (1); - feval ("fflush", args); - feval ("pclose", args); - - if (fids.numel () > 1) - { - args(0) = fids(1); - feval ("pclose", args); - - if (fids.numel () > 2) - { - args(0) = fids(2); - feval ("waitpid", args); - } - } - } - } - } -}; - -graphics_toolkit -graphics_toolkit::default_toolkit (void) -{ - if (available_toolkits.size () == 0) - register_toolkit (new gnuplot_toolkit ()); - - return available_toolkits["gnuplot"]; -} - -std::map<std::string, graphics_toolkit> graphics_toolkit::available_toolkits; - -// --------------------------------------------------------------------- - void base_graphics_object::update_axis_limits (const std::string& axis_type) { @@ -2936,7 +2919,8 @@ { currentfigure = val; - gh_manager::push_figure (val); + if (val.ok ()) + gh_manager::push_figure (val); } else gripe_set_invalid ("currentfigure"); @@ -5698,7 +5682,7 @@ } if ((min_val <= 0 && max_val > 0)) { - warning ("axis: omitting nonpositive data in log plot"); + warning ("axis: omitting non-positive data in log plot"); min_val = min_pos; } // FIXME -- maybe this test should also be relative? @@ -5745,8 +5729,8 @@ retval.resize (1, 2); + retval(1) = max_val; retval(0) = min_val; - retval(1) = max_val; return retval; } @@ -7392,7 +7376,16 @@ handle_map[0] = graphics_object (new root_figure ()); // Make sure the default graphics toolkit is registered. - graphics_toolkit::default_toolkit (); + gtk_manager::default_toolkit (); +} + +void +gh_manager::create_instance (void) +{ + instance = new gh_manager (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); } graphics_handle @@ -8156,6 +8149,8 @@ int nargin = args.length (); + bool use_cell_format = false; + if (nargin == 1 || nargin == 2) { if (args(0).is_empty()) @@ -8170,8 +8165,6 @@ { octave_idx_type len = hcv.length (); - vals.resize (dim_vector (len, 1)); - if (nargin == 1 && len > 1) { std::string t0 = get_graphics_object_type (hcv(0)); @@ -8197,31 +8190,74 @@ if (! error_state) { - for (octave_idx_type n = 0; n < len; n++) + if (nargin > 1 && args(1).is_cellstr ()) { - graphics_object obj = gh_manager::get_object (hcv(n)); - - if (obj) + Array<std::string> plist = args(1).cellstr_value (); + + if (! error_state) { - if (nargin == 1) - vals(n) = obj.get (); - else + octave_idx_type plen = plist.numel (); + + use_cell_format = true; + + vals.resize (dim_vector (len, plen)); + + for (octave_idx_type n = 0; ! error_state && n < len; n++) { - caseless_str property = args(1).string_value (); - - if (! error_state) - vals(n) = obj.get (property); + graphics_object obj = gh_manager::get_object (hcv(n)); + + if (obj) + { + for (octave_idx_type m = 0; ! error_state && m < plen; m++) + { + caseless_str property = plist(m); + + vals(n, m) = obj.get (property); + } + } else { - error ("get: expecting property name as second argument"); + error ("get: invalid handle (= %g)", hcv(n)); break; } } } else + error ("get: expecting property name or cell array of property names as second argument"); + } + else + { + caseless_str property; + + if (nargin > 1) { - error ("get: invalid handle (= %g)", hcv(n)); - break; + property = args(1).string_value (); + + if (error_state) + error ("get: expecting property name or cell array of property names as second argument"); + } + + vals.resize (dim_vector (len, 1)); + + if (! error_state) + { + for (octave_idx_type n = 0; ! error_state && n < len; n++) + { + graphics_object obj = gh_manager::get_object (hcv(n)); + + if (obj) + { + if (nargin == 1) + vals(n) = obj.get (); + else + vals(n) = obj.get (property); + } + else + { + error ("get: invalid handle (= %g)", hcv(n)); + break; + } + } } } } @@ -8234,23 +8270,28 @@ if (! error_state) { - octave_idx_type len = vals.numel (); - - if (len == 0) - retval = Matrix (); - else if (len == 1) - retval = vals(0); - else if (len > 1 && nargin == 1) - { - OCTAVE_LOCAL_BUFFER (octave_scalar_map, tmp, len); - - for (octave_idx_type n = 0; n < len; n++) - tmp[n] = vals(n).scalar_map_value (); - - retval = octave_map::cat (0, len, tmp); - } + if (use_cell_format) + retval = vals; else - retval = vals; + { + octave_idx_type len = vals.numel (); + + if (len == 0) + retval = Matrix (); + else if (len == 1) + retval = vals(0); + else if (len > 1 && nargin == 1) + { + OCTAVE_LOCAL_BUFFER (octave_scalar_map, tmp, len); + + for (octave_idx_type n = 0; n < len; n++) + tmp[n] = vals(n).scalar_map_value (); + + retval = octave_map::cat (0, len, tmp); + } + else + retval = vals; + } } return retval; @@ -8724,40 +8765,7 @@ } if (! error_state) - { - for (octave_idx_type i = 0; i < vals.numel (); i++) - { - h = gh_manager::lookup (vals.elem (i)); - - if (h.ok ()) - { - graphics_object obj = gh_manager::get_object (h); - - // Don't do recursive deleting, due to callbacks - if (! obj.get_properties ().is_beingdeleted ()) - { - graphics_handle parent_h = obj.get_parent (); - - graphics_object parent_obj = - gh_manager::get_object (parent_h); - - // NOTE: free the handle before removing it from its - // parent's children, such that the object's - // state is correct when the deletefcn callback - // is executed - - gh_manager::free (h); - - // A callback function might have already deleted - // the parent - if (parent_obj.valid_object ()) - parent_obj.remove_child (h); - - Vdrawnow_requested = true; - } - } - } - } + delete_graphics_objects (vals); } else error ("delete: invalid graphics object"); @@ -8939,6 +8947,52 @@ return retval; } +gtk_manager *gtk_manager::instance = 0; + +void +gtk_manager::create_instance (void) +{ + instance = new gtk_manager (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); +} + +graphics_toolkit +gtk_manager::do_get_toolkit (void) const +{ + graphics_toolkit retval; + + const_loaded_toolkits_iterator pl = loaded_toolkits.find (dtk); + + if (pl == loaded_toolkits.end ()) + { + const_available_toolkits_iterator pa = available_toolkits.find (dtk); + + if (pa != available_toolkits.end ()) + { + octave_value_list args; + args(0) = dtk; + feval ("graphics_toolkit", args); + + if (! error_state) + pl = loaded_toolkits.find (dtk); + + if (error_state || pl == loaded_toolkits.end ()) + error ("failed to load %s graphics toolkit", dtk.c_str ()); + else + retval = pl->second; + } + else + error ("default graphics toolkit `%s' is not available!", + dtk.c_str ()); + } + else + retval = pl->second; + + return retval; +} + DEFUN (available_graphics_toolkits, , , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} available_graphics_toolkits ()\n\ @@ -8947,7 +9001,43 @@ { gh_manager::auto_lock guard; - return octave_value (graphics_toolkit::available_toolkits_list ()); + return octave_value (gtk_manager::available_toolkits_list ()); +} + +DEFUN (register_graphics_toolkit, args, , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} register_graphics_toolkit (@var{toolkit})\n\ +List @var{toolkit} as an available graphics toolkit.\n\ +@end deftypefn") +{ + octave_value retval; + + gh_manager::auto_lock guard; + + if (args.length () == 1) + { + std::string name = args(0).string_value (); + + if (! error_state) + gtk_manager::register_toolkit (name); + else + error ("register_graphics_toolkit: expecting character string"); + } + else + print_usage (); + + return retval; +} + +DEFUN (loaded_graphics_toolkits, , , + "-*- texinfo -*-\n\ +@deftypefn {Built-in Function} {} loaded_graphics_toolkits ()\n\ +Return a cell array of the currently loaded graphics toolkits.\n\ +@end deftypefn") +{ + gh_manager::auto_lock guard; + + return octave_value (gtk_manager::loaded_toolkits_list ()); } DEFUN (drawnow, args, , @@ -8964,7 +9054,6 @@ @end deftypefn") { static int drawnow_executing = 0; - static bool __go_close_all_registered__ = false; octave_value retval; @@ -8977,13 +9066,6 @@ if (++drawnow_executing <= 1) { - if (! __go_close_all_registered__) - { - octave_add_atexit_function ("__go_close_all__"); - - __go_close_all_registered__ = true; - } - if (args.length () == 0 || args.length () == 1) { Matrix hlist = gh_manager::figure_handle_list (true);
--- a/src/graphics.h.in +++ b/src/graphics.h.in @@ -42,6 +42,7 @@ #include "gripes.h" #include "oct-map.h" #include "oct-mutex.h" +#include "oct-refcount.h" #include "ov.h" #include "txt-eng-ft.h" @@ -482,7 +483,7 @@ private: int id; - int count; + octave_refcount<int> count; std::string name; graphics_handle parent; bool hidden; @@ -1910,7 +1911,7 @@ ~property (void) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; } @@ -1965,7 +1966,7 @@ property& operator = (const property& p) { - if (rep && --rep->count <= 0) + if (rep && --rep->count == 0) delete rep; rep = p.rep; @@ -2131,9 +2132,13 @@ void finalize (const graphics_handle&); + // Close the graphics toolkit. + virtual void close (void) + { gripe_invalid ("base_graphics_toolkit::close"); } + private: std::string name; - int count; + octave_refcount<int> count; private: void gripe_invalid (const std::string& fname) const @@ -2228,48 +2233,200 @@ void finalize (const graphics_handle& h) { rep->finalize (h); } - OCTINTERP_API static graphics_toolkit default_toolkit (void); - - static void register_toolkit (const graphics_toolkit& b) - { available_toolkits[b.get_name ()] = b; } + // Close the graphics toolkit. + void close (void) { rep->close (); } + +private: + + base_graphics_toolkit *rep; +}; + +class gtk_manager +{ +public: + + static graphics_toolkit get_toolkit (void) + { + return instance_ok () ? instance->do_get_toolkit () : graphics_toolkit (); + } + + static void register_toolkit (const std::string& name) + { + if (instance_ok ()) + instance->do_register_toolkit (name); + } static void unregister_toolkit (const std::string& name) - { available_toolkits.erase (name); } + { + if (instance_ok ()) + instance->do_unregister_toolkit (name); + } + + static void load_toolkit (const graphics_toolkit& tk) + { + if (instance_ok ()) + instance->do_load_toolkit (tk); + } + + static void unload_toolkit (const std::string& name) + { + if (instance_ok ()) + instance->do_unload_toolkit (name); + } static graphics_toolkit find_toolkit (const std::string& name) { - const_available_toolkits_iterator p = available_toolkits.find (name); - - if (p != available_toolkits.end ()) - return p->second; - else - return default_toolkit (); + return instance_ok () + ? instance->do_find_toolkit (name) : graphics_toolkit (); } static Cell available_toolkits_list (void) { + return instance_ok () ? instance->do_available_toolkits_list () : Cell (); + } + + static Cell loaded_toolkits_list (void) + { + return instance_ok () ? instance->do_loaded_toolkits_list () : Cell (); + } + + static void unload_all_toolkits (void) + { + if (instance_ok ()) + instance->do_unload_all_toolkits (); + } + + static std::string default_toolkit (void) + { + return instance_ok () ? instance->do_default_toolkit () : std::string (); + } + +private: + + // FIXME -- default toolkit should be configurable. + + gtk_manager (void) + : dtk ("gnuplot"), available_toolkits (), loaded_toolkits () { } + + ~gtk_manager (void) { } + + static void create_instance (void); + + static bool instance_ok (void) + { + bool retval = true; + + if (! instance) + create_instance (); + + if (! instance) + { + ::error ("unable to create gh_manager!"); + + retval = false; + } + + return retval; + } + + static void cleanup_instance (void) { delete instance; instance = 0; } + + static gtk_manager *instance; + + // The name of the default toolkit. + std::string dtk; + + // The list of toolkits that we know about. + std::set<std::string> available_toolkits; + + // The list of toolkits we have actually loaded. + std::map<std::string, graphics_toolkit> loaded_toolkits; + + typedef std::set<std::string>::iterator available_toolkits_iterator; + + typedef std::set<std::string>::const_iterator + const_available_toolkits_iterator; + + typedef std::map<std::string, graphics_toolkit>::iterator + loaded_toolkits_iterator; + + typedef std::map<std::string, graphics_toolkit>::const_iterator + const_loaded_toolkits_iterator; + + graphics_toolkit do_get_toolkit (void) const; + + void do_register_toolkit (const std::string& name) + { + available_toolkits.insert (name); + } + + void do_unregister_toolkit (const std::string& name) + { + available_toolkits.erase (name); + } + + void do_load_toolkit (const graphics_toolkit& tk) + { + loaded_toolkits[tk.get_name ()] = tk; + } + + void do_unload_toolkit (const std::string& name) + { + loaded_toolkits.erase (name); + } + + graphics_toolkit do_find_toolkit (const std::string& name) const + { + const_loaded_toolkits_iterator p = loaded_toolkits.find (name); + + if (p != loaded_toolkits.end ()) + return p->second; + else + return graphics_toolkit (); + } + + Cell do_available_toolkits_list (void) const + { Cell m (1 , available_toolkits.size ()); - const_available_toolkits_iterator p; - int i; - - for (i = 0, p = available_toolkits.begin (); - p != available_toolkits.end (); p++, i++) - m(i) = p->first; + + octave_idx_type i = 0; + for (const_available_toolkits_iterator p = available_toolkits.begin (); + p != available_toolkits.end (); p++) + m(i++) = *p; return m; } -private: - base_graphics_toolkit *rep; - - static OCTINTERP_API std::map<std::string, graphics_toolkit> - available_toolkits; - - typedef std::map<std::string, graphics_toolkit>::iterator - available_toolkits_iterator; - - typedef std::map<std::string, graphics_toolkit>::const_iterator - const_available_toolkits_iterator; + Cell do_loaded_toolkits_list (void) const + { + Cell m (1 , loaded_toolkits.size ()); + + octave_idx_type i = 0; + for (const_loaded_toolkits_iterator p = loaded_toolkits.begin (); + p != loaded_toolkits.end (); p++) + m(i++) = p->first; + + return m; + } + + void do_unload_all_toolkits (void) + { + while (! loaded_toolkits.empty ()) + { + loaded_toolkits_iterator p = loaded_toolkits.begin (); + + std::string name = p->first; + + p->second.close (); + + // The toolkit may have unloaded itself. If not, we'll do + // it here. + if (loaded_toolkits.find (name) != loaded_toolkits.end ()) + unload_toolkit (name); + } + } + + std::string do_default_toolkit (void) { return dtk; } }; // --------------------------------------------------------------------- @@ -2739,7 +2896,7 @@ protected: // A reference count. - int count; + octave_refcount<int> count; // A flag telling whether this object is a valid object // in the backend context. @@ -3010,7 +3167,7 @@ root_figure (void) : xproperties (0, graphics_handle ()), default_properties () { } - ~root_figure (void) { xproperties.delete_children (); } + ~root_figure (void) { } void mark_modified (void) { } @@ -3121,7 +3278,7 @@ graphics_toolkit get_toolkit (void) const { if (! toolkit) - toolkit = graphics_toolkit::default_toolkit (); + toolkit = gtk_manager::get_toolkit (); return toolkit; } @@ -3135,7 +3292,7 @@ if (val.is_string ()) { std::string nm = val.string_value (); - graphics_toolkit b = graphics_toolkit::find_toolkit (nm); + graphics_toolkit b = gtk_manager::find_toolkit (nm); if (b.get_name () != nm) { error ("set___graphics_toolkit__: invalid graphics toolkit"); @@ -3258,10 +3415,7 @@ xproperties.override_defaults (*this); } - ~figure (void) - { - xproperties.delete_children (); - } + ~figure (void) { } void override_defaults (base_graphics_object& obj) { @@ -3862,7 +4016,7 @@ xproperties.update_transform (); } - ~axes (void) { xproperties.delete_children (); } + ~axes (void) { } void override_defaults (base_graphics_object& obj) { @@ -3999,7 +4153,7 @@ xproperties.override_defaults (*this); } - ~line (void) { xproperties.delete_children (); } + ~line (void) { } base_properties& get_properties (void) { return xproperties; } @@ -4139,7 +4293,7 @@ xproperties.override_defaults (*this); } - ~text (void) { xproperties.delete_children (); } + ~text (void) { } base_properties& get_properties (void) { return xproperties; } @@ -4263,7 +4417,7 @@ xproperties.override_defaults (*this); } - ~image (void) { xproperties.delete_children (); } + ~image (void) { } base_properties& get_properties (void) { return xproperties; } @@ -4381,7 +4535,7 @@ xproperties.override_defaults (*this); } - ~patch (void) { xproperties.delete_children (); } + ~patch (void) { } base_properties& get_properties (void) { return xproperties; } @@ -4534,7 +4688,7 @@ xproperties.override_defaults (*this); } - ~surface (void) { xproperties.delete_children (); } + ~surface (void) { } base_properties& get_properties (void) { return xproperties; } @@ -4602,7 +4756,7 @@ xproperties.override_defaults (*this); } - ~hggroup (void) { xproperties.delete_children (); } + ~hggroup (void) { } base_properties& get_properties (void) { return xproperties; } @@ -4666,7 +4820,7 @@ xproperties.override_defaults (*this); } - ~uimenu (void) { xproperties.delete_children (); } + ~uimenu (void) { } base_properties& get_properties (void) { return xproperties; } @@ -4712,7 +4866,7 @@ xproperties.override_defaults (*this); } - ~uicontextmenu (void) { xproperties.delete_children (); } + ~uicontextmenu (void) { } base_properties& get_properties (void) { return xproperties; } @@ -4805,7 +4959,7 @@ xproperties.override_defaults (*this); } - ~uicontrol (void) { xproperties.delete_children (); } + ~uicontrol (void) { } base_properties& get_properties (void) { return xproperties; } @@ -4871,7 +5025,7 @@ xproperties.override_defaults (*this); } - ~uipanel (void) { xproperties.delete_children (); } + ~uipanel (void) { } base_properties& get_properties (void) { return xproperties; } @@ -4910,7 +5064,7 @@ xproperties.override_defaults (*this); } - ~uitoolbar (void) { xproperties.delete_children (); } + ~uitoolbar (void) { } void override_defaults (base_graphics_object& obj) { @@ -5008,7 +5162,7 @@ xproperties.override_defaults (*this); } - ~uipushtool (void) { xproperties.delete_children (); } + ~uipushtool (void) { } base_properties& get_properties (void) { return xproperties; } @@ -5061,7 +5215,7 @@ xproperties.override_defaults (*this); } - ~uitoggletool (void) { xproperties.delete_children (); } + ~uitoggletool (void) { } base_properties& get_properties (void) { return xproperties; } @@ -5097,7 +5251,7 @@ virtual void execute (void) = 0; private: - int count; + octave_refcount<int> count; }; class @@ -5169,12 +5323,14 @@ public: + static void create_instance (void); + static bool instance_ok (void) { bool retval = true; if (! instance) - instance = new gh_manager (); + create_instance (); if (! instance) { @@ -5186,6 +5342,8 @@ return retval; } + static void cleanup_instance (void) { delete instance; instance = 0; } + static graphics_handle get_handle (bool integer_figure_handle) { return instance_ok () @@ -5382,6 +5540,12 @@ return retval; } + static void close_all_figures (void) + { + if (instance_ok ()) + instance->do_close_all_figures (); + } + public: class auto_lock : public octave_autolock { @@ -5547,6 +5711,8 @@ int do_process_events (bool force = false); + void do_close_all_figures (void); + static void restore_gcbo (void) { if (instance_ok ()) @@ -5572,4 +5738,6 @@ // This function is NOT equivalent to the scripting language function gca. OCTINTERP_API graphics_handle gca (void); +OCTINTERP_API void close_all_figures (void); + #endif
--- a/src/help.cc +++ b/src/help.cc @@ -642,13 +642,6 @@ @seealso{global}\n\ @end deftypefn"), - pair_type ("replot", - "-*- texinfo -*-\n\ -@deftypefn {Keyword} {} replot\n\ -Replot a graphic.\n\ -@seealso{plot}\n\ -@end deftypefn"), - pair_type ("return", "-*- texinfo -*-\n\ @deftypefn {Keyword} {} return\n\ @@ -1268,6 +1261,7 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} doc_cache_file ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} doc_cache_file (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} doc_cache_file (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the name of the\n\ Octave documentation cache file. A cache file significantly improves\n\ the performance of the @code{lookfor} command. The default value is \n\ @@ -1277,6 +1271,10 @@ The default value may be overridden by the environment variable\n\ @w{@env{OCTAVE_DOC_CACHE_FILE}}, or the command line argument\n\ @samp{--doc-cache-file NAME}.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{lookfor, info_program, doc, help, makeinfo_program}\n\ @end deftypefn") { @@ -1287,6 +1285,7 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} info_file ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} info_file (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} info_file (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the name of the\n\ Octave info file. The default value is\n\ @file{@var{octave-home}/info/octave.info}, in\n\ @@ -1294,6 +1293,10 @@ The default value may be overridden by the environment variable\n\ @w{@env{OCTAVE_INFO_FILE}}, or the command line argument\n\ @samp{--info-file NAME}.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{info_program, doc, help, makeinfo_program}\n\ @end deftypefn") { @@ -1304,6 +1307,7 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} info_program ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} info_program (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} info_program (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the name of the\n\ info program to run. The default value is\n\ @file{@var{octave-home}/libexec/octave/@var{version}/exec/@var{arch}/info}\n\ @@ -1313,6 +1317,10 @@ default value may be overridden by the environment variable\n\ @w{@env{OCTAVE_INFO_PROGRAM}}, or the command line argument\n\ @samp{--info-program NAME}.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{info_file, doc, help, makeinfo_program}\n\ @end deftypefn") { @@ -1323,9 +1331,14 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} makeinfo_program ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} makeinfo_program (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} makeinfo_program (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the name of the\n\ program that Octave runs to format help text containing\n\ Texinfo markup commands. The default value is @code{makeinfo}.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{info_file, info_program, doc, help}\n\ @end deftypefn") { @@ -1336,9 +1349,14 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} suppress_verbose_help_message ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} suppress_verbose_help_message (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} suppress_verbose_help_message (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether Octave\n\ will add additional help information to the end of the output from\n\ the @code{help} command and usage messages for built-in commands.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (suppress_verbose_help_message);
--- a/src/input.cc +++ b/src/input.cc @@ -749,17 +749,15 @@ if (retval == 0 && global_command) { - global_command->accept (*current_evaluator); + unwind_protect inner_frame; - // FIXME -- To avoid a memory leak, global_command should be - // deleted, I think. But doing that here causes trouble if - // an error occurs while executing a debugging command - // (dbstep, for example). It's not clear to me why that - // happens. - // - // delete global_command; - // - // global_command = 0; + // Use an unwind-protect cleanup function so that the + // global_command list will be deleted in the event of an + // interrupt. + + inner_frame.add_fcn (cleanup_statement_list, &global_command); + + global_command->accept (*current_evaluator); if (octave_completion_matches_called) octave_completion_matches_called = false; @@ -1360,6 +1358,7 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} PS1 ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} PS1 (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} PS1 (@var{new_val}, \"local\")\n\ Query or set the primary prompt string. When executing interactively,\n\ Octave displays the primary prompt when it is ready to read a command.\n\ \n\ @@ -1385,6 +1384,10 @@ \n\ @noindent\n\ will give the default Octave prompt a red coloring.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{PS2, PS4}\n\ @end deftypefn") { @@ -1395,12 +1398,17 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} PS2 ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} PS2 (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} PS2 (@var{new_val}, \"local\")\n\ Query or set the secondary prompt string. The secondary prompt is\n\ printed when Octave is expecting additional input to complete a\n\ command. For example, if you are typing a @code{for} loop that spans several\n\ lines, Octave will print the secondary prompt at the beginning of\n\ each line after the first. The default value of the secondary prompt\n\ string is @code{\"> \"}.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{PS1, PS4}\n\ @end deftypefn") { @@ -1411,10 +1419,15 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} PS4 ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} PS4 (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} PS4 (@var{new_val}, \"local\")\n\ Query or set the character string used to prefix output produced\n\ when echoing commands is enabled.\n\ The default value is @code{\"+ \"}.\n\ @xref{Diary and Echo Commands}, for a description of echoing commands.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{echo, echo_executing_commands, PS1, PS2}\n\ @end deftypefn") { @@ -1425,9 +1438,14 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} completion_append_char ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} completion_append_char (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} completion_append_char (@var{new_val}, \"local\")\n\ Query or set the internal character variable that is appended to\n\ successful command-line completion attempts. The default\n\ value is @code{\" \"} (a single space).\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (completion_append_char); @@ -1437,6 +1455,7 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} echo_executing_commands ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} echo_executing_commands (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} echo_executing_commands (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls the echo state.\n\ It may be the sum of the following values:\n\ \n\ @@ -1456,6 +1475,10 @@ \n\ The value of @code{echo_executing_commands} may be set by the @kbd{echo}\n\ command or the command line option @option{--echo-commands}.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (echo_executing_commands); @@ -1506,6 +1529,7 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} filemarker ()\n\ @deftypefnx {Built-in Function} {} filemarker (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} filemarker (@var{new_val}, \"local\")\n\ Query or set the character used to separate filename from the\n\ the subfunction names contained within the file. This can be used in\n\ a generic manner to interact with subfunctions. For example,\n\ @@ -1526,6 +1550,10 @@ \n\ @noindent\n\ will set a breakpoint at the first line of the subfunction @code{mysubfunc}.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { char tmp = Vfilemarker;
--- a/src/lex.h +++ b/src/lex.h @@ -43,6 +43,10 @@ // Delete a buffer. extern OCTINTERP_API void delete_buffer (YY_BUFFER_STATE buf); +extern OCTINTERP_API void clear_all_buffers (void); + +extern OCTINTERP_API void cleanup_parser (void); + // Is the given string a keyword? extern bool is_keyword (const std::string& s);
--- a/src/lex.ll +++ b/src/lex.ll @@ -1416,6 +1416,22 @@ yy_delete_buffer (buf); } +// Delete all buffers from the stack. +void +clear_all_buffers (void) +{ + while (current_buffer ()) + octave_pop_buffer_state (); +} + +void +cleanup_parser (void) +{ + reset_parser (); + + clear_all_buffers (); +} + // Restore a buffer (for unwind-prot). void
--- a/src/load-path.cc +++ b/src/load-path.cc @@ -32,6 +32,7 @@ #include "file-stat.h" #include "oct-env.h" #include "pathsearch.h" +#include "singleton-cleanup.h" #include "defaults.h" #include "defun.h" @@ -290,7 +291,12 @@ bool retval = true; if (! instance) - instance = new load_path (); + { + instance = new load_path (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) {
--- a/src/load-path.h +++ b/src/load-path.h @@ -443,6 +443,8 @@ static load_path *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + static hook_fcn_ptr add_hook; static hook_fcn_ptr remove_hook;
--- a/src/load-save.cc +++ b/src/load-save.cc @@ -1565,7 +1565,7 @@ @noindent\n\ saves the variable @samp{a} and all variables beginning with @samp{b} to\n\ the file @file{data} in Octave's binary format.\n\ -@seealso{load, default_save_options, dlmread, csvread, fread}\n\ +@seealso{load, default_save_options, save_header_format_string, dlmread, csvread, fread}\n\ @end deftypefn") { octave_value_list retval; @@ -1748,9 +1748,14 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} crash_dumps_octave_core ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} crash_dumps_octave_core (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} crash_dumps_octave_core (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether Octave tries\n\ to save all current variables to the file \"octave-core\" if it\n\ crashes or receives a hangup, terminate or similar signal.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{octave_core_file_limit, octave_core_file_name, octave_core_file_options}\n\ @end deftypefn") { @@ -1761,10 +1766,15 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} default_save_options ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} default_save_options (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} default_save_options (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the default options\n\ for the @code{save} command, and defines the default format.\n\ Typical values include @code{\"-ascii\"}, @code{\"-text -zip\"}.\n\ The default value is @option{-text}.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{save}\n\ @end deftypefn") { @@ -1775,6 +1785,7 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} octave_core_file_limit ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} octave_core_file_limit (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} octave_core_file_limit (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the maximum amount\n\ of memory (in kilobytes) of the top-level workspace that Octave will\n\ attempt to save when writing data to the crash dump file (the name of\n\ @@ -1783,6 +1794,10 @@ then @var{octave_core_file_limit} will be approximately the maximum\n\ size of the file. If a text file format is used, then the file could\n\ be much larger than the limit. The default value is -1 (unlimited)\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{crash_dumps_octave_core, octave_core_file_name, octave_core_file_options}\n\ @end deftypefn") { @@ -1793,9 +1808,14 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} octave_core_file_name ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} octave_core_file_name (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} octave_core_file_name (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the name of the file\n\ used for saving data from the top-level workspace if Octave aborts.\n\ The default value is @code{\"octave-core\"}\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{crash_dumps_octave_core, octave_core_file_name, octave_core_file_options}\n\ @end deftypefn") { @@ -1806,11 +1826,16 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} octave_core_file_options ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} octave_core_file_options (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} octave_core_file_options (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the options used for\n\ saving the workspace data if Octave aborts. The value of\n\ @code{octave_core_file_options} should follow the same format as the\n\ options for the @code{save} function. The default value is Octave's binary\n\ format.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{crash_dumps_octave_core, octave_core_file_name, octave_core_file_limit}\n\ @end deftypefn") { @@ -1821,6 +1846,7 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} save_header_format_string ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} save_header_format_string (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} save_header_format_string (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the format\n\ string used for the comment line written at the beginning of\n\ text-format data files saved by Octave. The format string is\n\ @@ -1834,6 +1860,10 @@ @smallexample\n\ \"# Created by Octave VERSION, %a %b %d %H:%M:%S %Y %Z <USER@@HOST>\"\n\ @end smallexample\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{strftime, save}\n\ @end deftypefn") {
--- a/src/ls-oct-ascii.cc +++ b/src/ls-oct-ascii.cc @@ -419,8 +419,13 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} save_precision ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} save_precision (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} save_precision (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the number of\n\ digits to keep when saving data in text format.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE_WITH_LIMITS (save_precision, -1, INT_MAX);
--- a/src/mappers.cc +++ b/src/mappers.cc @@ -67,20 +67,20 @@ } /* -%!assert(abs (1), 1); -%!assert(abs (-3.5), 3.5); -%!assert(abs (3+4i), 5); -%!assert(abs (3-4i), 5); -%!assert(abs ([1.1, 3i; 3+4i, -3-4i]), [1.1, 3; 5, 5]); +%!assert (abs (1), 1) +%!assert (abs (-3.5), 3.5) +%!assert (abs (3+4i), 5) +%!assert (abs (3-4i), 5) +%!assert (abs ([1.1, 3i; 3+4i, -3-4i]), [1.1, 3; 5, 5]) -%!assert(abs (single(1)), single(1)); -%!assert(abs (single(-3.5)), single(3.5)); -%!assert(abs (single(3+4i)), single(5)); -%!assert(abs (single(3-4i)), single(5)); -%!assert(abs (single([1.1, 3i; 3+4i, -3-4i])), single([1.1, 3; 5, 5])); +%!assert (abs (single (1)), single (1)) +%!assert (abs (single (-3.5)), single (3.5)) +%!assert (abs (single (3+4i)), single (5)) +%!assert (abs (single (3-4i)), single (5)) +%!assert (abs (single ([1.1, 3i; 3+4i, -3-4i])), single ([1.1, 3; 5, 5])) -%!error abs (); -%!error abs (1, 2); +%!error abs () +%!error abs (1, 2) */ DEFUN (acos, args, , @@ -100,22 +100,22 @@ } /* -%!test +%!shared rt2, rt3 %! rt2 = sqrt (2); %! rt3 = sqrt (3); -%! v = [0, pi/6, pi/4, pi/3, pi/2, 2*pi/3, 3*pi/4, 5*pi/6, pi]; -%! x = [1, rt3/2, rt2/2, 1/2, 0, -1/2, -rt2/2, -rt3/2, -1]; -%! assert(acos (x), v, sqrt(eps)); %!test -%! rt2 = sqrt (2); -%! rt3 = sqrt (3); -%! v = single ([0, pi/6, pi/4, pi/3, pi/2, 2*pi/3, 3*pi/4, 5*pi/6, pi]); +%! x = [1, rt3/2, rt2/2, 1/2, 0, -1/2, -rt2/2, -rt3/2, -1]; +%! v = [0, pi/6, pi/4, pi/3, pi/2, 2*pi/3, 3*pi/4, 5*pi/6, pi]; +%! assert (acos (x), v, sqrt (eps)); + +%!test %! x = single ([1, rt3/2, rt2/2, 1/2, 0, -1/2, -rt2/2, -rt3/2, -1]); -%! assert(acos (x), v, sqrt(eps('single'))); +%! v = single ([0, pi/6, pi/4, pi/3, pi/2, 2*pi/3, 3*pi/4, 5*pi/6, pi]); +%! assert (acos (x), v, sqrt (eps ('single'))); -%!error acos (); -%!error acos (1, 2); +%!error acos () +%!error acos (1, 2) */ DEFUN (acosh, args, , @@ -136,17 +136,17 @@ /* %!test +%! x = [1, 0, -1, 0]; %! v = [0, pi/2*i, pi*i, pi/2*i]; -%! x = [1, 0, -1, 0]; -%! assert(acosh (x), v, sqrt(eps)); +%! assert (acosh (x), v, sqrt (eps)); %!test -%! v = single([0, pi/2*i, pi*i, pi/2*i]); -%! x = single([1, 0, -1, 0]); -%! assert(acosh (x), v, sqrt (eps('single'))); +%! x = single ([1, 0, -1, 0]); +%! v = single ([0, pi/2*i, pi*i, pi/2*i]); +%! assert (acosh (x), v, sqrt (eps ('single'))); -%!error acosh (); -%!error acosh (1, 2); +%!error acosh () +%!error acosh (1, 2) */ DEFUN (angle, args, , @@ -197,26 +197,26 @@ } /* -%!assert(arg (1), 0); -%!assert(arg (i), pi/2); -%!assert(arg (-1), pi); -%!assert(arg (-i), -pi/2); -%!assert(arg ([1, i; -1, -i]), [0, pi/2; pi, -pi/2]); +%!assert (arg (1), 0) +%!assert (arg (i), pi/2) +%!assert (arg (-1), pi) +%!assert (arg (-i), -pi/2) +%!assert (arg ([1, i; -1, -i]), [0, pi/2; pi, -pi/2]) -%!assert(arg (single(1)), single(0)); -%!assert(arg (single(i)), single(pi/2)); +%!assert (arg (single (1)), single (0)) +%!assert (arg (single (i)), single (pi/2)) %!test %! if (ismac ()) %! ## Avoid failing for a MacOS feature -%! assert(arg (single(-1)), single(pi), 2*eps(single(1))); +%! assert (arg (single (-1)), single (pi), 2*eps (single (1))); %! else -%! assert(arg (single(-1)), single(pi)); +%! assert (arg (single (-1)), single (pi)); %! endif -%!assert(arg (single(-i)), single(-pi/2)); -%!assert(arg (single([1, i; -1, -i])), single([0, pi/2; pi, -pi/2]), 2e1*eps('single')); +%!assert (arg (single (-i)), single (-pi/2)) +%!assert (arg (single ([1, i; -1, -i])), single ([0, pi/2; pi, -pi/2]), 2e1*eps ('single')) -%!error arg (); -%!error arg (1, 2); +%!error arg () +%!error arg (1, 2) */ DEFUN (asin, args, , @@ -239,11 +239,12 @@ %!test %! rt2 = sqrt (2); %! rt3 = sqrt (3); +%! x = [0, 1/2, rt2/2, rt3/2, 1, rt3/2, rt2/2, 1/2, 0]; %! v = [0, pi/6, pi/4, pi/3, pi/2, pi/3, pi/4, pi/6, 0]; -%! x = [0, 1/2, rt2/2, rt3/2, 1, rt3/2, rt2/2, 1/2, 0]; -%! assert(all (abs (asin (x) - v) < sqrt (eps))); -%!error asin (); -%!error asin (1, 2); +%! assert (all (abs (asin (x) - v) < sqrt (eps))); + +%!error asin () +%!error asin (1, 2) */ DEFUN (asinh, args, , @@ -266,15 +267,15 @@ %!test %! v = [0, pi/2*i, 0, -pi/2*i]; %! x = [0, i, 0, -i]; -%! assert(asinh (x), v, sqrt (eps)); +%! assert (asinh (x), v, sqrt (eps)); %!test -%! v = single([0, pi/2*i, 0, -pi/2*i]); -%! x = single([0, i, 0, -i]); -%! assert(asinh (x), v, sqrt (eps('single'))); +%! v = single ([0, pi/2*i, 0, -pi/2*i]); +%! x = single ([0, i, 0, -i]); +%! assert (asinh (x), v, sqrt (eps ('single'))); -%!error asinh (); -%!error asinh (1, 2); +%!error asinh () +%!error asinh (1, 2) */ DEFUN (atan, args, , @@ -294,22 +295,22 @@ } /* -%!test +%!shared rt2, rt3 %! rt2 = sqrt (2); %! rt3 = sqrt (3); -%! v = [0, pi/6, pi/4, pi/3, -pi/3, -pi/4, -pi/6, 0]; -%! x = [0, rt3/3, 1, rt3, -rt3, -1, -rt3/3, 0]; -%! assert(atan (x), v, sqrt (eps)); %!test -%! rt2 = sqrt (2); -%! rt3 = sqrt (3); -%! v = single([0, pi/6, pi/4, pi/3, -pi/3, -pi/4, -pi/6, 0]); -%! x = single([0, rt3/3, 1, rt3, -rt3, -1, -rt3/3, 0]); -%! assert(atan (x), v, sqrt (eps('single'))); +%! v = [0, pi/6, pi/4, pi/3, -pi/3, -pi/4, -pi/6, 0]; +%! x = [0, rt3/3, 1, rt3, -rt3, -1, -rt3/3, 0]; +%! assert (atan (x), v, sqrt (eps)); -%!error atan (); -%!error atan (1, 2); +%!test +%! v = single ([0, pi/6, pi/4, pi/3, -pi/3, -pi/4, -pi/6, 0]); +%! x = single ([0, rt3/3, 1, rt3, -rt3, -1, -rt3/3, 0]); +%! assert (atan (x), v, sqrt (eps ('single'))); + +%!error atan () +%!error atan (1, 2) */ DEFUN (atanh, args, , @@ -332,15 +333,15 @@ %!test %! v = [0, 0]; %! x = [0, 0]; -%! assert(atanh (x), v, sqrt (eps)); +%! assert (atanh (x), v, sqrt (eps)); %!test -%! v = single([0, 0]); -%! x = single([0, 0]); -%! assert(atanh (x), v, sqrt (eps('single'))); +%! v = single ([0, 0]); +%! x = single ([0, 0]); +%! assert (atanh (x), v, sqrt (eps ('single'))); -%!error atanh (); -%!error atanh (1, 2); +%!error atanh () +%!error atanh (1, 2) */ DEFUN (cbrt, args, , @@ -370,6 +371,9 @@ %!assert (cbrt (NaN), NaN) %!assert (cbrt (2^300), 2^100) %!assert (cbrt (125*2^300), 5*2^100) + +%!error cbrt () +%!error cbrt (1, 2) */ DEFUN (ceil, args, , @@ -399,19 +403,19 @@ /* %% double precision -%!assert(ceil ([2, 1.1, -1.1, -1]), [2, 2, -1, -1]); +%!assert (ceil ([2, 1.1, -1.1, -1]), [2, 2, -1, -1]) -%% compelx double precison -%!assert(ceil ([2+2i, 1.1+1.1i, -1.1-1.1i, -1-i]), [2+2i, 2+2i, -1-i, -1-i]); +%% complex double precison +%!assert (ceil ([2+2i, 1.1+1.1i, -1.1-1.1i, -1-i]), [2+2i, 2+2i, -1-i, -1-i]) %% single precision -%!assert(ceil (single([2, 1.1, -1.1, -1])), single([2, 2, -1, -1])); +%!assert (ceil (single ([2, 1.1, -1.1, -1])), single ([2, 2, -1, -1])) -%% compelx single preci -%!assert(ceil (single ([2+2i, 1.1+1.1i, -1.1-1.1i, -1-i])), single([2+2i, 2+2i, -1-i, -1-i])); +%% complex single precision +%!assert (ceil (single ([2+2i, 1.1+1.1i, -1.1-1.1i, -1-i])), single ([2+2i, 2+2i, -1-i, -1-i])) -%!error ceil (); -%!error ceil (1, 2); +%!error ceil () +%!error ceil (1, 2) */ DEFUN (conj, args, , @@ -437,20 +441,20 @@ } /* -%!assert(conj (1), 1); -%!assert(conj (i), -i) -%!assert(conj (1+i), 1-i) -%!assert(conj (1-i), 1+i) -%!assert(conj ([-1, -i; -1+i, -1-i]), [-1, i; -1-i, -1+i]); +%!assert (conj (1), 1) +%!assert (conj (i), -i) +%!assert (conj (1+i), 1-i) +%!assert (conj (1-i), 1+i) +%!assert (conj ([-1, -i; -1+i, -1-i]), [-1, i; -1-i, -1+i]) -%!assert(conj (single(1)), single(1)); -%!assert(conj (single(i)), single(-i)) -%!assert(conj (single(1+i)), single(1-i)) -%!assert(conj (single(1-i)), single(1+i)) -%!assert(conj (single([-1, -i; -1+i, -1-i])), single([-1, i; -1-i, -1+i])); +%!assert (conj (single (1)), single (1)) +%!assert (conj (single (i)), single (-i)) +%!assert (conj (single (1+i)), single (1-i)) +%!assert (conj (single (1-i)), single (1+i)) +%!assert (conj (single ([-1, -i; -1+i, -1-i])), single ([-1, i; -1-i, -1+i])) -%!error conj (); -%!error conj (1, 2); +%!error conj () +%!error conj (1, 2) */ DEFUN (cos, args, , @@ -470,22 +474,24 @@ } /* -%!test +%!shared rt2, rt3 %! rt2 = sqrt (2); %! rt3 = sqrt (3); + +%!test %! x = [0, pi/6, pi/4, pi/3, pi/2, 2*pi/3, 3*pi/4, 5*pi/6, pi]; %! v = [1, rt3/2, rt2/2, 1/2, 0, -1/2, -rt2/2, -rt3/2, -1]; -%! assert(cos (x), v, sqrt (eps)); +%! assert (cos (x), v, sqrt (eps)); %!test %! rt2 = sqrt (2); %! rt3 = sqrt (3); -%! x = single([0, pi/6, pi/4, pi/3, pi/2, 2*pi/3, 3*pi/4, 5*pi/6, pi]); -%! v = single([1, rt3/2, rt2/2, 1/2, 0, -1/2, -rt2/2, -rt3/2, -1]); -%! assert(cos (x), v, sqrt (eps('single'))); +%! x = single ([0, pi/6, pi/4, pi/3, pi/2, 2*pi/3, 3*pi/4, 5*pi/6, pi]); +%! v = single ([1, rt3/2, rt2/2, 1/2, 0, -1/2, -rt2/2, -rt3/2, -1]); +%! assert (cos (x), v, sqrt (eps ('single'))); -%!error cos (); -%!error cos (1, 2); +%!error cos () +%!error cos (1, 2) */ DEFUN (cosh, args, , @@ -508,15 +514,15 @@ %!test %! x = [0, pi/2*i, pi*i, 3*pi/2*i]; %! v = [1, 0, -1, 0]; -%! assert(cosh (x), v, sqrt (eps)); +%! assert (cosh (x), v, sqrt (eps)); %!test -%! x = single([0, pi/2*i, pi*i, 3*pi/2*i]); -%! v = single([1, 0, -1, 0]); -%! assert(cosh (x), v, sqrt (eps ('single'))); +%! x = single ([0, pi/2*i, pi*i, 3*pi/2*i]); +%! v = single ([1, 0, -1, 0]); +%! assert (cosh (x), v, sqrt (eps ('single'))); -%!error cosh (); -%!error cosh (1, 2); +%!error cosh () +%!error cosh (1, 2) */ DEFUN (erf, args, , @@ -556,28 +562,31 @@ /* %!test -%! a = -1i*sqrt(-1/(6.4187*6.4187)); -%! assert (erf(a), erf(real(a))); +%! a = -1i*sqrt (-1/(6.4187*6.4187)); +%! assert (erf (a), erf (real (a))); %!test -%! x=[0,.5,1]; -%! v=[0, .520499877813047, .842700792949715]; -%! assert(all(abs(erf(x)-v)<1.e-10) && all(abs(erf(-x)+v)<1.e-10) && all(abs(erfc(x)+v-1)<1.e-10) && all(abs(erfinv(v)-x)<1.e-10)); +%! x = [0,.5,1]; +%! v = [0, .520499877813047, .842700792949715]; +%! assert (all (abs (erf (x)-v) < 1.e-10)); +%! assert (all (abs (erf (-x)+v) < 1.e-10)); +%! assert (all (abs (erfc (x)+v-1) < 1.e-10)); +%! assert (all (abs (erfinv (v)-x) < 1.e-10)); %!test -%! a = -1i*sqrt(single (-1/(6.4187*6.4187))); -%! assert (erf(a), erf(real(a))); +%! a = -1i*sqrt (single (-1/(6.4187*6.4187))); +%! assert (erf (a), erf (real (a))); %!test -%! x=single ([0,.5,1]); -%! v=single ([0, .520499877813047, .842700792949715]); -%! assert(all(abs(erf(x)-v)<1.e-6) && all(abs(erf(-x)+v)<1.e-6) && all(abs(erfc(x)+v-1)<1.e-6) && all(abs(erfinv(v)-x)<1.e-6)); +%! x = single ([0,.5,1]); +%! v = single ([0, .520499877813047, .842700792949715]); +%! assert (all (abs (erf (x)-v) < 1.e-6)); +%! assert (all (abs (erf (-x)+v) < 1.e-6)); +%! assert (all (abs (erfc (x)+v-1) < 1.e-6)); +%! assert (all (abs (erfinv (v)-x) < 1.e-6)); -%% test/octave.test/arith/erf-2.m -%!error erf(); - -%% test/octave.test/arith/erf-3.m -%!error erf(1,2); +%!error erf () +%!error erf (1, 2) */ DEFUN (erfinv, args, , @@ -613,6 +622,9 @@ %% exceptional %!assert (erfinv ([-1, 1, 1.1, -2.1]), [-Inf, Inf, NaN, NaN]) %!error erfinv (1+2i) + +%!error erfinv () +%!error erfinv (1, 2) */ DEFUN (erfc, args, , @@ -639,8 +651,11 @@ /* %!test -%! a = -1i*sqrt(-1/(6.4187*6.4187)); -%! assert (erfc(a), erfc(real(a))); +%! a = -1i*sqrt (-1/(6.4187*6.4187)); +%! assert (erfc (a), erfc (real (a))); + +%!error erfc () +%!error erfc (1, 2) */ DEFUN (erfcx, args, , @@ -671,6 +686,13 @@ return retval; } +/* +%% FIXME: Need a test for erfcx + +%!error erfcx () +%!error erfcx (1, 2) +*/ + DEFUN (exp, args, , "-*- texinfo -*-\n\ @deftypefn {Mapping Function} {} exp (@var{x})\n\ @@ -696,16 +718,16 @@ } /* -%!assert(exp ([0, 1, -1, -1000]), [1, e, 1/e, 0], sqrt (eps)); -%!assert(exp (1+i), e * (cos (1) + sin (1) * i), sqrt (eps)); -%!assert(exp (single([0, 1, -1, -1000])), single([1, e, 1/e, 0]), sqrt (eps('single'))); -%!assert(exp (single(1+i)), single (e * (cos (1) + sin (1) * i)), sqrt (eps('single'))); +%!assert (exp ([0, 1, -1, -1000]), [1, e, 1/e, 0], sqrt (eps)) +%!assert (exp (1+i), e * (cos (1) + sin (1) * i), sqrt (eps)) +%!assert (exp (single ([0, 1, -1, -1000])), single ([1, e, 1/e, 0]), sqrt (eps ('single'))) +%!assert (exp (single (1+i)), single (e * (cos (1) + sin (1) * i)), sqrt (eps ('single'))) -%!error exp (); -%!error exp (1, 2); +%!assert (exp ([Inf, -Inf, NaN]), [Inf 0 NaN]) +%!assert (exp (single ([Inf, -Inf, NaN])), single ([Inf 0 NaN])) -%!assert(exp (Inf) == Inf && exp (-Inf) == 0 && isnan (exp (NaN))); -%!assert(exp (Inf ('single')) == Inf('single') && exp (-Inf('single')) == 0 && isnan (exp (NaN('single')))); +%!error exp () +%!error exp (1, 2) */ DEFUN (expm1, args, , @@ -731,6 +753,16 @@ return retval; } +/* +%!assert (expm1 (2*eps), 2*eps, 1e-29) + +%!assert (expm1 ([Inf, -Inf, NaN]), [Inf -1 NaN]) +%!assert (expm1 (single ([Inf, -Inf, NaN])), single ([Inf -1 NaN])) + +%!error expm1 () +%!error expm1 (1, 2) +*/ + DEFUN (isfinite, args, , "-*- texinfo -*-\n\ @deftypefn {Mapping Function} {} isfinite (@var{x})\n\ @@ -758,13 +790,16 @@ } /* -%!assert(!(finite (Inf))); -%!assert(!(finite (NaN))); -%!assert(finite (rand(1,10))); +%!assert (!finite (Inf)) +%!assert (!finite (NaN)) +%!assert (finite (rand (1,10))) -%!assert(!(finite (single(Inf)))); -%!assert(!(finite (single(NaN)))); -%!assert(finite (single(rand(1,10)))); +%!assert (!finite (single (Inf))) +%!assert (!finite (single (NaN))) +%!assert (finite (single (rand (1,10)))) + +%!error finite () +%!error finite (1, 2) */ DEFUN (fix, args, , @@ -793,13 +828,13 @@ } /* -%!assert(fix ([1.1, 1, -1.1, -1]), [1, 1, -1, -1]); -%!assert(fix ([1.1+1.1i, 1+i, -1.1-1.1i, -1-i]), [1+i, 1+i, -1-i, -1-i]); -%!assert(fix (single([1.1, 1, -1.1, -1])), single([1, 1, -1, -1])); -%!assert(fix (single([1.1+1.1i, 1+i, -1.1-1.1i, -1-i])), single([1+i, 1+i, -1-i, -1-i])); +%!assert (fix ([1.1, 1, -1.1, -1]), [1, 1, -1, -1]) +%!assert (fix ([1.1+1.1i, 1+i, -1.1-1.1i, -1-i]), [1+i, 1+i, -1-i, -1-i]) +%!assert (fix (single ([1.1, 1, -1.1, -1])), single ([1, 1, -1, -1])) +%!assert (fix (single ([1.1+1.1i, 1+i, -1.1-1.1i, -1-i])), single ([1+i, 1+i, -1-i, -1-i])) -%!error fix (); -%!error fix (1, 2); +%!error fix () +%!error fix (1, 2) */ DEFUN (floor, args, , @@ -828,13 +863,13 @@ } /* -%!assert(floor ([2, 1.1, -1.1, -1]), [2, 1, -2, -1]); -%!assert(floor ([2+2i, 1.1+1.1i, -1.1-1.1i, -1-i]), [2+2i, 1+i, -2-2i, -1-i]); -%!assert(floor (single ([2, 1.1, -1.1, -1])), single ([2, 1, -2, -1])); -%!assert(floor (single([2+2i, 1.1+1.1i, -1.1-1.1i, -1-i])), single([2+2i, 1+i, -2-2i, -1-i])); +%!assert (floor ([2, 1.1, -1.1, -1]), [2, 1, -2, -1]) +%!assert (floor ([2+2i, 1.1+1.1i, -1.1-1.1i, -1-i]), [2+2i, 1+i, -2-2i, -1-i]) +%!assert (floor (single ([2, 1.1, -1.1, -1])), single ([2, 1, -2, -1])) +%!assert (floor (single ([2+2i, 1.1+1.1i, -1.1-1.1i, -1-i])), single ([2+2i, 1+i, -2-2i, -1-i])) -%!error floor (); -%!error floor (1, 2); +%!error floor () +%!error floor (1, 2) */ DEFUN (gamma, args, , @@ -874,31 +909,31 @@ /* %!test -%! a = -1i*sqrt(-1/(6.4187*6.4187)); -%! assert (gamma(a), gamma(real(a))); +%! a = -1i*sqrt (-1/(6.4187*6.4187)); +%! assert (gamma (a), gamma (real (a))); %!test %! x = [.5, 1, 1.5, 2, 3, 4, 5]; %! v = [sqrt(pi), 1, .5*sqrt(pi), 1, 2, 6, 24]; -%! assert(gamma(x), v, sqrt(eps)) +%! assert (gamma (x), v, sqrt (eps)); %!test -%! a = single(-1i*sqrt(-1/(6.4187*6.4187))); -%! assert (gamma(a), gamma(real(a))); +%! a = single (-1i*sqrt (-1/(6.4187*6.4187))); +%! assert (gamma (a), gamma (real (a))); %!test -%! x = single([.5, 1, 1.5, 2, 3, 4, 5]); -%! v = single([sqrt(pi), 1, .5*sqrt(pi), 1, 2, 6, 24]); -%! assert(gamma(x), v, sqrt(eps('single'))) +%! x = single ([.5, 1, 1.5, 2, 3, 4, 5]); +%! v = single ([sqrt(pi), 1, .5*sqrt(pi), 1, 2, 6, 24]); +%! assert (gamma (x), v, sqrt (eps ('single'))); %!test %! x = [-1, 0, 1, Inf]; %! v = [Inf, Inf, 1, Inf]; -%! assert (gamma(x), v); -%! assert (gamma(single (x)), single (v)); +%! assert (gamma (x), v); +%! assert (gamma (single (x)), single (v)); -%!error gamma(); -%!error gamma(1,2); +%!error gamma () +%!error gamma (1, 2) */ DEFUN (imag, args, , @@ -918,18 +953,18 @@ } /* -%!assert(imag (1), 0); -%!assert(imag (i), 1); -%!assert(imag (1+i), 1); -%!assert(imag ([i, 1; 1, i]), full (eye (2))); +%!assert (imag (1), 0) +%!assert (imag (i), 1) +%!assert (imag (1+i), 1) +%!assert (imag ([i, 1; 1, i]), full (eye (2))) -%!assert(imag (single(1)), single(0)); -%!assert(imag (single(i)), single(1)); -%!assert(imag (single(1+i)), single(1)); -%!assert(imag (single([i, 1; 1, i])), full (eye (2,'single'))); +%!assert (imag (single (1)), single (0)) +%!assert (imag (single (i)), single (1)) +%!assert (imag (single (1+i)), single (1)) +%!assert (imag (single ([i, 1; 1, i])), full (eye (2,'single'))) -%!error imag (); -%!error imag (1, 2); +%!error imag () +%!error imag (1, 2) */ DEFUNX ("isalnum", Fisalnum, args, , @@ -952,15 +987,15 @@ /* %!test -%! charset = setstr (0:127); -%! result = zeros (1, 128); -%! result ((toascii("A"):toascii("Z"))+1) = 1; -%! result ((toascii("0"):toascii("9"))+1) = 1; -%! result ((toascii("a"):toascii("z"))+1) = 1; -%! assert(all (isalnum (charset) == result)); +%! charset = char (0:127); +%! result = false (1, 128); +%! result(toascii ("A":"Z") + 1) = true; +%! result(toascii ("0":"9") + 1) = true; +%! result(toascii ("a":"z") + 1) = true; +%! assert (all (isalnum (charset) == result)); -%!error isalnum (1, 2); -%!error isalnum (); +%!error isalnum () +%!error isalnum (1, 2) */ DEFUNX ("isalpha", Fisalpha, args, , @@ -983,14 +1018,14 @@ /* %!test -%! charset = setstr (0:127); -%! result = zeros (1, 128); -%! result ((toascii("A"):toascii("Z"))+1) = 1; -%! result ((toascii("a"):toascii("z"))+1) = 1; -%! assert(all (isalpha (charset) == result)); +%! charset = char (0:127); +%! result = false (1, 128); +%! result(toascii ("A":"Z") + 1) = true; +%! result(toascii ("a":"z") + 1) = true; +%! assert (all (isalpha (charset) == result)); -%!error isalpha (1, 2); -%!error isalpha (); +%!error isalpha () +%!error isalpha (1, 2) */ DEFUNX ("isascii", Fisascii, args, , @@ -1012,12 +1047,12 @@ /* %!test -%! charset = setstr (0:127); -%! result = ones (1, 128); -%! assert(all (isascii (charset) == result)); +%! charset = char (0:127); +%! result = true (1, 128); +%! assert (all (isascii (charset) == result)); -%!error isascii (1, 2); -%!error isascii (); +%!error isascii () +%!error isascii (1, 2) */ DEFUNX ("iscntrl", Fiscntrl, args, , @@ -1038,16 +1073,15 @@ } /* -%% test/octave.test/string/iscntrl-1.m %!test -%! charset = setstr (0:127); -%! result = zeros (1, 128); -%! result (1:32) = 1; -%! result (128) = 1; -%! assert(all (iscntrl (charset) == result)); +%! charset = char (0:127); +%! result = false (1, 128); +%! result(1:32) = true; +%! result(128) = true; +%! assert (all (iscntrl (charset) == result)); -%!error iscntrl (1, 2); -%!error iscntrl (); +%!error iscntrl () +%!error iscntrl (1, 2) */ DEFUNX ("isdigit", Fisdigit, args, , @@ -1069,13 +1103,13 @@ /* %!test -%! charset = setstr (0:127); -%! result = zeros (1, 128); -%! result ((toascii("0"):toascii("9"))+1) = 1; -%! assert(all (isdigit (charset) == result)); +%! charset = char (0:127); +%! result = false (1, 128); +%! result(toascii ("0":"9") + 1) = true; +%! assert (all (isdigit (charset) == result)); -%!error isdigit (1, 2); -%!error isdigit (); +%!error isdigit () +%!error isdigit (1, 2) */ DEFUN (isinf, args, , @@ -1104,17 +1138,20 @@ } /* -%!assert(isinf (Inf)); -%!assert(!isinf (NaN)); -%!assert(!(isinf (NA))); -%!assert(isinf (rand(1,10)), false(1,10)); -%!assert(isinf([NaN -Inf -1 0 1 Inf NA]), [false, true, false, false, false, true, false]); +%!assert (isinf (Inf)) +%!assert (!isinf (NaN)) +%!assert (!isinf (NA)) +%!assert (isinf (rand(1,10)), false (1,10)) +%!assert (isinf ([NaN -Inf -1 0 1 Inf NA]), [false, true, false, false, false, true, false]) -%!assert(isinf (single(Inf))); -%!assert(!(isinf (single(NaN)))); -%!assert(!(isinf (single(NA)))); -%!assert(isinf (single(rand(1,10))), false(1,10)); -%!assert(isinf(single([NaN -Inf -1 0 1 Inf NA])), [false, true, false, false, false, true, false]); +%!assert (isinf (single (Inf))) +%!assert (!isinf (single (NaN))) +%!assert (!isinf (single (NA))) +%!assert (isinf (single (rand(1,10))), false (1,10)) +%!assert (isinf (single ([NaN -Inf -1 0 1 Inf NA])), [false, true, false, false, false, true, false]) + +%!error isinf () +%!error isinf (1, 2) */ DEFUNX ("isgraph", Fisgraph, args, , @@ -1137,13 +1174,13 @@ /* %!test -%! charset = setstr (0:127); -%! result = zeros (1, 128); -%! result (34:127) = 1; -%! assert(all (isgraph (charset) == result)); +%! charset = char (0:127); +%! result = false (1, 128); +%! result(34:127) = true; +%! assert (all (isgraph (charset) == result)); -%!error isgraph (1, 2); -%!error isgraph (); +%!error isgraph () +%!error isgraph (1, 2) */ DEFUNX ("islower", Fislower, args, , @@ -1165,13 +1202,13 @@ /* %!test -%! charset = setstr (0:127); -%! result = zeros (1, 128); -%! result ((toascii("a"):toascii("z"))+1) = 1; -%! assert(all (islower (charset) == result)); +%! charset = char (0:127); +%! result = false (1, 128); +%! result(toascii ("a":"z") + 1) = true; +%! assert (all (islower (charset) == result)); -%!error islower (1, 2); -%!error islower (); +%!error islower () +%!error islower (1, 2) */ DEFUN (isna, args, , @@ -1200,17 +1237,20 @@ } /* -%!assert(!(isna (Inf))); -%!assert(!isna (NaN)); -%!assert(isna (NA)); -%!assert(isna (rand(1,10)), false(1,10)); -%!assert(isna([NaN -Inf -1 0 1 Inf NA]), [false, false, false, false, false, false, true]); +%!assert (!isna (Inf)) +%!assert (!isna (NaN)) +%!assert (isna (NA)) +%!assert (isna (rand(1,10)), false (1,10)) +%!assert (isna ([NaN -Inf -1 0 1 Inf NA]), [false, false, false, false, false, false, true]) -%!assert(!(isna (single(Inf)))); -%!assert(!isna (single(NaN))); -%!assert(isna (single(NA))); -%!assert(isna (single(rand(1,10))), false(1,10)); -%!assert(isna(single([NaN -Inf -1 0 1 Inf NA])), [false, false, false, false, false, false, true]); +%!assert (!isna (single (Inf))) +%!assert (!isna (single (NaN))) +%!assert (isna (single (NA))) +%!assert (isna (single (rand(1,10))), false (1,10)) +%!assert (isna (single ([NaN -Inf -1 0 1 Inf NA])), [false, false, false, false, false, false, true]) + +%!error isna () +%!error isna (1, 2) */ DEFUN (isnan, args, , @@ -1239,17 +1279,20 @@ } /* -%!assert(!(isnan (Inf))); -%!assert(isnan (NaN)); -%!assert(isnan (NA)); -%!assert(isnan (rand(1,10)), false(1,10)); -%!assert(isnan([NaN -Inf -1 0 1 Inf NA]), [true, false, false, false, false, false, true]); +%!assert (!isnan (Inf)) +%!assert (isnan (NaN)) +%!assert (isnan (NA)) +%!assert (isnan (rand(1,10)), false (1,10)) +%!assert (isnan ([NaN -Inf -1 0 1 Inf NA]), [true, false, false, false, false, false, true]) -%!assert(!(isnan (single(Inf)))); -%!assert(isnan (single(NaN))); -%!assert(isnan (single(NA))); -%!assert(isnan (single(rand(1,10))), false(1,10)); -%!assert(isnan(single([NaN -Inf -1 0 1 Inf NA])), [true, false, false, false, false, false, true]); +%!assert (!isnan (single (Inf))) +%!assert (isnan (single (NaN))) +%!assert (isnan (single (NA))) +%!assert (isnan (single (rand(1,10))), false (1,10)) +%!assert (isnan (single ([NaN -Inf -1 0 1 Inf NA])), [true, false, false, false, false, false, true]) + +%!error isnan () +%!error isnan (1, 2) */ DEFUNX ("isprint", Fisprint, args, , @@ -1272,16 +1315,13 @@ /* %!test -%! charset = setstr (0:127); -%! result = zeros (1, 128); -%! result (33:127) = 1; -%! if (ispc () && ! isunix ()) -%! result(10) = 1; -%! endif -%! assert(all (isprint (charset) == result)); +%! charset = char (0:127); +%! result = false (1, 128); +%! result(33:127) = true; +%! assert (all (isprint (charset) == result)); -%!error isprint (1, 2); -%!error isprint (); +%!error isprint () +%!error isprint (1, 2) */ DEFUNX ("ispunct", Fispunct, args, , @@ -1303,16 +1343,16 @@ /* %!test -%! charset = setstr (0:127); -%! result = zeros (1, 128); -%! result (34:48) = 1; -%! result (59:65) = 1; -%! result (92:97) = 1; -%! result (124:127) = 1; -%! assert(all (ispunct (charset) == result)); +%! charset = char (0:127); +%! result = false (1, 128); +%! result(34:48) = true; +%! result(59:65) = true; +%! result(92:97) = true; +%! result(124:127) = true; +%! assert (all (ispunct (charset) == result)); -%!error ispunct (1, 2); -%!error ispunct (); +%!error ispunct () +%!error ispunct (1, 2) */ DEFUNX ("isspace", Fisspace, args, , @@ -1335,13 +1375,13 @@ /* %!test -%! charset = setstr (0:127); -%! result = zeros (1, 128); -%! result (toascii (" \f\n\r\t\v")+1) = 1; -%! assert(all (isspace (charset) == result)); +%! charset = char (0:127); +%! result = false (1, 128); +%! result(toascii (" \f\n\r\t\v") + 1) = true; +%! assert (all (isspace (charset) == result)); -%!error isspace (1, 2); -%!error isspace (); +%!error isspace () +%!error isspace (1, 2) */ DEFUNX ("isupper", Fisupper, args, , @@ -1363,13 +1403,13 @@ /* %!test -%! charset = setstr (0:127); -%! result = zeros (1, 128); -%! result ((toascii("A"):toascii("Z"))+1) = 1; -%! assert(all (isupper (charset) == result)); +%! charset = char (0:127); +%! result = false (1, 128); +%! result(toascii ("A":"Z") + 1) = true; +%! assert (all (isupper (charset) == result)); -%!error isupper (1, 2); -%!error isupper (); +%!error isupper () +%!error isupper (1, 2) */ DEFUNX ("isxdigit", Fisxdigit, args, , @@ -1391,15 +1431,15 @@ /* %!test -%! charset = setstr (0:127); -%! result = zeros (1, 128); -%! result ((toascii("A"):toascii("F"))+1) = 1; -%! result ((toascii("0"):toascii("9"))+1) = 1; -%! result ((toascii("a"):toascii("f"))+1) = 1; -%! assert(all (isxdigit (charset) == result)); +%! charset = char (0:127); +%! result = false (1, 128); +%! result(toascii ("A":"F") + 1) = true; +%! result(toascii ("0":"9") + 1) = true; +%! result(toascii ("a":"f") + 1) = true; +%! assert (all (isxdigit (charset) == result)); -%!error isxdigit (1, 2); -%!error isxdigit (); +%!error isxdigit () +%!error isxdigit (1, 2) */ DEFUN (lgamma, args, , @@ -1421,31 +1461,31 @@ /* %!test -%! a = -1i*sqrt(-1/(6.4187*6.4187)); +%! a = -1i*sqrt (-1/(6.4187*6.4187)); %! assert (lgamma(a), lgamma(real(a))); %!test %! x = [.5, 1, 1.5, 2, 3, 4, 5]; %! v = [sqrt(pi), 1, .5*sqrt(pi), 1, 2, 6, 24]; -%! assert(lgamma(x), log(v), sqrt(eps)) +%! assert (lgamma(x), log(v), sqrt (eps)) %!test -%! a = single(-1i*sqrt(-1/(6.4187*6.4187))); +%! a = single (-1i*sqrt (-1/(6.4187*6.4187))); %! assert (lgamma(a), lgamma(real(a))); %!test -%! x = single([.5, 1, 1.5, 2, 3, 4, 5]); -%! v = single([sqrt(pi), 1, .5*sqrt(pi), 1, 2, 6, 24]); -%! assert(lgamma(x), log(v), sqrt(eps ('single'))) +%! x = single ([.5, 1, 1.5, 2, 3, 4, 5]); +%! v = single ([sqrt(pi), 1, .5*sqrt(pi), 1, 2, 6, 24]); +%! assert (lgamma(x), log(v), sqrt (eps ('single'))) %!test %! x = [-1, 0, 1, Inf]; %! v = [Inf, Inf, 0, Inf]; %! assert (lgamma(x), v); -%! assert (lgamma(single (x)), single(v)); +%! assert (lgamma(single (x)), single (v)); -%!error lgamma(); -%!error lgamma(1,2); +%!error lgamma() +%!error lgamma(1,2) */ DEFUN (log, args, , @@ -1473,14 +1513,14 @@ } /* -%!assert(log ([1, e, e^2]), [0, 1, 2], sqrt (eps)); -%!assert(log ([-0.5, -1.5, -2.5]), log([0.5, 1.5, 2.5]) + pi*1i, sqrt (eps)); +%!assert (log ([1, e, e^2]), [0, 1, 2], sqrt (eps)) +%!assert (log ([-0.5, -1.5, -2.5]), log([0.5, 1.5, 2.5]) + pi*1i, sqrt (eps)) -%!assert(log (single([1, e, e^2])), single([0, 1, 2]), sqrt (eps('single'))); -%!assert(log (single([-0.5, -1.5, -2.5])), single(log([0.5, 1.5, 2.5]) + pi*1i), 4*eps('single')); +%!assert (log (single ([1, e, e^2])), single ([0, 1, 2]), sqrt (eps ('single'))) +%!assert (log (single ([-0.5, -1.5, -2.5])), single (log([0.5, 1.5, 2.5]) + pi*1i), 4*eps ('single')) -%!error log (); -%!error log (1, 2); +%!error log () +%!error log (1, 2) */ DEFUN (log10, args, , @@ -1500,11 +1540,11 @@ } /* -%!assert(log10 ([0.01, 0.1, 1, 10, 100]), [-2, -1, 0, 1, 2], sqrt (eps)); -%!assert(log10 (single([0.01, 0.1, 1, 10, 100])), single([-2, -1, 0, 1, 2]), sqrt (eps ('single'))); +%!assert (log10 ([0.01, 0.1, 1, 10, 100]), [-2, -1, 0, 1, 2], sqrt (eps)) +%!assert (log10 (single ([0.01, 0.1, 1, 10, 100])), single ([-2, -1, 0, 1, 2]), sqrt (eps ('single'))) -%!error log10 (); -%!error log10 (1, 2); +%!error log10 () +%!error log10 (1, 2) */ DEFUN (log1p, args, , @@ -1530,6 +1570,14 @@ return retval; } +/* +%!assert (log1p ([0, 2*eps, -2*eps]), [0, 2*eps, -2*eps], 1e-29) +%!assert (log1p (single ([0, 2*eps, -2*eps])), single([0, 2*eps, -2*eps]), 1e-29) + +%!error log1p () +%!error log1p (1, 2) +*/ + DEFUN (real, args, , "-*- texinfo -*-\n\ @deftypefn {Mapping Function} {} real (@var{z})\n\ @@ -1547,18 +1595,18 @@ } /* -%!assert(real (1), 1); -%!assert(real (i), 0); -%!assert(real (1+i), 1); -%!assert(real ([1, i; i, 1]), full (eye (2))); +%!assert (real (1), 1) +%!assert (real (i), 0) +%!assert (real (1+i), 1) +%!assert (real ([1, i; i, 1]), full (eye (2))) -%!assert(real (single(1)), single(1)); -%!assert(real (single(i)), single(0)); -%!assert(real (single(1+i)), single(1)); -%!assert(real (single([1, i; i, 1])), full (eye (2,'single'))); +%!assert (real (single (1)), single (1)) +%!assert (real (single (i)), single (0)) +%!assert (real (single (1+i)), single (1)) +%!assert (real (single ([1, i; i, 1])), full (eye (2,'single'))) -%!error real (); -%!error real (1, 2); +%!error real () +%!error real (1, 2) */ DEFUN (round, args, , @@ -1587,24 +1635,24 @@ } /* -%!assert(round (1), 1); -%!assert(round (1.1), 1); -%!assert(round (5.5), 6); -%!assert(round (i), i); -%!assert(round (2.5+3.5i), 3+4i); -%!assert(round (-2.6), -3); -%!assert(round ([1.1, -2.4; -3.7, 7.1]), [1, -2; -4, 7]); +%!assert (round (1), 1) +%!assert (round (1.1), 1) +%!assert (round (5.5), 6) +%!assert (round (i), i) +%!assert (round (2.5+3.5i), 3+4i) +%!assert (round (-2.6), -3) +%!assert (round ([1.1, -2.4; -3.7, 7.1]), [1, -2; -4, 7]) -%!assert(round (single(1)), single(1)); -%!assert(round (single(1.1)), single(1)); -%!assert(round (single(5.5)), single(6)); -%!assert(round (single(i)), single(i)); -%!assert(round (single(2.5+3.5i)), single(3+4i)); -%!assert(round (single(-2.6)), single(-3)); -%!assert(round (single([1.1, -2.4; -3.7, 7.1])), single([1, -2; -4, 7])); +%!assert (round (single (1)), single (1)) +%!assert (round (single (1.1)), single (1)) +%!assert (round (single (5.5)), single (6)) +%!assert (round (single (i)), single (i)) +%!assert (round (single (2.5+3.5i)), single (3+4i)) +%!assert (round (single (-2.6)), single (-3)) +%!assert (round (single ([1.1, -2.4; -3.7, 7.1])), single ([1, -2; -4, 7])) -%!error round (); -%!error round (1, 2); +%!error round () +%!error round (1, 2) */ DEFUN (roundb, args, , @@ -1625,6 +1673,29 @@ return retval; } +/* +%!assert (roundb (1), 1) +%!assert (roundb (1.1), 1) +%!assert (roundb (1.5), 2) +%!assert (roundb (4.5), 4) +%!assert (roundb (i), i) +%!assert (roundb (2.5+3.5i), 2+4i) +%!assert (roundb (-2.6), -3) +%!assert (roundb ([1.1, -2.4; -3.7, 7.1]), [1, -2; -4, 7]) + +%!assert (roundb (single (1)), single (1)) +%!assert (roundb (single (1.1)), single (1)) +%!assert (roundb (single (1.5)), single (2)) +%!assert (roundb (single (4.5)), single (4)) +%!assert (roundb (single (i)), single (i)) +%!assert (roundb (single (2.5+3.5i)), single (2+4i)) +%!assert (roundb (single (-2.6)), single (-3)) +%!assert (roundb (single ([1.1, -2.4; -3.7, 7.1])), single ([1, -2; -4, 7])) + +%!error roundb () +%!error roundb (1, 2) +*/ + DEFUN (sign, args, , "-*- texinfo -*-\n\ @deftypefn {Mapping Function} {} sign (@var{x})\n\ @@ -1659,18 +1730,18 @@ } /* -%!assert(sign (-2) , -1); -%!assert(sign (3), 1); -%!assert(sign (0), 0); -%!assert(sign ([1, -pi; e, 0]), [1, -1; 1, 0]); +%!assert (sign (-2) , -1) +%!assert (sign (0), 0) +%!assert (sign (3), 1) +%!assert (sign ([1, -pi; e, 0]), [1, -1; 1, 0]) -%!assert(sign (single(-2)) , single(-1)); -%!assert(sign (single(3)), single(1)); -%!assert(sign (single(0)), single(0)); -%!assert(sign (single([1, -pi; e, 0])), single([1, -1; 1, 0])); +%!assert (sign (single (-2)) , single (-1)) +%!assert (sign (single (0)), single (0)) +%!assert (sign (single (3)), single (1)) +%!assert (sign (single ([1, -pi; e, 0])), single ([1, -1; 1, 0])) -%!error sign (); -%!error sign (1, 2); +%!error sign () +%!error sign (1, 2) */ DEFUN (sin, args, , @@ -1690,22 +1761,22 @@ } /* -%!test +%!shared rt2, rt3 %! rt2 = sqrt (2); %! rt3 = sqrt (3); -%! x = [0, pi/6, pi/4, pi/3, pi/2, 2*pi/3, 3*pi/4, 5*pi/6, pi]; -%! v = [0, 1/2, rt2/2, rt3/2, 1, rt3/2, rt2/2, 1/2, 0]; -%! assert(sin (x), v, sqrt (eps)); %!test -%! rt2 = sqrt (2); -%! rt3 = sqrt (3); -%! x = single([0, pi/6, pi/4, pi/3, pi/2, 2*pi/3, 3*pi/4, 5*pi/6, pi]); -%! v = single([0, 1/2, rt2/2, rt3/2, 1, rt3/2, rt2/2, 1/2, 0]); -%! assert(sin (x), v, sqrt (eps('single'))); +%! x = [0, pi/6, pi/4, pi/3, pi/2, 2*pi/3, 3*pi/4, 5*pi/6, pi]; +%! v = [0, 1/2, rt2/2, rt3/2, 1, rt3/2, rt2/2, 1/2, 0]; +%! assert (sin (x), v, sqrt (eps)); -%!error sin (); -%!error sin (1, 2); +%!test +%! x = single ([0, pi/6, pi/4, pi/3, pi/2, 2*pi/3, 3*pi/4, 5*pi/6, pi]); +%! v = single ([0, 1/2, rt2/2, rt3/2, 1, rt3/2, rt2/2, 1/2, 0]); +%! assert (sin (x), v, sqrt (eps ('single'))); + +%!error sin () +%!error sin (1, 2) */ DEFUN (sinh, args, , @@ -1728,15 +1799,15 @@ %!test %! x = [0, pi/2*i, pi*i, 3*pi/2*i]; %! v = [0, i, 0, -i]; -%! assert(sinh (x), v, sqrt (eps)); +%! assert (sinh (x), v, sqrt (eps)); %!test -%! x = single([0, pi/2*i, pi*i, 3*pi/2*i]); -%! v = single([0, i, 0, -i]); -%! assert(sinh (x), v, sqrt (eps('single'))); +%! x = single ([0, pi/2*i, pi*i, 3*pi/2*i]); +%! v = single ([0, i, 0, -i]); +%! assert (sinh (x), v, sqrt (eps ('single'))); -%!error sinh (); -%!error sinh (1, 2); +%!error sinh () +%!error sinh (1, 2) */ DEFUN (sqrt, args, , @@ -1758,18 +1829,18 @@ } /* -%!assert(sqrt (4), 2) -%!assert(sqrt (-1), i) -%!assert(sqrt (1+i), exp (0.5 * log (1+i)), sqrt (eps)); -%!assert(sqrt([4, -4; i, 1-i]), [2, 2i; exp(0.5 * log (i)), exp(0.5 * log (1-i))], sqrt(eps)); +%!assert (sqrt (4), 2) +%!assert (sqrt (-1), i) +%!assert (sqrt (1+i), exp (0.5 * log (1+i)), sqrt (eps)) +%!assert (sqrt ([4, -4; i, 1-i]), [2, 2i; exp(0.5 * log (i)), exp(0.5 * log (1-i))], sqrt (eps)) -%!assert(sqrt (single(4)), single(2)) -%!assert(sqrt (single(-1)), single(i)) -%!assert(sqrt (single(1+i)), single(exp (0.5 * log (1+i))), sqrt (eps('single'))); -%!assert(sqrt(single([4, -4; i, 1-i])), single([2, 2i; exp(0.5 * log (i)), exp(0.5 * log (1-i))]), sqrt(eps('single'))); +%!assert (sqrt (single (4)), single (2)) +%!assert (sqrt (single (-1)), single (i)) +%!assert (sqrt (single (1+i)), single (exp (0.5 * log (1+i))), sqrt (eps ('single'))) +%!assert (sqrt (single ([4, -4; i, 1-i])), single ([2, 2i; exp(0.5 * log (i)), exp(0.5 * log (1-i))]), sqrt (eps ('single'))) -%!error sqrt (); -%!error sqrt (1, 2); +%!error sqrt () +%!error sqrt (1, 2) */ DEFUN (tan, args, , @@ -1789,22 +1860,22 @@ } /* -%!test +%!shared rt2, rt3 %! rt2 = sqrt (2); %! rt3 = sqrt (3); -%! x = [0, pi/6, pi/4, pi/3, 2*pi/3, 3*pi/4, 5*pi/6, pi]; -%! v = [0, rt3/3, 1, rt3, -rt3, -1, -rt3/3, 0]; -%! assert(tan (x), v, sqrt (eps)); %!test -%! rt2 = sqrt (2); -%! rt3 = sqrt (3); -%! x = single([0, pi/6, pi/4, pi/3, 2*pi/3, 3*pi/4, 5*pi/6, pi]); -%! v = single([0, rt3/3, 1, rt3, -rt3, -1, -rt3/3, 0]); -%! assert(tan (x), v, sqrt (eps('single'))); +%! x = [0, pi/6, pi/4, pi/3, 2*pi/3, 3*pi/4, 5*pi/6, pi]; +%! v = [0, rt3/3, 1, rt3, -rt3, -1, -rt3/3, 0]; +%! assert (tan (x), v, sqrt (eps)); -%!error tan (); -%!error tan (1, 2); +%!test +%! x = single ([0, pi/6, pi/4, pi/3, 2*pi/3, 3*pi/4, 5*pi/6, pi]); +%! v = single ([0, rt3/3, 1, rt3, -rt3, -1, -rt3/3, 0]); +%! assert (tan (x), v, sqrt (eps ('single'))); + +%!error tan () +%!error tan (1, 2) */ DEFUN (tanh, args, , @@ -1827,15 +1898,15 @@ %!test %! x = [0, pi*i]; %! v = [0, 0]; -%! assert(tanh (x), v, sqrt (eps)); +%! assert (tanh (x), v, sqrt (eps)); %!test -%! x = single([0, pi*i]); -%! v = single([0, 0]); -%! assert(tanh (x), v, sqrt (eps('single'))); +%! x = single ([0, pi*i]); +%! v = single ([0, 0]); +%! assert (tanh (x), v, sqrt (eps ('single'))); -%!error tanh (); -%!error tanh (1, 2); +%!error tanh () +%!error tanh (1, 2) */ DEFUNX ("toascii", Ftoascii, args, , @@ -1863,14 +1934,15 @@ } /* -%!assert(toascii (char (0:127)), 0:127); -%!assert(toascii (" ":"@"), 32:64); -%!assert(toascii ("A":"Z"), 65:90); -%!assert(toascii ("[":"`"), 91:96); -%!assert(toascii ("a":"z"), 97:122); -%!assert(toascii ("{":"~"), 123:126); -%!error toascii (1, 2); -%!error toascii (1, 2); +%!assert (toascii (char (0:127)), 0:127) +%!assert (toascii (" ":"@"), 32:64) +%!assert (toascii ("A":"Z"), 65:90) +%!assert (toascii ("[":"`"), 91:96) +%!assert (toascii ("a":"z"), 97:122) +%!assert (toascii ("{":"~"), 123:126) + +%!error toascii () +%!error toascii (1, 2) */ DEFUNX ("tolower", Ftolower, args, , @@ -1902,26 +1974,26 @@ DEFALIAS (lower, tolower); /* -%!error <Invalid call to tolower> tolower(); -%!error <Invalid call to tolower> lower(); -%!error tolower (1, 2); -%!assert(tolower("OCTAVE"), "octave"); -%!assert(tolower("123OCTave!_&"), "123octave!_&"); -%!assert(tolower({"ABC", "DEF", {"GHI", {"JKL"}}}), {"abc", "def", {"ghi", {"jkl"}}}); -%!assert(tolower(["ABC"; "DEF"]), ["abc"; "def"]); -%!assert(tolower({["ABC"; "DEF"]}), {["abc";"def"]}); -%!assert(tolower(68), "d"); -%!assert(tolower({[68, 68; 68, 68]}), {["dd";"dd"]}); +%!assert (tolower("OCTAVE"), "octave") +%!assert (tolower("123OCTave!_&"), "123octave!_&") +%!assert (tolower({"ABC", "DEF", {"GHI", {"JKL"}}}), {"abc", "def", {"ghi", {"jkl"}}}) +%!assert (tolower(["ABC"; "DEF"]), ["abc"; "def"]) +%!assert (tolower({["ABC"; "DEF"]}), {["abc";"def"]}) +%!assert (tolower(68), "d") +%!assert (tolower({[68, 68; 68, 68]}), {["dd";"dd"]}) %!test %! a(3,3,3,3) = "D"; %! assert(tolower(a)(3,3,3,3), "d"); %!test -%! charset = setstr (0:127); +%! charset = char (0:127); %! result = charset; -%! result ((toascii("A"):toascii("Z"))+1) \ -%! = result ((toascii("a"):toascii("z"))+1); -%! assert(all (tolower (charset) == result)); +%! result(toascii ("A":"Z") + 1) = result(toascii ("a":"z") + 1); +%! assert (all (tolower (charset) == result)); + +%!error <Invalid call to tolower> tolower() +%!error <Invalid call to tolower> lower() +%!error tolower (1, 2) */ DEFUNX ("toupper", Ftoupper, args, , @@ -1953,25 +2025,25 @@ DEFALIAS (upper, toupper); /* -%!error <Invalid call to toupper> toupper(); -%!error <Invalid call to toupper> upper(); -%!error toupper (1, 2); -%!assert(toupper("octave"), "OCTAVE"); -%!assert(toupper("123OCTave!_&"), "123OCTAVE!_&"); -%!assert(toupper({"abc", "def", {"ghi", {"jkl"}}}), {"ABC", "DEF", {"GHI", {"JKL"}}}); -%!assert(toupper(["abc"; "def"]), ["ABC"; "DEF"]); -%!assert(toupper({["abc"; "def"]}), {["ABC";"DEF"]}); -%!assert(toupper(100), "D"); -%!assert(toupper({[100, 100; 100, 100]}), {["DD";"DD"]}); +%!assert (toupper ("octave"), "OCTAVE") +%!assert (toupper ("123OCTave!_&"), "123OCTAVE!_&") +%!assert (toupper ({"abc", "def", {"ghi", {"jkl"}}}), {"ABC", "DEF", {"GHI", {"JKL"}}}) +%!assert (toupper (["abc"; "def"]), ["ABC"; "DEF"]) +%!assert (toupper ({["abc"; "def"]}), {["ABC";"DEF"]}) +%!assert (toupper (100), "D") +%!assert (toupper ({[100, 100; 100, 100]}), {["DD";"DD"]}) %!test %! a(3,3,3,3) = "d"; -%! assert(toupper(a)(3,3,3,3), "D"); +%! assert(toupper (a)(3,3,3,3), "D"); %!test -%! charset = setstr (0:127); +%! charset = char (0:127); %! result = charset; -%! result ((toascii("a"):toascii("z"))+1) \ -%! = result ((toascii("A"):toascii("Z"))+1); -%! assert(all (toupper (charset) == result)); +%! result(toascii ("a":"z") + 1) = result(toascii ("A":"Z") + 1); +%! assert (all (toupper (charset) == result)); + +%!error <Invalid call to toupper> toupper() +%!error <Invalid call to toupper> upper() +%!error toupper (1, 2) */ DEFALIAS (gammaln, lgamma);
--- a/src/oct-errno.cc.in +++ b/src/oct-errno.cc.in @@ -27,6 +27,8 @@ #include <cerrno> +#include "singleton-cleanup.h" + #include "oct-errno.h" #include "oct-map.h" #include "error.h" @@ -292,7 +294,12 @@ bool retval = true; if (! instance) - instance = new octave_errno (); + { + instance = new octave_errno (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) {
--- a/src/oct-errno.h +++ b/src/oct-errno.h @@ -43,6 +43,8 @@ static bool instance_ok (void); + static void cleanup_instance (void) { delete instance; instance = 0; } + static int lookup (const std::string& name); static octave_scalar_map list (void);
--- a/src/oct-hist.cc +++ b/src/oct-hist.cc @@ -734,6 +734,7 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} history_timestamp_format_string ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} history_timestamp_format_string (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} history_timestamp_format_string (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the format string\n\ for the comment line that is written to the history file when Octave\n\ exits. The format string is passed to @code{strftime}. The default\n\ @@ -742,6 +743,10 @@ @example\n\ \"# Octave VERSION, %a %b %d %H:%M:%S %Y %Z <USER@@HOST>\"\n\ @end example\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{strftime, history_file, history_size, saving_history}\n\ @end deftypefn") { @@ -752,8 +757,13 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} saving_history ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} saving_history (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} saving_history (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether commands entered\n\ on the command line are saved in the history file.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{history_control, history_file, history_size, history_timestamp_format_string}\n\ @end deftypefn") {
--- a/src/oct-map.cc +++ b/src/oct-map.cc @@ -755,14 +755,19 @@ // Try the fast case. bool all_same = true; - for (octave_idx_type i = 0; i < n; i++) + + if (nf > 0) { - all_same = map_list[idx].xkeys.is_same (map_list[i].xkeys); - if (! all_same) - break; + for (octave_idx_type i = 0; i < n; i++) + { + all_same = map_list[idx].xkeys.is_same (map_list[i].xkeys); + + if (! all_same) + break; + } } - if (all_same) + if (all_same && nf > 0) do_cat (dim, n, map_list, retval); else {
--- a/src/oct-map.h +++ b/src/oct-map.h @@ -53,8 +53,8 @@ static fields_rep *nil_rep (void) { - static fields_rep *nr = new fields_rep (); - return nr; + static fields_rep nr; + return &nr; } public: @@ -73,8 +73,12 @@ { if (rep->count > 1) { - --rep->count; - rep = new fields_rep (*rep); + fields_rep *r = new fields_rep (*rep); + + if (--rep->count == 0) + delete rep; + + rep = r; } }
--- a/src/oct-parse.yy +++ b/src/oct-parse.yy @@ -3565,7 +3565,11 @@ int status = yyparse (); - delete global_command; + // Use an unwind-protect cleanup function so that the + // global_command list will be deleted in the event of an + // interrupt. + + frame.add_fcn (cleanup_statement_list, &global_command); fcn_ptr = primary_fcn_ptr; @@ -4345,6 +4349,14 @@ { if (command_list) { + unwind_protect inner_frame; + + // Use an unwind-protect cleanup function so that the + // global_command list will be deleted in the event of an + // interrupt. + + inner_frame.add_fcn (cleanup_statement_list, &command_list); + tree_statement *stmt = 0; if (command_list->length () == 1 @@ -4381,10 +4393,6 @@ else error ("eval: invalid use of statement list"); - delete command_list; - - command_list = 0; - if (error_state || tree_return_command::returning || tree_break_command::breaking @@ -4428,6 +4436,16 @@ return eval_string (s, silent, parse_status, nargout); } +void +cleanup_statement_list (tree_statement_list **lst) +{ + if (*lst) + { + delete *lst; + *lst = 0; + } +} + DEFUN (eval, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} eval (@var{try}, @var{catch})\n\
--- a/src/oct-stream.cc +++ b/src/oct-stream.cc @@ -40,8 +40,9 @@ #include "lo-ieee.h" #include "lo-mappers.h" #include "lo-utils.h" +#include "quit.h" +#include "singleton-cleanup.h" #include "str-vec.h" -#include "quit.h" #include "error.h" #include "gripes.h" @@ -3916,7 +3917,12 @@ bool retval = true; if (! instance) - instance = new octave_stream_list (); + { + instance = new octave_stream_list (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) { @@ -4175,9 +4181,9 @@ { retval.resize (3); - retval(0) = os.name (); + retval(2) = oct_mach_info::float_format_as_string (os.float_format ()); retval(1) = octave_stream::mode_as_string (os.mode ()); - retval(2) = oct_mach_info::float_format_as_string (os.float_format ()); + retval(0) = os.name (); } else ::error ("invalid file id = %d", fid);
--- a/src/oct-stream.h +++ b/src/oct-stream.h @@ -37,6 +37,7 @@ #include "data-conv.h" #include "lo-utils.h" #include "mach-info.h" +#include "oct-refcount.h" class OCTINTERP_API @@ -427,7 +428,7 @@ private: // A reference count. - octave_idx_type count; + octave_refcount<octave_idx_type> count; // The permission bits for the file. Should be some combination of // std::ios::open_mode bits. @@ -689,6 +690,8 @@ static octave_stream_list *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + int do_insert (octave_stream& os); octave_stream do_lookup (int fid, const std::string& who = std::string ()) const;
--- a/src/ov-base.cc +++ b/src/ov-base.cc @@ -1530,6 +1530,7 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} sparse_auto_mutate ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} sparse_auto_mutate (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} sparse_auto_mutate (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether Octave will\n\ automatically mutate sparse matrices to real matrices to save memory.\n\ For example:\n\ @@ -1547,6 +1548,10 @@ @result{} matrix\n\ @end group\n\ @end example\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (sparse_auto_mutate);
--- a/src/ov-base.h +++ b/src/ov-base.h @@ -167,9 +167,9 @@ const std::string t::c_name (c); \ void t::register_type (void) \ { \ - t_id = octave_value_typeinfo::register_type (t::t_name, \ - t::c_name, \ - octave_value (new t ())); \ + static t exemplar; \ + octave_value v (&exemplar, true); \ + t_id = octave_value_typeinfo::register_type (t::t_name, t::c_name, v); \ } // A base value type, so that derived types only have to redefine what
new file mode 100644 --- /dev/null +++ b/src/ov-oncleanup.cc @@ -0,0 +1,227 @@ +/* + +Copyright (C) 2010-2011 VZLU Prague + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "defun.h" +#include "ov-oncleanup.h" +#include "ov-fcn.h" +#include "ov-usr-fcn.h" +#include "pt-misc.h" +#include "toplev.h" + +DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_oncleanup, "onCleanup", + "onCleanup"); + +octave_oncleanup::octave_oncleanup (const octave_value& f) + : fcn (f) +{ + if (f.is_function_handle ()) + { + octave_function *fptr = f.function_value (true); + if (fptr) + { + octave_user_function *uptr + = dynamic_cast<octave_user_function *> (fptr); + + if (uptr != 0) + { + tree_parameter_list *pl = uptr->parameter_list (); + + if (pl != 0 && pl->length () > 0) + warning ("onCleanup: cleanup action takes parameters"); + } + } + else + error ("onCleanup: no default dispatch for function handle"); + } + else + { + fcn = octave_value (); + error ("onCleanup: argument must be a function handle"); + } +} + +octave_oncleanup::~octave_oncleanup (void) +{ + if (fcn.is_undefined ()) + return; + + unwind_protect frame; + + // Clear interrupts. + frame.protect_var (octave_interrupt_state); + octave_interrupt_state = 0; + + // Disallow quit(). + frame.protect_var (quit_allowed); + quit_allowed = false; + + // Clear errors. + frame.protect_var (error_state); + error_state = 0; + + try + { + // Run the actual code. + fcn.do_multi_index_op (0, octave_value_list ()); + } + catch (octave_interrupt_exception) + { + // Swallow the interrupt. + warning ("onCleanup: interrupt occured in cleanup action"); + } + catch (std::bad_alloc) + { + // Swallow the exception. + warning ("onCleanup: out of memory occured in cleanup action"); + } + catch (...) // Yes, the black hole. We're in a d-tor. + { + // This shouldn't happen, in theory. + error ("onCleanup: internal error: unhandled exception in cleanup action"); + } + + // We don't want to ignore errors that occur in the cleanup code, so + // if an error is encountered there, leave error_state alone. + // Otherwise, set it back to what it was before. + if (error_state) + { + frame.discard_top (); + octave_call_stack::backtrace_error_message (); + } +} + +octave_scalar_map +octave_oncleanup::scalar_map_value (void) const +{ + octave_scalar_map retval; + retval.setfield ("task", fcn); + return retval; +} + +static void +warn_save_load (void) +{ + warning ("onCleanup: load and save not supported"); +} + +bool +octave_oncleanup::save_ascii (std::ostream& /* os */) +{ + warn_save_load (); + return true; +} + +bool +octave_oncleanup::load_ascii (std::istream& /* is */) +{ + warn_save_load (); + return true; +} + +bool +octave_oncleanup::save_binary (std::ostream& /* os */, bool& /* save_as_floats */) +{ + warn_save_load (); + return true; +} + +bool +octave_oncleanup::load_binary (std::istream& /* is */, bool /* swap */, + oct_mach_info::float_format /* fmt */) +{ + warn_save_load (); + return true; +} + +#if defined (HAVE_HDF5) +bool +octave_oncleanup::save_hdf5 (hid_t /* loc_id */, const char * /* name */, + bool /* save_as_floats */) +{ + warn_save_load (); + return true; +} + +bool +octave_oncleanup::load_hdf5 (hid_t /* loc_id */, const char * /* name */) +{ + warn_save_load (); + return true; +} +#endif + +void +octave_oncleanup::print (std::ostream& os, bool pr_as_read_syntax) const +{ + print_raw (os, pr_as_read_syntax); + newline (os); +} + +void +octave_oncleanup::print_raw (std::ostream& os, bool pr_as_read_syntax) const +{ + os << "onCleanup ("; + if (fcn.is_defined ()) + fcn.print_raw (os, pr_as_read_syntax); + os << ")"; +} + +DEFUN (onCleanup, args, , + "-*- texinfo -*-\n\ +@deftypefn {Loadable Function} {@var{c} =} onCleanup (@var{action})\n\ +Create a special object that executes a given function upon destruction.\n\ +If the object is copied to multiple variables (or cell or struct array\n\ +elements) or returned from a function, @var{action} will be executed after\n\ +clearing the last copy of the object. Note that if multiple local onCleanup\n\ +variables are created, the order in which they are called is unspecified.\n\ +For similar functionality @xref{The @code{unwind_protect} Statement}.\n\ +@end deftypefn") +{ + octave_value retval; + + if (args.length () == 1) + retval = octave_value (new octave_oncleanup (args(0))); + else + print_usage (); + + return retval; +} + +/* + +%!test +%! old_wstate = warning ("query"); +%! unwind_protect +%! trigger = onCleanup (@() warning ("on", "__MY_WARNING__")); +%! warning ("off", "__MY_WARNING__"); +%! assert ((warning ("query", "__MY_WARNING__")).state, "off"); +%! clear trigger +%! assert ((warning ("query", "__MY_WARNING__")).state, "on"); +%! unwind_protect_cleanup +%! warning (old_wstate); +%! end_unwind_protect + +*/
new file mode 100644 --- /dev/null +++ b/src/ov-oncleanup.h @@ -0,0 +1,101 @@ +/* + +Copyright (C) 2010-2011 VZLU Prague + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <iosfwd> + +#include "ov-base.h" +#include "ov-struct.h" +#include "ov.h" + +static void +gripe_internal (void) +{ + error ("onCleanup: internal error: cloning nonempty object"); +} + +class octave_oncleanup : public octave_base_value +{ +public: + octave_oncleanup (void) : fcn () { } + + octave_oncleanup (const octave_value& fcn); + + octave_base_value *clone (void) const + { + if (fcn.is_defined ()) + gripe_internal (); + + return empty_clone (); + } + + octave_base_value *empty_clone (void) const + { + return new octave_oncleanup (); + } + + ~octave_oncleanup (void); + + bool is_defined (void) const { return true; } + + bool is_object (void) const { return true; } // do we want this? + + octave_map map_value (void) const { return scalar_map_value (); } + + octave_scalar_map scalar_map_value (void) const; + + dim_vector dims (void) const + { + static dim_vector dv (1, 1); + return dv; + } + + bool save_ascii (std::ostream& os); + + bool load_ascii (std::istream& is); + + bool save_binary (std::ostream& os, bool& save_as_floats); + + bool load_binary (std::istream& is, bool swap, + oct_mach_info::float_format fmt); + +#if defined (HAVE_HDF5) + bool save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats); + + bool load_hdf5 (hid_t loc_id, const char *name); +#endif + + void print (std::ostream& os, bool pr_as_read_syntax = false) const; + + void print_raw (std::ostream& os, bool pr_as_read_syntax = false) const; + +private: + + DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA + +protected: + + octave_value fcn; +};
--- a/src/ov-range.cc +++ b/src/ov-range.cc @@ -649,10 +649,15 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} allow_noninteger_range_as_index ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} allow_noninteger_range_as_index (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} allow_noninteger_range_as_index (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether non-integer\n\ ranges are allowed as indices. This might be useful for @sc{matlab}\n\ compatibility; however, it is still not entirely compatible because\n\ @sc{matlab} treats the range expression differently in different contexts.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (allow_noninteger_range_as_index); @@ -664,7 +669,7 @@ %! save = allow_noninteger_range_as_index (); %! warn_state = warning ("query", "Octave:noninteger-range-as-index"); %! unwind_protect -%! save = allow_noninteger_range_as_index (false); +%! allow_noninteger_range_as_index (false); %! fail ('x(2.1:5)'); %! assert (x(2:5), 1:4); %! allow_noninteger_range_as_index (true);
--- a/src/ov-struct.cc +++ b/src/ov-struct.cc @@ -2216,8 +2216,13 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} struct_levels_to_print ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} struct_levels_to_print (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} struct_levels_to_print (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the number of\n\ structure levels to display.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE_WITH_LIMITS (struct_levels_to_print, @@ -2228,11 +2233,16 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} print_struct_array_contents ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} print_struct_array_contents (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} print_struct_array_contents (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies whether to print struct\n\ array contents. If true, values of struct array elements are printed.\n\ This variable does not affect scalar structures. Their elements\n\ are always printed. In both cases, however, printing will be limited to\n\ the number of levels specified by @var{struct_levels_to_print}.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (print_struct_array_contents);
--- a/src/ov-typeinfo.cc +++ b/src/ov-typeinfo.cc @@ -24,10 +24,12 @@ #include <config.h> #endif -#include "ov-typeinfo.h" +#include "Array.h" +#include "singleton-cleanup.h" #include "defun.h" #include "error.h" +#include "ov-typeinfo.h" const int octave_value_typeinfo::init_tab_sz (16); @@ -35,14 +37,18 @@ octave_value_typeinfo * octave_value_typeinfo::instance (0); -#include <Array.h> - bool octave_value_typeinfo::instance_ok (void) { bool retval = true; + if (! instance) - instance = new octave_value_typeinfo (); + { + instance = new octave_value_typeinfo (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) {
--- a/src/ov-typeinfo.h +++ b/src/ov-typeinfo.h @@ -208,12 +208,16 @@ type_conv_ops (dim_vector (init_tab_sz, init_tab_sz), 0), widening_ops (dim_vector (init_tab_sz, init_tab_sz), 0) { } + ~octave_value_typeinfo (void) { } + private: static const int init_tab_sz; static octave_value_typeinfo *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + int num_types; Array<std::string> types;
--- a/src/ov-usr-fcn.cc +++ b/src/ov-usr-fcn.cc @@ -775,9 +775,14 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} optimize_subsasgn_calls ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} optimize_subsasgn_calls (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} optimize_subsasgn_calls (@var{new_val}, \"local\")\n\ Query or set the internal flag for subsasgn method call optimizations.\n\ If true, Octave will attempt to eliminate the redundant copying when calling\n\ subsasgn method of a user-defined class.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (optimize_subsasgn_calls);
--- a/src/ov.cc +++ b/src/ov.cc @@ -65,6 +65,7 @@ #include "ov-range.h" #include "ov-struct.h" #include "ov-class.h" +#include "ov-oncleanup.h" #include "ov-cs-list.h" #include "ov-colon.h" #include "ov-builtin.h" @@ -2689,6 +2690,7 @@ octave_null_str::register_type (); octave_null_sq_str::register_type (); octave_lazy_index::register_type (); + octave_oncleanup::register_type (); } DEFUN (sizeof, args, ,
--- a/src/ov.h +++ b/src/ov.h @@ -315,8 +315,12 @@ { if (rep->count > 1) { - --rep->count; - rep = rep->unique_clone (); + octave_base_value *r = rep->unique_clone (); + + if (--rep->count == 0) + delete rep; + + rep = r; } } @@ -327,8 +331,12 @@ { if (rep->count > obsolete_copies + 1) { - --rep->count; - rep = rep->unique_clone (); + octave_base_value *r = rep->unique_clone (); + + if (--rep->count == 0) + delete rep; + + rep = r; } }
--- a/src/pager.cc +++ b/src/pager.cc @@ -30,16 +30,16 @@ #include "cmd-edit.h" #include "oct-env.h" +#include "singleton-cleanup.h" -#include "procstream.h" - -#include <defaults.h> +#include "defaults.h" #include "defun.h" #include "error.h" #include "gripes.h" #include "input.h" #include "oct-obj.h" #include "pager.h" +#include "procstream.h" #include "sighandlers.h" #include "unwind-prot.h" #include "utils.h" @@ -311,27 +311,24 @@ delete pb; } -octave_pager_stream& +std::ostream& octave_pager_stream::stream (void) { - if (! instance) - instance = new octave_pager_stream (); - - return *instance; + return instance_ok () ? *instance : std::cout; } void octave_pager_stream::flush_current_contents_to_diary (void) { - if (pb) - pb->flush_current_contents_to_diary (); + if (instance_ok ()) + instance->do_flush_current_contents_to_diary (); } void octave_pager_stream::set_diary_skip (void) { - if (pb) - pb->set_diary_skip (); + if (instance_ok ()) + instance->do_set_diary_skip (); } // Reinitialize the pager buffer to avoid hanging on to large internal @@ -342,10 +339,22 @@ void octave_pager_stream::reset (void) { - if (! instance) - instance = new octave_pager_stream (); + if (instance_ok ()) + instance->do_reset (); +} - instance->do_reset (); +void +octave_pager_stream::do_flush_current_contents_to_diary (void) +{ + if (pb) + pb->flush_current_contents_to_diary (); +} + +void +octave_pager_stream::do_set_diary_skip (void) +{ + if (pb) + pb->set_diary_skip (); } void @@ -357,6 +366,29 @@ setf (unitbuf); } +bool +octave_pager_stream::instance_ok (void) +{ + bool retval = true; + + if (! instance) + { + instance = new octave_pager_stream (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } + + if (! instance) + { + ::error ("unable to create pager_stream object!"); + + retval = false; + } + + return retval; +} + octave_diary_stream *octave_diary_stream::instance = 0; octave_diary_stream::octave_diary_stream (void) : std::ostream (0), db (0) @@ -372,13 +404,10 @@ delete db; } -octave_diary_stream& +std::ostream& octave_diary_stream::stream (void) { - if (! instance) - instance = new octave_diary_stream (); - - return *instance; + return instance_ok () ? *instance : std::cout; } // Reinitialize the diary buffer to avoid hanging on to large internal @@ -389,10 +418,8 @@ void octave_diary_stream::reset (void) { - if (! instance) - instance = new octave_diary_stream (); - - instance->do_reset (); + if (instance_ok ()) + instance->do_reset (); } void @@ -404,6 +431,29 @@ setf (unitbuf); } +bool +octave_diary_stream::instance_ok (void) +{ + bool retval = true; + + if (! instance) + { + instance = new octave_diary_stream (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } + + if (! instance) + { + ::error ("unable to create diary_stream object!"); + + retval = false; + } + + return retval; +} + void flush_octave_stdout (void) { @@ -437,7 +487,7 @@ // // will do the right thing. - octave_stdout.flush_current_contents_to_diary (); + octave_pager_stream::flush_current_contents_to_diary (); if (external_diary_file.is_open ()) { @@ -454,7 +504,7 @@ // If there is pending output in the pager buf, it should not go // into the diary file. - octave_stdout.set_diary_skip (); + octave_pager_stream::set_diary_skip (); external_diary_file.open (diary_file.c_str (), std::ios::app); @@ -590,11 +640,16 @@ DEFUN (page_output_immediately, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} page_output_immediately ()\n\ -@deftypefnx {Built-in Function} {@var{val} =} page_output_immediately (@var{new_val})\n\ +@deftypefnx {Built-in Function} {@var{old_val} =} page_output_immediately (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} page_output_immediately (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether Octave sends\n\ output to the pager as soon as it is available. Otherwise, Octave\n\ buffers its output and waits until just before the prompt is printed to\n\ flush it to the pager.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (page_output_immediately); @@ -604,11 +659,16 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} page_screen_output ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} page_screen_output (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} page_screen_output (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether output intended\n\ for the terminal window that is longer than one page is sent through a\n\ pager. This allows you to view one screenful at a time. Some pagers\n\ (such as @code{less}---see @ref{Installation}) are also capable of moving\n\ backward on the output.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (page_screen_output); @@ -618,11 +678,16 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} PAGER ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} PAGER (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} PAGER (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the program to use\n\ to display terminal output on your system. The default value is\n\ normally @code{\"less\"}, @code{\"more\"}, or\n\ @code{\"pg\"}, depending on what programs are installed on your system.\n\ @xref{Installation}.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{more, page_screen_output, page_output_immediately, PAGER_FLAGS}\n\ @end deftypefn") { @@ -633,8 +698,13 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} PAGER_FLAGS ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} PAGER_FLAGS (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} PAGER_FLAGS (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the options to pass\n\ to the pager.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{PAGER}\n\ @end deftypefn") {
--- a/src/pager.h +++ b/src/pager.h @@ -62,20 +62,28 @@ ~octave_pager_stream (void); - void flush_current_contents_to_diary (void); + static void flush_current_contents_to_diary (void); - void set_diary_skip (void); + static void set_diary_skip (void); - static octave_pager_stream& stream (void); + static std::ostream& stream (void); static void reset (void); private: + void do_flush_current_contents_to_diary (void); + + void do_set_diary_skip (void); + void do_reset (void); static octave_pager_stream *instance; + static bool instance_ok (void); + + static void cleanup_instance (void) { delete instance; instance = 0; } + octave_pager_buf *pb; // No copying! @@ -110,7 +118,7 @@ ~octave_diary_stream (void); - static octave_diary_stream& stream (void); + static std::ostream& stream (void); static void reset (void); @@ -120,6 +128,10 @@ static octave_diary_stream *instance; + static bool instance_ok (void); + + static void cleanup_instance (void) { delete instance; instance = 0; } + octave_diary_buf *db; // No copying!
--- a/src/parse.h +++ b/src/parse.h @@ -36,6 +36,7 @@ class tree; class tree_matrix; class tree_identifier; +class tree_statement_list; class octave_function; #include "oct-obj.h" @@ -113,4 +114,6 @@ extern OCTINTERP_API octave_value eval_string (const std::string&, bool silent, int& parse_status); +extern OCTINTERP_API void cleanup_statement_list (tree_statement_list **lst); + #endif
--- a/src/pr-output.cc +++ b/src/pr-output.cc @@ -3952,6 +3952,7 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} fixed_point_format ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} fixed_point_format (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} fixed_point_format (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether Octave will\n\ use a scaled format to print matrix values such that the largest\n\ element may be written with a single leading digit with the scaling\n\ @@ -3976,6 +3977,10 @@ Notice that first value appears to be zero when it is actually 1. For\n\ this reason, you should be careful when setting\n\ @code{fixed_point_format} to a nonzero value.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{format, output_max_field_width, output_precision}\n\ @end deftypefn") { @@ -3986,6 +3991,7 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} print_empty_dimensions ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} print_empty_dimensions (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} print_empty_dimensions (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether the\n\ dimensions of empty matrices are printed along with the empty matrix\n\ symbol, @samp{[]}. For example, the expression\n\ @@ -4000,6 +4006,10 @@ @example\n\ ans = [](3x0)\n\ @end example\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{format}\n\ @end deftypefn") { @@ -4010,6 +4020,7 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} split_long_rows ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} split_long_rows (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} split_long_rows (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether rows of a matrix\n\ may be split when displayed to a terminal window. If the rows are split,\n\ Octave will display the matrix in a series of smaller pieces, each of\n\ @@ -4033,6 +4044,10 @@ 0.44672 0.94303 0.56564 0.82150\n\ @end group\n\ @end example\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{format}\n\ @end deftypefn") { @@ -4043,8 +4058,13 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} output_max_field_width ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} output_max_field_width (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} output_max_field_width (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the maximum width\n\ of a numeric output field.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{format, fixed_point_format, output_precision}\n\ @end deftypefn") { @@ -4055,8 +4075,13 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} output_precision ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} output_precision (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} output_precision (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the minimum number of\n\ significant figures to display for numeric output.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{format, fixed_point_format, output_max_field_width}\n\ @end deftypefn") {
--- a/src/pt-assign.cc +++ b/src/pt-assign.cc @@ -73,7 +73,7 @@ "debug_on_interrupt", "debug_on_warning", "debug_symtab_lookups", - "default_save_format", + "default_save_options", "echo_executing_commands", "fixed_point_format", "gnuplot_binary",
--- a/src/pt-binop.cc +++ b/src/pt-binop.cc @@ -282,6 +282,7 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} do_braindead_shortcircuit_evaluation ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} do_braindead_shortcircuit_evaluation (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} do_braindead_shortcircuit_evaluation (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether Octave will\n\ do short-circuit evaluation of @samp{|} and @samp{&} operators inside the\n\ conditions of if or while statements.\n\ @@ -291,6 +292,10 @@ \n\ To obtain short-circuit behavior for logical expressions in new programs,\n\ you should always use the @samp{&&} and @samp{||} operators.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (do_braindead_shortcircuit_evaluation);
--- a/src/pt-const.cc +++ b/src/pt-const.cc @@ -34,8 +34,7 @@ // We are likely to have a lot of tree_constant objects to allocate, // so make the grow_size large. -octave_allocator -tree_constant::allocator (sizeof (tree_constant), 1024); +DEFINE_OCTAVE_ALLOCATOR2 (tree_constant, 1024); void tree_constant::print (std::ostream& os, bool pr_as_read_syntax, bool pr_orig_text)
--- a/src/pt-const.h +++ b/src/pt-const.h @@ -55,10 +55,6 @@ bool has_magic_end (void) const { return false; } - void *operator new (size_t size) { return allocator.alloc (size); } - - void operator delete (void *p, size_t size) { allocator.free (p, size); } - // Type. It would be nice to eliminate the need for this. bool is_constant (void) const { return true; } @@ -91,9 +87,6 @@ private: - // For custom memory management. - static octave_allocator allocator; - // The actual value that this constant refers to. octave_value val; @@ -105,6 +98,8 @@ tree_constant (const tree_constant&); tree_constant& operator = (const tree_constant&); + + DECLARE_OCTAVE_ALLOCATOR }; #endif
--- a/src/pt-eval.cc +++ b/src/pt-eval.cc @@ -323,7 +323,6 @@ octave_idx_type steps = rng.nelem (); double b = rng.base (); double increment = rng.inc (); - bool quit = false; for (octave_idx_type i = 0; i < steps; i++) { @@ -363,8 +362,6 @@ // A matrix or cell is reshaped to 2 dimensions and iterated by // columns. - bool quit = false; - dim_vector dv = rhs.dims ().redim (2); octave_idx_type nrows = dv(0), steps = dv(1); @@ -1196,9 +1193,14 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} max_recursion_depth ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} max_recursion_depth (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} max_recursion_depth (@var{new_val}, \"local\")\n\ Query or set the internal limit on the number of times a function may\n\ be called recursively. If the limit is exceeded, an error message is\n\ printed and control returns to the top level.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (max_recursion_depth); @@ -1219,10 +1221,15 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} silent_functions ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} silent_functions (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} silent_functions (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether internal\n\ output from a function is suppressed. If this option is disabled,\n\ Octave will display the results produced by evaluating expressions\n\ within a function body that are not terminated with a semicolon.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (silent_functions);
--- a/src/pt-idx.cc +++ b/src/pt-idx.cc @@ -113,6 +113,13 @@ delete *p; args.erase (p); } + + while (! dyn_field.empty ()) + { + std::list<tree_expression *>::iterator p = dyn_field.begin (); + delete *p; + dyn_field.erase (p); + } } bool
--- a/src/pt-loop.cc +++ b/src/pt-loop.cc @@ -91,6 +91,7 @@ tree_simple_for_command::~tree_simple_for_command (void) { + delete lhs; delete expr; delete maxproc; delete list; @@ -119,6 +120,7 @@ tree_complex_for_command::~tree_complex_for_command (void) { + delete lhs; delete expr; delete list; delete lead_comm;
--- a/src/pt-mat.cc +++ b/src/pt-mat.cc @@ -1391,6 +1391,7 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} string_fill_char ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} string_fill_char (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} string_fill_char (@var{new_val}, \"local\")\n\ Query or set the internal variable used to pad all rows of a character\n\ matrix to the same length. It must be a single character. The default\n\ value is @code{\" \"} (a single space). For example:\n\ @@ -1404,6 +1405,10 @@ \"strings\"\n\ @end group\n\ @end example\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (string_fill_char);
--- a/src/sighandlers.cc +++ b/src/sighandlers.cc @@ -35,6 +35,7 @@ #include "cmd-edit.h" #include "oct-syscalls.h" #include "quit.h" +#include "singleton-cleanup.h" #include "debug.h" #include "defun.h" @@ -804,7 +805,12 @@ bool retval = true; if (! instance) - instance = new octave_child_list_rep (); + { + instance = new octave_child_list_rep (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) { @@ -955,10 +961,15 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} debug_on_interrupt ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} debug_on_interrupt (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} debug_on_interrupt (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether Octave will try\n\ to enter debugging mode when it receives an interrupt signal (typically\n\ generated with @kbd{C-c}). If a second interrupt signal is received\n\ before reaching the debugging mode, a normal interrupt will occur.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (debug_on_interrupt); @@ -979,9 +990,14 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} sighup_dumps_octave_core ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} sighup_dumps_octave_core (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} sighup_dumps_octave_core (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether Octave tries\n\ to save all current variables to the file \"octave-core\" if it receives\n\ a hangup signal.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (sighup_dumps_octave_core); @@ -1002,9 +1018,14 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} sigterm_dumps_octave_core ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} sigterm_dumps_octave_core (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} sigterm_dumps_octave_core (@var{new_val}, \"local\")\n\ Query or set the internal variable that controls whether Octave tries\n\ to save all current variables to the file \"octave-core\" if it receives\n\ a terminate signal.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (sigterm_dumps_octave_core);
--- a/src/sighandlers.h +++ b/src/sighandlers.h @@ -170,6 +170,8 @@ static bool instance_ok (void); static octave_child_list_rep *instance; + + static void cleanup_instance (void) { delete instance; instance = 0; } }; #endif
--- a/src/sparse.cc +++ b/src/sparse.cc @@ -177,7 +177,7 @@ if (! error_state && (m < 0 || n < 0)) - error ("sparse: dimensions must be nonnegative"); + error ("sparse: dimensions must be non-negative"); } else if (nargin != 3) print_usage ();
--- a/src/symtab.cc +++ b/src/symtab.cc @@ -25,24 +25,25 @@ #include <config.h> #endif +#include "file-ops.h" +#include "file-stat.h" #include "oct-env.h" #include "oct-time.h" -#include "file-ops.h" -#include "file-stat.h" +#include "singleton-cleanup.h" +#include "debug.h" #include "defun.h" #include "dirfns.h" #include "input.h" #include "load-path.h" -#include "symtab.h" #include "ov-fcn.h" #include "ov-usr-fcn.h" #include "pager.h" #include "parse.h" #include "pt-arg-list.h" +#include "symtab.h" #include "unwind-prot.h" #include "utils.h" -#include "debug.h" symbol_table *symbol_table::instance = 0; @@ -70,6 +71,14 @@ static int Vignore_function_time_stamp = 1; void +symbol_table::scope_id_cache::create_instance (void) +{ + instance = new scope_id_cache (); + + singleton_cleanup_list::add (cleanup_instance); +} + +void symbol_table::symbol_record::symbol_record_rep::dump (std::ostream& os, const std::string& prefix) const {
--- a/src/symtab.h +++ b/src/symtab.h @@ -31,12 +31,13 @@ #include <string> #include "glob-match.h" -#include "regex-match.h" +#include "regexp.h" class tree_argument_list; class octave_user_function; #include "oct-obj.h" +#include "oct-refcount.h" #include "ov.h" class @@ -81,12 +82,14 @@ return instance_ok () ? instance->do_scopes () : std::list<scope_id> (); } + static void create_instance (void); + static bool instance_ok (void) { bool retval = true; if (! instance) - instance = new scope_id_cache (); + create_instance (); if (! instance) { @@ -108,6 +111,8 @@ static scope_id_cache *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + // The next available scope not in the free list. scope_id next_available; @@ -383,7 +388,7 @@ fcn_info *finfo; - size_t count; + octave_refcount<size_t> count; private: @@ -724,7 +729,7 @@ octave_value built_in_function; - size_t count; + octave_refcount<size_t> count; private: @@ -1679,7 +1684,7 @@ { std::list<symbol_record> retval; - regex_match pat (pattern); + ::regexp pat (pattern); for (global_table_const_iterator p = global_table.begin (); p != global_table.end (); p++) @@ -1688,7 +1693,7 @@ // the results from regexp_variables and regexp_global_variables // may be handled the same way. - if (pat.match (p->first)) + if (pat.is_match (p->first)) retval.push_back (symbol_record (p->first, p->second, symbol_record::global)); } @@ -2310,7 +2315,7 @@ void do_clear_variable_regexp (const std::string& pat) { - regex_match pattern (pat); + ::regexp pattern (pat); for (table_iterator p = table.begin (); p != table.end (); p++) { @@ -2318,7 +2323,7 @@ if (sr.is_defined () || sr.is_global ()) { - if (pattern.match (sr.name ())) + if (pattern.is_match (sr.name ())) sr.clear (); } } @@ -2385,11 +2390,11 @@ { std::list<symbol_record> retval; - regex_match pat (pattern); + ::regexp pat (pattern); for (table_const_iterator p = table.begin (); p != table.end (); p++) { - if (pat.match (p->first)) + if (pat.is_match (p->first)) { const symbol_record& sr = p->second;
--- a/src/syscalls.cc +++ b/src/syscalls.cc @@ -145,8 +145,8 @@ int status = octave_syscalls::dup2 (i_old, i_new, msg); + retval(1) = msg; retval(0) = status; - retval(1) = msg; } } } @@ -224,8 +224,8 @@ int status = octave_syscalls::execvp (exec_file, exec_args, msg); + retval(1) = msg; retval(0) = status; - retval(1) = msg; } } else @@ -347,9 +347,9 @@ Cell file_ids (1, 2); - retval(0) = octave_stream_list::insert (os); + retval(2) = pid; retval(1) = octave_stream_list::insert (is); - retval(2) = pid; + retval(0) = octave_stream_list::insert (os); } else error (msg.c_str ()); @@ -496,8 +496,8 @@ int status = octave_fcntl (fid, req, arg, msg); + retval(1) = msg; retval(0) = status; - retval(1) = msg; } } } @@ -546,8 +546,8 @@ pid_t pid = octave_syscalls::fork (msg); + retval(1) = msg; retval(0) = pid; - retval(1) = msg; } else print_usage (); @@ -572,8 +572,8 @@ { std::string msg; + retval(1) = msg; retval(0) = octave_syscalls::getpgrp (msg); - retval(1) = msg; } else print_usage (); @@ -865,10 +865,9 @@ octave_stream os = octave_stdiostream::create (nm, ofile, std::ios::out); + retval(2) = status; retval(1) = octave_stream_list::insert (os); retval(0) = octave_stream_list::insert (is); - - retval(2) = status; } } else @@ -1270,8 +1269,8 @@ int status = octave_unlink (name, msg); + retval(1) = msg; retval(0) = status; - retval(1) = msg; } else error ("unlink: FILE must be a string"); @@ -1354,9 +1353,9 @@ pid_t result = octave_syscalls::waitpid (pid, &status, options, msg); - retval(0) = result; + retval(2) = msg; retval(1) = status; - retval(2) = msg; + retval(0) = result; } else error ("waitpid: OPTIONS must be an integer");
--- a/src/sysdep.cc +++ b/src/sysdep.cc @@ -896,7 +896,7 @@ %! setenv ("HOME", "foobar"); %! endif %! home = getenv ("HOME"); -%! assert (tilde_expand ("~/foobar"), [home filesep() "foobar"]); +%! assert (tilde_expand ("~/foobar"), strcat (home, "/foobar")); %! assert (tilde_expand ("/foo/bar"), "/foo/bar"); %! assert (tilde_expand ("foo/bar"), "foo/bar"); */
--- a/src/toplev.cc +++ b/src/toplev.cc @@ -44,25 +44,27 @@ #include "lo-error.h" #include "lo-mappers.h" #include "oct-env.h" +#include "oct-locbuf.h" #include "quit.h" +#include "singleton-cleanup.h" #include "str-vec.h" -#include "oct-locbuf.h" -#include <defaults.h> +#include "defaults.h" #include "defun.h" #include "error.h" #include "file-io.h" +#include "graphics.h" #include "input.h" #include "lex.h" -#include <oct-conf.h> +#include "oct-conf.h" #include "oct-hist.h" #include "oct-map.h" #include "oct-obj.h" +#include "ov.h" #include "pager.h" #include "parse.h" #include "pathsearch.h" #include "procstream.h" -#include "ov.h" #include "pt-eval.h" #include "pt-jump.h" #include "pt-stmt.h" @@ -73,7 +75,7 @@ #include "unwind-prot.h" #include "utils.h" #include "variables.h" -#include <version.h> +#include "version.h" void (*octave_exit) (int) = ::exit; @@ -97,6 +99,19 @@ octave_call_stack *octave_call_stack::instance = 0; +void +octave_call_stack::create_instance (void) +{ + instance = new octave_call_stack (); + + if (instance) + { + instance->do_push (0, symbol_table::top_scope (), 0); + + singleton_cleanup_list::add (cleanup_instance); + } +} + int octave_call_stack::do_current_line (void) const { @@ -571,11 +586,13 @@ { if (global_command) { - global_command->accept (*current_evaluator); + // Use an unwind-protect cleanup function so that the + // global_command list will be deleted in the event of + // an interrupt. - delete global_command; + frame.add_fcn (cleanup_statement_list, &global_command); - global_command = 0; + global_command->accept (*current_evaluator); octave_quit (); @@ -645,25 +662,6 @@ return retval; } -// Call a function with exceptions handled to avoid problems with -// errors while shutting down. - -#define IGNORE_EXCEPTION(E) \ - catch (E) \ - { \ - std::cerr << "error: ignoring " #E " while preparing to exit" << std::endl; \ - recover_from_exception (); \ - } - -#define SAFE_CALL(F, ARGS) \ - try \ - { \ - F ARGS; \ - } \ - IGNORE_EXCEPTION (octave_interrupt_exception) \ - IGNORE_EXCEPTION (octave_execution_exception) \ - IGNORE_EXCEPTION (std::bad_alloc) - // Fix up things before exiting. void @@ -671,10 +669,19 @@ { do_octave_atexit (); - // Clean up symbol table. - SAFE_CALL (symbol_table::cleanup, ()); + OCTAVE_SAFE_CALL (gh_manager::close_all_figures, ()); + + OCTAVE_SAFE_CALL (gtk_manager::unload_all_toolkits, ()); + + OCTAVE_SAFE_CALL (symbol_table::cleanup, ()); - SAFE_CALL (sysdep_cleanup, ()) + OCTAVE_SAFE_CALL (cleanup_parser, ()); + + OCTAVE_SAFE_CALL (sysdep_cleanup, ()); + + OCTAVE_SAFE_CALL (singleton_cleanup_list::cleanup, ()); + + OCTAVE_SAFE_CALL (octave_chunk_buffer::clear, ()); if (octave_exit) (*octave_exit) (retval == EOF ? 0 : retval); @@ -705,9 +712,13 @@ if (! error_state) { - quitting_gracefully = true; + // Instead of simply calling exit, we simulate an interrupt + // with a request to exit cleanly so that no matter where the + // call to quit occurs, we will run the unwind_protect stack, + // clear the OCTAVE_LOCAL_BUFFER allocations, etc. before + // exiting. - // Simulate interrupt. + quitting_gracefully = true; octave_interrupt_state = -1; @@ -816,8 +827,8 @@ else cmd_status = 127; + retval(1) = output_buf.str (); retval(0) = cmd_status; - retval(1) = output_buf.str (); } else error ("unable to start subprocess for `%s'", cmd_str.c_str ()); @@ -829,31 +840,36 @@ DEFUN (system, args, nargout, "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {[@var{status}, @var{output}]} system (@var{string}, @var{return_output}, @var{type})\n\ -@deftypefnx {Built-in Function} {[@var{status}, @var{output}]} shell_cmd (@var{string}, @var{return_output}, @var{type})\n\ +@deftypefn {Built-in Function} {} system (\"@var{string}\")\n\ +@deftypefnx {Built-in Function} {} system (\"@var{string}\", @var{return_output})\n\ +@deftypefnx {Built-in Function} {} system (\"@var{string}\", @var{return_output}, @var{type})\n\ +@deftypefnx {Built-in Function} {[@var{status}, @var{output}] =} system (@dots{})\n\ Execute a shell command specified by @var{string}.\n\ -If the optional argument @var{type} is @code{\"async\"}, the process\n\ -is started in the background and the process id of the child process\n\ -is returned immediately. Otherwise, the process is started, and\n\ -Octave waits until it exits. If the @var{type} argument is omitted, a\n\ -value of @code{\"sync\"} is assumed.\n\ +If the optional argument @var{type} is \"async\", the process\n\ +is started in the background and the process ID of the child process\n\ +is returned immediately. Otherwise, the child process is started and\n\ +Octave waits until it exits. If the @var{type} argument is omitted, it\n\ +defaults to the value \"sync\".\n\ \n\ -If the optional argument @var{return_output} is true and the subprocess\n\ -is started synchronously, or if @var{system} is called with one input\n\ -argument and one or more output arguments, the output from the command\n\ -is returned. Otherwise, if the subprocess is executed synchronously, its\n\ -output is sent to the standard output. To send the output of a command\n\ -executed with @code{system} through the pager, use a command like\n\ +If @var{system} is called with one or more output arguments, or if the\n\ +optional argument @var{return_output} is true and the subprocess is started\n\ +synchronously, then the output from the command is returned as a variable. \n\ +Otherwise, if the subprocess is executed synchronously, its output is sent\n\ +to the standard output. To send the output of a command executed with\n\ +@code{system} through the pager, use a command like\n\ \n\ @example\n\ -disp (system (cmd, 1));\n\ +@group\n\ +[output, text] = system (\"cmd\");\n\ +disp (text);\n\ +@end group\n\ @end example\n\ \n\ @noindent\n\ or\n\ \n\ @example\n\ -printf (\"%s\\n\", system (cmd, 1));\n\ +printf (\"%s\\n\", nthargout (2, \"system\", \"cmd\"));\n\ @end example\n\ \n\ The @code{system} function can return two values. The first is the\n\ @@ -870,6 +886,7 @@ \n\ For commands run asynchronously, @var{status} is the process id of the\n\ command shell that is started to run the command.\n\ +@seealso{unix, dos}\n\ @end deftypefn") { octave_value_list retval; @@ -1000,20 +1017,16 @@ return retval; } -DEFALIAS (shell_cmd, system); - /* -%!error (system ()); -%!error (system (1, 2, 3)); %!test -%! if (ispc ()) -%! cmd = "dir"; -%! else -%! cmd = "ls"; -%! endif +%! cmd = ls_command (); %! [status, output] = system (cmd); +%! assert (status, 0); %! assert (ischar (output)); %! assert (! isempty (output)); + +%!error system () +%!error system (1, 2, 3) */ // FIXME -- this should really be static, but that causes @@ -1031,11 +1044,11 @@ octave_atexit_functions.pop_front (); - SAFE_CALL (reset_error_handler, ()) + OCTAVE_SAFE_CALL (reset_error_handler, ()); - SAFE_CALL (feval, (fcn, octave_value_list (), 0)) + OCTAVE_SAFE_CALL (feval, (fcn, octave_value_list (), 0)); - SAFE_CALL (flush_octave_stdout, ()) + OCTAVE_SAFE_CALL (flush_octave_stdout, ()); } if (! deja_vu) @@ -1045,23 +1058,23 @@ // Do this explicitly so that destructors for mex file objects // are called, so that functions registered with mexAtExit are // called. - SAFE_CALL (clear_mex_functions, ()) + OCTAVE_SAFE_CALL (clear_mex_functions, ()); - SAFE_CALL (command_editor::restore_terminal_state, ()) + OCTAVE_SAFE_CALL (command_editor::restore_terminal_state, ()); // FIXME -- is this needed? Can it cause any trouble? - SAFE_CALL (raw_mode, (0)) + OCTAVE_SAFE_CALL (raw_mode, (0)); - SAFE_CALL (octave_history_write_timestamp, ()) + OCTAVE_SAFE_CALL (octave_history_write_timestamp, ()); if (! command_history::ignoring_entries ()) - SAFE_CALL (command_history::clean_up_and_save, ()) + OCTAVE_SAFE_CALL (command_history::clean_up_and_save, ()); - SAFE_CALL (close_files, ()) + OCTAVE_SAFE_CALL (close_files, ()); - SAFE_CALL (cleanup_tmp_files, ()) + OCTAVE_SAFE_CALL (cleanup_tmp_files, ()); - SAFE_CALL (flush_octave_stdout, ()) + OCTAVE_SAFE_CALL (flush_octave_stdout, ()); if (! quitting_gracefully && (interactive || forced_interactive)) { @@ -1070,7 +1083,7 @@ // Yes, we want this to be separate from the call to // flush_octave_stdout above. - SAFE_CALL (flush_octave_stdout, ()) + OCTAVE_SAFE_CALL (flush_octave_stdout, ()); } } }
--- a/src/toplev.h +++ b/src/toplev.h @@ -112,22 +112,20 @@ typedef std::deque<call_stack_elt>::reverse_iterator reverse_iterator; typedef std::deque<call_stack_elt>::const_reverse_iterator const_reverse_iterator; + static void create_instance (void); + static bool instance_ok (void) { bool retval = true; if (! instance) - { - instance = new octave_call_stack (); + create_instance (); - if (instance) - instance->do_push (0, symbol_table::top_scope (), 0); - else - { - ::error ("unable to create call stack object!"); + if (! instance) + { + ::error ("unable to create call stack object!"); - retval = false; - } + retval = false; } return retval; @@ -300,6 +298,8 @@ static octave_call_stack *instance; + static void cleanup_instance (void) { delete instance; instance = 0; } + int do_current_line (void) const; int do_current_column (void) const; @@ -418,4 +418,38 @@ void do_backtrace_error_message (void) const; }; +// Call a function with exceptions handled to avoid problems with +// errors while shutting down. + +#define OCTAVE_IGNORE_EXCEPTION(E) \ + catch (E) \ + { \ + std::cerr << "error: ignoring " #E " while preparing to exit" << std::endl; \ + recover_from_exception (); \ + } + +#define OCTAVE_SAFE_CALL(F, ARGS) \ + do \ + { \ + try \ + { \ + unwind_protect frame; \ + \ + frame.protect_var (Vdebug_on_error); \ + frame.protect_var (Vdebug_on_warning); \ + \ + Vdebug_on_error = false; \ + Vdebug_on_warning = false; \ + \ + F ARGS; \ + } \ + OCTAVE_IGNORE_EXCEPTION (octave_interrupt_exception) \ + OCTAVE_IGNORE_EXCEPTION (octave_execution_exception) \ + OCTAVE_IGNORE_EXCEPTION (std::bad_alloc) \ + \ + if (error_state) \ + error_state = 0; \ + } \ + while (0) + #endif
--- a/src/txt-eng-ft.cc +++ b/src/txt-eng-ft.cc @@ -24,14 +24,16 @@ #include <config.h> #endif -#if HAVE_FREETYPE +#if defined (HAVE_FREETYPE) -#if HAVE_FONTCONFIG +#if defined (HAVE_FONTCONFIG) #include <fontconfig/fontconfig.h> #endif #include <iostream> +#include "singleton-cleanup.h" + #include "error.h" #include "pr-output.h" #include "txt-eng-ft.h" @@ -72,7 +74,12 @@ bool retval = true; if (! instance) - instance = new ft_manager (); + { + instance = new ft_manager (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } if (! instance) { @@ -84,6 +91,8 @@ return retval; } + static void cleanup_instance (void) { delete instance; instance = 0; } + static FT_Face get_font (const std::string& name, const std::string& weight, const std::string& angle, double size) { return (instance_ok () @@ -102,37 +111,39 @@ ft_manager& operator = (const ft_manager&); - ft_manager (void) : library () -#if HAVE_FONTCONFIG - , fc_init_done (false) -#endif + ft_manager (void) + : library (), freetype_initialized (false), fontconfig_initialized (false) { if (FT_Init_FreeType (&library)) - { - ::error ("unable to initialize freetype library"); - } + ::error ("unable to initialize freetype library"); + else + freetype_initialized = true; -#if HAVE_FONTCONFIG - fc_init_done = false; +#if defined (HAVE_FONTCONFIG) if (! FcInit ()) - { - ::error ("unable to initialize fontconfig library"); - } + ::error ("unable to initialize fontconfig library"); else - { - fc_init_done = true; - } + fontconfig_initialized = true; #endif } ~ft_manager (void) { -#if HAVE_FONTCONFIG - FcFini (); - fc_init_done = false; + if (freetype_initialized) + FT_Done_FreeType (library); + +#if defined (HAVE_FONTCONFIG) + // FIXME -- Skip the call to FcFini because it can trigger the + // assertion + // + // octave: fccache.c:507: FcCacheFini: Assertion `fcCacheChains[i] == ((void *)0)' failed. + // + // if (fontconfig_initialized) + // FcFini (); #endif } + FT_Face do_get_font (const std::string& name, const std::string& weight, const std::string& angle, double size) { @@ -140,8 +151,8 @@ std::string file; -#if HAVE_FONTCONFIG - if (fc_init_done) +#if defined (HAVE_FONTCONFIG) + if (fontconfig_initialized) { int fc_weight, fc_angle; @@ -218,9 +229,8 @@ private: FT_Library library; -#if HAVE_FONTCONFIG - bool fc_init_done; -#endif + bool freetype_initialized; + bool fontconfig_initialized; }; ft_manager* ft_manager::instance = 0;
--- a/src/utils.cc +++ b/src/utils.cc @@ -36,6 +36,8 @@ #include <sys/types.h> #include <unistd.h> +#include "vasnprintf.h" + #include "quit.h" #include "dir-ops.h" @@ -1194,10 +1196,10 @@ return m; } -int +size_t octave_format (std::ostream& os, const char *fmt, ...) { - int retval = -1; + size_t retval; va_list args; va_start (args, fmt); @@ -1209,123 +1211,43 @@ return retval; } -int +size_t octave_vformat (std::ostream& os, const char *fmt, va_list args) { - int retval = -1; + std::string s = octave_vasprintf (fmt, args); -#if defined (__GNUG__) && !CXX_ISO_COMPLIANT_LIBRARY + os << s; - std::streambuf *sb = os.rdbuf (); + return s.length (); +} - if (sb) - { - BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; +std::string +octave_vasprintf (const char *fmt, va_list args) +{ + std::string retval; + + char *result; - retval = sb->vform (fmt, args); + int status = gnulib::vasprintf (&result, fmt, args); - END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; + if (status >= 0) + { + retval = result; + ::free (result); } -#else - - char *s = octave_vsnprintf (fmt, args); - - if (s) - { - os << s; - - retval = strlen (s); - } - -#endif - return retval; } -// We manage storage. User should not free it, and its contents are -// only valid until next call to vsnprintf. - -// Interrupts might happen if someone makes a call with something that -// will require a very large buffer. If we are interrupted in that -// case, we should make the buffer size smaller for the next call. - -#define BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE_FOR_VSNPRINTF \ - BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE_1; \ - delete [] buf; \ - buf = 0; \ - size = initial_size; \ - octave_rethrow_exception (); \ - BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE_2 - -#if defined __GNUC__ && defined __va_copy -#define SAVE_ARGS(saved_args, args) __va_copy (saved_args, args) -#elif defined va_copy -#define SAVE_ARGS(saved_args, args) va_copy (saved_args, args) -#else -#define SAVE_ARGS(saved_args, args) saved_args = args -#endif - -char * -octave_vsnprintf (const char *fmt, va_list args) +std::string +octave_asprintf (const char *fmt, ...) { - static const size_t initial_size = 100; - - static size_t size = initial_size; - - static char *buf = 0; - - volatile int nchars = 0; - - if (! buf) - buf = new char [size]; - - if (! buf) - return 0; - - while (1) - { - va_list saved_args; - - SAVE_ARGS (saved_args, args); - - BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE_FOR_VSNPRINTF; - - nchars = octave_raw_vsnprintf (buf, size, fmt, saved_args); - - va_end (saved_args); - - END_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; - - // Cast to avoid signed/unsigned comparison is safe due to - // short-circuiting - if (nchars > -1 && static_cast<size_t>(nchars) < size) - break; - else - { - delete [] buf; - - size = nchars + 1;; - - buf = new char [size]; - - if (! buf) - return 0; - } - } - - return buf; -} - -char * -octave_snprintf (const char *fmt, ...) -{ - char *retval = 0; + std::string retval; va_list args; va_start (args, fmt); - retval = octave_vsnprintf (fmt, args); + retval = octave_vasprintf (fmt, args); va_end (args);
--- a/src/utils.h +++ b/src/utils.h @@ -103,15 +103,16 @@ extern OCTINTERP_API FloatMatrix float_identity_matrix (octave_idx_type nr, octave_idx_type nc); -extern OCTINTERP_API int +extern OCTINTERP_API size_t octave_format (std::ostream& os, const char *fmt, ...); -extern OCTINTERP_API int +extern OCTINTERP_API size_t octave_vformat (std::ostream& os, const char *fmt, va_list args); -extern OCTINTERP_API char *octave_vsnprintf (const char *fmt, va_list args); +extern OCTINTERP_API std::string +octave_vasprintf (const char *fmt, va_list args); -extern OCTINTERP_API char *octave_snprintf (const char *fmt, ...); +extern OCTINTERP_API std::string octave_asprintf (const char *fmt, ...); extern OCTINTERP_API void octave_sleep (double seconds);
--- a/src/variables.cc +++ b/src/variables.cc @@ -36,7 +36,7 @@ #include "oct-env.h" #include "file-ops.h" #include "glob-match.h" -#include "regex-match.h" +#include "regexp.h" #include "str-vec.h" #include <defaults.h> @@ -2050,9 +2050,7 @@ { if (have_regexp) { - regex_match pattern (patstr); - - if (pattern.match (nm)) + if (is_regexp_match (patstr, nm)) { retval = true; break; @@ -2462,6 +2460,7 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} whos_line_format ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} whos_line_format (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} whos_line_format (@var{new_val}, \"local\")\n\ Query or set the format string used by the command @code{whos}.\n\ \n\ A full format string is:\n\ @@ -2523,6 +2522,10 @@ \n\ The default format is\n\ @code{\" %a:4; %ln:6; %cs:16:6:1; %rb:12; %lc:-1;\\n\"}.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @seealso{whos}\n\ @end deftypefn") { @@ -2535,8 +2538,13 @@ "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {@var{val} =} missing_function_hook ()\n\ @deftypefnx {Built-in Function} {@var{old_val} =} missing_function_hook (@var{new_val})\n\ +@deftypefnx {Built-in Function} {} missing_function_hook (@var{new_val}, \"local\")\n\ Query or set the internal variable that specifies the function to call when\n\ an unknown identifier is requested.\n\ +\n\ +When called from inside a function with the \"local\" option, the variable is\n\ +changed locally for the function and any subroutines it calls. The original\n\ +variable value is restored when exiting the function.\n\ @end deftypefn") { return SET_INTERNAL_VARIABLE (missing_function_hook);
--- a/src/xpow.cc +++ b/src/xpow.cc @@ -1245,7 +1245,7 @@ if (a_dims != b_dims) { - if (is_valid_bsxfun (a_dims, b_dims)) + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) { //Potentially complex results NDArray xa = octave_value_extract<NDArray> (a); @@ -1333,7 +1333,7 @@ if (a_dims != b_dims) { - if (is_valid_bsxfun (a_dims, b_dims)) + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) { return bsxfun_pow (a, b); } @@ -1432,7 +1432,7 @@ if (a_dims != b_dims) { - if (is_valid_bsxfun (a_dims, b_dims)) + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) { return bsxfun_pow (a, b); } @@ -1482,7 +1482,7 @@ if (a_dims != b_dims) { - if (is_valid_bsxfun (a_dims, b_dims)) + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) { return bsxfun_pow (a, b); } @@ -2598,7 +2598,7 @@ if (a_dims != b_dims) { - if (is_valid_bsxfun (a_dims, b_dims)) + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) { //Potentially complex results FloatNDArray xa = octave_value_extract<FloatNDArray> (a); @@ -2686,7 +2686,7 @@ if (a_dims != b_dims) { - if (is_valid_bsxfun (a_dims, b_dims)) + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) { return bsxfun_pow (a, b); } @@ -2785,7 +2785,7 @@ if (a_dims != b_dims) { - if (is_valid_bsxfun (a_dims, b_dims)) + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) { return bsxfun_pow (a, b); } @@ -2835,7 +2835,7 @@ if (a_dims != b_dims) { - if (is_valid_bsxfun (a_dims, b_dims)) + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) { return bsxfun_pow (a, b); }