# HG changeset patch # User Jordi Gutiérrez Hermoso # Date 1314384010 18000 # Node ID 7df7650492e85245c6653062ad4610af4bb6fd6c # Parent c67f7d390a1a6d1794b43cd8cc0aa09e7e5cee0d# Parent 38b52a073cfaeaafb412368f88a3df76d065c35f Merge with Savannah diff -r c67f7d390a1a -r 7df7650492e8 NEWS --- a/NEWS Thu Aug 25 20:12:31 2011 +0200 +++ b/NEWS Fri Aug 26 13:40:10 2011 -0500 @@ -3,6 +3,10 @@ ** The PCRE library is now required to build Octave. + ** Octave now features a profiler, thanks to the work of Daniel Kraft + under the Google Summer of Code mentorship program. The manual has + been updated to reflect this addition. + ** strread, textscan, and textread have been completely revamped. They now support nearly all Matlab functionality including: @@ -12,12 +16,24 @@ * ML-compatible options: 'whitespace', treatasempty', format string repeat count, user-specified comment style, uneven-length output arrays, %n and %u conversion specifiers (provisionally) + + ** Certain string functions have been modified for greater Matlab compatibility + and for 15X greater performance when operating on cell array of strings. + + deblank : Now requires character or cellstr input + strtrim : Now requires character or cellstr input. + No longer trims nulls ("\0") from string for ML compatibility. + strmatch: Follows documentation precisely and ignores trailing spaces + in pattern and in string. Note that Matlab documents this + behavior but the implementation does *not* always follow it. ** New functions added. iscolumn issrow zscore + profile + profshow ** Deprecated functions. diff -r c67f7d390a1a -r 7df7650492e8 build-aux/bootstrap.conf --- a/build-aux/bootstrap.conf Thu Aug 25 20:12:31 2011 +0200 +++ b/build-aux/bootstrap.conf Fri Aug 26 13:40:10 2011 -0500 @@ -25,6 +25,10 @@ fcntl filemode fnmatch + fopen + fflush + fseek + ftell getcwd gethostname getopt-gnu diff -r c67f7d390a1a -r 7df7650492e8 doc/interpreter/container.txi --- a/doc/interpreter/container.txi Thu Aug 25 20:12:31 2011 +0200 +++ b/doc/interpreter/container.txi Fri Aug 26 13:40:10 2011 -0500 @@ -563,16 +563,11 @@ @example @group c@{1:2@} + @result{} ans = a string @result{} ans = - (, - [1] = a string - [2] = - 0.593993 0.627732 0.377037 0.033643 - - ,) @end group @end example diff -r c67f7d390a1a -r 7df7650492e8 doc/interpreter/contributors.in --- a/doc/interpreter/contributors.in Thu Aug 25 20:12:31 2011 +0200 +++ b/doc/interpreter/contributors.in Fri Aug 26 13:40:10 2011 -0500 @@ -149,6 +149,7 @@ Stefan Monnier Antoine Moreau Kai P. Mueller +Hannes Müller Victor Munoz Carmen Navarrete Todd Neal diff -r c67f7d390a1a -r 7df7650492e8 doc/interpreter/debug.txi --- a/doc/interpreter/debug.txi Thu Aug 25 20:12:31 2011 +0200 +++ b/doc/interpreter/debug.txi Fri Aug 26 13:40:10 2011 -0500 @@ -35,6 +35,8 @@ * Breakpoints:: * Debug Mode:: * Call Stack:: +* Profiling:: +* Profiler Example:: @end menu @node Entering Debug Mode @@ -182,3 +184,256 @@ @DOCSTRING(dbup) @DOCSTRING(dbdown) + +@node Profiling +@section Profiling +@cindex profiler +@cindex code profiling + +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 behaviour, 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. + +The main command for profiling is @code{profile}, which can be used to +start or stop the profiler and also to query collected data afterwards. +The data is returned in an Octave data structure which can then be +examined or further processed by other routines or tools. + +@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{profile} as input and prints a flat profile, for instance: + +@example +@group + Function Attr Time (s) Calls +---------------------------------------- + >myfib R 2.195 13529 +binary <= 0.061 13529 + binary - 0.050 13528 + binary + 0.026 6764 +@end group +@end example + +This shows that most of the runtime 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 +and the profiler also records that it is recursive. + +@DOCSTRING(profshow) + +@node Profiler Example +@section Profiler Example + +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: + +@example +@group +global N A; + +N = 300; +A = rand (N, N); + +function xt = timesteps (steps, x0, expM) + global N; + + if (steps == 0) + xt = NA (N, 0); + else + xt = NA (N, steps); + x1 = expM * x0; + xt(:, 1) = x1; + xt(:, 2 : end) = timesteps (steps - 1, x1, expM); + endif +endfunction + +function foo () + global N A; + + initial = @@(x) sin (x); + x0 = (initial (linspace (0, 2 * pi, N)))'; + + expA = expm (A); + xt = timesteps (100, x0, expA); +endfunction + +function fib = bar (N) + if (N <= 2) + fib = 1; + else + fib = bar (N - 1) + bar (N - 2); + endif +endfunction +@end group +@end example + +If we execute the two main functions, we get: + +@example +@group +tic; foo; toc; +@result{} Elapsed time is 2.37338 seconds. + +tic; bar (20); toc; +@result{} Elapsed time is 2.04952 seconds. +@end group +@end example + +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, +we can use the profiler. + +@example +@group +profile on; +foo; +profile off; + +data = profile ('info'); +profshow (data, 10); +@end group +@end example + +This prints a table like: + +@example +@group + # Function Attr Time (s) Calls +--------------------------------------------- + 7 expm 1.034 1 + 3 binary * 0.823 117 + 41 binary \ 0.188 1 + 38 binary ^ 0.126 2 + 43 timesteps R 0.111 101 + 44 NA 0.029 101 + 39 binary + 0.024 8 + 34 norm 0.011 1 + 40 binary - 0.004 101 + 33 balance 0.003 1 +@end group +@end example + +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 +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 +multiplication operator, but fortunately this operator appears only at +one place in the code and thus we know which occurence takes so much +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 +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 +(@ref{Structure Arrays}) which contains the field @code{FunctionTable}. +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: + +@example +@group + scalar structure containing the fields: + + FunctionName = binary \ + TotalTime = 0.18765 + NumCalls = 1 + IsRecursive = 0 + Parents = 7 + Children = [](1x0) +@end group +@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 +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 +internally by @code{expm}. + +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): + +@example +@group +profile on; +bar (20); +profile off; + +profshow (profile ('info')); +@end group +@end example + +This gives: + +@example + # Function Attr Time (s) Calls +------------------------------------------------------- + 1 bar R 2.091 13529 + 2 binary <= 0.062 13529 + 3 binary - 0.042 13528 + 4 binary + 0.023 6764 + 5 profile 0.000 1 + 8 false 0.000 1 + 6 nargin 0.000 1 + 7 binary != 0.000 1 + 9 __profiler_enable__ 0.000 1 +@end example + +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 runtime 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: + +@example +@group +profile resume; +foo; +profile off; + +profshow (profile ('info'), 10); +@end group +@end example + +As you can see in the table below, now we have both profiles mixed +together. + +@example +@group + # Function Attr Time (s) Calls +--------------------------------------------- + 1 bar R 2.091 13529 + 16 expm 1.122 1 + 12 binary * 0.798 117 + 46 binary \ 0.185 1 + 45 binary ^ 0.124 2 + 48 timesteps R 0.115 101 + 2 binary <= 0.062 13529 + 3 binary - 0.045 13629 + 4 binary + 0.041 6772 + 49 NA 0.036 101 +@end group +@end example diff -r c67f7d390a1a -r 7df7650492e8 doc/interpreter/install.txi --- a/doc/interpreter/install.txi Thu Aug 25 20:12:31 2011 +0200 +++ b/doc/interpreter/install.txi Fri Aug 26 13:40:10 2011 -0500 @@ -32,7 +32,7 @@ under the terms of the GNU General Public License as published by the Free Software Foundation. -@strong{Note:} This file is automatically generated from +@strong{Note}: This file is automatically generated from @file{doc/interpreter/install.txi} in the Octave sources. To update the documentation make changes to the .txi source file rather than this derived file. diff -r c67f7d390a1a -r 7df7650492e8 doc/interpreter/oop.txi --- a/doc/interpreter/oop.txi Thu Aug 25 20:12:31 2011 +0200 +++ b/doc/interpreter/oop.txi Fri Aug 26 13:40:10 2011 -0500 @@ -578,8 +578,8 @@ @item @tab a / b @tab mrdivide (a, b) @tab Matrix right division operator @tab @item @tab a .\ b @tab ldivide (a, b) @tab Element-wise left division operator @tab @item @tab a \ b @tab mldivide (a, b) @tab Matrix left division operator @tab -@item @tab a .^ b @tab ldivide (a, b) @tab Element-wise power operator @tab -@item @tab a ^ b @tab mldivide (a, b) @tab Matrix power operator @tab +@item @tab a .^ b @tab power (a, b) @tab Element-wise power operator @tab +@item @tab a ^ b @tab mpower (a, b) @tab Matrix power operator @tab @item @tab a < b @tab lt (a, b) @tab Less than operator @tab @item @tab a <= b @tab le (a, b) @tab Less than or equal to operator @tab @item @tab a > b @tab gt (a, b) @tab Greater than operator @tab diff -r c67f7d390a1a -r 7df7650492e8 etc/README.MacOS --- a/etc/README.MacOS Thu Aug 25 20:12:31 2011 +0200 +++ b/etc/README.MacOS Fri Aug 26 13:40:10 2011 -0500 @@ -334,67 +334,83 @@ includes a port file for octave-devel. To build and run the most recent development snapshots, enter the commands below. - sudo port selfupdate - sudo port install octave-devel + sudo port selfupdate + sudo port install octave-devel To build the developers sources in one's own way, or if MacPorts' version is outdated, a custom port file can be added. This requires setting up a local port file repository (link below). - http://guide.macports.org/#development.local-repositories + http://guide.macports.org/#development.local-repositories The octave-devel port file may be used as an initial starting point. The port file is accessible from the web at the link below. - http://trac.macports.org/browser/trunk/dports/math/octave-devel/Portfile + http://trac.macports.org/browser/trunk/dports/math/octave-devel/Portfile It is also available locally at the location below. The parameter ${prefix} is corresponds to where MacPorts is install, which by default is "/opt/local". - ${prefix}/var/macports/sources/rsync.macports.org/release/ports/math/octave-devel/Portfile + ${prefix}/var/macports/sources/rsync.macports.org/release/ports/math/octave-devel/Portfile + +If the Portfile is missing the dependencies, epstools, epstoedit, and transfig, +those should be installed manually or added to the Portfile. To install +manually, type the command below. + + sudo port install epstools epstoedit transfig The local source tarball must be placed in the location below, where ${name} and ${distname} are each specified in the port file. - ${prefix}/var/macports/distfiles/${name}/${disname}.tar.gz + ${prefix}/var/macports/distfiles/${name}/${disname}.tar.gz 2.4.2 Building for Active Development of Octave ----------------------------------------------- -To satisfy Octave's dependencies, first install the octave-devel port. - - sudo port selfupdate - sudo port install octave-devel +To satisfy most of Octave's dependencies, first install the octave-devel port. -Next run octave to determine the configure options needed to build Octave -using MacPorts. At Octave's prompt type the command below and make note of -the result, ${config_opts}. - - octave:1> octave_config_info.config_opts + sudo port selfupdate + sudo port install octave-devel Now uninstall the Octave port. - sudo port deactivate octave-devel + sudo port deactivate octave-devel + +This will remove Octave and leave its dependencies in place. Some additional +dependencies may be needed. + + sudo port install epstools epstoedit transfig + +Octave may now be built from a local mercurial archive by typing the commands +below (these assume gcc-4.4 is installed by macports). -This will remove Octave and leave its dependencies in place. Now Octave may -be built from the local mercurial archive by typing the commands below, where -the configure options mentioned above are substituted for the parameter -${config_opts}. If the sources being built are from the mercurial archive, -then ./autogen.sh must be run prior to ./configure. - - ./configure ${config_opts} - make + ./autogen.sh + export PREFIX=/opt/local + export CC=/opt/local/bin/gcc-mp-4.4 + export CXX=/opt/local/bin/g++-mp-4.4 + export CXXCPP="/opt/local/bin/g++-mp-4.4 -E" + export F77=/opt/local/bin/gfortran-mp-4.4 + export FC=/opt/local/bin/gfortran-mp-4.4 + export CXXFLAGS="-pipe -O2 -m64" + export FFLAGS="$CXXFLAGS -D_THREAD_SAFE -pthread" + export CFLAGS="$FFLAGS -lstdc++" + export LDFLAGS=-L$PREFIX/lib + export CPPFLAGS=-I$PREFIX/include + export BLAS_LIBS="-lcblas -lf77blas -latlas" + export LAPACK_LIBS=-llapack + ./configure --prefix="/opt/local" --without-framework-carbon --with-x + make Octave's integrated tests may be run. - make check + make check -However, "make install" should not be run as it may damage or corrupt the -MacPorts installation. To run Octave, type the command below from the root of -the mercurial archive. +"make install" should not be run as it will bypass the macports package +management. To run Octave, type the command below from the root of the +mercurial archive. - ./run-octave + ./run-octave John W. Eaton diff -r c67f7d390a1a -r 7df7650492e8 libgnu/Makefile.am diff -r c67f7d390a1a -r 7df7650492e8 liboctave/MArray.cc --- a/liboctave/MArray.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/MArray.cc Fri Aug 26 13:40:10 2011 -0500 @@ -339,7 +339,7 @@ MArray \ FCN (const MArray& a, const MArray& b) \ { \ - return do_mm_binary_op (a, b, FN, #FCN); \ + return do_mm_binary_op (a, b, FN, FN, FN, #FCN); \ } MARRAY_NDND_OP (operator +, +, mx_inline_add) diff -r c67f7d390a1a -r 7df7650492e8 liboctave/MDiagArray2.cc --- a/liboctave/MDiagArray2.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/MDiagArray2.cc Fri Aug 26 13:40:10 2011 -0500 @@ -82,7 +82,7 @@ { \ if (a.d1 != b.d1 || a.d2 != b.d2) \ gripe_nonconformant (#FCN, a.d1, a.d2, b.d1, b.d2); \ - return MDiagArray2 (do_mm_binary_op (a, b, FN, #FCN), a.d1, a.d2); \ + return MDiagArray2 (do_mm_binary_op (a, b, FN, FN, FN, #FCN), a.d1, a.d2); \ } MARRAY_DADA_OP (operator +, +, mx_inline_add) diff -r c67f7d390a1a -r 7df7650492e8 liboctave/Makefile.am --- a/liboctave/Makefile.am Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/Makefile.am Fri Aug 26 13:40:10 2011 -0500 @@ -188,6 +188,7 @@ base-dae.h \ base-de.h \ base-min.h \ + bsxfun.h \ byte-swap.h \ caseless-str.h \ cmd-edit.h \ diff -r c67f7d390a1a -r 7df7650492e8 liboctave/bsxfun.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/liboctave/bsxfun.h Fri Aug 26 13:40:10 2011 -0500 @@ -0,0 +1,44 @@ +/* + +Copyright (C) 2011 Jordi Gutiérrez Hermoso + +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 +. + +*/ +#if !defined (bsxfun_h) +#define bsxfun_h 1 + +#include + +#include "Array.h" +#include "dim-vector.h" + +inline +bool +is_valid_bsxfun (const dim_vector& dx, const dim_vector& dy) +{ + for (int i = 0; i < std::min (dx.length (), dy.length ()); i++) + { + if ( dx(i) > 1 && dy(i) > 1 && dx(i) != dy(i)) + return false; + } + return true; +} + +#include "bsxfun-defs.cc" + +#endif diff -r c67f7d390a1a -r 7df7650492e8 liboctave/chMatrix.cc --- a/liboctave/chMatrix.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/chMatrix.cc Fri Aug 26 13:40:10 2011 -0500 @@ -74,8 +74,8 @@ elem (0, i) = s[i]; } -charMatrix::charMatrix (const string_vector& s) - : Array (dim_vector (s.length (), s.max_length ()), 0) +charMatrix::charMatrix (const string_vector& s, char fill_value) + : Array (dim_vector (s.length (), s.max_length ()), fill_value) { octave_idx_type nr = rows (); diff -r c67f7d390a1a -r 7df7650492e8 liboctave/chMatrix.h --- a/liboctave/chMatrix.h Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/chMatrix.h Fri Aug 26 13:40:10 2011 -0500 @@ -62,7 +62,7 @@ charMatrix (const std::string& s); - charMatrix (const string_vector& s); + charMatrix (const string_vector& s, char fill_value = '\0'); charMatrix& operator = (const charMatrix& a) { diff -r c67f7d390a1a -r 7df7650492e8 liboctave/dMatrix.cc --- a/liboctave/dMatrix.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/dMatrix.cc Fri Aug 26 13:40:10 2011 -0500 @@ -3111,15 +3111,19 @@ */ /* Test some simple identities -%!shared M, cv, rv -%! M = randn(10,10); +%!shared M, cv, rv, Mt, rvt +%! M = randn(10,10)+100*eye(10,10); +%! Mt = M'; %! cv = randn(10,1); %! rv = randn(1,10); +%! rvt = rv'; %!assert([M*cv,M*cv],M*[cv,cv],1e-14) -%!assert([M'*cv,M'*cv],M'*[cv,cv],1e-14) -%!assert([rv*M;rv*M],[rv;rv]*M,1e-14) -%!assert([rv*M';rv*M'],[rv;rv]*M',1e-14) -%!assert(2*rv*cv,[rv,rv]*[cv;cv],1e-14) +%!assert([M'*cv,M'*cv],M'*[cv,cv],3e-14) +%!assert([rv*M;rv*M],[rv;rv]*M,3e-14) +%!assert([rv*M';rv*M'],[rv;rv]*M',3e-14) +%!assert(2*rv*cv,[rv,rv]*[cv;cv],3e-14) +%!assert(M'\cv,Mt\cv,1e-14) +%!assert(M'\rv',Mt\rvt,1e-14) */ static inline char diff -r c67f7d390a1a -r 7df7650492e8 liboctave/dNDArray.cc --- a/liboctave/dNDArray.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/dNDArray.cc Fri Aug 26 13:40:10 2011 -0500 @@ -925,3 +925,5 @@ BSXFUN_OP_DEF_MXLOOP (pow, NDArray, mx_inline_pow) BSXFUN_OP2_DEF_MXLOOP (pow, ComplexNDArray, ComplexNDArray, NDArray, mx_inline_pow) +BSXFUN_OP2_DEF_MXLOOP (pow, ComplexNDArray, NDArray, + ComplexNDArray, mx_inline_pow) diff -r c67f7d390a1a -r 7df7650492e8 liboctave/dNDArray.h --- a/liboctave/dNDArray.h Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/dNDArray.h Fri Aug 26 13:40:10 2011 -0500 @@ -185,5 +185,7 @@ BSXFUN_OP_DECL (pow, NDArray, OCTAVE_API) BSXFUN_OP2_DECL (pow, ComplexNDArray, ComplexNDArray, NDArray, OCTAVE_API) +BSXFUN_OP2_DECL (pow, ComplexNDArray, NDArray, + ComplexNDArray, OCTAVE_API) #endif diff -r c67f7d390a1a -r 7df7650492e8 liboctave/int16NDArray.cc --- a/liboctave/int16NDArray.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/int16NDArray.cc Fri Aug 26 13:40:10 2011 -0500 @@ -54,3 +54,5 @@ BSXFUN_STDOP_DEFS_MXLOOP (int16NDArray) BSXFUN_STDREL_DEFS_MXLOOP (int16NDArray) + +BSXFUN_OP_DEF_MXLOOP (pow, int16NDArray, mx_inline_pow) diff -r c67f7d390a1a -r 7df7650492e8 liboctave/int32NDArray.cc --- a/liboctave/int32NDArray.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/int32NDArray.cc Fri Aug 26 13:40:10 2011 -0500 @@ -54,3 +54,5 @@ BSXFUN_STDOP_DEFS_MXLOOP (int32NDArray) BSXFUN_STDREL_DEFS_MXLOOP (int32NDArray) + +BSXFUN_OP_DEF_MXLOOP (pow, int32NDArray, mx_inline_pow) diff -r c67f7d390a1a -r 7df7650492e8 liboctave/int64NDArray.cc --- a/liboctave/int64NDArray.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/int64NDArray.cc Fri Aug 26 13:40:10 2011 -0500 @@ -54,3 +54,5 @@ BSXFUN_STDOP_DEFS_MXLOOP (int64NDArray) BSXFUN_STDREL_DEFS_MXLOOP (int64NDArray) + +BSXFUN_OP_DEF_MXLOOP (pow, int64NDArray, mx_inline_pow) diff -r c67f7d390a1a -r 7df7650492e8 liboctave/int8NDArray.cc --- a/liboctave/int8NDArray.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/int8NDArray.cc Fri Aug 26 13:40:10 2011 -0500 @@ -54,3 +54,5 @@ BSXFUN_STDOP_DEFS_MXLOOP (int8NDArray) BSXFUN_STDREL_DEFS_MXLOOP (int8NDArray) + +BSXFUN_OP_DEF_MXLOOP (pow, int8NDArray, mx_inline_pow) diff -r c67f7d390a1a -r 7df7650492e8 liboctave/lo-utils.cc --- a/liboctave/lo-utils.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/lo-utils.cc Fri Aug 26 13:40:10 2011 -0500 @@ -196,44 +196,57 @@ } static inline double -read_inf_nan_na (std::istream& is, char c, char sign = '+') +read_inf_nan_na (std::istream& is, char c0, char sign = '+') { double d = 0.0; - switch (c) + switch (c0) { case 'i': case 'I': { - c = is.get (); - if (c == 'n' || c == 'N') + char c1 = is.get (); + if (c1 == 'n' || c1 == 'N') { - c = is.get (); - if (c == 'f' || c == 'F') + char c2 = is.get (); + if (c2 == 'f' || c2 == 'F') d = sign == '-' ? -octave_Inf : octave_Inf; else - is.putback (c); + { + is.putback (c2); + is.putback (c1); + is.putback (c0); + is.setstate (std::ios::failbit); + } } else - is.putback (c); + { + is.putback (c1); + is.putback (c0); + is.setstate (std::ios::failbit); + } } break; case 'n': case 'N': { - c = is.get (); - if (c == 'a' || c == 'A') + char c1 = is.get (); + if (c1 == 'a' || c1 == 'A') { - c = is.get (); - if (c == 'n' || c == 'N') + char c2 = is.get (); + if (c2 == 'n' || c2 == 'N') d = octave_NaN; else { - is.putback (c); + is.putback (c2); d = octave_NA; } } else - is.putback (c); + { + is.putback (c1); + is.putback (c0); + is.setstate (std::ios::failbit); + } } break; @@ -346,44 +359,57 @@ } static inline float -read_float_inf_nan_na (std::istream& is, char c, char sign = '+') +read_float_inf_nan_na (std::istream& is, char c0, char sign = '+') { float d = 0.0; - switch (c) + switch (c0) { case 'i': case 'I': { - c = is.get (); - if (c == 'n' || c == 'N') + char c1 = is.get (); + if (c1 == 'n' || c1 == 'N') { - c = is.get (); - if (c == 'f' || c == 'F') - d = sign == '-' ? -octave_Inf : octave_Inf; + char c2 = is.get (); + if (c2 == 'f' || c2 == 'F') + d = sign == '-' ? -octave_Float_Inf : octave_Float_Inf; else - is.putback (c); + { + is.putback (c2); + is.putback (c1); + is.putback (c0); + is.setstate (std::ios::failbit); + } } else - is.putback (c); + { + is.putback (c1); + is.putback (c0); + is.setstate (std::ios::failbit); + } } break; case 'n': case 'N': { - c = is.get (); - if (c == 'a' || c == 'A') + char c1 = is.get (); + if (c1 == 'a' || c1 == 'A') { - c = is.get (); - if (c == 'n' || c == 'N') - d = octave_NaN; + char c2 = is.get (); + if (c2 == 'n' || c2 == 'N') + d = octave_Float_NaN; else { - is.putback (c); - d = octave_NA; + is.putback (c2); + d = octave_Float_NA; } } else - is.putback (c); + { + is.putback (c1); + is.putback (c0); + is.setstate (std::ios::failbit); + } } break; diff -r c67f7d390a1a -r 7df7650492e8 liboctave/mx-inlines.cc --- a/liboctave/mx-inlines.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/mx-inlines.cc Fri Aug 26 13:40:10 2011 -0500 @@ -37,6 +37,8 @@ #include "Array.h" #include "Array-util.h" +#include "bsxfun.h" + // Provides some commonly repeated, basic loop templates. template @@ -286,7 +288,10 @@ inline void F (size_t n, R *r, X x, const Y *y) throw () \ { for (size_t i = 0; i < n; i++) r[i] = FUN (x, y[i]); } -DEFMXMAPPER2X (mx_inline_pow, std::pow) +// Let the compiler decide which pow to use, whichever best matches the +// arguments provided. +using std::pow; +DEFMXMAPPER2X (mx_inline_pow, pow) // Arbitrary function appliers. The function is a template parameter to enable // inlining. @@ -336,11 +341,12 @@ return r; } - template inline Array do_mm_binary_op (const Array& x, const Array& y, void (*op) (size_t, R *, const X *, const Y *) throw (), + void (*op1) (size_t, R *, X, const Y *) throw (), + void (*op2) (size_t, R *, const X *, Y) throw (), const char *opname) { dim_vector dx = x.dims (), dy = y.dims (); @@ -350,6 +356,10 @@ op (r.length (), r.fortran_vec (), x.data (), y.data ()); return r; } + else if (is_valid_bsxfun (dx, dy)) + { + return do_bsxfun_op (x, y, op, op1, op2); + } else { gripe_nonconformant (opname, dx, dy); diff -r c67f7d390a1a -r 7df7650492e8 liboctave/mx-op-defs.h --- a/liboctave/mx-op-defs.h Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/mx-op-defs.h Fri Aug 26 13:40:10 2011 -0500 @@ -72,7 +72,7 @@ R \ F (const V1& v1, const V2& v2) \ { \ - return do_mm_binary_op (v1, v2, OP, #F); \ + return do_mm_binary_op (v1, v2, OP, OP, OP, #F); \ } #define VV_BIN_OPS(R, V1, V2) \ @@ -173,7 +173,7 @@ R \ OP (const M1& m1, const M2& m2) \ { \ - return do_mm_binary_op (m1, m2, F, #OP); \ + return do_mm_binary_op (m1, m2, F, F, F, #OP); \ } #define MM_BIN_OPS(R, M1, M2) \ @@ -186,7 +186,7 @@ boolMatrix \ F (const M1& m1, const M2& m2) \ { \ - return do_mm_binary_op (m1, m2, OP, #F); \ + return do_mm_binary_op (m1, m2, OP, OP, OP, #F); \ } #define MM_CMP_OPS(M1, M2) \ @@ -203,7 +203,7 @@ { \ MNANCHK (m1, M1::element_type); \ MNANCHK (m2, M2::element_type); \ - return do_mm_binary_op (m1, m2, OP, #F); \ + return do_mm_binary_op (m1, m2, OP, OP, OP, #F); \ } #define MM_BOOL_OPS(M1, M2) \ @@ -310,7 +310,7 @@ R \ OP (const ND1& m1, const ND2& m2) \ { \ - return do_mm_binary_op (m1, m2, F, #OP); \ + return do_mm_binary_op (m1, m2, F, F, F, #OP); \ } #define NDND_BIN_OPS(R, ND1, ND2) \ @@ -323,7 +323,7 @@ boolNDArray \ F (const ND1& m1, const ND2& m2) \ { \ - return do_mm_binary_op (m1, m2, OP, #F); \ + return do_mm_binary_op (m1, m2, OP, OP, OP, #F); \ } #define NDND_CMP_OPS(ND1, ND2) \ @@ -340,7 +340,7 @@ { \ MNANCHK (m1, ND1::element_type); \ MNANCHK (m2, ND2::element_type); \ - return do_mm_binary_op (m1, m2, OP, #F); \ + return do_mm_binary_op (m1, m2, OP, OP, OP, #F); \ } #define NDND_BOOL_OPS(ND1, ND2) \ @@ -583,7 +583,7 @@ T \ FCN (const T& a, const T& b) \ { \ - return do_mm_binary_op (a, b, mx_inline_x##FCN, #FCN); \ + return do_mm_binary_op (a, b, mx_inline_x##FCN, mx_inline_x##FCN, mx_inline_x##FCN, #FCN); \ } #define MINMAX_FCNS(T, S) \ diff -r c67f7d390a1a -r 7df7650492e8 liboctave/oct-binmap.h --- a/liboctave/oct-binmap.h Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/oct-binmap.h Fri Aug 26 13:40:10 2011 -0500 @@ -27,9 +27,13 @@ #include "Sparse.h" #include "Array-util.h" -// This source implements a general binary maping function for arrays. -// The syntax is binmap (a, b, f, [name]). type denotes the expected -// return type of the operation. a, b, should be one of the 6 combinations: +#include "bsxfun.h" + +// This source file implements a general binary maping function for +// arrays. The syntax is binmap (a, b, f, [name]). type denotes +// the expected return type of the operation. a, b, should be one of +// the 6 combinations: +// // Array-Array // Array-scalar // scalar-Array @@ -37,11 +41,12 @@ // Sparse-scalar // scalar-Sparse // -// If both operands are nonscalar, name must be supplied. It is used as the base for error message -// when operands are nonconforming. +// If both operands are nonscalar, name must be supplied. It is used +// as the base for error message when operands are nonconforming. // -// The operation needs not be homogeneous, i.e. a, b and the result may be of distinct types. -// f can have any of the four signatures: +// The operation needs not be homogeneous, i.e. a, b and the result +// may be of distinct types. f can have any of the four signatures: +// // U f (T, R) // U f (const T&, R) // U f (T, const R&) @@ -49,7 +54,51 @@ // // Additionally, f can be an arbitrary functor object. // -// octave_quit() is called at appropriate places, hence the operation is breakable. +// octave_quit() is called at appropriate places, hence the operation +// is breakable. + +// The following template wrappers are provided for automatic bsxfun +// calls (see the function signature for do_bsxfun_op). + +template +class bsxfun_wrapper +{ +private: + static F f; + +public: + static void + set_f (const F& f_in) + { + f = f_in; + } + + static void + op_mm (size_t n, R* r, const X* x , const Y* y) + { + for (size_t i = 0; i < n; i++) + r[i] = f (x[i], y[i]); + } + + static void + op_sm (size_t n, R* r, X x, const Y* y) + { + for (size_t i = 0; i < n; i++) + r[i] = f (x, y[i]); + } + + static void + op_ms (size_t n , R* r, const X* x, Y y) + { + for (size_t i = 0; i < n; i++) + r[i] = f (x[i], y); + } +}; + +// Static init +template +F bsxfun_wrapper::f; + // scalar-Array template @@ -118,12 +167,24 @@ Array binmap (const Array& xa, const Array& ya, F fcn, const char *name) { + dim_vector xad = xa.dims (), yad = ya.dims (); if (xa.numel () == 1) return binmap (xa(0), ya, fcn); else if (ya.numel () == 1) return binmap (xa, ya(0), fcn); - else if (xa.dims () != ya.dims ()) - gripe_nonconformant (name, xa.dims (), ya.dims ()); + else if (xad != yad) + { + if (is_valid_bsxfun (xad, yad)) + { + bsxfun_wrapper::set_f(fcn); + return do_bsxfun_op (xa, ya, + bsxfun_wrapper::op_mm, + bsxfun_wrapper::op_sm, + bsxfun_wrapper::op_ms); + } + else + gripe_nonconformant (name, xad, yad); + } octave_idx_type len = xa.numel (); @@ -273,134 +334,134 @@ fcn, name)); } -// Overloads for function references. +// Overloads for function pointers. // Signature (T, R) template inline Array -binmap (const Array& xa, const Array& ya, U (&fcn) (T, R), const char *name) -{ return binmap (xa, ya, fcn, name); } +binmap (const Array& xa, const Array& ya, U (*fcn) (T, R), const char *name) +{ return binmap (xa, ya, fcn, name); } template inline Array -binmap (const T& x, const Array& ya, U (&fcn) (T, R)) -{ return binmap (x, ya, fcn); } +binmap (const T& x, const Array& ya, U (*fcn) (T, R)) +{ return binmap (x, ya, fcn); } template inline Array -binmap (const Array& xa, const R& y, U (&fcn) (T, R)) -{ return binmap (xa, y, fcn); } +binmap (const Array& xa, const R& y, U (*fcn) (T, R)) +{ return binmap (xa, y, fcn); } template inline Sparse -binmap (const Sparse& xa, const Sparse& ya, U (&fcn) (T, R), const char *name) -{ return binmap (xa, ya, fcn, name); } +binmap (const Sparse& xa, const Sparse& ya, U (*fcn) (T, R), const char *name) +{ return binmap (xa, ya, fcn, name); } template inline Sparse -binmap (const T& x, const Sparse& ya, U (&fcn) (T, R)) -{ return binmap (x, ya, fcn); } +binmap (const T& x, const Sparse& ya, U (*fcn) (T, R)) +{ return binmap (x, ya, fcn); } template inline Sparse -binmap (const Sparse& xa, const R& y, U (&fcn) (T, R)) -{ return binmap (xa, y, fcn); } +binmap (const Sparse& xa, const R& y, U (*fcn) (T, R)) +{ return binmap (xa, y, fcn); } // Signature (const T&, const R&) template inline Array -binmap (const Array& xa, const Array& ya, U (&fcn) (const T&, const R&), const char *name) -{ return binmap (xa, ya, fcn, name); } +binmap (const Array& xa, const Array& ya, U (*fcn) (const T&, const R&), const char *name) +{ return binmap (xa, ya, fcn, name); } template inline Array -binmap (const T& x, const Array& ya, U (&fcn) (const T&, const R&)) -{ return binmap (x, ya, fcn); } +binmap (const T& x, const Array& ya, U (*fcn) (const T&, const R&)) +{ return binmap (x, ya, fcn); } template inline Array -binmap (const Array& xa, const R& y, U (&fcn) (const T&, const R&)) -{ return binmap (xa, y, fcn); } +binmap (const Array& xa, const R& y, U (*fcn) (const T&, const R&)) +{ return binmap (xa, y, fcn); } template inline Sparse -binmap (const Sparse& xa, const Sparse& ya, U (&fcn) (const T&, const R&), const char *name) -{ return binmap (xa, ya, fcn, name); } +binmap (const Sparse& xa, const Sparse& ya, U (*fcn) (const T&, const R&), const char *name) +{ return binmap (xa, ya, fcn, name); } template inline Sparse -binmap (const T& x, const Sparse& ya, U (&fcn) (const T&, const R&)) -{ return binmap (x, ya, fcn); } +binmap (const T& x, const Sparse& ya, U (*fcn) (const T&, const R&)) +{ return binmap (x, ya, fcn); } template inline Sparse -binmap (const Sparse& xa, const R& y, U (&fcn) (const T&, const R&)) -{ return binmap (xa, y, fcn); } +binmap (const Sparse& xa, const R& y, U (*fcn) (const T&, const R&)) +{ return binmap (xa, y, fcn); } // Signature (const T&, R) template inline Array -binmap (const Array& xa, const Array& ya, U (&fcn) (const T&, R), const char *name) -{ return binmap (xa, ya, fcn, name); } +binmap (const Array& xa, const Array& ya, U (*fcn) (const T&, R), const char *name) +{ return binmap (xa, ya, fcn, name); } template inline Array -binmap (const T& x, const Array& ya, U (&fcn) (const T&, R)) -{ return binmap (x, ya, fcn); } +binmap (const T& x, const Array& ya, U (*fcn) (const T&, R)) +{ return binmap (x, ya, fcn); } template inline Array -binmap (const Array& xa, const R& y, U (&fcn) (const T&, R)) -{ return binmap (xa, y, fcn); } +binmap (const Array& xa, const R& y, U (*fcn) (const T&, R)) +{ return binmap (xa, y, fcn); } template inline Sparse -binmap (const Sparse& xa, const Sparse& ya, U (&fcn) (const T&, R), const char *name) -{ return binmap (xa, ya, fcn, name); } +binmap (const Sparse& xa, const Sparse& ya, U (*fcn) (const T&, R), const char *name) +{ return binmap (xa, ya, fcn, name); } template inline Sparse -binmap (const T& x, const Sparse& ya, U (&fcn) (const T&, R)) -{ return binmap (x, ya, fcn); } +binmap (const T& x, const Sparse& ya, U (*fcn) (const T&, R)) +{ return binmap (x, ya, fcn); } template inline Sparse -binmap (const Sparse& xa, const R& y, U (&fcn) (const T&, R)) -{ return binmap (xa, y, fcn); } +binmap (const Sparse& xa, const R& y, U (*fcn) (const T&, R)) +{ return binmap (xa, y, fcn); } // Signature (T, const R&) template inline Array -binmap (const Array& xa, const Array& ya, U (&fcn) (T, const R&), const char *name) -{ return binmap (xa, ya, fcn, name); } +binmap (const Array& xa, const Array& ya, U (*fcn) (T, const R&), const char *name) +{ return binmap (xa, ya, fcn, name); } template inline Array -binmap (const T& x, const Array& ya, U (&fcn) (T, const R&)) -{ return binmap (x, ya, fcn); } +binmap (const T& x, const Array& ya, U (*fcn) (T, const R&)) +{ return binmap (x, ya, fcn); } template inline Array -binmap (const Array& xa, const R& y, U (&fcn) (T, const R&)) -{ return binmap (xa, y, fcn); } +binmap (const Array& xa, const R& y, U (*fcn) (T, const R&)) +{ return binmap (xa, y, fcn); } template inline Sparse -binmap (const Sparse& xa, const Sparse& ya, U (&fcn) (T, const R&), const char *name) -{ return binmap (xa, ya, fcn, name); } +binmap (const Sparse& xa, const Sparse& ya, U (*fcn) (T, const R&), const char *name) +{ return binmap (xa, ya, fcn, name); } template inline Sparse -binmap (const T& x, const Sparse& ya, U (&fcn) (T, const R&)) -{ return binmap (x, ya, fcn); } +binmap (const T& x, const Sparse& ya, U (*fcn) (T, const R&)) +{ return binmap (x, ya, fcn); } template inline Sparse -binmap (const Sparse& xa, const R& y, U (&fcn) (T, const R&)) -{ return binmap (xa, y, fcn); } +binmap (const Sparse& xa, const R& y, U (*fcn) (T, const R&)) +{ return binmap (xa, y, fcn); } #endif diff -r c67f7d390a1a -r 7df7650492e8 liboctave/str-vec.cc --- a/liboctave/str-vec.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/str-vec.cc Fri Aug 26 13:40:10 2011 -0500 @@ -163,6 +163,26 @@ return *this; } +std::string +string_vector::join (const std::string& sep) const +{ + std::string retval; + + octave_idx_type len = length (); + + if (len > 0) + { + octave_idx_type i; + + for (i = 0; i < len - 1; i++) + retval += elem(i) + sep; + + retval += elem(i); + } + + return retval; +} + char ** string_vector::c_str_vec (void) const { diff -r c67f7d390a1a -r 7df7650492e8 liboctave/str-vec.h --- a/liboctave/str-vec.h Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/str-vec.h Fri Aug 26 13:40:10 2011 -0500 @@ -105,6 +105,8 @@ string_vector& append (const string_vector& sv); + std::string join (const std::string& sep = std::string ()) const; + char **c_str_vec (void) const; static void delete_c_str_vec (const char * const*); diff -r c67f7d390a1a -r 7df7650492e8 liboctave/uint16NDArray.cc --- a/liboctave/uint16NDArray.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/uint16NDArray.cc Fri Aug 26 13:40:10 2011 -0500 @@ -54,3 +54,5 @@ BSXFUN_STDOP_DEFS_MXLOOP (uint16NDArray) BSXFUN_STDREL_DEFS_MXLOOP (uint16NDArray) + +BSXFUN_OP_DEF_MXLOOP (pow, uint16NDArray, mx_inline_pow) diff -r c67f7d390a1a -r 7df7650492e8 liboctave/uint32NDArray.cc --- a/liboctave/uint32NDArray.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/uint32NDArray.cc Fri Aug 26 13:40:10 2011 -0500 @@ -54,3 +54,5 @@ BSXFUN_STDOP_DEFS_MXLOOP (uint32NDArray) BSXFUN_STDREL_DEFS_MXLOOP (uint32NDArray) + +BSXFUN_OP_DEF_MXLOOP (pow, uint32NDArray, mx_inline_pow) diff -r c67f7d390a1a -r 7df7650492e8 liboctave/uint64NDArray.cc --- a/liboctave/uint64NDArray.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/uint64NDArray.cc Fri Aug 26 13:40:10 2011 -0500 @@ -54,3 +54,5 @@ BSXFUN_STDOP_DEFS_MXLOOP (uint64NDArray) BSXFUN_STDREL_DEFS_MXLOOP (uint64NDArray) + +BSXFUN_OP_DEF_MXLOOP (pow, uint64NDArray, mx_inline_pow) diff -r c67f7d390a1a -r 7df7650492e8 liboctave/uint8NDArray.cc --- a/liboctave/uint8NDArray.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/liboctave/uint8NDArray.cc Fri Aug 26 13:40:10 2011 -0500 @@ -54,3 +54,5 @@ BSXFUN_STDOP_DEFS_MXLOOP (uint8NDArray) BSXFUN_STDREL_DEFS_MXLOOP (uint8NDArray) + +BSXFUN_OP_DEF_MXLOOP (pow, uint8NDArray, mx_inline_pow) diff -r c67f7d390a1a -r 7df7650492e8 scripts/audio/wavread.m --- a/scripts/audio/wavread.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/audio/wavread.m Fri Aug 26 13:40:10 2011 -0500 @@ -55,135 +55,139 @@ error ("wavread: FILENAME must be a character string"); endif - # Open file for binary reading. - [fid, msg] = fopen (filename, "rb"); - if (fid < 0) - error ("wavread: %s", msg); - endif + fid = -1; + + unwind_protect - ## Get file size. - fseek (fid, 0, "eof"); - file_size = ftell (fid); - fseek (fid, 0, "bof"); + [fid, msg] = fopen (filename, "rb"); + + if (fid < 0) + error ("wavread: %s", msg); + endif - ## Find RIFF chunk. - riff_size = find_chunk (fid, "RIFF", file_size); - riff_pos = ftell (fid); - if (riff_size == -1) - fclose (fid); - error ("wavread: file contains no RIFF chunk"); - endif + ## Get file size. + fseek (fid, 0, "eof"); + file_size = ftell (fid); + fseek (fid, 0, "bof"); - riff_type = char (fread (fid, 4))'; - if (! strcmp (riff_type, "WAVE")) - fclose (fid); - error ("wavread: file contains no WAVE signature"); - endif - riff_pos = riff_pos + 4; - riff_size = riff_size - 4; + ## Find RIFF chunk. + riff_size = find_chunk (fid, "RIFF", file_size); + riff_pos = ftell (fid); + if (riff_size == -1) + error ("wavread: file contains no RIFF chunk"); + endif + + riff_type = char (fread (fid, 4))'; + if (! strcmp (riff_type, "WAVE")) + error ("wavread: file contains no WAVE signature"); + endif + riff_pos = riff_pos + 4; + riff_size = riff_size - 4; - ## Find format chunk inside the RIFF chunk. - fseek (fid, riff_pos, "bof"); - fmt_size = find_chunk (fid, "fmt ", riff_size); - fmt_pos = ftell(fid); - if (fmt_size == -1) - fclose (fid); - error ("wavread: file contains no format chunk"); - endif + ## Find format chunk inside the RIFF chunk. + fseek (fid, riff_pos, "bof"); + fmt_size = find_chunk (fid, "fmt ", riff_size); + fmt_pos = ftell(fid); + if (fmt_size == -1) + error ("wavread: file contains no format chunk"); + endif + + ## Find data chunk inside the RIFF chunk. + ## We don't assume that it comes after the format chunk. + fseek (fid, riff_pos, "bof"); + data_size = find_chunk (fid, "data", riff_size); + data_pos = ftell (fid); + if (data_size == -1) + error ("wavread: file contains no data chunk"); + endif - ## Find data chunk inside the RIFF chunk. - ## We don't assume that it comes after the format chunk. - fseek (fid, riff_pos, "bof"); - data_size = find_chunk (fid, "data", riff_size); - data_pos = ftell (fid); - if (data_size == -1) - fclose (fid); - error ("wavread: file contains no data chunk"); - endif + ### Read format chunk. + fseek (fid, fmt_pos, "bof"); - ### Read format chunk. - fseek (fid, fmt_pos, "bof"); + ## Sample format code. + format_tag = fread (fid, 1, "uint16", 0, BYTEORDER); + if (format_tag != FORMAT_PCM && format_tag != FORMAT_IEEE_FLOAT) + error ("wavread: sample format %#x is not supported", format_tag); + endif - ## Sample format code. - format_tag = fread (fid, 1, "uint16", 0, BYTEORDER); - if (format_tag != FORMAT_PCM && format_tag != FORMAT_IEEE_FLOAT) - fclose (fid); - error ("wavread: sample format %#x is not supported", format_tag); - endif + ## Number of interleaved channels. + channels = fread (fid, 1, "uint16", 0, BYTEORDER); - ## Number of interleaved channels. - channels = fread (fid, 1, "uint16", 0, BYTEORDER); + ## Sample rate. + samples_per_sec = fread (fid, 1, "uint32", 0, BYTEORDER); - ## Sample rate. - samples_per_sec = fread (fid, 1, "uint32", 0, BYTEORDER); + ## Bits per sample. + fseek (fid, 6, "cof"); + bits_per_sample = fread (fid, 1, "uint16", 0, BYTEORDER); - ## Bits per sample. - fseek (fid, 6, "cof"); - bits_per_sample = fread (fid, 1, "uint16", 0, BYTEORDER); + ### Read data chunk. + fseek (fid, data_pos, "bof"); - ### Read data chunk. - fseek (fid, data_pos, "bof"); + ## Determine sample data type. + if (format_tag == FORMAT_PCM) + switch (bits_per_sample) + case 8 + format = "uint8"; + case 16 + format = "int16"; + case 24 + format = "uint8"; + case 32 + format = "int32"; + otherwise + error ("wavread: %d bits sample resolution is not supported with PCM", + bits_per_sample); + endswitch + else + switch (bits_per_sample) + case 32 + format = "float32"; + case 64 + format = "float64"; + otherwise + error ("wavread: %d bits sample resolution is not supported with IEEE float", + bits_per_sample); + endswitch + endif - ## Determine sample data type. - if (format_tag == FORMAT_PCM) - switch (bits_per_sample) - case 8 - format = "uint8"; - case 16 - format = "int16"; - case 24 - format = "uint8"; - case 32 - format = "int32"; - otherwise - fclose (fid); - error ("wavread: %d bits sample resolution is not supported with PCM", - bits_per_sample); - endswitch - else - switch (bits_per_sample) - case 32 - format = "float32"; - case 64 - format = "float64"; - otherwise - fclose (fid); - error ("wavread: %d bits sample resolution is not supported with IEEE float", - bits_per_sample); - endswitch - endif + ## Parse arguments. + if (nargin == 1) + length = idivide (8 * data_size, bits_per_sample); + else + nparams = numel (param); + if (nparams == 1) + ## Number of samples is given. + length = param * channels; + elseif (nparams == 2) + ## Sample range is given. + if (fseek (fid, (param(1)-1) * channels * (bits_per_sample/8), "cof") < 0) + warning ("wavread: seeking failed"); + endif + length = (param(2)-param(1)+1) * channels; + elseif (nparams == 4 && char (param) == "size") + ## Size of the file is requested. + tmp = idivide (8 * data_size, channels * bits_per_sample); + y = [tmp, channels]; + return; + else + error ("wavread: invalid PARAM argument"); + endif + endif - ## Parse arguments. - if (nargin == 1) - length = 8 * data_size / bits_per_sample; - else - nparams = numel (param); - if (nparams == 1) - ## Number of samples is given. - length = param * channels; - elseif (nparams == 2) - ## Sample range is given. - if (fseek (fid, (param(1)-1) * channels * (bits_per_sample/8), "cof") < 0) - warning ("wavread: seeking failed"); - endif - length = (param(2)-param(1)+1) * channels; - elseif (nparams == 4 && char (param) == "size") - ## Size of the file is requested. + ## Read samples and close file. + if (bits_per_sample == 24) + length *= 3; + endif + + [yi, n] = fread (fid, length, format, 0, BYTEORDER); + + unwind_protect_cleanup + + if (fid >= 0) fclose (fid); - y = [data_size/channels/(bits_per_sample/8), channels]; - return; - else - fclose (fid); - error ("wavread: invalid PARAM argument"); endif - endif - ## Read samples and close file. - if (bits_per_sample == 24) - length *= 3; - endif - [yi, n] = fread (fid, length, format, 0, BYTEORDER); - fclose (fid); + end_unwind_protect ## Check data. if (mod (numel (yi), channels) != 0) diff -r c67f7d390a1a -r 7df7650492e8 scripts/general/accumdim.m --- a/scripts/general/accumdim.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/general/accumdim.m Fri Aug 26 13:40:10 2011 -0500 @@ -42,12 +42,12 @@ ## ## An example of the use of @code{accumdim} is: ## -## @example +## @smallexample ## @group ## accumdim ([1, 2, 1, 2, 1], [7,-10,4;-5,-12,8;-12,2,8;-10,9,-3;-5,-3,-13]) ## @result{} ans = [-10,-11,-1;-15,-3,5] ## @end group -## @end example +## @end smallexample ## ## @seealso{accumarray} ## @end deftypefn diff -r c67f7d390a1a -r 7df7650492e8 scripts/general/profile.m --- a/scripts/general/profile.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/general/profile.m Fri Aug 26 13:40:10 2011 -0500 @@ -48,9 +48,13 @@ ## ## @item @var{T} = profile ('info') ## Return the collected profiling statistics in the structure @var{T}. -## Currently, the only field is @code{FunctionTable} which is an array -## of structures, each entry corresponding to a function which was called -## and for which profiling statistics are present. +## The flat profile is returned in the field @code{FunctionTable} which is an +## array of structures, each entry corresponding to a function which was called +## and for which profiling statistics are present. Furthermore, the field +## @code{Hierarchical} contains the hierarchical call-tree. Each node +## has an index into the @code{FunctionTable} identifying the function it +## corresponds to as well as data fields for number of calls and time spent +## at this level in the call-tree. ## @end table ## @end deftypefn @@ -65,20 +69,20 @@ switch (option) case 'on' - __profiler_reset (); - __profiler_enable (true); + __profiler_reset__ (); + __profiler_enable__ (true); case 'off' - __profiler_enable (false); + __profiler_enable__ (false); case 'clear' - __profiler_reset (); + __profiler_reset__ (); case 'resume' - __profiler_enable (true); + __profiler_enable__ (true); case 'status' - enabled = __profiler_enable (); + enabled = __profiler_enable__ (); if (enabled) enabled = 'on'; else @@ -87,8 +91,8 @@ retval = struct ('ProfilerStatus', enabled); case 'info' - data = __profiler_data (); - retval = struct ('FunctionTable', data); + [flat, tree] = __profiler_data__ (); + retval = struct ('FunctionTable', flat, 'Hierarchical', tree); otherwise warning ("profile: Unrecognized option '%s'", option); diff -r c67f7d390a1a -r 7df7650492e8 scripts/general/profshow.m --- a/scripts/general/profshow.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/general/profshow.m Fri Aug 26 13:40:10 2011 -0500 @@ -63,18 +63,19 @@ for i = 1 : n nameLen = max (nameLen, length (data.FunctionTable(p(i)).FunctionName)); endfor - headerFormat = sprintf ("%%%ds %%4s %%12s %%12s\n", nameLen); - rowFormat = sprintf ("%%%ds %%4s %%12.3f %%12d\n", nameLen); + headerFormat = sprintf ("%%4s %%%ds %%4s %%12s %%12s\n", nameLen); + rowFormat = sprintf ("%%4d %%%ds %%4s %%12.3f %%12d\n", nameLen); - printf (headerFormat, "Function", "Attr", "Time (s)", "Calls"); - printf ("%s\n", repmat ("-", 1, nameLen + 2 * 13 + 5)); + printf (headerFormat, "#", "Function", "Attr", "Time (s)", "Calls"); + printf ("%s\n", repmat ("-", 1, nameLen + 2 * 5 + 2 * 13)); for i = 1 : n row = data.FunctionTable(p(i)); attr = ""; if (row.IsRecursive) attr = "R"; endif - printf (rowFormat, row.FunctionName, attr, row.TotalTime, row.NumCalls); + printf (rowFormat, p(i), row.FunctionName, attr, ... + row.TotalTime, row.NumCalls); endfor endfunction diff -r c67f7d390a1a -r 7df7650492e8 scripts/general/quadl.m --- a/scripts/general/quadl.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/general/quadl.m Fri Aug 26 13:40:10 2011 -0500 @@ -62,14 +62,12 @@ ## * replace global variable terminate2 with local function need_warning ## * add paper ref to docs -function q = quadl (f, a, b, tol, trace, varargin) - need_warning (1); - if (nargin < 4) - tol = []; +function q = quadl (f, a, b, tol = [], trace = false, varargin) + + if (nargin < 3) + print_usage (); endif - if (nargin < 5) - trace = []; - endif + if (isa (a, "single") || isa (b, "single")) myeps = eps ("single"); else @@ -79,16 +77,23 @@ tol = myeps; endif if (isempty (trace)) - trace = 0; + trace = false; endif if (tol < myeps) tol = myeps; endif + ## Track whether recursion has occurred + global __quadl_recurse_done__; + __quadl_recurse_done__ = false; + ## Track whether warning about machine precision has been issued + global __quadl_need_warning__; + __quadl_need_warning__ = true; + m = (a+b)/2; h = (b-a)/2; - alpha = sqrt(2/3); - beta = 1/sqrt(5); + alpha = sqrt (2/3); + beta = 1/sqrt (5); x1 = .942882415695480; x2 = .641853342345781; @@ -104,12 +109,12 @@ i2 = (h/6)*(y(1) + y(13) + 5*(y(5)+y(9))); - i1 = (h/1470)*(77*(y(1)+y(13)) + i1 = (h/1470)*( 77*(y(1)+y(13)) + 432*(y(3)+y(11)) + 625*(y(5)+y(9)) + 672*y(7)); - is = h*(.0158271919734802*(y(1)+y(13)) + is = h*( .0158271919734802*(y(1)+y(13)) +.0942738402188500*(y(2)+y(12)) + .155071987336585*(y(3)+y(11)) + .188821573960182*(y(4)+y(10)) @@ -117,102 +122,96 @@ + .224926465333340*(y(6)+y(8)) + .242611071901408*y(7)); - s = sign(is); - + s = sign (is); if (s == 0) s = 1; endif - erri1 = abs(i1-is); - erri2 = abs(i2-is); - R = 1; + erri1 = abs (i1-is); + erri2 = abs (i2-is); if (erri2 != 0) R = erri1/erri2; + else + R = 1; endif if (R > 0 && R < 1) tol = tol/R; endif - is = s*abs(is)*tol/myeps; + is = s * abs(is) * tol/myeps; if (is == 0) is = b-a; endif + q = adaptlobstp (f, a, b, fa, fb, is, trace, varargin{:}); + endfunction ## ADAPTLOBSTP Recursive function used by QUADL. ## ## Q = ADAPTLOBSTP('F', A, B, FA, FB, IS, TRACE) tries to ## approximate the integral of F(X) from A to B to -## an appropriate relative error. The argument 'F' is +## an appropriate relative error. The argument 'F' is ## a string containing the name of f. The remaining ## arguments are generated by ADAPTLOB or by recursion. ## ## Walter Gautschi, 08/03/98 function q = adaptlobstp (f, a, b, fa, fb, is, trace, varargin) + global __quadl_recurse_done__; + global __quadl_need_warning__; + h = (b-a)/2; m = (a+b)/2; - alpha = sqrt(2/3); - beta = 1/sqrt(5); + alpha = sqrt (2/3); + beta = 1 / sqrt(5); mll = m-alpha*h; - ml = m-beta*h; - mr = m+beta*h; + ml = m-beta*h; + mr = m+beta*h; mrr = m+alpha*h; x = [mll, ml, m, mr, mrr]; - y = feval(f, x, varargin{:}); + y = feval (f, x, varargin{:}); fmll = y(1); - fml = y(2); - fm = y(3); - fmr = y(4); + fml = y(2); + fm = y(3); + fmr = y(4); fmrr = y(5); i2 = (h/6)*(fa + fb + 5*(fml+fmr)); i1 = (h/1470)*(77*(fa+fb) + 432*(fmll+fmrr) + 625*(fml+fmr) + 672*fm); - if (is+(i1-i2) == is || mll <= a || b <= mrr) - if ((m <= a || b <= m) && need_warning ()) + if ((is+(i1-i2) == is || mll <= a || b <= mrr) && __quadl_recurse_done__) + if ((m <= a || b <= m) && __quadl_need_warning__) warning ("quadl: interval contains no more machine number"); warning ("quadl: required tolerance may not be met"); - need_warning (0); + __quadl_need_warning__ = false; endif q = i1; if (trace) disp ([a, b-a, q]); endif else - q = (adaptlobstp (f, a, mll, fa, fmll, is, trace, varargin{:}) - + adaptlobstp (f, mll, ml, fmll, fml, is, trace, varargin{:}) - + adaptlobstp (f, ml, m, fml, fm, is, trace, varargin{:}) - + adaptlobstp (f, m, mr, fm, fmr, is, trace, varargin{:}) - + adaptlobstp (f, mr, mrr, fmr, fmrr, is, trace, varargin{:}) - + adaptlobstp (f, mrr, b, fmrr, fb, is, trace, varargin{:})); - endif -endfunction - -function r = need_warning (v) - persistent w = []; - if (nargin == 0) - r = w; - else - w = v; + __quadl_recurse_done__ = true; + q = ( adaptlobstp (f, a , mll, fa , fmll, is, trace, varargin{:}) + + adaptlobstp (f, mll, ml , fmll, fml , is, trace, varargin{:}) + + adaptlobstp (f, ml , m , fml , fm , is, trace, varargin{:}) + + adaptlobstp (f, m , mr , fm , fmr , is, trace, varargin{:}) + + adaptlobstp (f, mr , mrr, fmr , fmrr, is, trace, varargin{:}) + + adaptlobstp (f, mrr, b , fmrr, fb , is, trace, varargin{:})); endif endfunction ## basic functionality -%!assert( quadl (@(x) sin (x), 0, pi, [], []), 2, -3e-16) +%!assert (quadl (@(x) sin (x), 0, pi, [], []), 2, -3e-16) ## 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), +%!assert (quadl (@(x) sin (3*x).*cosh (x).*sinh (x),10,15), %! 2.588424538641647e+10, -9e-15) ## extra parameters %!assert (quadl (@(x,a,b) sin (a + b*x), 0, 1, [], [], 2, 3), %! cos(2)/3 - cos(5)/3, - 3e-16) -## test different tolerances. This test currently fails for a very high -## tolerances. -%!assert ( quadl (@(x) sin (2 + 3*x).^2, 0, 10, 0.3, []), +## test different tolerances. +%!assert (quadl (@(x) sin (2 + 3*x).^2, 0, 10, 0.3, []), %! (60 + sin(4) - sin(64))/12, -0.3) +%!assert (quadl (@(x) sin (2 + 3*x).^2, 0, 10, 0.1, []), +%! (60 + sin(4) - sin(64))/12, -0.1) - -## for lower tolerances the test passes. -%!assert ( quadl (@(x) sin (2 + 3*x).^2, 0, 10, 0.1, []), -%! (60 + sin(4) - sin(64))/12, -0.1) \ No newline at end of file diff -r c67f7d390a1a -r 7df7650492e8 scripts/io/strread.m --- a/scripts/io/strread.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/io/strread.m Fri Aug 26 13:40:10 2011 -0500 @@ -471,7 +471,7 @@ endif endfor ## Done - words_period = iwrd - 1; + words_period = max (iwrd - 1, 1); num_lines = ceil (num_words / words_period); ## 2. Pad words array so that it can be reshaped @@ -633,7 +633,7 @@ if (pad_out) data(end+1:num_lines) = {""} endif - varargout{k} = strtrunc (data, 3)'; + varargout{k} = strtrunc (data, swidth)'; k++; otherwise endswitch diff -r c67f7d390a1a -r 7df7650492e8 scripts/miscellaneous/edit.m --- a/scripts/miscellaneous/edit.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/miscellaneous/edit.m Fri Aug 26 13:40:10 2011 -0500 @@ -54,7 +54,7 @@ ## filename. If @file{name.ext} is not modifiable, it will be copied to ## @env{HOME} before editing. ## -## @strong{WARNING!} You may need to clear name before the new definition +## @strong{Warning:} You may need to clear name before the new definition ## is available. If you are editing a .cc file, you will need ## to mkoctfile @file{name.cc} before the definition will be available. ## @end itemize diff -r c67f7d390a1a -r 7df7650492e8 scripts/miscellaneous/private/__xzip__.m --- a/scripts/miscellaneous/private/__xzip__.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/miscellaneous/private/__xzip__.m Fri Aug 26 13:40:10 2011 -0500 @@ -80,14 +80,16 @@ commandname, status); endif - if (nargout > 0) - if (nargin == 5) + if (nargin == 5) + if (nargout > 0) entries = cellfun( @(x) fullfile (outdir, sprintf ("%s.%s", x, extension)), f, "uniformoutput", false); - else - movefile (cellfun(@(x) sprintf ("%s.%s", x, extension), f, - "uniformoutput", false), cwd); + endif + else + movefile (cellfun(@(x) sprintf ("%s.%s", x, extension), f, + "uniformoutput", false), cwd); + if (nargout > 0) ## FIXME this does not work when you try to compress directories entries = cellfun(@(x) sprintf ("%s.%s", x, extension), files, "uniformoutput", false); diff -r c67f7d390a1a -r 7df7650492e8 scripts/miscellaneous/tar.m --- a/scripts/miscellaneous/tar.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/miscellaneous/tar.m Fri Aug 26 13:40:10 2011 -0500 @@ -42,7 +42,7 @@ files = cellstr (files); endif - if (ischar (tarfile) && iscellstr (files) && ischar (root)) + if (! (ischar (tarfile) && iscellstr (files) && ischar (root))) error ("tar: all arguments must be character strings"); endif diff -r c67f7d390a1a -r 7df7650492e8 scripts/miscellaneous/xor.m --- a/scripts/miscellaneous/xor.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/miscellaneous/xor.m Fri Aug 26 13:40:10 2011 -0500 @@ -48,7 +48,11 @@ ## Typecast to logicals is necessary for other numeric types. z = logical (x) != logical (y); else - error ("xor: X and Y must be of common size or scalars"); + try + z = bsxfun (@xor, x, y); + catch + error ("xor: X and Y must be of compatible size or scalars"); + end_try_catch endif else print_usage (); diff -r c67f7d390a1a -r 7df7650492e8 scripts/plot/isonormals.m --- a/scripts/plot/isonormals.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/plot/isonormals.m Fri Aug 26 13:40:10 2011 -0500 @@ -46,47 +46,49 @@ ## ## For example: ## -## @example +## @c Set example in small font to prevent overfull line +## @smallexample ## function [] = isofinish (p) -## set (gca, "PlotBoxAspectRatioMode","manual","PlotBoxAspectRatio",[1 1 1]); -## set (p, "VertexNormals", -get(p,"VertexNormals")); ## Revert normals +## set (gca, "PlotBoxAspectRatioMode", "manual", ... +## "PlotBoxAspectRatio",[1 1 1]); +## set (p, "VertexNormals", -get(p,"VertexNormals")); # Revert normals ## set (p, "FaceColor", "interp"); ## ## set (p, "FaceLighting", "phong"); -## ## light ("Position", [1 1 5]); ## Available with JHandles +## ## light ("Position", [1 1 5]); # Available with JHandles ## endfunction ## -## N = 15; ## Increase number of vertices in each direction -## iso = .4; ## Change isovalue to .1 to display a sphere +## N = 15; # Increase number of vertices in each direction +## iso = .4; # Change isovalue to .1 to display a sphere ## lin = linspace (0, 2, N); ## [x, y, z] = meshgrid (lin, lin, lin); ## c = abs ((x-.5).^2 + (y-.5).^2 + (z-.5).^2); -## figure (); ## Open another figure window +## figure (); # Open another figure window ## ## subplot (2, 2, 1); view (-38, 20); ## [f, v, cdat] = isosurface (x, y, z, c, iso, y); ## p = patch ("Faces", f, "Vertices", v, "FaceVertexCData", cdat, \ -## "FaceColor", "interp", "EdgeColor", "none"); +## "FaceColor", "interp", "EdgeColor", "none"); ## isofinish (p); ## Call user function isofinish ## ## subplot (2, 2, 2); view (-38, 20); ## p = patch ("Faces", f, "Vertices", v, "FaceVertexCData", cdat, \ -## "FaceColor", "interp", "EdgeColor", "none"); -## isonormals (x, y, z, c, p); ## Directly modify patch +## "FaceColor", "interp", "EdgeColor", "none"); +## isonormals (x, y, z, c, p); # Directly modify patch ## isofinish (p); ## ## subplot (2, 2, 3); view (-38, 20); ## p = patch ("Faces", f, "Vertices", v, "FaceVertexCData", cdat, \ -## "FaceColor", "interp", "EdgeColor", "none"); -## n = isonormals (x, y, z, c, v); ## Compute normals of isosurface -## set (p, "VertexNormals", n); ## Manually set vertex normals +## "FaceColor", "interp", "EdgeColor", "none"); +## n = isonormals (x, y, z, c, v); # Compute normals of isosurface +## set (p, "VertexNormals", n); # Manually set vertex normals ## isofinish (p); ## ## subplot (2, 2, 4); view (-38, 20); ## p = patch ("Faces", f, "Vertices", v, "FaceVertexCData", cdat, \ -## "FaceColor", "interp", "EdgeColor", "none"); -## isonormals (x, y, z, c, v, "negate"); ## Use reverse directly +## "FaceColor", "interp", "EdgeColor", "none"); +## isonormals (x, y, z, c, v, "negate"); # Use reverse directly ## isofinish (p); -## @end example +## @end smallexample ## ## @seealso{isosurface, isocolors} ## @end deftypefn diff -r c67f7d390a1a -r 7df7650492e8 scripts/plot/isosurface.m --- a/scripts/plot/isosurface.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/plot/isosurface.m Fri Aug 26 13:40:10 2011 -0500 @@ -71,24 +71,27 @@ ## Another example for an isosurface geometry with different additional ## coloring ## -## @example -## N = 15; ## Increase number of vertices in each direction -## iso = .4; ## Change isovalue to .1 to display a sphere +## @c Set example in small font to prevent overfull line +## @smallexample +## N = 15; # Increase number of vertices in each direction +## iso = .4; # Change isovalue to .1 to display a sphere ## lin = linspace (0, 2, N); ## [x, y, z] = meshgrid (lin, lin, lin); ## c = abs ((x-.5).^2 + (y-.5).^2 + (z-.5).^2); -## figure (); ## Open another figure window +## figure (); # Open another figure window ## ## subplot (2, 2, 1); view (-38, 20); ## [f, v] = isosurface (x, y, z, c, iso); ## p = patch ("Faces", f, "Vertices", v, "EdgeColor", "none"); -## set (gca, "PlotBoxAspectRatioMode","manual", "PlotBoxAspectRatio", [1 1 1]); +## set (gca, "PlotBoxAspectRatioMode","manual", ... +## "PlotBoxAspectRatio", [1 1 1]); ## # set (p, "FaceColor", "green", "FaceLighting", "phong"); -## # light ("Position", [1 1 5]); ## Available with the JHandles package +## # light ("Position", [1 1 5]); # Available with the JHandles package ## ## subplot (2, 2, 2); view (-38, 20); ## p = patch ("Faces", f, "Vertices", v, "EdgeColor", "blue"); -## set (gca, "PlotBoxAspectRatioMode","manual", "PlotBoxAspectRatio", [1 1 1]); +## set (gca, "PlotBoxAspectRatioMode","manual", ... +## "PlotBoxAspectRatio", [1 1 1]); ## # set (p, "FaceColor", "none", "FaceLighting", "phong"); ## # light ("Position", [1 1 5]); ## @@ -96,17 +99,19 @@ ## [f, v, c] = isosurface (x, y, z, c, iso, y); ## p = patch ("Faces", f, "Vertices", v, "FaceVertexCData", c, \ ## "FaceColor", "interp", "EdgeColor", "none"); -## set (gca, "PlotBoxAspectRatioMode","manual", "PlotBoxAspectRatio", [1 1 1]); +## set (gca, "PlotBoxAspectRatioMode","manual", ... +## "PlotBoxAspectRatio", [1 1 1]); ## # set (p, "FaceLighting", "phong"); ## # light ("Position", [1 1 5]); ## ## subplot (2, 2, 4); view (-38, 20); ## p = patch ("Faces", f, "Vertices", v, "FaceVertexCData", c, \ ## "FaceColor", "interp", "EdgeColor", "blue"); -## set (gca, "PlotBoxAspectRatioMode","manual", "PlotBoxAspectRatio", [1 1 1]); +## set (gca, "PlotBoxAspectRatioMode","manual", ... +## "PlotBoxAspectRatio", [1 1 1]); ## # set (p, "FaceLighting", "phong"); ## # light ("Position", [1 1 5]); -## @end example +## @end smallexample ## ## @seealso{isonormals, isocolors} ## @end deftypefn diff -r c67f7d390a1a -r 7df7650492e8 scripts/plot/private/__axis_label__.m --- a/scripts/plot/private/__axis_label__.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/plot/private/__axis_label__.m Fri Aug 26 13:40:10 2011 -0500 @@ -25,24 +25,20 @@ function retval = __axis_label__ (caller, txt, varargin) - if (ischar (txt)) - ca = gca (); + ca = gca (); - h = get (gca (), caller); + h = get (gca (), caller); - set (h, "fontangle", get (ca, "fontangle"), - "fontname", get (ca, "fontname"), - "fontsize", get (ca, "fontsize"), - "fontunits", get (ca, "fontunits"), - "fontweight", get (ca, "fontweight"), - "string", txt, - varargin{:}); + set (h, "fontangle", get (ca, "fontangle"), + "fontname", get (ca, "fontname"), + "fontsize", get (ca, "fontsize"), + "fontunits", get (ca, "fontunits"), + "fontweight", get (ca, "fontweight"), + "string", txt, + varargin{:}); - if (nargout > 0) - retval = h; - endif - else - error ("%s: expecting first argument to be character string", caller); + if (nargout > 0) + retval = h; endif endfunction diff -r c67f7d390a1a -r 7df7650492e8 scripts/plot/private/__go_draw_axes__.m --- a/scripts/plot/private/__go_draw_axes__.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/plot/private/__go_draw_axes__.m Fri Aug 26 13:40:10 2011 -0500 @@ -1250,6 +1250,11 @@ colorspec = get_text_colorspec (color, mono); endif + if (ischar (obj.string)) + num_lines = size (obj.string, 1); + else + num_lines = numel (obj.string); + endif switch valign ## Text offset in characters. This relies on gnuplot for font metrics. case "top" @@ -1257,17 +1262,18 @@ case "cap" dy = -0.5; case "middle" - dy = 0; + dy = 0.5 * (num_lines - 1); case "baseline" - dy = 0.5; + dy = 0.5 + (num_lines - 1); case "bottom" - dy = 0.5; + dy = 0.5 + (num_lines - 1); endswitch ## Gnuplot's Character units are different for x/y and vary with fontsize. The aspect ratio ## of 1:1.7 was determined by experiment to work for eps/ps/etc. For the MacOS aqua terminal ## a value of 2.5 is needed. However, the difference is barely noticable. dx_and_dy = [(-dy * sind (angle)), (dy * cosd(angle))] .* [1.7 1]; + ## FIXME - Multiline text produced the gnuplot "warning: ft_render: skipping glyph" if (nd == 3) ## This produces the desired vertical alignment in 3D. fprintf (plot_stream, @@ -2129,10 +2135,31 @@ bld = false; endif + ## The text object maybe multiline, and may be of any class str = getfield (obj, fld); + if (ischar (str) && size (str, 1) > 1) + str = cellstr (str); + elseif (isnumeric (str)) + str = cellstr (num2str (str(:))); + endif + if (iscellstr (str)) + for n = 1:numel(str) + if (isnumeric (str{n})) + str{n} = num2str (str{n}); + endif + endfor + str = sprintf ("%s\n", str{:})(1:end-1); + endif + if (enhanced) if (strcmpi (obj.interpreter, "tex")) - str = __tex2enhanced__ (str, fnt, it, bld); + if (iscellstr (str)) + for n = 1:numel(str) + str{n} = __tex2enhanced__ (str{n}, fnt, it, bld); + endfor + else + str = __tex2enhanced__ (str, fnt, it, bld); + endif elseif (strcmpi (obj.interpreter, "latex")) if (! warned_latex) warning ("latex markup not supported for text objects"); diff -r c67f7d390a1a -r 7df7650492e8 scripts/plot/text.m --- a/scripts/plot/text.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/plot/text.m Fri Aug 26 13:40:10 2011 -0500 @@ -47,15 +47,33 @@ endif label = varargin{offset}; - if (ischar (label) || iscellstr (label)) - varargin(1:offset) = []; - if (ischar (label)) + varargin(1:offset) = []; + + nx = numel (x); + ny = numel (y); + nz = numel (z); + if (ischar (label) || isnumeric (label)) + nt = size (label, 1); + if (nx > 1 && nt == 1) + ## Mutiple text objects with same string + label = repmat ({label}, [nx, 1]); + nt = nx; + elseif (nx > 1 && nt == nx) + ## Mutiple text objects with different strings label = cellstr (label); + elseif (ischar (label)) + ## Single text object with one or more lines + label = {label}; endif - n = numel (label); - nx = numel (x); - ny = numel (y); - nz = numel (z); + elseif (iscell (label)) + nt = numel (label); + if (nx > 1 && nt == 1) + label = repmat ({label}, [nx, 1]); + nt = nx; + elseif (! (nx > 1 && nt == nx)) + label = {label}; + nt = 1; + endif else error ("text: expecting LABEL to be a character string or cell array of character strings"); endif @@ -63,35 +81,35 @@ x = y = z = 0; nx = ny = nz = 1; label = {""}; - n = 1; + nt = 1; endif if (rem (numel (varargin), 2) == 0) - if (nx == ny && nx == nz) + if (nx == ny && nx == nz && (nt == nx || nt == 1 || nx == 1)) pos = [x(:), y(:), z(:)]; ca = gca (); - tmp = zeros (n, 1); - if (n == 1) - label = label{1}; - for i = 1:nx - tmp(i) = __go_text__ (ca, "string", label, + tmp = zeros (nt, 1); + if (nx == 1) + ## TODO - Modify __go_text__() to accept cell-strings + tmp = __go_text__ (ca, "string", "foobar", + varargin{:}, + "position", pos); + set (tmp, "string", label{1}); + elseif (nt == nx) + for n = 1:nt + tmp(n) = __go_text__ (ca, "string", label{n}, varargin{:}, - "position", pos(i,:)); - endfor - __request_drawnow__ (); - elseif (n == nx) - for i = 1:nx - tmp(i) = __go_text__ (ca, "string", label{i}, - varargin{:}, - "position", pos(i,:)); + "position", pos(n,:)); endfor __request_drawnow__ (); else error ("text: dimension mismatch for coordinates and LABEL"); endif + elseif (nt == nx || nt == 1 || nx == 1) + error ("text: dimension mismatch for coordinates"); else - error ("text: dimension mismatch for coordinates"); + error ("text: mismatch betwween coordinates and strings"); endif if (nargout > 0) @@ -142,3 +160,61 @@ %! endfor %! caxis ([-100 100]) %! title ("Vertically Aligned at Bottom") + +%!demo +%! clf +%! axis ([0 8 0 8]) +%! title (["First title";"Second title"]) +%! xlabel (["First xlabel";"Second xlabel"]) +%! ylabel (["First ylabel";"Second ylabel"]) +%! text (4, 4, {"Hello", "World"}, ... +%! "horizontalalignment", "center", ... +%! "verticalalignment", "middle") +%! grid on + +%!demo +%! clf +%! h = mesh (peaks, "edgecolor", 0.7 * [1 1 1], ... +%! "facecolor", "none", ... +%! "facealpha", 0); +%! title (["First title";"Second title"]) +%! xlabel (["First xlabel";"Second xlabel"]) +%! ylabel (["First ylabel";"Second ylabel"]) +%! zlabel (["First zlabel";"Second zlabel"]) +%! text (0, 0, 5, {"Hello", "World"}, ... +%! "horizontalalignment", "center", ... +%! "verticalalignment", "middle") +%! hold on +%! plot3 (0, 0, 5, "+k") +%! + +%!demo +%! clf +%! h = text (0.5, 0.3, "char"); +%! assert ("char", class (get (h, "string"))) +%! h = text (0.5, 0.4, ["char row 1"; "char row 2"]); +%! 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"))) +%! h = text (0.5, 0.8, "foobar"); +%! 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"))) +%! 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"))) +%! 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"))) +%! 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"))) +%! h = text (0.7, 0.6, "single 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) + diff -r c67f7d390a1a -r 7df7650492e8 scripts/plot/uimenu.m --- a/scripts/plot/uimenu.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/plot/uimenu.m Fri Aug 26 13:40:10 2011 -0500 @@ -66,8 +66,10 @@ ## @group ## 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)"); +## uimenu(f, "label", "Close", "accelerator", "q", ... +## "callback", "close (gcf)"); +## uimenu(e, "label", "Toggle &Grid", "accelerator", "g", ... +## "callback", "grid (gca)"); ## @end group ## @end example ## @seealso{figure} diff -r c67f7d390a1a -r 7df7650492e8 scripts/polynomial/polyval.m --- a/scripts/polynomial/polyval.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/polynomial/polyval.m Fri Aug 26 13:40:10 2011 -0500 @@ -20,7 +20,7 @@ ## @deftypefn {Function File} {@var{y} =} polyval (@var{p}, @var{x}) ## @deftypefnx {Function File} {@var{y} =} polyval (@var{p}, @var{x}, [], @var{mu}) ## Evaluate the polynomial @var{p} at the specified values of @var{x}. When -## @var{mu} is present evaluate the polynomial for +## @var{mu} is present, evaluate the polynomial for ## (@var{x}-@var{mu}(1))/@var{mu}(2). ## If @var{x} is a vector or matrix, the polynomial is evaluated for each of ## the elements of @var{x}. @@ -39,17 +39,19 @@ ## Created: June 1994 ## Adapted-By: jwe -function [y, dy] = polyval (p, x, s, mu) +function [y, dy] = polyval (p, x, s = [], mu) if (nargin < 2 || nargin > 4 || (nargout == 2 && nargin < 3)) print_usage (); endif - if (nargin < 3) - s = []; - endif - - if (! (isvector (p) || isempty (p))) + if (isempty (x)) + y = []; + return; + elseif (isempty (p)) + y = zeros (size (x)); + return; + elseif (! isvector (p)) error ("polyval: first argument must be a vector"); endif @@ -57,16 +59,6 @@ x = (x - mu(1)) / mu(2); endif - if (isempty (x)) - y = []; - return; - endif - - if (length (p) == 0) - y = p; - return; - endif - n = length (p) - 1; y = p(1) * ones (size (x)); for i = 2:n+1 @@ -80,10 +72,23 @@ ## dy = t * sqrt (1 + sumsq (A/s.R, 2)) * s.normr / sqrt (s.df) ## If my inference is correct, then t must equal 1 for polyval. ## This is because finv (0.5, n, n) = 1.0 for any n. - k = numel (x); - A = (x(:) * ones (1, n+1)) .^ (ones (k, 1) * (n:-1:0)); - dy = sqrt (1 + sumsq (A/s.R, 2)) * s.normr / sqrt (s.df); - dy = reshape (dy, size (x)); + try + k = numel (x); + A = (x(:) * ones (1, n+1)) .^ (ones (k, 1) * (n:-1:0)); + dy = sqrt (1 + sumsq (A/s.R, 2)) * s.normr / sqrt (s.df); + dy = reshape (dy, size (x)); + catch + if (isempty (s)) + error ("polyval: third input is required.") + elseif (isstruct (s) + && all (ismember ({"R", "normr", "df"}, fieldnames (s)))) + error (lasterr ()) + elseif (isstruct (s)) + error ("polyval: third input is missing the required fields."); + else + error ("polyval: third input is not a structure."); + endif + end_try_catch endif endfunction @@ -142,3 +147,6 @@ %! assert (y, polyval(p,x), eps) %! x = reshape(x, [1, 1, 5, 2]); +%!assert (zeros (1, 10), polyval ([], 1:10)) +%!assert ([], polyval (1, [])) +%!assert ([], polyval ([], [])) diff -r c67f7d390a1a -r 7df7650492e8 scripts/statistics/base/quantile.m --- a/scripts/statistics/base/quantile.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/statistics/base/quantile.m Fri Aug 26 13:40:10 2011 -0500 @@ -90,13 +90,14 @@ ## ## Examples: ## -## @example +## @c Set example in small font to prevent overfull line +## @smallexample ## @group -## x = randi (1000, [10, 1]); # Create random empirical data in range 1-1000 -## q = quantile (x, [0, 1]); # Return minimum, maximum of empirical distribution -## q = quantile (x, [0.25 0.5 0.75]); # Return quartiles of empirical distribution +## x = randi (1000, [10, 1]); # Create empirical data in range 1-1000 +## q = quantile (x, [0, 1]); # Return minimum, maximum of distribution +## q = quantile (x, [0.25 0.5 0.75]); # Return quartiles of distribution ## @end group -## @end example +## @end smallexample ## @seealso{prctile} ## @end deftypefn diff -r c67f7d390a1a -r 7df7650492e8 scripts/statistics/tests/wilcoxon_test.m --- a/scripts/statistics/tests/wilcoxon_test.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/statistics/tests/wilcoxon_test.m Fri Aug 26 13:40:10 2011 -0500 @@ -23,7 +23,7 @@ ## @var{y}) == 1/2. Under the null, the test statistic @var{z} ## approximately follows a standard normal distribution when @var{n} > 25. ## -## @strong{Warning}: This function assumes a normal distribution for @var{z} +## @strong{Caution:} This function assumes a normal distribution for @var{z} ## and thus is invalid for @var{n} @leq{} 25. ## ## With the optional argument string @var{alt}, the alternative of diff -r c67f7d390a1a -r 7df7650492e8 scripts/strings/deblank.m --- a/scripts/strings/deblank.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/strings/deblank.m Fri Aug 26 13:40:10 2011 -0500 @@ -20,8 +20,20 @@ ## @deftypefn {Function File} {} deblank (@var{s}) ## Remove trailing whitespace and nulls from @var{s}. If @var{s} ## is a matrix, @var{deblank} trims each row to the length of longest -## string. If @var{s} is a cell array, operate recursively on each -## element of the cell array. +## string. If @var{s} is a cell array of strings, operate recursively on each +## string element. +## +## Examples: +## @example +## @group +## deblank (" abc ") +## @result{} " abc" +## +## deblank ([" abc "; " def "]) +## @result{} [" abc " ; " def"] +## @end group +## @end example +## @seealso{strtrim} ## @end deftypefn ## Author: Kurt Hornik @@ -42,7 +54,7 @@ s = s(:,1:ceil (max (k) / rows (s))); endif - elseif (iscell (s)) + elseif (iscellstr (s)) s = regexprep (s, "[\\s\v\\0]+$", ''); @@ -62,4 +74,5 @@ %!error deblank (); %!error deblank ("foo", "bar"); %!error deblank (1); +%!error deblank ({[]}); diff -r c67f7d390a1a -r 7df7650492e8 scripts/strings/str2num.m --- a/scripts/strings/str2num.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/strings/str2num.m Fri Aug 26 13:40:10 2011 -0500 @@ -17,7 +17,8 @@ ## . ## -*- texinfo -*- -## @deftypefn {Function File} {} str2num (@var{s}) +## @deftypefn {Function File} {@var{x} =} str2num (@var{s}) +## @deftypefnx {Function File} {[@var{x}, @var{state}] =} str2num (@var{s}) ## Convert the string (or character array) @var{s} to a number (or an ## array). Examples: ## @@ -33,6 +34,10 @@ ## @end group ## @end example ## +## The optional second output, @var{state}, is logically true when the +## coversion is successful. If the conversion fails the numeric output, +## @var{n}, is empty and @var{state} is false. +## ## @strong{Caution:} As @code{str2num} uses the @code{eval} function ## to do the conversion, @code{str2num} will execute any code contained ## in the string @var{s}. Use @code{str2double} instead if you want to @@ -42,16 +47,18 @@ ## Author: jwe -function m = str2num (s) +function [m, state] = str2num (s) if (nargin == 1 && ischar (s)) [nr, nc] = size (s); sep = ";"; sep = sep (ones (nr, 1), 1); s = sprintf ("m = [%s];", reshape ([s, sep]', 1, nr * (nc + 1))); - eval (s, "m = [];"); + state = true; + eval (s, "m = []; state = false;"); if (ischar (m)) m = []; + state = false; endif else print_usage (); @@ -65,3 +72,8 @@ %!error str2num ("string", 1); +%!test +%! [x, state] = str2num ("pi"); +%! assert (state) +%! [x, state] = str2num (tmpnam); +%! assert (! state) diff -r c67f7d390a1a -r 7df7650492e8 scripts/strings/strmatch.m --- a/scripts/strings/strmatch.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/strings/strmatch.m Fri Aug 26 13:40:10 2011 -0500 @@ -43,7 +43,7 @@ ## @end group ## @end example ## -## @strong{Note:} @code{strmatch} is scheduled for deprecation. Use +## @strong{Caution:} @code{strmatch} is scheduled for deprecation. Use ## @code{strcmpi} or @code{strncmpi} in all new code. ## @seealso{strfind, findstr, strcmp, strncmp, strcmpi, strncmpi, find} ## @end deftypefn diff -r c67f7d390a1a -r 7df7650492e8 scripts/strings/strtrim.m --- a/scripts/strings/strtrim.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/strings/strtrim.m Fri Aug 26 13:40:10 2011 -0500 @@ -20,18 +20,19 @@ ## @deftypefn {Function File} {} strtrim (@var{s}) ## Remove leading and trailing whitespace from @var{s}. If ## @var{s} is a matrix, @var{strtrim} trims each row to the length of -## longest string. If @var{s} is a cell array, operate recursively on -## each element of the cell array. For example: +## longest string. If @var{s} is a cell array of strings, operate recursively +## on each string element. For example: ## ## @example ## @group ## strtrim (" abc ") -## @result{} "abc" +## @result{} "abc" ## ## strtrim ([" abc "; " def "]) -## @result{} ["abc "; " def"] +## @result{} ["abc " ; " def"] ## @end group ## @end example +## @seealso{deblank} ## @end deftypefn ## Author: John Swensen @@ -53,7 +54,7 @@ s = s(:, ceil (min (k) / rows (s)):ceil (max (k) / rows (s))); endif - elseif (iscell (s)) + elseif (iscellstr (s)) s = regexprep (s, "^[\\s\v]+|[\\s\v]+$", ''); @@ -73,4 +74,5 @@ %!error strtrim (); %!error strtrim ("abc", "def"); %!error strtrim (1); +%!error strtrim ({[]}); diff -r c67f7d390a1a -r 7df7650492e8 scripts/time/datenum.m --- a/scripts/time/datenum.m Thu Aug 25 20:12:31 2011 +0200 +++ b/scripts/time/datenum.m Fri Aug 26 13:40:10 2011 -0500 @@ -50,7 +50,7 @@ ## Days can be fractional. ## @end itemize ## -## @strong{Warning:} this function does not attempt to handle Julian +## @strong{Caution:} this function does not attempt to handle Julian ## calendars so dates before Octave 15, 1582 are wrong by as much ## as eleven days. Also be aware that only Roman Catholic countries ## adopted the calendar in 1582. It took until 1924 for it to be diff -r c67f7d390a1a -r 7df7650492e8 src/DLD-FUNCTIONS/__init_fltk__.cc --- a/src/DLD-FUNCTIONS/__init_fltk__.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/DLD-FUNCTIONS/__init_fltk__.cc Fri Aug 26 13:40:10 2011 -0500 @@ -1840,10 +1840,10 @@ case figure::properties::ID_MENUBAR: figure_manager::toggle_menubar_visibility (ov.string_value (), fp.menubar_is("figure")); break; - case figure::properties::ID_NAME: case figure::properties::ID_CURRENTAXES: figure_manager::update_canvas (go.get_handle (), fp.get_currentaxes ()); break; + case figure::properties::ID_NAME: case figure::properties::ID_NUMBERTITLE: figure_manager::set_name (ov.string_value ()); break; diff -r c67f7d390a1a -r 7df7650492e8 src/DLD-FUNCTIONS/bsxfun.cc --- a/src/DLD-FUNCTIONS/bsxfun.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/DLD-FUNCTIONS/bsxfun.cc Fri Aug 26 13:40:10 2011 -0500 @@ -312,15 +312,18 @@ DEFUN_DLD (bsxfun, args, , "-*- texinfo -*-\n\ @deftypefn {Loadable Function} {} bsxfun (@var{f}, @var{A}, @var{B})\n\ -Apply a binary function @var{f} element-by-element to two matrix arguments\n\ -@var{A} and @var{B}. @var{f} is a function handle, inline function, or\n\ -string containing the name of the function to evaluate.\n\ -The function @var{f} must be capable of accepting two column-vector\n\ -arguments of equal length, or one column vector argument and a scalar.\n\ +The binary singleton expansion function applier does what its name\n\ +suggests: applies a binary function @var{f} element-by-element to two\n\ +array arguments @var{A} and @var{B}, and expands as necessary\n\ +singleton dimensions in either input argument. @var{f} is a function\n\ +handle, inline function, or string containing the name of the function\n\ +to evaluate. The function @var{f} must be capable of accepting two\n\ +column-vector arguments of equal length, or one column vector argument\n\ +and a scalar.\n\ \n\ -The dimensions of @var{A} and @var{B} must be equal or singleton. The\n\ -singleton dimensions of the matrices will be expanded to the same\n\ -dimensionality as the other matrix.\n\ +The dimensions of @var{A} and @var{B} must be equal or singleton. The\n\ +singleton dimensions of the arrays will be expanded to the same\n\ +dimensionality as the other array.\n\ @seealso{arrayfun, cellfun}\n\ @end deftypefn") { diff -r c67f7d390a1a -r 7df7650492e8 src/DLD-FUNCTIONS/cellfun.cc --- a/src/DLD-FUNCTIONS/cellfun.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/DLD-FUNCTIONS/cellfun.cc Fri Aug 26 13:40:10 2011 -0500 @@ -58,6 +58,8 @@ #include "ov-uint32.h" #include "ov-uint64.h" +#include "ov-fcn-handle.h" + static octave_value_list get_output_list (octave_idx_type count, octave_idx_type nargout, const octave_value_list& inputlist, @@ -222,6 +224,7 @@ } octave_value func = args(0); + bool symbol_table_lookup = false; if (! args(1).is_cell ()) { @@ -339,6 +342,8 @@ func = symbol_table::find_function (name); if (func.is_undefined ()) error ("cellfun: invalid function NAME: %s", name.c_str ()); + + symbol_table_lookup = true; } } } @@ -349,6 +354,30 @@ 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 (! 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; + } + octave_value f = symbol_table::find_function (func.function_value () + -> name ()); + if (f.is_defined ()) + func = f; + } + nevermind: + unwind_protect frame; frame.protect_var (buffer_error_messages); diff -r c67f7d390a1a -r 7df7650492e8 src/DLD-FUNCTIONS/urlwrite.cc --- a/src/DLD-FUNCTIONS/urlwrite.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/DLD-FUNCTIONS/urlwrite.cc Fri Aug 26 13:40:10 2011 -0500 @@ -112,11 +112,11 @@ { BEGIN_INTERRUPT_IMMEDIATELY_IN_FOREIGN_CODE; - CURLcode res = curl_easy_perform (curl); - if (res != CURLE_OK) + errnum = curl_easy_perform (curl); + if (errnum != CURLE_OK) { if (curlerror) - error ("%s", curl_easy_strerror (res)); + error ("%s", curl_easy_strerror (errnum)); } else retval = true; @@ -145,6 +145,7 @@ std::string host; bool valid; bool ascii; + mutable CURLcode errnum; private: CURL *curl; @@ -250,11 +251,7 @@ std::string lasterror (void) const { - CURLcode errnum; - - curl_easy_getinfo (rep->handle(), CURLINFO_OS_ERRNO, &errnum); - - return std::string (curl_easy_strerror (errnum)); + return std::string (curl_easy_strerror (rep->errnum)); } void set_ostream (std::ostream& os) const diff -r c67f7d390a1a -r 7df7650492e8 src/Makefile.am --- a/src/Makefile.am Thu Aug 25 20:12:31 2011 +0200 +++ b/src/Makefile.am Fri Aug 26 13:40:10 2011 -0500 @@ -541,7 +541,7 @@ ../libcruft/libcruft.la \ ../libcruft/libranlib.la \ ../libgnu/libgnu.la \ - $(FFTW_XLDFLAGS) $(FFTW_XLIBS) + $(FFTW_XLDFLAGS) $(FFTW_XLIBS) \ $(QHULL_LDFLAGS) $(QHULL_LIBS) \ $(QRUPDATE_LDFLAGS) $(QRUPDATE_LIBS) \ $(SPARSE_XLDFLAGS) $(SPARSE_XLIBS) \ diff -r c67f7d390a1a -r 7df7650492e8 src/OPERATORS/op-int.h --- a/src/OPERATORS/op-int.h Thu Aug 25 20:12:31 2011 +0200 +++ b/src/OPERATORS/op-int.h Fri Aug 26 13:40:10 2011 -0500 @@ -21,6 +21,7 @@ */ #include "quit.h" +#include "bsxfun.h" #define DEFINTBINOP_OP(name, t1, t2, op, t3) \ BINOPDECL (name, a1, a2) \ @@ -703,8 +704,15 @@ dim_vector b_dims = b.dims (); \ if (a_dims != b_dims) \ { \ - gripe_nonconformant ("operator .^", a_dims, b_dims); \ - return octave_value (); \ + if (is_valid_bsxfun (a_dims, b_dims)) \ + { \ + return bsxfun_pow (a, b); \ + } \ + else \ + { \ + gripe_nonconformant ("operator .^", a_dims, b_dims); \ + return octave_value (); \ + } \ } \ T1 ## NDArray result (a_dims); \ for (int i = 0; i < a.length (); i++) \ @@ -722,8 +730,15 @@ dim_vector b_dims = b.dims (); \ if (a_dims != b_dims) \ { \ - gripe_nonconformant ("operator .^", a_dims, b_dims); \ - return octave_value (); \ + if (is_valid_bsxfun (a_dims, b_dims)) \ + { \ + return bsxfun_pow (a, static_cast (b)); \ + } \ + else \ + { \ + gripe_nonconformant ("operator .^", a_dims, b_dims); \ + return octave_value (); \ + } \ } \ T1 ## NDArray result (a_dims); \ for (int i = 0; i < a.length (); i++) \ @@ -741,8 +756,15 @@ dim_vector b_dims = b.dims (); \ if (a_dims != b_dims) \ { \ - gripe_nonconformant ("operator .^", a_dims, b_dims); \ - return octave_value (); \ + if (is_valid_bsxfun (a_dims, b_dims)) \ + { \ + return bsxfun_pow (static_cast (a), b); \ + } \ + else \ + { \ + gripe_nonconformant ("operator .^", a_dims, b_dims); \ + return octave_value (); \ + } \ } \ T2 ## NDArray result (a_dims); \ for (int i = 0; i < a.length (); i++) \ @@ -760,8 +782,15 @@ dim_vector b_dims = b.dims (); \ if (a_dims != b_dims) \ { \ - gripe_nonconformant ("operator .^", a_dims, b_dims); \ - return octave_value (); \ + if (is_valid_bsxfun (a_dims, b_dims)) \ + { \ + return bsxfun_pow (a, static_cast (b)); \ + } \ + else \ + { \ + gripe_nonconformant ("operator .^", a_dims, b_dims); \ + return octave_value (); \ + } \ } \ T1 ## NDArray result (a_dims); \ for (int i = 0; i < a.length (); i++) \ @@ -779,8 +808,15 @@ dim_vector b_dims = b.dims (); \ if (a_dims != b_dims) \ { \ - gripe_nonconformant ("operator .^", a_dims, b_dims); \ - return octave_value (); \ + if (is_valid_bsxfun (a_dims, b_dims)) \ + { \ + return bsxfun_pow (static_cast (a), b); \ + } \ + else \ + { \ + gripe_nonconformant ("operator .^", a_dims, b_dims); \ + return octave_value (); \ + } \ } \ T2 ## NDArray result (a_dims); \ for (int i = 0; i < a.length (); i++) \ diff -r c67f7d390a1a -r 7df7650492e8 src/c-file-ptr-stream.cc --- a/src/c-file-ptr-stream.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/c-file-ptr-stream.cc Fri Aug 26 13:40:10 2011 -0500 @@ -195,9 +195,7 @@ int c_file_ptr_buf::seek (long offset, int origin) { - // gnulib::fseek doesn't seem to work, so don't use it until problem - // can be properly diagnosed and fixed. - return f ? fseek (f, offset, origin) : -1; + return f ? gnulib::fseek (f, offset, origin) : -1; } long diff -r c67f7d390a1a -r 7df7650492e8 src/file-io.cc --- a/src/file-io.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/file-io.cc Fri Aug 26 13:40:10 2011 -0500 @@ -494,7 +494,7 @@ { tmode.erase (pos, 1); - FILE *fptr = ::fopen (fname.c_str (), tmode.c_str ()); + FILE *fptr = gnulib::fopen (fname.c_str (), tmode.c_str ()); int fd = fileno (fptr); @@ -509,7 +509,7 @@ else #endif { - FILE *fptr = ::fopen (fname.c_str (), tmode.c_str ()); + FILE *fptr = gnulib::fopen (fname.c_str (), tmode.c_str ()); retval = octave_stdiostream::create (fname, fptr, md, flt_fmt); @@ -1176,11 +1176,13 @@ DEFUN (sscanf, args, , "-*- texinfo -*-\n\ -@deftypefn {Built-in Function} {[@var{val}, @var{count}] =} sscanf (@var{string}, @var{template}, @var{size})\n\ +@deftypefn {Built-in Function} {[@var{val}, @var{count}, @var{pos}] =} sscanf (@var{string}, @var{template}, @var{size})\n\ @deftypefnx {Built-in Function} {[@var{v1}, @var{v2}, @dots{}, @var{count}] =} sscanf (@var{string}, @var{template}, \"C\")\n\ This is like @code{fscanf}, except that the characters are taken from the\n\ string @var{string} instead of from a stream. Reaching the end of the\n\ -string is treated as an end-of-file condition.\n\ +string is treated as an end-of-file condition. In addition to the values\n\ +returned by @code{fscanf}, the index of the next character to be read\n\ +is returned in in @var{pos}.\n\ @seealso{fscanf, scanf, sprintf}\n\ @end deftypefn") { @@ -1247,7 +1249,8 @@ // position will clear it. std::string errmsg = os.error (); - retval(3) = os.tell () + 1; + retval(3) + = (os.eof () ? data.length () : os.tell ()) + 1; retval(2) = errmsg; retval(1) = count; retval(0) = tmp; diff -r c67f7d390a1a -r 7df7650492e8 src/genprops.awk --- a/src/genprops.awk Thu Aug 25 20:12:31 2011 +0200 +++ b/src/genprops.awk Fri Aug 26 13:40:10 2011 -0500 @@ -300,8 +300,9 @@ emit_get_accessor(i, "graphics_handle", "handle_value"); else if (type[i] == "string_property") emit_get_accessor(i, "std::string", "string_value"); - else if (type[i] == "string_array_property") - emit_get_accessor(i, "octave_value", "get"); + else if (type[i] == "string_array_property" \ + || type[i] == "text_label_property") + emit_get_accessor(i, "octave_value", "get"); else if (type[i] == "double_property") emit_get_accessor(i, "double", "double_value"); else if (type[i] == "double_radio_property") diff -r c67f7d390a1a -r 7df7650492e8 src/gl-render.cc --- a/src/gl-render.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/gl-render.cc Fri Aug 26 13:40:10 2011 -0500 @@ -2422,7 +2422,7 @@ void opengl_renderer::draw_text (const text::properties& props) { - if (props.get_string ().empty ()) + if (props.get_string ().is_empty ()) return; const Matrix pos = xform.scale (props.get_data_position ()); diff -r c67f7d390a1a -r 7df7650492e8 src/gl2ps-renderer.cc --- a/src/gl2ps-renderer.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/gl2ps-renderer.cc Fri Aug 26 13:40:10 2011 -0500 @@ -199,7 +199,7 @@ void glps_renderer::draw_text (const text::properties& props) { - if (props.get_string ().empty ()) + if (props.get_string ().is_empty ()) return; set_font (props); @@ -223,9 +223,15 @@ // FIXME: handle margin and surrounding box glRasterPos3d (pos(0), pos(1), pos(2)); - gl2psTextOpt (props.get_string ().c_str (), fontname.c_str (), fontsize, + + octave_value string_prop = props.get_string (); + + string_vector sv = string_prop.all_strings (); + + std::string s = sv.join ("\n"); + + gl2psTextOpt (s.c_str (), fontname.c_str (), fontsize, alignment_to_mode (halign, valign), props.get_rotation ()); - } #endif diff -r c67f7d390a1a -r 7df7650492e8 src/gl2ps.c --- a/src/gl2ps.c Thu Aug 25 20:12:31 2011 +0200 +++ b/src/gl2ps.c Fri Aug 26 13:40:10 2011 -0500 @@ -50,7 +50,7 @@ #include #endif -/********************************************************************* +/********************************************************************* * * Private definitions, data structures and prototypes * @@ -167,7 +167,6 @@ written to the file or not, and 'format' indicates if it is visible or not */ GLenum format, type; - GLfloat zoom_x, zoom_y; GLfloat *pixels; } GL2PSimage; @@ -228,7 +227,7 @@ GLboolean zerosurfacearea; GL2PSbsptree2d *imagetree; GL2PSprimitive *primitivetoadd; - + /* PDF-specific */ int streamlength; GL2PSlist *pdfprimlist, *pdfgrouplist; @@ -266,7 +265,7 @@ static GLint gl2psPrintPrimitives(void); -/********************************************************************* +/********************************************************************* * * Utility routines * @@ -283,7 +282,7 @@ case GL2PS_ERROR : fprintf(stderr, "GL2PS error: "); break; } va_start(args, fmt); - vfprintf(stderr, fmt, args); + vfprintf(stderr, fmt, args); va_end(args); fprintf(stderr, "\n"); } @@ -360,16 +359,16 @@ static int gl2psAllocCompress(unsigned int srcsize) { gl2psFreeCompress(); - + if(!gl2ps->compress || !srcsize) return GL2PS_ERROR; - + gl2ps->compress->srcLen = srcsize; gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12); gl2ps->compress->src = (Bytef*)gl2psMalloc(gl2ps->compress->srcLen); gl2ps->compress->start = gl2ps->compress->src; gl2ps->compress->dest = (Bytef*)gl2psMalloc(gl2ps->compress->destLen); - + return GL2PS_SUCCESS; } @@ -377,18 +376,18 @@ { if(!gl2ps->compress || !srcsize) return NULL; - + if(srcsize < gl2ps->compress->srcLen) return gl2ps->compress->start; - + gl2ps->compress->srcLen = srcsize; gl2ps->compress->destLen = (int)ceil(1.001 * gl2ps->compress->srcLen + 12); - gl2ps->compress->src = (Bytef*)gl2psRealloc(gl2ps->compress->src, + gl2ps->compress->src = (Bytef*)gl2psRealloc(gl2ps->compress->src, gl2ps->compress->srcLen); gl2ps->compress->start = gl2ps->compress->src; - gl2ps->compress->dest = (Bytef*)gl2psRealloc(gl2ps->compress->dest, + gl2ps->compress->dest = (Bytef*)gl2psRealloc(gl2ps->compress->dest, gl2ps->compress->destLen); - + return gl2ps->compress->start; } @@ -407,8 +406,8 @@ { /* For compatibility with older zlib versions, we use compress(...) instead of compress2(..., Z_BEST_COMPRESSION) */ - return compress(gl2ps->compress->dest, &gl2ps->compress->destLen, - gl2ps->compress->start, gl2ps->compress->srcLen); + return compress(gl2ps->compress->dest, &gl2ps->compress->destLen, + gl2ps->compress->start, gl2ps->compress->srcLen); } #endif @@ -456,7 +455,7 @@ /* add the gzip file header */ fwrite(tmp, 10, 1, gl2ps->stream); } -#endif +#endif } static void gl2psPrintGzipFooter() @@ -477,7 +476,7 @@ n += 4; /* DICTID */ } /* write the data, without the zlib header and footer */ - fwrite(gl2ps->compress->dest+n, gl2ps->compress->destLen-(n+4), + fwrite(gl2ps->compress->dest+n, gl2ps->compress->destLen-(n+4), 1, gl2ps->stream); /* add the gzip file footer */ crc = crc32(0L, gl2ps->compress->start, gl2ps->compress->srcLen); @@ -496,7 +495,7 @@ gl2psFree(gl2ps->compress); gl2ps->compress = NULL; } -#endif +#endif } /* The list handling routines */ @@ -545,7 +544,7 @@ static void gl2psListDelete(GL2PSlist *list) { - if(!list) return; + if(!list) return; gl2psFree(list->array); gl2psFree(list); } @@ -618,7 +617,7 @@ static void gl2psEncodeBase64Block(unsigned char in[3], unsigned char out[4], int len) { - static const char cb64[] = + static const char cb64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; out[0] = cb64[ in[0] >> 2 ]; @@ -671,7 +670,7 @@ return GL_FALSE; return GL_TRUE; } - + static GLboolean gl2psVertsSameColor(const GL2PSprimitive *prim) { int i; @@ -690,20 +689,20 @@ int i; if(n < 2) return GL_TRUE; - + for(i = 1; i < n; i++){ if(fabs(rgba[0][0] - rgba[i][0]) > threshold[0] || fabs(rgba[0][1] - rgba[i][1]) > threshold[1] || fabs(rgba[0][2] - rgba[i][2]) > threshold[2]) return GL_FALSE; } - + return GL_TRUE; } static void gl2psSetLastColor(GL2PSrgba rgba) { - int i; + int i; for(i = 0; i < 3; ++i){ gl2ps->lastrgba[i] = rgba[i]; } @@ -712,13 +711,13 @@ static GLfloat gl2psGetRGB(GL2PSimage *im, GLuint x, GLuint y, GLfloat *red, GLfloat *green, GLfloat *blue) { - + GLsizei width = im->width; GLsizei height = im->height; GLfloat *pixels = im->pixels; GLfloat *pimag; - /* OpenGL image is from down to up, PS image is up to down */ + /* OpenGL image is from down to up, PS image is up to down */ switch(im->format){ case GL_RGBA: pimag = pixels + 4 * (width * (height - 1 - y) + x); @@ -741,13 +740,11 @@ { int size; GL2PSimage *image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage)); - + image->width = im->width; image->height = im->height; image->format = im->format; image->type = im->type; - image->zoom_x = im->zoom_x; - image->zoom_y = im->zoom_y; switch(image->format){ case GL_RGBA: @@ -761,7 +758,7 @@ image->pixels = (GLfloat*)gl2psMalloc(size); memcpy(image->pixels, im->pixels, size); - + return image; } @@ -783,7 +780,7 @@ { unsigned int i; GL2PSlist *png = (GL2PSlist*)png_get_io_ptr(png_ptr); - for(i = 0; i < length; i++) + for(i = 0; i < length; i++) gl2psListAdd(png, &data[i]); } @@ -801,21 +798,21 @@ if(!(png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL))) return; - + if(!(info_ptr = png_create_info_struct(png_ptr))){ png_destroy_write_struct(&png_ptr, NULL); return; } - + if(setjmp(png_jmpbuf(png_ptr))) { png_destroy_write_struct(&png_ptr, &info_ptr); return; } - + png_set_write_fn(png_ptr, (void *)png, gl2psUserWritePNG, gl2psUserFlushPNG); png_set_compression_level(png_ptr, Z_DEFAULT_COMPRESSION); - png_set_IHDR(png_ptr, info_ptr, pixmap->width, pixmap->height, 8, - PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, + png_set_IHDR(png_ptr, info_ptr, pixmap->width, pixmap->height, 8, + PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); @@ -839,7 +836,7 @@ /* Helper routines for text strings */ -static GLint gl2psAddText(GLint type, const char *str, const char *fontname, +static GLint gl2psAddText(GLint type, const char *str, const char *fontname, GLshort fontsize, GLint alignment, GLfloat angle) { GLfloat pos[4]; @@ -871,7 +868,7 @@ glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba); prim->data.text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring)); prim->data.text->str = (char*)gl2psMalloc((strlen(str)+1)*sizeof(char)); - strcpy(prim->data.text->str, str); + strcpy(prim->data.text->str, str); prim->data.text->fontname = (char*)gl2psMalloc((strlen(fontname)+1)*sizeof(char)); strcpy(prim->data.text->fontname, fontname); prim->data.text->fontsize = fontsize; @@ -880,7 +877,7 @@ gl2psListAdd(gl2ps->auxprimitives, &prim); glPassThrough(GL2PS_TEXT_TOKEN); - + return GL2PS_SUCCESS; } @@ -888,13 +885,13 @@ { GL2PSstring *text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring)); text->str = (char*)gl2psMalloc((strlen(t->str)+1)*sizeof(char)); - strcpy(text->str, t->str); + strcpy(text->str, t->str); text->fontname = (char*)gl2psMalloc((strlen(t->fontname)+1)*sizeof(char)); strcpy(text->fontname, t->fontname); text->fontsize = t->fontsize; text->alignment = t->alignment; text->angle = t->angle; - + return text; } @@ -914,7 +911,7 @@ /* returns TRUE if gl2ps supports the argument combination: only two blending modes have been implemented so far */ - if( (sfactor == GL_SRC_ALPHA && dfactor == GL_ONE_MINUS_SRC_ALPHA) || + if( (sfactor == GL_SRC_ALPHA && dfactor == GL_ONE_MINUS_SRC_ALPHA) || (sfactor == GL_ONE && dfactor == GL_ZERO) ) return GL_TRUE; return GL_FALSE; @@ -934,7 +931,7 @@ v->rgba[3] = 1.0F; return; } - + switch(gl2ps->blendfunc[0]){ case GL_ONE: v->rgba[3] = 1.0F; @@ -955,9 +952,9 @@ a remarkable amount of PDF handling code inside this file depends on it if activated */ /* - t->prop = T_CONST_COLOR; + t->prop = T_CONST_COLOR; for(i = 0; i < 3; ++i){ - if(!GL2PS_ZERO(t->vertex[0].rgba[i] - t->vertex[1].rgba[i]) || + if(!GL2PS_ZERO(t->vertex[0].rgba[i] - t->vertex[1].rgba[i]) || !GL2PS_ZERO(t->vertex[1].rgba[i] - t->vertex[2].rgba[i])){ t->prop = T_VAR_COLOR; break; @@ -965,7 +962,7 @@ } */ - if(!GL2PS_ZERO(t->vertex[0].rgba[3] - t->vertex[1].rgba[3]) || + if(!GL2PS_ZERO(t->vertex[0].rgba[3] - t->vertex[1].rgba[3]) || !GL2PS_ZERO(t->vertex[1].rgba[3] - t->vertex[2].rgba[3])){ t->prop |= T_VAR_ALPHA; } @@ -1008,7 +1005,7 @@ } prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); - + prim->type = p->type; prim->numverts = p->numverts; prim->boundary = p->boundary; @@ -1044,17 +1041,17 @@ return GL_TRUE; } -/********************************************************************* +/********************************************************************* * - * 3D sorting routines + * 3D sorting routines * *********************************************************************/ static GLfloat gl2psComparePointPlane(GL2PSxyz point, GL2PSplane plane) { - return (plane[0] * point[0] + - plane[1] * point[1] + - plane[2] * point[2] + + return (plane[0] * point[0] + + plane[1] * point[1] + + plane[2] * point[2] + plane[3]); } @@ -1101,13 +1098,13 @@ switch(prim->type){ case GL2PS_TRIANGLE : case GL2PS_QUADRANGLE : - v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0]; - v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1]; - v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2]; - w[0] = prim->verts[2].xyz[0] - prim->verts[0].xyz[0]; - w[1] = prim->verts[2].xyz[1] - prim->verts[0].xyz[1]; - w[2] = prim->verts[2].xyz[2] - prim->verts[0].xyz[2]; - if((GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])) || + v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0]; + v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1]; + v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2]; + w[0] = prim->verts[2].xyz[0] - prim->verts[0].xyz[0]; + w[1] = prim->verts[2].xyz[1] - prim->verts[0].xyz[1]; + w[2] = prim->verts[2].xyz[2] - prim->verts[0].xyz[2]; + if((GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])) || (GL2PS_ZERO(w[0]) && GL2PS_ZERO(w[1]) && GL2PS_ZERO(w[2]))){ plane[0] = plane[1] = 0.0F; plane[2] = 1.0F; @@ -1115,16 +1112,16 @@ } else{ gl2psGetNormal(v, w, plane); - plane[3] = - - plane[0] * prim->verts[0].xyz[0] - - plane[1] * prim->verts[0].xyz[1] + plane[3] = + - plane[0] * prim->verts[0].xyz[0] + - plane[1] * prim->verts[0].xyz[1] - plane[2] * prim->verts[0].xyz[2]; } break; case GL2PS_LINE : - v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0]; - v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1]; - v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2]; + v[0] = prim->verts[1].xyz[0] - prim->verts[0].xyz[0]; + v[1] = prim->verts[1].xyz[1] - prim->verts[0].xyz[1]; + v[2] = prim->verts[1].xyz[2] - prim->verts[0].xyz[2]; if(GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])){ plane[0] = plane[1] = 0.0F; plane[2] = 1.0F; @@ -1135,9 +1132,9 @@ else if(GL2PS_ZERO(v[1])) w[1] = 1.0F; else w[2] = 1.0F; gl2psGetNormal(v, w, plane); - plane[3] = - - plane[0] * prim->verts[0].xyz[0] - - plane[1] * prim->verts[0].xyz[1] + plane[3] = + - plane[0] * prim->verts[0].xyz[0] + - plane[1] * prim->verts[0].xyz[1] - plane[2] * prim->verts[0].xyz[2]; } break; @@ -1172,11 +1169,11 @@ sect = -gl2psComparePointPlane(a->xyz, plane) / psca; else sect = 0.0F; - + c->xyz[0] = a->xyz[0] + v[0] * sect; c->xyz[1] = a->xyz[1] + v[1] * sect; c->xyz[2] = a->xyz[2] + v[2] * sect; - + c->rgba[0] = (1 - sect) * a->rgba[0] + sect * b->rgba[0]; c->rgba[1] = (1 - sect) * a->rgba[1] + sect * b->rgba[1]; c->rgba[2] = (1 - sect) * a->rgba[2] + sect * b->rgba[2]; @@ -1199,10 +1196,10 @@ numverts = 4; } switch(numverts){ - case 1 : child->type = GL2PS_POINT; break; - case 2 : child->type = GL2PS_LINE; break; - case 3 : child->type = GL2PS_TRIANGLE; break; - case 4 : child->type = GL2PS_QUADRANGLE; break; + case 1 : child->type = GL2PS_POINT; break; + case 2 : child->type = GL2PS_LINE; break; + case 3 : child->type = GL2PS_TRIANGLE; break; + case 4 : child->type = GL2PS_QUADRANGLE; break; default: child->type = GL2PS_NO_TYPE; break; } } @@ -1221,13 +1218,13 @@ child->verts[i] = parent->verts[index0[i]]; } else{ - gl2psCutEdge(&parent->verts[index0[i]], &parent->verts[index1[i]], + gl2psCutEdge(&parent->verts[index0[i]], &parent->verts[index1[i]], plane, &child->verts[i]); } } } -static void gl2psAddIndex(GLshort *index0, GLshort *index1, GLshort *nb, +static void gl2psAddIndex(GLshort *index0, GLshort *index1, GLshort *nb, GLshort i, GLshort j) { GLint k; @@ -1250,9 +1247,9 @@ { GLint type = GL2PS_COINCIDENT; GLshort i, j; - GLfloat d[5]; - - for(i = 0; i < prim->numverts; i++){ + GLfloat d[5]; + + for(i = 0; i < prim->numverts; i++){ d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane); } @@ -1264,11 +1261,11 @@ j = gl2psGetIndex(i, prim->numverts); if(d[j] > GL2PS_EPSILON){ if(type == GL2PS_COINCIDENT) type = GL2PS_IN_BACK_OF; - else if(type != GL2PS_IN_BACK_OF) return 1; + else if(type != GL2PS_IN_BACK_OF) return 1; if(d[i] < -GL2PS_EPSILON) return 1; } else if(d[j] < -GL2PS_EPSILON){ - if(type == GL2PS_COINCIDENT) type = GL2PS_IN_FRONT_OF; + if(type == GL2PS_COINCIDENT) type = GL2PS_IN_FRONT_OF; else if(type != GL2PS_IN_FRONT_OF) return 1; if(d[i] > GL2PS_EPSILON) return 1; } @@ -1277,16 +1274,16 @@ return 0; } -static GLint gl2psSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane, +static GLint gl2psSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane, GL2PSprimitive **front, GL2PSprimitive **back) { GLshort i, j, in = 0, out = 0, in0[5], in1[5], out0[5], out1[5]; GLint type; - GLfloat d[5]; + GLfloat d[5]; type = GL2PS_COINCIDENT; - for(i = 0; i < prim->numverts; i++){ + for(i = 0; i < prim->numverts; i++){ d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane); } @@ -1301,7 +1298,7 @@ j = gl2psGetIndex(i, prim->numverts); if(d[j] > GL2PS_EPSILON){ if(type == GL2PS_COINCIDENT) type = GL2PS_IN_BACK_OF; - else if(type != GL2PS_IN_BACK_OF) type = GL2PS_SPANNING; + else if(type != GL2PS_IN_BACK_OF) type = GL2PS_SPANNING; if(d[i] < -GL2PS_EPSILON){ gl2psAddIndex(in0, in1, &in, i, j); gl2psAddIndex(out0, out1, &out, i, j); @@ -1310,7 +1307,7 @@ gl2psAddIndex(out0, out1, &out, j, -1); } else if(d[j] < -GL2PS_EPSILON){ - if(type == GL2PS_COINCIDENT) type = GL2PS_IN_FRONT_OF; + if(type == GL2PS_COINCIDENT) type = GL2PS_IN_FRONT_OF; else if(type != GL2PS_IN_FRONT_OF) type = GL2PS_SPANNING; if(d[i] > GL2PS_EPSILON){ gl2psAddIndex(in0, in1, &in, i, j); @@ -1337,7 +1334,7 @@ return type; } -static void gl2psDivideQuad(GL2PSprimitive *quad, +static void gl2psDivideQuad(GL2PSprimitive *quad, GL2PSprimitive **t1, GL2PSprimitive **t2) { *t1 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); @@ -1366,17 +1363,17 @@ GL2PSprimitive *q, *w; GLfloat dq = 0.0F, dw = 0.0F, diff; int i; - + q = *(GL2PSprimitive**)a; w = *(GL2PSprimitive**)b; for(i = 0; i < q->numverts; i++){ - dq += q->verts[i].xyz[2]; + dq += q->verts[i].xyz[2]; } dq /= (GLfloat)q->numverts; for(i = 0; i < w->numverts; i++){ - dw += w->verts[i].xyz[2]; + dw += w->verts[i].xyz[2]; } dw /= (GLfloat)w->numverts; @@ -1427,7 +1424,7 @@ for(j = 0; j < gl2psListNbr(primitives); j++){ if(j != i){ prim2 = *(GL2PSprimitive**)gl2psListPointer(primitives, j); - count += gl2psTestSplitPrimitive(prim2, plane); + count += gl2psTestSplitPrimitive(prim2, plane); } if(count > best) break; } @@ -1461,7 +1458,7 @@ static void gl2psFreePrimitive(void *data) { GL2PSprimitive *q; - + q = *(GL2PSprimitive**)data; gl2psFree(q->verts); if(q->type == GL2PS_TEXT || q->type == GL2PS_SPECIAL){ @@ -1486,7 +1483,7 @@ gl2psListAdd(list, &t2); gl2psFreePrimitive(&prim); } - + } static void gl2psFreeBspTree(GL2PSbsptree **tree) @@ -1598,7 +1595,7 @@ } gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); } - else if(GL_TRUE == compare(-epsilon, result)){ + else if(GL_TRUE == compare(-epsilon, result)){ gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); if(inverse){ gl2psListActionInverse(tree->primitives, action); @@ -1666,18 +1663,18 @@ else if(prim->offset && (prim->type == GL2PS_TRIANGLE)){ factor = gl2ps->offset[0]; units = gl2ps->offset[1]; - area = - (prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) * - (prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) - - (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) * + area = + (prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) * + (prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) - + (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) * (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]); if(!GL2PS_ZERO(area)){ - dZdX = + dZdX = ((prim->verts[2].xyz[1] - prim->verts[1].xyz[1]) * (prim->verts[1].xyz[2] - prim->verts[0].xyz[2]) - (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]) * (prim->verts[2].xyz[2] - prim->verts[1].xyz[2])) / area; - dZdY = + dZdY = ((prim->verts[1].xyz[0] - prim->verts[0].xyz[0]) * (prim->verts[2].xyz[2] - prim->verts[1].xyz[2]) - (prim->verts[2].xyz[0] - prim->verts[1].xyz[0]) * @@ -1695,15 +1692,15 @@ } } -/********************************************************************* +/********************************************************************* * - * 2D sorting routines (for occlusion culling) + * 2D sorting routines (for occlusion culling) * *********************************************************************/ static GLint gl2psGetPlaneFromPoints(GL2PSxyz a, GL2PSxyz b, GL2PSplane plane) { - GLfloat n; + GLfloat n; plane[0] = b[1] - a[1]; plane[1] = a[0] - b[0]; @@ -1712,7 +1709,7 @@ if(!GL2PS_ZERO(n)){ plane[0] /= n; plane[1] /= n; - plane[3] = -plane[0]*a[0]-plane[1]*a[1]; + plane[3] = -plane[0]*a[0]-plane[1]*a[1]; return 1; } else{ @@ -1897,8 +1894,8 @@ } static void gl2psSplitPrimitive2D(GL2PSprimitive *prim, - GL2PSplane plane, - GL2PSprimitive **front, + GL2PSplane plane, + GL2PSprimitive **front, GL2PSprimitive **back) { /* cur will hold the position of the current vertex @@ -1907,10 +1904,10 @@ v1 and v2 represent the current and previous vertices, respectively flag is set if the current vertex should be checked against the plane */ GLint cur = -1, prev = -1, i, v1 = 0, v2 = 0, flag = 1, prev0 = -1; - + /* list of vertices that will go in front and back primitive */ GL2PSvertex *front_list = NULL, *back_list = NULL; - + /* number of vertices in front and back list */ GLshort front_count = 0, back_count = 0; @@ -1927,7 +1924,7 @@ if(i == 0){ prev0 = cur; } - } + } if(((prev == -1) || (prev == cur) || (prev == 0) || (cur == 0)) && (i < prim->numverts)){ if(cur == GL2PS_POINT_INFRONT){ @@ -1982,12 +1979,12 @@ { GLint ret = 0; GL2PSprimitive *frontprim = NULL, *backprim = NULL; - + /* FIXME: until we consider the actual extent of text strings and pixmaps, never cull them. Otherwise the whole string/pixmap gets culled as soon as the reference point is hidden */ - if(prim->type == GL2PS_PIXMAP || - prim->type == GL2PS_TEXT || + if(prim->type == GL2PS_PIXMAP || + prim->type == GL2PS_TEXT || prim->type == GL2PS_SPECIAL){ return 1; } @@ -2001,7 +1998,7 @@ else{ switch(gl2psCheckPrimitive(prim, (*tree)->plane)){ case GL2PS_IN_BACK_OF: return gl2psAddInBspImageTree(prim, &(*tree)->back); - case GL2PS_IN_FRONT_OF: + case GL2PS_IN_FRONT_OF: if((*tree)->front != NULL) return gl2psAddInBspImageTree(prim, &(*tree)->front); else return 0; case GL2PS_SPANNING: @@ -2136,14 +2133,14 @@ gl2psBuildPolygonBoundary(tree->front); } -/********************************************************************* +/********************************************************************* * * Feedback buffer parser * *********************************************************************/ -static void gl2psAddPolyPrimitive(GLshort type, GLshort numverts, - GL2PSvertex *verts, GLint offset, +static void gl2psAddPolyPrimitive(GLshort type, GLshort numverts, + GL2PSvertex *verts, GLint offset, GLushort pattern, GLint factor, GLfloat width, char boundary) { @@ -2210,7 +2207,7 @@ while(used > 0){ if(GL_TRUE == boundary) gl2ps->boundary = GL_TRUE; - + switch((GLint)*current){ case GL_POINT_TOKEN : current ++; @@ -2218,7 +2215,7 @@ i = gl2psGetVertex(&vertices[0], current); current += i; used -= i; - gl2psAddPolyPrimitive(GL2PS_POINT, 1, vertices, 0, + gl2psAddPolyPrimitive(GL2PS_POINT, 1, vertices, 0, pattern, factor, psize, 0); break; case GL_LINE_TOKEN : @@ -2231,7 +2228,7 @@ i = gl2psGetVertex(&vertices[1], current); current += i; used -= i; - gl2psAddPolyPrimitive(GL2PS_LINE, 2, vertices, 0, + gl2psAddPolyPrimitive(GL2PS_LINE, 2, vertices, 0, pattern, factor, lwidth, 0); break; case GL_POLYGON_TOKEN : @@ -2262,7 +2259,7 @@ else v ++; } - break; + break; case GL_BITMAP_TOKEN : case GL_DRAW_PIXEL_TOKEN : case GL_COPY_PIXEL_TOKEN : @@ -2271,7 +2268,7 @@ i = gl2psGetVertex(&vertices[0], current); current += i; used -= i; - break; + break; case GL_PASS_THROUGH_TOKEN : switch((GLint)current[1]){ case GL2PS_BEGIN_OFFSET_TOKEN : offset = 1; break; @@ -2281,32 +2278,32 @@ case GL2PS_END_STIPPLE_TOKEN : pattern = factor = 0; break; case GL2PS_BEGIN_BLEND_TOKEN : gl2ps->blending = GL_TRUE; break; case GL2PS_END_BLEND_TOKEN : gl2ps->blending = GL_FALSE; break; - case GL2PS_BEGIN_STIPPLE_TOKEN : + case GL2PS_BEGIN_STIPPLE_TOKEN : current += 2; - used -= 2; - pattern = (GLushort)current[1]; + used -= 2; + pattern = (GLushort)current[1]; current += 2; - used -= 2; - factor = (GLint)current[1]; + used -= 2; + factor = (GLint)current[1]; break; - case GL2PS_SRC_BLEND_TOKEN : - current += 2; - used -= 2; + case GL2PS_SRC_BLEND_TOKEN : + current += 2; + used -= 2; gl2ps->blendfunc[0] = (GLint)current[1]; break; - case GL2PS_DST_BLEND_TOKEN : - current += 2; - used -= 2; + case GL2PS_DST_BLEND_TOKEN : + current += 2; + used -= 2; gl2ps->blendfunc[1] = (GLint)current[1]; break; - case GL2PS_POINT_SIZE_TOKEN : - current += 2; - used -= 2; + case GL2PS_POINT_SIZE_TOKEN : + current += 2; + used -= 2; psize = current[1]; break; - case GL2PS_LINE_WIDTH_TOKEN : - current += 2; - used -= 2; + case GL2PS_LINE_WIDTH_TOKEN : + current += 2; + used -= 2; lwidth = current[1]; break; case GL2PS_IMAGEMAP_TOKEN : @@ -2320,26 +2317,24 @@ prim->pattern = 0; prim->factor = 0; prim->width = 1; - + node = (GL2PSimagemap*)gl2psMalloc(sizeof(GL2PSimagemap)); node->image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage)); node->image->type = 0; node->image->format = 0; - node->image->zoom_x = 1.0F; - node->image->zoom_y = 1.0F; node->next = NULL; - + if(gl2ps->imagemap_head == NULL) gl2ps->imagemap_head = node; else gl2ps->imagemap_tail->next = node; gl2ps->imagemap_tail = node; prim->data.image = node->image; - + current += 2; used -= 2; i = gl2psGetVertex(&prim->verts[0], ¤t[1]); current += i; used -= i; - + node->image->width = (GLint)current[2]; current += 2; used -= 2; node->image->height = (GLint)current[2]; @@ -2359,12 +2354,12 @@ sizeoffloat = sizeof(GLfloat); v = 2 * sizeoffloat; - vtot = node->image->height + node->image->height * + vtot = node->image->height + node->image->height * ((node->image->width - 1) / 8); node->image->pixels = (GLfloat*)gl2psMalloc(v + vtot); node->image->pixels[0] = prim->verts[0].xyz[0]; node->image->pixels[1] = prim->verts[0].xyz[1]; - + for(i = 0; i < vtot; i += sizeoffloat){ current += 2; used -= 2; if((vtot - i) >= 4) @@ -2378,15 +2373,15 @@ case GL2PS_DRAW_PIXELS_TOKEN : case GL2PS_TEXT_TOKEN : if(auxindex < gl2psListNbr(gl2ps->auxprimitives)) - gl2psListAdd(gl2ps->primitives, + gl2psListAdd(gl2ps->primitives, gl2psListPointer(gl2ps->auxprimitives, auxindex++)); else gl2psMsg(GL2PS_ERROR, "Wrong number of auxiliary tokens in buffer"); break; } - current += 2; - used -= 2; - break; + current += 2; + used -= 2; + break; default : gl2psMsg(GL2PS_WARNING, "Unknown token in buffer"); current ++; @@ -2398,7 +2393,7 @@ gl2psListReset(gl2ps->auxprimitives); } -/********************************************************************* +/********************************************************************* * * PostScript routines * @@ -2428,17 +2423,17 @@ if((width <= 0) || (height <= 0)) return; gl2psPrintf("gsave\n"); - gl2psPrintf("%.2f %.2f translate\n", x, y); - gl2psPrintf("%.2f %.2f scale\n", width * im->zoom_x, height * im->zoom_y); + gl2psPrintf("%.2f %.2f translate\n", x, y); + gl2psPrintf("%d %d scale\n", width, height); if(greyscale){ /* greyscale */ - gl2psPrintf("/picstr %d string def\n", width); - gl2psPrintf("%d %d %d\n", width, height, 8); - gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); + gl2psPrintf("/picstr %d string def\n", width); + gl2psPrintf("%d %d %d\n", width, height, 8); + gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); gl2psPrintf("{ currentfile picstr readhexstring pop }\n"); gl2psPrintf("image\n"); for(row = 0; row < height; row++){ - for(col = 0; col < width; col++){ + for(col = 0; col < width; col++){ gl2psGetRGB(im, col, row, &dr, &dg, &db); fgrey = (0.30F * dr + 0.59F * dg + 0.11F * db); grey = (unsigned char)(255. * fgrey); @@ -2446,8 +2441,8 @@ } gl2psPrintf("\n"); } - nbhex = width * height * 2; - gl2psPrintf("%%%% nbhex digit :%d\n", nbhex); + nbhex = width * height * 2; + gl2psPrintf("%%%% nbhex digit :%d\n", nbhex); } else if(nbit == 2){ /* color, 2 bits for r and g and b; rgbs following each other */ nrgb = width * 3; @@ -2468,7 +2463,7 @@ if(icase == 1) { if(col < width) { gl2psGetRGB(im, col, row, &dr, &dg, &db); - } + } else { dr = dg = db = 0; } @@ -2481,7 +2476,7 @@ b = (b<<2) + blue; if(col < width) { gl2psGetRGB(im, col, row, &dr, &dg, &db); - } + } else { dr = dg = db = 0; } @@ -2493,7 +2488,7 @@ gl2psWriteByte(b); b = 0; icase++; - } + } else if(icase == 2) { b = green; b = (b<<2) + blue; @@ -2512,7 +2507,7 @@ gl2psWriteByte(b); b = 0; icase++; - } + } else if(icase == 3) { b = blue; if(col < width) { @@ -2540,7 +2535,7 @@ nrgb = width * 3; nbits = nrgb * nbit; nbyte = nbits / 8; - if((nbyte * 8) != nbits) nbyte++; + if((nbyte * 8) != nbits) nbyte++; gl2psPrintf("/rgbstr %d string def\n", nbyte); gl2psPrintf("%d %d %d\n", width, height, nbit); gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); @@ -2554,7 +2549,7 @@ if(icase == 1) { if(col < width) { gl2psGetRGB(im, col, row, &dr, &dg, &db); - } + } else { dr = dg = db = 0; } @@ -2563,12 +2558,12 @@ green = (unsigned char)(15. * dg); gl2psPrintf("%x%x", red, green); icase++; - } + } else if(icase == 2) { blue = (unsigned char)(15. * db); if(col < width) { gl2psGetRGB(im, col, row, &dr, &dg, &db); - } + } else { dr = dg = db = 0; } @@ -2591,7 +2586,7 @@ nbyte = width * 3; gl2psPrintf("/rgbstr %d string def\n", nbyte); gl2psPrintf("%d %d %d\n", width, height, 8); - gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); + gl2psPrintf("[ %d 0 0 -%d 0 %d ]\n", width, height, height); gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n"); gl2psPrintf("false 3\n"); gl2psPrintf("colorimage\n"); @@ -2608,7 +2603,7 @@ gl2psPrintf("\n"); } } - + gl2psPrintf("grestore\n"); } @@ -2616,14 +2611,14 @@ GLsizei width, GLsizei height, const unsigned char *imagemap){ int i, size; - + if((width <= 0) || (height <= 0)) return; - + size = height + height * (width - 1) / 8; - + gl2psPrintf("gsave\n"); gl2psPrintf("%.2f %.2f translate\n", x, y); - gl2psPrintf("%d %d scale\n%d %d\ntrue\n", width, height,width, height); + gl2psPrintf("%d %d scale\n%d %d\ntrue\n", width, height,width, height); gl2psPrintf("[ %d 0 0 -%d 0 %d ] {<", width, height); for(i = 0; i < size; i++){ gl2psWriteByte(*imagemap); @@ -2657,7 +2652,7 @@ "%%%%LanguageLevel: 3\n" "%%%%DocumentData: Clean7Bit\n" "%%%%Pages: 1\n", - gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, + gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer, ctime(&now)); @@ -2666,18 +2661,18 @@ "%%%%DocumentMedia: Default %d %d 0 () ()\n", (gl2ps->options & GL2PS_LANDSCAPE) ? "Landscape" : "Portrait", (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] : - (int)gl2ps->viewport[2], - (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] : + (int)gl2ps->viewport[2], + (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] : (int)gl2ps->viewport[3]); } gl2psPrintf("%%%%BoundingBox: %d %d %d %d\n" "%%%%EndComments\n", - (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[1] : + (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[1] : (int)gl2ps->viewport[0], (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[0] : (int)gl2ps->viewport[1], - (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] : + (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[3] : (int)gl2ps->viewport[2], (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] : (int)gl2ps->viewport[3]); @@ -2725,7 +2720,7 @@ /* rotated text routines: same nameanem with R appended */ gl2psPrintf("/FCT { FC translate 0 0 } BD\n" - "/SR { gsave FCT moveto rotate show grestore } BD\n" + "/SR { gsave FCT moveto rotate show grestore } BD\n" "/SBCR{ gsave FCT moveto rotate SW -2 div 0 rmoveto show grestore } BD\n" "/SBRR{ gsave FCT moveto rotate SW neg 0 rmoveto show grestore } BD\n" "/SCLR{ gsave FCT moveto rotate 0 SH -2 div rmoveto show grestore} BD\n"); @@ -2740,7 +2735,7 @@ "/L { lineto } BD\n" "/LE { lineto stroke } BD\n" "/T { newpath moveto lineto lineto closepath fill } BD\n"); - + /* Smooth-shaded triangle with PostScript level 3 shfill operator: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STshfill */ @@ -2794,11 +2789,11 @@ " 4 index 10 index add 0.5 mul\n" /* g12 = (g1+g2)/2 */ " 4 index 10 index add 0.5 mul\n" /* b12 = (b1+b2)/2 */ " 5 copy 5 copy 40 5 roll 25 5 roll 15 5 roll 25 5 roll\n"); - + /* stack = (V3) (V13) (V23) (V13) (V12) (V23) (V13) (V1) (V12) (V23) (V12) (V2) */ gl2psPrintf(" STnoshfill STnoshfill STnoshfill STnoshfill } BD\n"); - + /* Gouraud shaded triangle using recursive subdivision until the difference between corner colors does not exceed the thresholds: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STnoshfill */ @@ -2832,7 +2827,7 @@ " ifelse }\n" " ifelse }\n" " ifelse } BD\n"); - + gl2psPrintf("tryPS3shading\n" "{ /shfill where\n" " { /ST { STshfill } BD }\n" @@ -2849,7 +2844,7 @@ "%%%%EndSetup\n" "%%%%Page: 1 1\n" "%%%%BeginPageSetup\n"); - + if(gl2ps->options & GL2PS_LANDSCAPE){ gl2psPrintf("%d 0 translate 90 rotate\n", (int)gl2ps->viewport[3]); @@ -2859,14 +2854,14 @@ "mark\n" "gsave\n" "1.0 1.0 scale\n"); - + if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ gl2psPrintf("%g %g %g C\n" "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n" "closepath fill\n", - gl2ps->bgcolor[0], gl2ps->bgcolor[1], gl2ps->bgcolor[2], - (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], - (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3], + gl2ps->bgcolor[0], gl2ps->bgcolor[1], gl2ps->bgcolor[2], + (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], + (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3], (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]); } } @@ -2896,7 +2891,7 @@ } } -static void gl2psParseStipplePattern(GLushort pattern, GLint factor, +static void gl2psParseStipplePattern(GLushort pattern, GLint factor, int *nb, int array[10]) { int i, n; @@ -2936,10 +2931,10 @@ if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor) return 0; - + gl2ps->lastpattern = pattern; gl2ps->lastfactor = factor; - + if(!pattern || !factor){ /* solid line */ len += gl2psPrintf("[] 0 %s\n", str); @@ -2953,7 +2948,7 @@ } len += gl2psPrintf("] 0 %s\n", str); } - + return len; } @@ -2976,7 +2971,7 @@ switch(prim->type){ case GL2PS_POINT : gl2psPrintPostScriptColor(prim->verts[0].rgba); - gl2psPrintf("%g %g %g P\n", + gl2psPrintf("%g %g %g P\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1], 0.5 * prim->width); break; case GL2PS_LINE : @@ -3139,14 +3134,14 @@ gl2psPrintf("%g %g %g C\n" "newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n" "closepath fill\n", - rgba[0], rgba[1], rgba[2], + rgba[0], rgba[1], rgba[2], x, y, x+w, y, x+w, y+h, x, y+h); } - + gl2psPrintf("newpath %d %d moveto %d %d lineto %d %d lineto %d %d lineto\n" "closepath clip\n", x, y, x+w, y, x+w, y+h, x, y+h); - + } static GLint gl2psPrintPostScriptEndViewport(void) @@ -3188,7 +3183,7 @@ "Encapsulated Postscript" }; -/********************************************************************* +/********************************************************************* * * LaTeX routines * @@ -3216,7 +3211,7 @@ time(&now); - fprintf(gl2ps->stream, + fprintf(gl2ps->stream, "%% Title: %s\n" "%% Creator: GL2PS %d.%d.%d%s, %s\n" "%% For: %s\n" @@ -3225,7 +3220,7 @@ GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer, ctime(&now)); - fprintf(gl2ps->stream, + fprintf(gl2ps->stream, "\\setlength{\\unitlength}{1pt}\n" "\\begin{picture}(0,0)\n" "\\includegraphics{%s}\n" @@ -3243,13 +3238,10 @@ switch(prim->type){ case GL2PS_TEXT : - fprintf(gl2ps->stream, "\\fontsize{%d}{0}\n\\selectfont", + fprintf(gl2ps->stream, "\\fontsize{%d}{0}\n\\selectfont", prim->data.text->fontsize); - fprintf(gl2ps->stream, "\\put(%g,%g)", + fprintf(gl2ps->stream, "\\put(%g,%g){\\makebox(0,0)", prim->verts[0].xyz[0], prim->verts[0].xyz[1]); - if(prim->data.text->angle) - fprintf(gl2ps->stream, "{\\rotatebox{%g}", prim->data.text->angle); - fprintf(gl2ps->stream, "{\\makebox(0,0)"); switch(prim->data.text->alignment){ case GL2PS_TEXT_C: fprintf(gl2ps->stream, "{"); @@ -3280,6 +3272,8 @@ fprintf(gl2ps->stream, "[bl]{"); break; } + if(prim->data.text->angle) + fprintf(gl2ps->stream, "\\rotatebox{%g}{", prim->data.text->angle); fprintf(gl2ps->stream, "\\textcolor[rgb]{%g,%g,%g}{{%s}}", prim->verts[0].rgba[0], prim->verts[0].rgba[1], prim->verts[0].rgba[2], prim->data.text->str); @@ -3307,7 +3301,7 @@ static void gl2psPrintTeXBeginViewport(GLint viewport[4]) { glRenderMode(GL_FEEDBACK); - + if(gl2ps->header){ gl2psPrintTeXHeader(); gl2ps->header = GL_FALSE; @@ -3336,7 +3330,7 @@ "LaTeX text" }; -/********************************************************************* +/********************************************************************* * * PDF routines * @@ -3372,7 +3366,7 @@ static int gl2psPrintPDFFillColor(GL2PSrgba rgba) { int i, offs = 0; - + for(i = 0; i < 3; ++i){ if(GL2PS_ZERO(rgba[i])) offs += gl2psPrintf("%.0f ", 0.); @@ -3398,18 +3392,18 @@ static void gl2psPutPDFText(GL2PSstring *text, int cnt, GLfloat x, GLfloat y) { GLfloat rad, crad, srad; - + if(text->angle == 0.0F){ gl2ps->streamlength += gl2psPrintf ("BT\n" "/F%d %d Tf\n" "%f %f Td\n" "(%s) Tj\n" - "ET\n", + "ET\n", cnt, text->fontsize, x, y, text->str); } else{ - rad = (GLfloat)M_PI * text->angle / 180.0F; + rad = M_PI * text->angle / 180.0F; srad = (GLfloat)sin(rad); crad = (GLfloat)cos(rad); gl2ps->streamlength += gl2psPrintf @@ -3434,23 +3428,23 @@ static void gl2psPDFstacksInit(void) { - gl2ps->objects_stack = 7 /* FIXED_XREF_ENTRIES */ + 1; - gl2ps->extgs_stack = 0; - gl2ps->font_stack = 0; - gl2ps->im_stack = 0; - gl2ps->trgroupobjects_stack = 0; - gl2ps->shader_stack = 0; - gl2ps->mshader_stack = 0; + gl2ps->objects_stack = 7 /* FIXED_XREF_ENTRIES */ + 1; + gl2ps->extgs_stack = 0; + gl2ps->font_stack = 0; + gl2ps->im_stack = 0; + gl2ps->trgroupobjects_stack = 0; + gl2ps->shader_stack = 0; + gl2ps->mshader_stack = 0; } static void gl2psPDFgroupObjectInit(GL2PSpdfgroup *gro) { if(!gro) return; - + gro->ptrlist = NULL; - gro->fontno = gro->gsno = gro->imno = gro->maskshno = gro->shno - = gro->trgroupno = gro->fontobjno = gro->imobjno = gro->shobjno + gro->fontno = gro->gsno = gro->imno = gro->maskshno = gro->shno + = gro->trgroupno = gro->fontobjno = gro->imobjno = gro->shobjno = gro->maskshobjno = gro->gsobjno = gro->trgroupobjno = -1; } @@ -3475,7 +3469,7 @@ gl2ps->pdfgrouplist = gl2psListCreate(500, 500, sizeof(GL2PSpdfgroup)); gl2psInitTriangle(&lastt); - for(i = 0; i < gl2psListNbr(gl2ps->pdfprimlist); ++i){ + for(i = 0; i < gl2psListNbr(gl2ps->pdfprimlist); ++i){ p = *(GL2PSprimitive**)gl2psListPointer(gl2ps->pdfprimlist, i); switch(p->type){ case GL2PS_PIXMAP: @@ -3493,7 +3487,7 @@ gl2psListAdd(gl2ps->pdfgrouplist, &gro); break; case GL2PS_LINE: - if(lasttype != p->type || lastwidth != p->width || + if(lasttype != p->type || lastwidth != p->width || lastpattern != p->pattern || lastfactor != p->factor || !gl2psSameColor(p->verts[0].rgba, lastrgba)){ gl2psPDFgroupObjectInit(&gro); @@ -3512,7 +3506,7 @@ lastrgba[2] = p->verts[0].rgba[2]; break; case GL2PS_POINT: - if(lasttype != p->type || lastwidth != p->width || + if(lasttype != p->type || lastwidth != p->width || !gl2psSameColor(p->verts[0].rgba, lastrgba)){ gl2psPDFgroupObjectInit(&gro); gro.ptrlist = gl2psListCreate(1,2,sizeof(GL2PSprimitive*)); @@ -3529,10 +3523,10 @@ break; case GL2PS_TRIANGLE: gl2psFillTriangleFromPrimitive(&tmpt, p, GL_TRUE); - lastTriangleWasNotSimpleWithSameColor = + lastTriangleWasNotSimpleWithSameColor = !(tmpt.prop & T_CONST_COLOR && tmpt.prop & T_ALPHA_1) || !gl2psSameColor(tmpt.vertex[0].rgba, lastt.vertex[0].rgba); - if(lasttype == p->type && tmpt.prop == lastt.prop && + if(lasttype == p->type && tmpt.prop == lastt.prop && lastTriangleWasNotSimpleWithSameColor){ /* TODO Check here for last alpha */ gl2psListAdd(gro.ptrlist, &p); @@ -3547,7 +3541,7 @@ break; default: break; - } + } lasttype = p->type; } } @@ -3556,7 +3550,7 @@ { GL2PStriangle t; GL2PSprimitive *prim = NULL; - + if(!gro) return; @@ -3569,35 +3563,35 @@ return; gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE); - - if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){ - gro->gsno = gl2ps->extgs_stack++; + + if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){ + gro->gsno = gl2ps->extgs_stack++; gro->gsobjno = gl2ps->objects_stack ++; } - else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){ + else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){ gro->gsno = gl2ps->extgs_stack++; gro->gsobjno = gl2ps->objects_stack++; - gro->trgroupno = gl2ps->trgroupobjects_stack++; + gro->trgroupno = gl2ps->trgroupobjects_stack++; gro->trgroupobjno = gl2ps->objects_stack++; gro->maskshno = gl2ps->mshader_stack++; gro->maskshobjno = gl2ps->objects_stack++; } - else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){ + else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){ gro->shno = gl2ps->shader_stack++; gro->shobjno = gl2ps->objects_stack++; } - else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){ + else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){ gro->gsno = gl2ps->extgs_stack++; gro->gsobjno = gl2ps->objects_stack++; - gro->shno = gl2ps->shader_stack++; + gro->shno = gl2ps->shader_stack++; gro->shobjno = gl2ps->objects_stack++; } - else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){ + else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){ gro->gsno = gl2ps->extgs_stack++; gro->gsobjno = gl2ps->objects_stack++; - gro->shno = gl2ps->shader_stack++; + gro->shno = gl2ps->shader_stack++; gro->shobjno = gl2ps->objects_stack++; - gro->trgroupno = gl2ps->trgroupobjects_stack++; + gro->trgroupno = gl2ps->trgroupobjects_stack++; gro->trgroupobjno = gl2ps->objects_stack++; gro->maskshno = gl2ps->mshader_stack++; gro->maskshobjno = gl2ps->objects_stack++; @@ -3630,14 +3624,14 @@ gl2ps->streamlength += gl2psPrintf("1 J\n"); gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width); gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba); - for(j = 0; j <= lastel; ++j){ + for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2ps->streamlength += gl2psPrintf("%f %f m %f %f l\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1], prim->verts[0].xyz[0], prim->verts[0].xyz[1]); } - gl2ps->streamlength += gl2psPrintf("S\n"); + gl2ps->streamlength += gl2psPrintf("S\n"); gl2ps->streamlength += gl2psPrintf("0 J\n"); break; case GL2PS_LINE: @@ -3648,10 +3642,10 @@ gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba); gl2ps->streamlength += gl2psPrintPostScriptDash(prim->pattern, prim->factor, "d"); /* start new path */ - gl2ps->streamlength += - gl2psPrintf("%f %f m\n", + gl2ps->streamlength += + gl2psPrintf("%f %f m\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1]); - + for(j = 1; j <= lastel; ++j){ prev = prim; prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); @@ -3659,38 +3653,38 @@ /* the starting point of the new segment does not match the end point of the previous line, so we end the current path and start a new one */ - gl2ps->streamlength += - gl2psPrintf("%f %f l\n", + gl2ps->streamlength += + gl2psPrintf("%f %f l\n", prev->verts[1].xyz[0], prev->verts[1].xyz[1]); - gl2ps->streamlength += - gl2psPrintf("%f %f m\n", + gl2ps->streamlength += + gl2psPrintf("%f %f m\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1]); } else{ /* the two segements are connected, so we just append to the current path */ - gl2ps->streamlength += + gl2ps->streamlength += gl2psPrintf("%f %f l\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1]); } } /* end last path */ - gl2ps->streamlength += - gl2psPrintf("%f %f l\n", + gl2ps->streamlength += + gl2psPrintf("%f %f l\n", prim->verts[1].xyz[0], prim->verts[1].xyz[1]); gl2ps->streamlength += gl2psPrintf("S\n"); break; case GL2PS_TRIANGLE: gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE); gl2psSortOutTrianglePDFgroup(gro); - + /* No alpha and const color: Simple PDF draw orders */ - if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_1){ - gl2ps->streamlength += gl2psPrintPDFFillColor(t.vertex[0].rgba); - for(j = 0; j <= lastel; ++j){ + if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_1){ + gl2ps->streamlength += gl2psPrintPDFFillColor(t.vertex[0].rgba); + for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); - gl2ps->streamlength + gl2ps->streamlength += gl2psPrintf("%f %f m\n" "%f %f l\n" "%f %f l\n" @@ -3700,17 +3694,17 @@ t.vertex[2].xyz[0], t.vertex[2].xyz[1]); } } - /* Const alpha < 1 and const color: Simple PDF draw orders + /* Const alpha < 1 and const color: Simple PDF draw orders and an extra extended Graphics State for the alpha const */ - else if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){ + else if(t.prop & T_CONST_COLOR && t.prop & T_ALPHA_LESS_1){ gl2ps->streamlength += gl2psPrintf("q\n" "/GS%d gs\n", gro->gsno); gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); - for(j = 0; j <= lastel; ++j){ + for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); - gl2ps->streamlength + gl2ps->streamlength += gl2psPrintf("%f %f m\n" "%f %f l\n" "%f %f l\n" @@ -3721,19 +3715,19 @@ } gl2ps->streamlength += gl2psPrintf("Q\n"); } - /* Variable alpha and const color: Simple PDF draw orders - and an extra extended Graphics State + Xobject + Shader + /* Variable alpha and const color: Simple PDF draw orders + and an extra extended Graphics State + Xobject + Shader object for the alpha mask */ - else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){ + else if(t.prop & T_CONST_COLOR && t.prop & T_VAR_ALPHA){ gl2ps->streamlength += gl2psPrintf("q\n" "/GS%d gs\n" "/TrG%d Do\n", gro->gsno, gro->trgroupno); gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); - for(j = 0; j <= lastel; ++j){ + for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); - gl2ps->streamlength + gl2ps->streamlength += gl2psPrintf("%f %f m\n" "%f %f l\n" "%f %f l\n" @@ -3746,23 +3740,23 @@ } /* Variable color and no alpha: Shader Object for the colored triangle(s) */ - else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){ + else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_1){ gl2ps->streamlength += gl2psPrintf("/Sh%d sh\n", gro->shno); } - /* Variable color and const alpha < 1: Shader Object for the - colored triangle(s) and an extra extended Graphics State + /* Variable color and const alpha < 1: Shader Object for the + colored triangle(s) and an extra extended Graphics State for the alpha const */ - else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){ + else if(t.prop & T_VAR_COLOR && t.prop & T_ALPHA_LESS_1){ gl2ps->streamlength += gl2psPrintf("q\n" "/GS%d gs\n" "/Sh%d sh\n" "Q\n", gro->gsno, gro->shno); } - /* Variable alpha and color: Shader Object for the colored - triangle(s) and an extra extended Graphics State + /* Variable alpha and color: Shader Object for the colored + triangle(s) and an extra extended Graphics State + Xobject + Shader object for the alpha mask */ - else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){ + else if(t.prop & T_VAR_COLOR && t.prop & T_VAR_ALPHA){ gl2ps->streamlength += gl2psPrintf("q\n" "/GS%d gs\n" "/TrG%d Do\n" @@ -3774,12 +3768,12 @@ case GL2PS_PIXMAP: for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); - gl2psPutPDFImage(prim->data.image, gro->imno, prim->verts[0].xyz[0], + gl2psPutPDFImage(prim->data.image, gro->imno, prim->verts[0].xyz[0], prim->verts[0].xyz[1]); } break; case GL2PS_TEXT: - for(j = 0; j <= lastel; ++j){ + for(j = 0; j <= lastel; ++j){ prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); gl2psPutPDFText(prim->data.text, gro->fontno, prim->verts[0].xyz[0], @@ -3788,7 +3782,7 @@ break; default: break; - } + } } } @@ -3801,15 +3795,15 @@ int i; offs += fprintf(gl2ps->stream, - "/ExtGState\n" + "/ExtGState\n" "<<\n" "/GSa 7 0 R\n"); - for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ - gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); if(gro->gsno >= 0) offs += fprintf(gl2ps->stream, "/GS%d %d 0 R\n", gro->gsno, gro->gsobjno); } - offs += fprintf(gl2ps->stream, ">>\n"); + offs += fprintf(gl2ps->stream, ">>\n"); return offs; } @@ -3824,14 +3818,14 @@ offs += fprintf(gl2ps->stream, "/Shading\n" "<<\n"); - for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ - gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); if(gro->shno >= 0) offs += fprintf(gl2ps->stream, "/Sh%d %d 0 R\n", gro->shno, gro->shobjno); if(gro->maskshno >= 0) offs += fprintf(gl2ps->stream, "/TrSh%d %d 0 R\n", gro->maskshno, gro->maskshobjno); } - offs += fprintf(gl2ps->stream,">>\n"); + offs += fprintf(gl2ps->stream,">>\n"); return offs; } @@ -3848,8 +3842,8 @@ "/XObject\n" "<<\n"); - for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ - gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); if(!gl2psListNbr(gro->ptrlist)) continue; p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); @@ -3881,8 +3875,8 @@ offs += fprintf(gl2ps->stream, "/Font\n<<\n"); - for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ - gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); if(gro->fontno < 0) continue; gro->fontobjno = gl2ps->objects_stack++; @@ -3897,11 +3891,11 @@ { int i; GL2PSpdfgroup *gro = NULL; - + if(!gl2ps->pdfgrouplist) return; - for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist,i); gl2psListDelete(gro->ptrlist); } @@ -3917,10 +3911,10 @@ int offs; time_t now; struct tm *newtime; - + time(&now); newtime = gmtime(&now); - + offs = fprintf(gl2ps->stream, "1 0 obj\n" "<<\n" @@ -3930,20 +3924,20 @@ gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer); - + if(!newtime){ - offs += fprintf(gl2ps->stream, + offs += fprintf(gl2ps->stream, ">>\n" "endobj\n"); return offs; } - - offs += fprintf(gl2ps->stream, + + offs += fprintf(gl2ps->stream, "/CreationDate (D:%d%02d%02d%02d%02d%02d)\n" ">>\n" "endobj\n", - newtime->tm_year+1900, - newtime->tm_mon+1, + newtime->tm_year+1900, + newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min, @@ -3955,7 +3949,7 @@ static int gl2psPrintPDFCatalog(void) { - return fprintf(gl2ps->stream, + return fprintf(gl2ps->stream, "2 0 obj\n" "<<\n" "/Type /Catalog\n" @@ -3966,9 +3960,9 @@ static int gl2psPrintPDFPages(void) { - return fprintf(gl2ps->stream, + return fprintf(gl2ps->stream, "3 0 obj\n" - "<<\n" + "<<\n" "/Type /Pages\n" "/Kids [6 0 R]\n" "/Count 1\n" @@ -3981,13 +3975,13 @@ static int gl2psOpenPDFDataStream(void) { int offs = 0; - - offs += fprintf(gl2ps->stream, + + offs += fprintf(gl2ps->stream, "4 0 obj\n" - "<<\n" + "<<\n" "/Length 5 0 R\n" ); offs += gl2psPrintPDFCompressorType(); - offs += fprintf(gl2ps->stream, + offs += fprintf(gl2ps->stream, ">>\n" "stream\n"); return offs; @@ -4000,13 +3994,13 @@ int offs; offs = gl2psPrintf("/GSa gs\n"); - + if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ offs += gl2psPrintPDFFillColor(gl2ps->bgcolor); offs += gl2psPrintf("%d %d %d %d re\n", (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); - offs += gl2psPrintf("f\n"); + offs += gl2psPrintf("f\n"); } return offs; } @@ -4019,26 +4013,26 @@ gl2ps->pdfprimlist = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*)); gl2psPDFstacksInit(); - gl2ps->xreflist = (int*)gl2psMalloc(sizeof(int) * gl2ps->objects_stack); + gl2ps->xreflist = (int*)gl2psMalloc(sizeof(int) * gl2ps->objects_stack); #if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ gl2psSetupCompress(); } -#endif +#endif gl2ps->xreflist[0] = 0; offs += fprintf(gl2ps->stream, "%%PDF-1.4\n"); gl2ps->xreflist[1] = offs; - + offs += gl2psPrintPDFInfo(); gl2ps->xreflist[2] = offs; - + offs += gl2psPrintPDFCatalog(); gl2ps->xreflist[3] = offs; - + offs += gl2psPrintPDFPages(); gl2ps->xreflist[4] = offs; - + offs += gl2psOpenPDFDataStream(); gl2ps->xreflist[5] = offs; /* finished in gl2psPrintPDFFooter */ gl2ps->streamlength = gl2psOpenPDFDataStreamWritePreface(); @@ -4050,7 +4044,7 @@ { GL2PSprimitive *prim = *(GL2PSprimitive**)data; - if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) + if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return; prim = gl2psCopyPrimitive(prim); /* deep copy */ @@ -4062,7 +4056,7 @@ static int gl2psClosePDFDataStream(void) { int offs = 0; - + #if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ if(Z_OK != gl2psDeflate()) @@ -4070,13 +4064,13 @@ else fwrite(gl2ps->compress->dest, gl2ps->compress->destLen, 1, gl2ps->stream); gl2ps->streamlength += gl2ps->compress->destLen; - + offs += gl2ps->streamlength; gl2psFreeCompress(); } -#endif - - offs += fprintf(gl2ps->stream, +#endif + + offs += fprintf(gl2ps->stream, "endstream\n" "endobj\n"); return offs; @@ -4097,27 +4091,27 @@ static int gl2psPrintPDFOpenPage(void) { int offs; - + /* Write fixed part */ - - offs = fprintf(gl2ps->stream, + + offs = fprintf(gl2ps->stream, "6 0 obj\n" - "<<\n" + "<<\n" "/Type /Page\n" "/Parent 3 0 R\n" "/MediaBox [%d %d %d %d]\n", (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); - + if(gl2ps->options & GL2PS_LANDSCAPE) offs += fprintf(gl2ps->stream, "/Rotate -90\n"); - + offs += fprintf(gl2ps->stream, "/Contents 4 0 R\n" - "/Resources\n" - "<<\n" + "/Resources\n" + "<<\n" "/ProcSet [/PDF /Text /ImageB /ImageC] %%/ImageI\n"); - + return offs; /* End fixed part, proceeds in gl2psPDFgroupListWriteVariableResources() */ @@ -4126,19 +4120,19 @@ static int gl2psPDFgroupListWriteVariableResources(void) { int offs = 0; - + /* a) Graphics States for shader alpha masks*/ - offs += gl2psPDFgroupListWriteGStateResources(); - - /* b) Shader and shader masks */ - offs += gl2psPDFgroupListWriteShaderResources(); - + offs += gl2psPDFgroupListWriteGStateResources(); + + /* b) Shader and shader masks */ + offs += gl2psPDFgroupListWriteShaderResources(); + /* c) XObjects (Images & Shader Masks) */ offs += gl2psPDFgroupListWriteXObjectResources(); - + /* d) Fonts */ offs += gl2psPDFgroupListWriteFontResources(); - + /* End resources and page */ offs += fprintf(gl2ps->stream, ">>\n" @@ -4169,10 +4163,10 @@ /* Put vertex' edge flag (8bit) and coordinates (32bit) in shader stream */ -static int gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex *vertex, - size_t (*action)(unsigned long data, - size_t size), - GLfloat dx, GLfloat dy, +static int gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex *vertex, + size_t (*action)(unsigned long data, + size_t size), + GLfloat dx, GLfloat dy, GLfloat xmin, GLfloat ymin) { int offs = 0; @@ -4188,7 +4182,7 @@ /* The Shader stream in PDF requires to be in a 'big-endian' order */ - + if(GL2PS_ZERO(dx * dy)){ offs += (*action)(0, 4); offs += (*action)(0, 4); @@ -4201,7 +4195,7 @@ diff = 0.0F; imap = (unsigned long)(diff * dmax); offs += (*action)(imap, 4); - + diff = (vertex->xyz[1] - ymin) / dy; if(diff > 1) diff = 1.0F; @@ -4210,14 +4204,14 @@ imap = (unsigned long)(diff * dmax); offs += (*action)(imap, 4); } - + return offs; } /* Put vertex' rgb value (8bit for every component) in shader stream */ static int gl2psPrintPDFShaderStreamDataRGB(GL2PSvertex *vertex, - size_t (*action)(unsigned long data, + size_t (*action)(unsigned long data, size_t size)) { int offs = 0; @@ -4229,20 +4223,20 @@ imap = (unsigned long)((vertex->rgba[0]) * dmax); offs += (*action)(imap, 1); - + imap = (unsigned long)((vertex->rgba[1]) * dmax); offs += (*action)(imap, 1); - + imap = (unsigned long)((vertex->rgba[2]) * dmax); offs += (*action)(imap, 1); - + return offs; } /* Put vertex' alpha (8/16bit) in shader stream */ -static int gl2psPrintPDFShaderStreamDataAlpha(GL2PSvertex *vertex, - size_t (*action)(unsigned long data, +static int gl2psPrintPDFShaderStreamDataAlpha(GL2PSvertex *vertex, + size_t (*action)(unsigned long data, size_t size), int sigbyte) { @@ -4255,48 +4249,48 @@ if(sigbyte != 8 && sigbyte != 16) sigbyte = 8; - + sigbyte /= 8; - + imap = (unsigned long)((vertex->rgba[3]) * dmax); - + offs += (*action)(imap, sigbyte); - + return offs; } /* Put a triangles raw data in shader stream */ -static int gl2psPrintPDFShaderStreamData(GL2PStriangle *triangle, - GLfloat dx, GLfloat dy, +static int gl2psPrintPDFShaderStreamData(GL2PStriangle *triangle, + GLfloat dx, GLfloat dy, GLfloat xmin, GLfloat ymin, - size_t (*action)(unsigned long data, + size_t (*action)(unsigned long data, size_t size), int gray) { int i, offs = 0; GL2PSvertex v; - + if(gray && gray != 8 && gray != 16) gray = 8; - + for(i = 0; i < 3; ++i){ offs += gl2psPrintPDFShaderStreamDataCoord(&triangle->vertex[i], action, dx, dy, xmin, ymin); - if(gray){ + if(gray){ v = triangle->vertex[i]; - offs += gl2psPrintPDFShaderStreamDataAlpha(&v, action, gray); + offs += gl2psPrintPDFShaderStreamDataAlpha(&v, action, gray); } else{ offs += gl2psPrintPDFShaderStreamDataRGB(&triangle->vertex[i], action); } } - + return offs; } -static void gl2psPDFRectHull(GLfloat *xmin, GLfloat *xmax, - GLfloat *ymin, GLfloat *ymax, +static void gl2psPDFRectHull(GLfloat *xmin, GLfloat *xmax, + GLfloat *ymin, GLfloat *ymax, GL2PStriangle *triangles, int cnt) { int i, j; @@ -4305,7 +4299,7 @@ *xmax = triangles[0].vertex[0].xyz[0]; *ymin = triangles[0].vertex[0].xyz[1]; *ymax = triangles[0].vertex[0].xyz[1]; - + for(i = 0; i < cnt; ++i){ for(j = 0; j < 3; ++j){ if(*xmin > triangles[i].vertex[j].xyz[0]) @@ -4320,17 +4314,17 @@ } } -/* Writes shaded triangle +/* Writes shaded triangle gray == 0 means write RGB triangles gray == 8 8bit-grayscale (for alpha masks) gray == 16 16bit-grayscale (for alpha masks) */ -static int gl2psPrintPDFShader(int obj, GL2PStriangle *triangles, +static int gl2psPrintPDFShader(int obj, GL2PStriangle *triangles, int size, int gray) { int i, offs = 0, vertexbytes, done = 0; GLfloat xmin, xmax, ymin, ymax; - + switch(gray){ case 0: vertexbytes = 1+4+4+1+1+1; @@ -4346,9 +4340,9 @@ vertexbytes = 1+4+4+1; break; } - + gl2psPDFRectHull(&xmin, &xmax, &ymin, &ymax, triangles, size); - + offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<< " @@ -4359,18 +4353,18 @@ "/BitsPerFlag 8 " "/Decode [%f %f %f %f 0 1 %s] ", obj, - (gray) ? "/DeviceGray" : "/DeviceRGB", + (gray) ? "/DeviceGray" : "/DeviceRGB", (gray) ? gray : 8, xmin, xmax, ymin, ymax, (gray) ? "" : "0 1 0 1"); - + #if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ gl2psAllocCompress(vertexbytes * size * 3); for(i = 0; i < size; ++i) gl2psPrintPDFShaderStreamData(&triangles[i], - xmax-xmin, ymax-ymin, xmin, ymin, + xmax-xmin, ymax-ymin, xmin, ymin, gl2psWriteBigEndianCompress, gray); if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){ @@ -4380,8 +4374,8 @@ ">>\n" "stream\n", (int)gl2ps->compress->destLen); - offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, - gl2ps->compress->destLen, + offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, + gl2ps->compress->destLen, 1, gl2ps->stream); done = 1; } @@ -4402,11 +4396,11 @@ xmax-xmin, ymax-ymin, xmin, ymin, gl2psWriteBigEndian, gray); } - + offs += fprintf(gl2ps->stream, "\nendstream\n" "endobj\n"); - + return offs; } @@ -4415,7 +4409,7 @@ static int gl2psPrintPDFShaderMask(int obj, int childobj) { int offs = 0, len; - + offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<<\n" @@ -4427,11 +4421,11 @@ obj, (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); - - len = (childobj>0) + + len = (childobj>0) ? strlen("/TrSh sh\n") + (int)log10((double)childobj)+1 - : strlen("/TrSh0 sh\n"); - + : strlen("/TrSh0 sh\n"); + offs += fprintf(gl2ps->stream, "/Length %d\n" ">>\n" @@ -4443,7 +4437,7 @@ offs += fprintf(gl2ps->stream, "endstream\n" "endobj\n"); - + return offs; } @@ -4454,16 +4448,16 @@ static int gl2psPrintPDFShaderExtGS(int obj, int childobj) { int offs = 0; - + offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<<\n", obj); - + offs += fprintf(gl2ps->stream, "/SMask << /S /Alpha /G %d 0 R >> ", childobj); - + offs += fprintf(gl2ps->stream, ">>\n" "endobj\n"); @@ -4475,7 +4469,7 @@ static int gl2psPrintPDFShaderSimpleExtGS(int obj, GLfloat alpha) { int offs = 0; - + offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<<\n" @@ -4489,8 +4483,8 @@ /* Similar groups of functions for pixmaps and text */ static int gl2psPrintPDFPixmapStreamData(GL2PSimage *im, - size_t (*action)(unsigned long data, - size_t size), + size_t (*action)(unsigned long data, + size_t size), int gray) { int x, y, shift; @@ -4503,7 +4497,7 @@ gray = 8; gray /= 8; - + shift = (sizeof(unsigned long) - 1) * 8; for(y = 0; y < im->height; ++y){ @@ -4534,10 +4528,10 @@ if(gray && gray !=8 && gray != 16) gray = 8; - + if(gray) - sigbytes = gray / 8; - + sigbytes = gray / 8; + offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<<\n" @@ -4555,13 +4549,13 @@ "/SMask %d 0 R\n", childobj); } - + #if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ gl2psAllocCompress((int)(im->width * im->height * sigbytes)); - + gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndianCompress, gray); - + if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){ offs += gl2psPrintPDFCompressorType(); offs += fprintf(gl2ps->stream, @@ -4576,7 +4570,7 @@ gl2psFreeCompress(); } #endif - + if(!done){ /* no compression, or too long after compression, or compress error -> write non-compressed entry */ @@ -4587,18 +4581,18 @@ (int)(im->width * im->height * sigbytes)); offs += gl2psPrintPDFPixmapStreamData(im, gl2psWriteBigEndian, gray); } - + offs += fprintf(gl2ps->stream, "\nendstream\n" "endobj\n"); - + return offs; } static int gl2psPrintPDFText(int obj, GL2PSstring *s, int fontnumber) { int offs = 0; - + offs += fprintf(gl2ps->stream, "%d 0 obj\n" "<<\n" @@ -4626,9 +4620,9 @@ if(!gl2ps->pdfgrouplist) return offs; - - for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ - gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); if(!gl2psListNbr(gro->ptrlist)) continue; p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); @@ -4640,7 +4634,7 @@ case GL2PS_TRIANGLE: size = gl2psListNbr(gro->ptrlist); triangles = (GL2PStriangle*)gl2psMalloc(sizeof(GL2PStriangle) * size); - for(j = 0; j < size; ++j){ + for(j = 0; j < size; ++j){ p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); gl2psFillTriangleFromPrimitive(&triangles[j], p, GL_TRUE); } @@ -4682,7 +4676,7 @@ break; default: break; - } + } } return offs; } @@ -4693,29 +4687,29 @@ static void gl2psPrintPDFFooter(void) { - int i, offs; + int i, offs; gl2psPDFgroupListInit(); gl2psPDFgroupListWriteMainStream(); - - offs = gl2ps->xreflist[5] + gl2ps->streamlength; + + offs = gl2ps->xreflist[5] + gl2ps->streamlength; offs += gl2psClosePDFDataStream(); gl2ps->xreflist[5] = offs; - + offs += gl2psPrintPDFDataStreamLength(gl2ps->streamlength); gl2ps->xreflist[6] = offs; gl2ps->streamlength = 0; - + offs += gl2psPrintPDFOpenPage(); offs += gl2psPDFgroupListWriteVariableResources(); gl2ps->xreflist = (int*)gl2psRealloc(gl2ps->xreflist, sizeof(int) * (gl2ps->objects_stack + 1)); gl2ps->xreflist[7] = offs; - + offs += gl2psPrintPDFGSObject(); gl2ps->xreflist[8] = offs; - - gl2ps->xreflist[gl2ps->objects_stack] = + + gl2ps->xreflist[gl2ps->objects_stack] = gl2psPDFgroupListWriteObjects(gl2ps->xreflist[8]); /* Start cross reference table. The file has to been opened in @@ -4724,13 +4718,13 @@ "xref\n" "0 %d\n" "%010d 65535 f \n", gl2ps->objects_stack, 0); - + for(i = 1; i < gl2ps->objects_stack; ++i) fprintf(gl2ps->stream, "%010d 00000 n \n", gl2ps->xreflist[i]); - + fprintf(gl2ps->stream, "trailer\n" - "<<\n" + "<<\n" "/Size %d\n" "/Info 1 0 R\n" "/Root 2 0 R\n" @@ -4738,13 +4732,13 @@ "startxref\n%d\n" "%%%%EOF\n", gl2ps->objects_stack, gl2ps->xreflist[gl2ps->objects_stack]); - - /* Free auxiliary lists and arrays */ + + /* Free auxiliary lists and arrays */ gl2psFree(gl2ps->xreflist); gl2psListAction(gl2ps->pdfprimlist, gl2psFreePrimitive); gl2psListDelete(gl2ps->pdfprimlist); gl2psPDFgroupListDelete(); - + #if defined(GL2PS_HAVE_ZLIB) if(gl2ps->options & GL2PS_COMPRESS){ gl2psFreeCompress(); @@ -4762,16 +4756,16 @@ GLint index; GLfloat rgba[4]; int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; - + glRenderMode(GL_FEEDBACK); - + if(gl2ps->header){ gl2psPrintPDFHeader(); gl2ps->header = GL_FALSE; } offs += gl2psPrintf("q\n"); - + if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); @@ -4791,18 +4785,18 @@ } else{ offs += gl2psPrintf("%d %d %d %d re\n" - "W\n" + "W\n" "n\n", - x, y, w, h); - } - + x, y, w, h); + } + gl2ps->streamlength += offs; } static GLint gl2psPrintPDFEndViewport(void) { GLint res; - + res = gl2psPrintPrimitives(); gl2ps->streamlength += gl2psPrintf("Q\n"); return res; @@ -4825,13 +4819,13 @@ "Portable Document Format" }; -/********************************************************************* +/********************************************************************* * * SVG routines * *********************************************************************/ -static void gl2psSVGGetCoordsAndColors(int n, GL2PSvertex *verts, +static void gl2psSVGGetCoordsAndColors(int n, GL2PSvertex *verts, GL2PSxyz *xyz, GL2PSrgba *rgba) { int i, j; @@ -4861,9 +4855,9 @@ int x, y, width, height; char col[32]; time_t now; - + time(&now); - + if (gl2ps->options & GL2PS_LANDSCAPE){ x = (int)gl2ps->viewport[1]; y = (int)gl2ps->viewport[0]; @@ -4876,10 +4870,10 @@ width = (int)gl2ps->viewport[2]; height = (int)gl2ps->viewport[3]; } - + /* Compressed SVG files (.svgz) are simply gzipped SVG files */ gl2psPrintGzipHeader(); - + gl2psPrintf("\n"); gl2psPrintf("options & GL2PS_DRAW_BACKGROUND){ gl2psSVGGetColorString(gl2ps->bgcolor, col); gl2psPrintf("\n", col, - (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], - (int)gl2ps->viewport[2], (int)gl2ps->viewport[1], - (int)gl2ps->viewport[2], (int)gl2ps->viewport[3], + (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], + (int)gl2ps->viewport[2], (int)gl2ps->viewport[1], + (int)gl2ps->viewport[2], (int)gl2ps->viewport[3], (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]); } @@ -4924,52 +4918,52 @@ gl2psSVGGetColorString(rgba[0], col); gl2psPrintf("\n", xyz[0][0], xyz[0][1], + gl2psPrintf("points=\"%g,%g %g,%g %g,%g\"/>\n", xyz[0][0], xyz[0][1], xyz[1][0], xyz[1][1], xyz[2][0], xyz[2][1]); } else{ /* subdivide into 4 subtriangles */ for(i = 0; i < 3; i++){ - xyz2[0][i] = xyz[0][i]; + xyz2[0][i] = xyz[0][i]; xyz2[1][i] = 0.5F * (xyz[0][i] + xyz[1][i]); xyz2[2][i] = 0.5F * (xyz[0][i] + xyz[2][i]); } for(i = 0; i < 4; i++){ - rgba2[0][i] = rgba[0][i]; + rgba2[0][i] = rgba[0][i]; rgba2[1][i] = 0.5F * (rgba[0][i] + rgba[1][i]); rgba2[2][i] = 0.5F * (rgba[0][i] + rgba[2][i]); } gl2psPrintSVGSmoothTriangle(xyz2, rgba2); for(i = 0; i < 3; i++){ xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[1][i]); - xyz2[1][i] = xyz[1][i]; + xyz2[1][i] = xyz[1][i]; xyz2[2][i] = 0.5F * (xyz[1][i] + xyz[2][i]); } for(i = 0; i < 4; i++){ rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[1][i]); - rgba2[1][i] = rgba[1][i]; + rgba2[1][i] = rgba[1][i]; rgba2[2][i] = 0.5F * (rgba[1][i] + rgba[2][i]); } gl2psPrintSVGSmoothTriangle(xyz2, rgba2); for(i = 0; i < 3; i++){ xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[2][i]); - xyz2[1][i] = xyz[2][i]; + xyz2[1][i] = xyz[2][i]; xyz2[2][i] = 0.5F * (xyz[1][i] + xyz[2][i]); } for(i = 0; i < 4; i++){ rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[2][i]); - rgba2[1][i] = rgba[2][i]; + rgba2[1][i] = rgba[2][i]; rgba2[2][i] = 0.5F * (rgba[1][i] + rgba[2][i]); } gl2psPrintSVGSmoothTriangle(xyz2, rgba2); for(i = 0; i < 3; i++){ xyz2[0][i] = 0.5F * (xyz[0][i] + xyz[1][i]); - xyz2[1][i] = 0.5F * (xyz[1][i] + xyz[2][i]); + xyz2[1][i] = 0.5F * (xyz[1][i] + xyz[2][i]); xyz2[2][i] = 0.5F * (xyz[0][i] + xyz[2][i]); } for(i = 0; i < 4; i++){ rgba2[0][i] = 0.5F * (rgba[0][i] + rgba[1][i]); - rgba2[1][i] = 0.5F * (rgba[1][i] + rgba[2][i]); + rgba2[1][i] = 0.5F * (rgba[1][i] + rgba[2][i]); rgba2[2][i] = 0.5F * (rgba[0][i] + rgba[2][i]); } gl2psPrintSVGSmoothTriangle(xyz2, rgba2); @@ -4995,7 +4989,7 @@ { int i; if(gl2ps->lastvertex.rgba[0] >= 0.){ - gl2psPrintf("%g,%g\"/>\n", gl2ps->lastvertex.xyz[0], + gl2psPrintf("%g,%g\"/>\n", gl2ps->lastvertex.xyz[0], gl2ps->viewport[3] - gl2ps->lastvertex.xyz[1]); for(i = 0; i < 3; i++) gl2ps->lastvertex.xyz[i] = -1.; @@ -5017,7 +5011,7 @@ file), we need to encode the pixmap into PNG in memory, then encode it into base64. */ - png = gl2psListCreate(pixmap->width * pixmap->height * 3, 1000, + png = gl2psListCreate(pixmap->width * pixmap->height * 3, 1000, sizeof(unsigned char)); gl2psConvertPixmapToPNG(pixmap, png); gl2psListEncodeBase64(png); @@ -5086,7 +5080,7 @@ gl2ps->lastfactor = prim->factor; if(newline){ gl2psSVGGetColorString(rgba[0], col); - gl2psPrintf("width); if(rgba[0][3] < 1.0F) gl2psPrintf("stroke-opacity=\"%g\" ", rgba[0][3]); gl2psPrintSVGDash(prim->pattern, prim->factor); @@ -5112,42 +5106,6 @@ if(prim->data.text->angle) gl2psPrintf("transform=\"rotate(%g, %g, %g)\" ", -prim->data.text->angle, xyz[0][0], xyz[0][1]); - switch(prim->data.text->alignment){ - case GL2PS_TEXT_C: - gl2psPrintf("text-anchor=\"middle\" baseline-shift=\"%d\" ", - -prim->data.text->fontsize / 2); - break; - case GL2PS_TEXT_CL: - gl2psPrintf("text-anchor=\"start\" baseline-shift=\"%d\" ", - -prim->data.text->fontsize / 2); - break; - case GL2PS_TEXT_CR: - gl2psPrintf("text-anchor=\"end\" baseline-shift=\"%d\" ", - -prim->data.text->fontsize / 2); - break; - case GL2PS_TEXT_B: - gl2psPrintf("text-anchor=\"middle\" baseline-shift=\"0\" "); - break; - case GL2PS_TEXT_BR: - gl2psPrintf("text-anchor=\"end\" baseline-shift=\"0\" "); - break; - case GL2PS_TEXT_T: - gl2psPrintf("text-anchor=\"middle\" baseline-shift=\"%d\" ", - -prim->data.text->fontsize); - break; - case GL2PS_TEXT_TL: - gl2psPrintf("text-anchor=\"start\" baseline-shift=\"%d\" ", - -prim->data.text->fontsize); - break; - case GL2PS_TEXT_TR: - gl2psPrintf("text-anchor=\"end\" baseline-shift=\"%d\" ", - -prim->data.text->fontsize); - break; - case GL2PS_TEXT_BL: - default: /* same as GL2PS_TEXT_BL */ - gl2psPrintf("text-anchor=\"start\" baseline-shift=\"0\" "); - break; - } if(!strcmp(prim->data.text->fontname, "Times-Roman")) gl2psPrintf("font-family=\"Times\">"); else if(!strcmp(prim->data.text->fontname, "Times-Bold")) @@ -5186,8 +5144,8 @@ static void gl2psPrintSVGFooter(void) { gl2psPrintf("\n"); - gl2psPrintf("\n"); - + gl2psPrintf("\n"); + gl2psPrintGzipFooter(); } @@ -5199,7 +5157,7 @@ int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; glRenderMode(GL_FEEDBACK); - + if(gl2ps->header){ gl2psPrintSVGHeader(); gl2ps->header = GL_FALSE; @@ -5217,18 +5175,18 @@ rgba[3] = 1.0F; } gl2psSVGGetColorString(rgba, col); - gl2psPrintf("\n", col, - x, gl2ps->viewport[3] - y, - x + w, gl2ps->viewport[3] - y, - x + w, gl2ps->viewport[3] - (y + h), + gl2psPrintf("\n", col, + x, gl2ps->viewport[3] - y, + x + w, gl2ps->viewport[3] - y, + x + w, gl2ps->viewport[3] - (y + h), x, gl2ps->viewport[3] - (y + h)); } gl2psPrintf("\n", x, y, w, h); - gl2psPrintf(" \n", - x, gl2ps->viewport[3] - y, - x + w, gl2ps->viewport[3] - y, - x + w, gl2ps->viewport[3] - (y + h), + gl2psPrintf(" \n", + x, gl2ps->viewport[3] - y, + x + w, gl2ps->viewport[3] - y, + x + w, gl2ps->viewport[3] - (y + h), x, gl2ps->viewport[3] - (y + h)); gl2psPrintf("\n"); gl2psPrintf("\n", x, y, w, h); @@ -5282,7 +5240,7 @@ time(&now); - fprintf(gl2ps->stream, + fprintf(gl2ps->stream, "%% Title: %s\n" "%% Creator: GL2PS %d.%d.%d%s, %s\n" "%% For: %s\n" @@ -5336,7 +5294,7 @@ case GL2PS_TEXT_T : return "north"; case GL2PS_TEXT_TL : return "north west"; case GL2PS_TEXT_TR : return "north east"; - case GL2PS_TEXT_BL : + case GL2PS_TEXT_BL : default : return "south west"; } } @@ -5351,7 +5309,7 @@ case GL2PS_POINT : /* Points in openGL are rectangular */ gl2psPrintPGFColor(prim->verts[0].rgba); - fprintf(gl2ps->stream, + fprintf(gl2ps->stream, "\\pgfpathrectangle{\\pgfpoint{%fpt}{%fpt}}" "{\\pgfpoint{%fpt}{%fpt}}\n\\pgfusepath{fill}\n", prim->verts[0].xyz[0]-0.5*prim->width, @@ -5365,7 +5323,7 @@ fprintf(gl2ps->stream, "\\pgfsetlinewidth{%fpt}\n", gl2ps->lastlinewidth); } gl2psPrintPGFDash(prim->pattern, prim->factor); - fprintf(gl2ps->stream, + fprintf(gl2ps->stream, "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n" "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" "\\pgfusepath{stroke}\n", @@ -5378,7 +5336,7 @@ fprintf(gl2ps->stream, "\\pgfsetlinewidth{0.01pt}\n"); } gl2psPrintPGFColor(prim->verts[0].rgba); - fprintf(gl2ps->stream, + fprintf(gl2ps->stream, "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n" "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" @@ -5447,14 +5405,14 @@ rgba[3] = 1.0F; } gl2psPrintPGFColor(rgba); - fprintf(gl2ps->stream, + fprintf(gl2ps->stream, "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}" "{\\pgfpoint{%dpt}{%dpt}}\n" "\\pgfusepath{fill}\n", x, y, w, h); } - - fprintf(gl2ps->stream, + + fprintf(gl2ps->stream, "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}" "{\\pgfpoint{%dpt}{%dpt}}\n" "\\pgfusepath{clip}\n", @@ -5486,7 +5444,7 @@ "PGF Latex Graphics" }; -/********************************************************************* +/********************************************************************* * * General primitive printing routine * @@ -5521,7 +5479,7 @@ if(prim->verts[i].xyz[1] > gl2ps->viewport[3]) gl2ps->viewport[3] = (GLint)(prim->verts[i].xyz[1] + 0.5F); } -} +} static GLint gl2psPrintPrimitives(void) { @@ -5542,7 +5500,7 @@ gl2psRescaleAndOffset(); if(gl2ps->header){ - if(gl2psListNbr(gl2ps->primitives) && + if(gl2psListNbr(gl2ps->primitives) && (gl2ps->options & GL2PS_TIGHT_BOUNDING_BOX)){ gl2ps->viewport[0] = gl2ps->viewport[1] = 100000; gl2ps->viewport[2] = gl2ps->viewport[3] = -100000; @@ -5584,7 +5542,7 @@ gl2psAddInImageTree, 1); gl2psFreeBspImageTree(&gl2ps->imagetree); } - gl2psTraverseBspTree(root, eye, GL2PS_EPSILON, gl2psGreater, + gl2psTraverseBspTree(root, eye, GL2PS_EPSILON, gl2psGreater, gl2psbackends[gl2ps->format]->printPrimitive, 0); gl2psFreeBspTree(&root); /* reallocate the primitive list (it's been deleted by @@ -5597,13 +5555,13 @@ return GL2PS_SUCCESS; } -/********************************************************************* +/********************************************************************* * * Public routines * *********************************************************************/ -GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, +GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, GLint viewport[4], GLint format, GLint sort, GLint options, GLint colormode, GLint colorsize, GL2PSrgba *colormap, @@ -5671,7 +5629,7 @@ if(!gl2ps->viewport[2] || !gl2ps->viewport[3]){ gl2psMsg(GL2PS_ERROR, "Incorrect viewport (x=%d, y=%d, width=%d, height=%d)", - gl2ps->viewport[0], gl2ps->viewport[1], + gl2ps->viewport[0], gl2ps->viewport[1], gl2ps->viewport[2], gl2ps->viewport[3]); gl2psFree(gl2ps); gl2ps = NULL; @@ -5695,11 +5653,11 @@ gl2ps->lastfactor = 0; gl2ps->imagetree = NULL; gl2ps->primitivetoadd = NULL; - gl2ps->zerosurfacearea = GL_FALSE; + gl2ps->zerosurfacearea = GL_FALSE; gl2ps->pdfprimlist = NULL; gl2ps->pdfgrouplist = NULL; gl2ps->xreflist = NULL; - + /* get default blending mode from current OpenGL state (enabled by default for SVG) */ gl2ps->blending = (gl2ps->format == GL2PS_SVG) ? GL_TRUE : glIsEnabled(GL_BLEND); @@ -5742,7 +5700,7 @@ gl2ps->title = (char*)gl2psMalloc((strlen(title)+1)*sizeof(char)); strcpy(gl2ps->title, title); } - + if(!producer){ gl2ps->producer = (char*)gl2psMalloc(sizeof(char)); gl2ps->producer[0] = '\0'; @@ -5751,7 +5709,7 @@ gl2ps->producer = (char*)gl2psMalloc((strlen(producer)+1)*sizeof(char)); strcpy(gl2ps->producer, producer); } - + if(!filename){ gl2ps->filename = (char*)gl2psMalloc(sizeof(char)); gl2ps->filename[0] = '\0'; @@ -5765,7 +5723,7 @@ gl2ps->auxprimitives = gl2psListCreate(100, 100, sizeof(GL2PSprimitive*)); gl2ps->feedback = (GLfloat*)gl2psMalloc(gl2ps->buffersize * sizeof(GLfloat)); glFeedbackBuffer(gl2ps->buffersize, GL_3D_COLOR, gl2ps->feedback); - glRenderMode(GL_FEEDBACK); + glRenderMode(GL_FEEDBACK); return GL2PS_SUCCESS; } @@ -5780,7 +5738,7 @@ if(res != GL2PS_OVERFLOW) (gl2psbackends[gl2ps->format]->printFooter)(); - + fflush(gl2ps->stream); gl2psListDelete(gl2ps->primitives); @@ -5802,7 +5760,7 @@ if(!gl2ps) return GL2PS_UNINITIALIZED; (gl2psbackends[gl2ps->format]->beginViewport)(viewport); - + return GL2PS_SUCCESS; } @@ -5820,7 +5778,7 @@ return res; } -GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, +GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, GLshort fontsize, GLint alignment, GLfloat angle) { return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, alignment, angle); @@ -5838,11 +5796,11 @@ GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height, GLint xorig, GLint yorig, - GLenum format, GLenum type, + GLenum format, GLenum type, const void *pixels) { int size, i; - GLfloat pos[4], *piv, zoom_x, zoom_y; + GLfloat pos[4], *piv; GL2PSprimitive *prim; GLboolean valid; @@ -5862,8 +5820,6 @@ if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */ glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); - glGetFloatv(GL_ZOOM_X, &zoom_x); - glGetFloatv(GL_ZOOM_Y, &zoom_y); prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); prim->type = GL2PS_PIXMAP; @@ -5882,8 +5838,6 @@ prim->data.image = (GL2PSimage*)gl2psMalloc(sizeof(GL2PSimage)); prim->data.image->width = width; prim->data.image->height = height; - prim->data.image->zoom_x = zoom_x; - prim->data.image->zoom_y = zoom_y; prim->data.image->format = format; prim->data.image->type = type; @@ -5897,9 +5851,9 @@ piv = (GLfloat*)pixels; for(i = 0; i < size; ++i, ++piv){ prim->data.image->pixels[i] = *piv; - if(!((i + 1) % 3)) + if(!((i+1)%3)) ++piv; - } + } } else{ size = height * width * 4; @@ -5926,11 +5880,11 @@ const unsigned char *imagemap){ int size, i; int sizeoffloat = sizeof(GLfloat); - + if(!gl2ps || !imagemap) return GL2PS_UNINITIALIZED; if((width <= 0) || (height <= 0)) return GL2PS_ERROR; - + size = height + height * ((width - 1) / 8); glPassThrough(GL2PS_IMAGEMAP_TOKEN); glBegin(GL_POINTS); @@ -6010,7 +5964,7 @@ glPassThrough(GL2PS_POINT_SIZE_TOKEN); glPassThrough(value); - + return GL2PS_SUCCESS; } diff -r c67f7d390a1a -r 7df7650492e8 src/gl2ps.h --- a/src/gl2ps.h Thu Aug 25 20:12:31 2011 +0200 +++ b/src/gl2ps.h Fri Aug 26 13:40:10 2011 -0500 @@ -139,9 +139,9 @@ #define GL2PS_BLEND 4 /* Text alignment (o=raster position; default mode is BL): - +---+ +---+ +---+ +---+ +---+ +---+ +-o-+ o---+ +---o - | o | o | | o | | | | | | | | | | | | - +---+ +---+ +---+ +-o-+ o---+ +---o +---+ +---+ +---+ + +---+ +---+ +---+ +---+ +---+ +---+ +-o-+ o---+ +---o + | o | o | | o | | | | | | | | | | | | + +---+ +---+ +---+ +-o-+ o---+ +---o +---+ +---+ +---+ C CL CR B BL BR T TL TR */ #define GL2PS_TEXT_C 1 @@ -160,10 +160,10 @@ extern "C" { #endif -GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, +GL2PSDLL_API GLint gl2psBeginPage(const char *title, const char *producer, GLint viewport[4], GLint format, GLint sort, GLint options, GLint colormode, - GLint colorsize, GL2PSrgba *colormap, + GLint colorsize, GL2PSrgba *colormap, GLint nr, GLint ng, GLint nb, GLint buffersize, FILE *stream, const char *filename); GL2PSDLL_API GLint gl2psEndPage(void); @@ -171,9 +171,9 @@ GL2PSDLL_API GLint gl2psGetOptions(GLint *options); GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4]); GL2PSDLL_API GLint gl2psEndViewport(void); -GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, +GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize); -GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, +GL2PSDLL_API GLint gl2psTextOpt(const char *str, const char *fontname, GLshort fontsize, GLint align, GLfloat angle); GL2PSDLL_API GLint gl2psSpecial(GLint format, const char *str); GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height, diff -r c67f7d390a1a -r 7df7650492e8 src/graphics.cc --- a/src/graphics.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/graphics.cc Fri Aug 26 13:40:10 2011 -0500 @@ -4341,7 +4341,7 @@ text::properties& xlabel_props = reinterpret_cast (gh_manager::get_object (get_xlabel ()).get_properties ()); - bool is_empty = xlabel_props.get_string ().empty (); + bool is_empty = xlabel_props.get_string ().is_empty (); unwind_protect frame; frame.protect_var (updating_xlabel_position); @@ -4432,7 +4432,7 @@ text::properties& ylabel_props = reinterpret_cast (gh_manager::get_object (get_ylabel ()).get_properties ()); - bool is_empty = ylabel_props.get_string ().empty (); + bool is_empty = ylabel_props.get_string ().is_empty (); unwind_protect frame; frame.protect_var (updating_ylabel_position); @@ -4524,7 +4524,7 @@ (gh_manager::get_object (get_zlabel ()).get_properties ()); bool camAuto = cameraupvectormode_is ("auto"); - bool is_empty = zlabel_props.get_string ().empty (); + bool is_empty = zlabel_props.get_string ().is_empty (); unwind_protect frame; frame.protect_var (updating_zlabel_position); @@ -4896,7 +4896,7 @@ Matrix text_pos = text_props.get_position ().matrix_value (); text_pos = xform.transform (text_pos(0), text_pos(1), text_pos(2)); - if (text_props.get_string ().empty ()) + if (text_props.get_string ().is_empty ()) { ext(0) = std::min (ext(0), text_pos(0)); ext(1) = std::min (ext(1), text_pos(1)); @@ -6006,6 +6006,7 @@ text::properties::update_text_extent (void) { #ifdef HAVE_FREETYPE + int halign = 0, valign = 0; if (horizontalalignment_is ("center")) @@ -6021,11 +6022,17 @@ valign = 1; Matrix bbox; + // FIXME: string should be parsed only when modified, for efficiency - renderer.text_to_pixels (get_string (), pixels, bbox, + + octave_value string_prop = get_string (); + + string_vector sv = string_prop.all_strings (); + + renderer.text_to_pixels (sv.join ("\n"), pixels, bbox, halign, valign, get_rotation ()); - set_extent (bbox); + #endif if (autopos_tag_is ("xlabel") || autopos_tag_is ("ylabel") || diff -r c67f7d390a1a -r 7df7650492e8 src/graphics.h.in --- a/src/graphics.h.in Thu Aug 25 20:12:31 2011 +0200 +++ b/src/graphics.h.in Fri Aug 26 13:40:10 2011 -0500 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include "caseless-str.h" @@ -692,6 +693,178 @@ // --------------------------------------------------------------------- +class text_label_property : public base_property +{ +public: + enum type { char_t, cellstr_t }; + + text_label_property (const std::string& s, const graphics_handle& h, + const std::string& val = "") + : base_property (s, h), value (val), stored_type (char_t) + { } + + text_label_property (const std::string& s, const graphics_handle& h, + const NDArray& nda) + : base_property (s, h), stored_type (char_t) + { + octave_idx_type nel = nda.numel (); + + value.resize (nel); + + for (octave_idx_type i = 0; i < nel; i++) + { + std::ostringstream buf; + buf << nda(i); + value[i] = buf.str (); + } + } + + text_label_property (const std::string& s, const graphics_handle& h, + const Cell& c) + : base_property (s, h), stored_type (cellstr_t) + { + octave_idx_type nel = c.numel (); + + value.resize (nel); + + for (octave_idx_type i = 0; i < nel; i++) + { + octave_value tmp = c(i); + + if (tmp.is_string ()) + value[i] = c(i).string_value (); + else + { + double d = c(i).double_value (); + + if (! error_state) + { + std::ostringstream buf; + buf << d; + value[i] = buf.str (); + } + else + break; + } + } + } + + text_label_property (const text_label_property& p) + : base_property (p), value (p.value), stored_type (p.stored_type) + { } + + bool empty (void) const + { + octave_value tmp = get (); + return tmp.is_empty (); + } + + octave_value get (void) const + { + if (stored_type == char_t) + return octave_value (char_value ()); + else + return octave_value (cell_value ()); + } + + std::string string_value (void) const + { + return value.empty () ? std::string () : value[0]; + } + + string_vector string_vector_value (void) const { return value; } + + charMatrix char_value (void) const { return charMatrix (value, ' '); } + + Cell cell_value (void) const {return Cell (value); } + + text_label_property& operator = (const octave_value& val) + { + set (val); + return *this; + } + + base_property* clone (void) const { return new text_label_property (*this); } + +protected: + + bool do_set (const octave_value& val) + { + if (val.is_string ()) + { + value = val.all_strings (); + + stored_type = char_t; + } + else if (val.is_cell ()) + { + Cell c = val.cell_value (); + + octave_idx_type nel = c.numel (); + + value.resize (nel); + + for (octave_idx_type i = 0; i < nel; i++) + { + octave_value tmp = c(i); + + if (tmp.is_string ()) + value[i] = c(i).string_value (); + else + { + double d = c(i).double_value (); + + if (! error_state) + { + std::ostringstream buf; + buf << d; + value[i] = buf.str (); + } + else + return false; + } + } + + stored_type = cellstr_t; + } + else + { + NDArray nda = val.array_value (); + + if (! error_state) + { + octave_idx_type nel = nda.numel (); + + value.resize (nel); + + for (octave_idx_type i = 0; i < nel; i++) + { + std::ostringstream buf; + buf << nda(i); + value[i] = buf.str (); + } + + stored_type = char_t; + } + else + { + error ("set: invalid string property value for \"%s\"", + get_name ().c_str ()); + + return false; + } + } + + return true; + } + +private: + string_vector value; + type stored_type; +}; + +// --------------------------------------------------------------------- + class radio_values { public: @@ -3686,7 +3859,7 @@ // properties declarations. BEGIN_PROPERTIES (text) - string_property string u , "" + text_label_property string u , "" radio_property units u , "{data}|pixels|normalized|inches|centimeters|points" array_property position mu , Matrix (1, 3, 0.0) double_property rotation mu , 0 diff -r c67f7d390a1a -r 7df7650492e8 src/input.cc --- a/src/input.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/input.cc Fri Aug 26 13:40:10 2011 -0500 @@ -428,7 +428,7 @@ FILE *instream = 0; if (name.length () > 0) - instream = fopen (name.c_str (), "rb"); + instream = gnulib::fopen (name.c_str (), "rb"); if (! instream && warn) warning ("%s: no such file or directory", name.c_str ()); @@ -951,14 +951,11 @@ unwind_protect frame; - // FIXME -- we shouldn't need both the - // command_history object and the - // Vsaving_history variable... + frame.add_fcn (command_history::ignore_entries, + command_history::ignoring_entries ()); + command_history::ignore_entries (false); - frame.add_fcn (command_history::ignore_entries, ! Vsaving_history); - - frame.protect_var (Vsaving_history); frame.protect_var (Vdebugging); frame.add_fcn (octave_call_stack::restore_frame, @@ -970,7 +967,6 @@ // tree_print_code tpc (octave_stdout); // stmt.accept (tpc); - Vsaving_history = true; Vdebugging = true; std::string prompt = "debug> "; diff -r c67f7d390a1a -r 7df7650492e8 src/oct-hist.cc --- a/src/oct-hist.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/oct-hist.cc Fri Aug 26 13:40:10 2011 -0500 @@ -88,9 +88,6 @@ return file; } -// Where history is saved. -static std::string Vhistory_file = default_history_file (); - static int default_history_size (void) { @@ -109,27 +106,6 @@ return size; } -// The number of lines to keep in the history file. -static int Vhistory_size = default_history_size (); - -static std::string -default_history_control (void) -{ - std::string retval; - - std::string env_histcontrol = octave_env::getenv ("OCTAVE_HISTCONTROL"); - - if (! env_histcontrol.empty ()) - { - return env_histcontrol; - } - - return retval; -} - -// The number of lines to keep in the history file. -static std::string Vhistory_control = default_history_control (); - static std::string default_history_timestamp_format (void) { @@ -146,9 +122,6 @@ static std::string Vhistory_timestamp_format_string = default_history_timestamp_format (); -// TRUE if we are saving history. -bool Vsaving_history = true; - // Display, save, or load history. Stolen and modified from bash. // // Arg of -w FILENAME means write file, arg of -r FILENAME @@ -160,6 +133,10 @@ { int numbered_output = 1; + unwind_protect frame; + + frame.add_fcn (command_history::set_file, command_history::file ()); + int i; for (i = 1; i < argc; i++) { @@ -537,8 +514,10 @@ void initialize_history (bool read_history_file) { - command_history::initialize (read_history_file, Vhistory_file, Vhistory_size, - Vhistory_control); + command_history::initialize (read_history_file, + default_history_file (), + default_history_size (), + octave_env::getenv ("OCTAVE_HISTCONTROL")); } void @@ -691,12 +670,15 @@ @seealso{history_file, history_size, history_timestamp_format_string, saving_history}\n\ @end deftypefn") { - std::string saved_history_control = Vhistory_control; + std::string old_history_control = command_history::histcontrol (); + + std::string tmp = old_history_control; - octave_value retval = SET_INTERNAL_VARIABLE (history_control); + octave_value retval = set_internal_variable (tmp, args, nargout, + "history_control"); - if (Vhistory_control != saved_history_control) - command_history::process_histcontrol (Vhistory_control); + if (tmp != old_history_control) + command_history::process_histcontrol (tmp); return retval; } @@ -711,13 +693,15 @@ @seealso{history_file, history_timestamp_format_string, saving_history}\n\ @end deftypefn") { - int saved_history_size = Vhistory_size; + int old_history_size = command_history::size (); + + int tmp = old_history_size; - octave_value retval - = SET_INTERNAL_VARIABLE_WITH_LIMITS (history_size, -1, INT_MAX); + octave_value retval = set_internal_variable (tmp, args, nargout, + "history_size", -1, INT_MAX); - if (Vhistory_size != saved_history_size) - command_history::set_size (Vhistory_size); + if (tmp != old_history_size) + command_history::set_size (tmp); return retval; } @@ -733,12 +717,15 @@ @seealso{history_size, saving_history, history_timestamp_format_string}\n\ @end deftypefn") { - std::string saved_history_file = Vhistory_file; + std::string old_history_file = command_history::file (); + + std::string tmp = old_history_file; - octave_value retval = SET_INTERNAL_VARIABLE (history_file); + octave_value retval = set_internal_variable (tmp, args, nargout, + "history_file"); - if (Vhistory_file != saved_history_file) - command_history::set_file (Vhistory_file); + if (tmp != old_history_file) + command_history::set_file (tmp); return retval; } @@ -770,9 +757,15 @@ @seealso{history_control, history_file, history_size, history_timestamp_format_string}\n\ @end deftypefn") { - octave_value retval = SET_INTERNAL_VARIABLE (saving_history); + bool old_saving_history = ! command_history::ignoring_entries (); + + bool tmp = old_saving_history; - command_history::ignore_entries (! Vsaving_history); + octave_value retval = set_internal_variable (tmp, args, nargout, + "saving_history"); + + if (tmp != old_saving_history) + command_history::ignore_entries (! tmp); return retval; } diff -r c67f7d390a1a -r 7df7650492e8 src/oct-hist.h --- a/src/oct-hist.h Thu Aug 25 20:12:31 2011 +0200 +++ b/src/oct-hist.h Fri Aug 26 13:40:10 2011 -0500 @@ -35,7 +35,4 @@ // TRUE means input is coming from temporary history file. extern bool input_from_tmp_history_file; -// TRUE if we are saving history. -extern bool Vsaving_history; - #endif diff -r c67f7d390a1a -r 7df7650492e8 src/oct-parse.yy --- a/src/oct-parse.yy Thu Aug 25 20:12:31 2011 +0200 +++ b/src/oct-parse.yy Fri Aug 26 13:40:10 2011 -0500 @@ -3471,18 +3471,11 @@ parsing_subfunctions = false; endfunction_found = false; - // The next four lines must be in this order. - frame.add_fcn (command_history::ignore_entries, ! Vsaving_history); - - // FIXME -- we shouldn't need both the - // command_history object and the - // Vsaving_history variable... + frame.add_fcn (command_history::ignore_entries, + command_history::ignoring_entries ()); + command_history::ignore_entries (); - frame.protect_var (Vsaving_history); - - Vsaving_history = false; - FILE *ffile = get_input_from_file (ff, 0); frame.add_fcn (safe_fclose, ffile); @@ -4215,12 +4208,26 @@ @noindent\n\ calls the function @code{acos} with the argument @samp{-1}.\n\ \n\ -The function @code{feval} is necessary in order to be able to write\n\ -functions that call user-supplied functions, because Octave does not\n\ -have a way to declare a pointer to a function (like C) or to declare a\n\ -special kind of variable that can be used to hold the name of a function\n\ -(like @code{EXTERNAL} in Fortran). Instead, you must refer to functions\n\ -by name, and use @code{feval} to call them.\n\ +The function @code{feval} can also be used with function handles of\n\ +any sort (@pxref{Function Handles}). Historically, @code{feval} was\n\ +the only way to call user-supplied functions in strings, but\n\ +function handles are now preferred due to the cleaner syntax they\n\ +offer. For example,\n\ +\n\ +@example\n\ +@group\n\ +@var{f} = @@exp;\n\ +feval (@var{f}, 1)\n\ + @result{} 2.7183\n\ +@var{f} (1)\n\ + @result{} 2.7183\n\ +@end group\n\ +@end example\n\ +\n\ +@noindent\n\ +are equivalent ways to call the function referred to by @var{f}. If it\n\ +cannot be predicted beforehand that @var{f} is a function handle or the\n\ +function name in a string, @code{feval} can be used instead.\n\ @end deftypefn") { octave_value_list retval; diff -r c67f7d390a1a -r 7df7650492e8 src/oct-stream.cc --- a/src/oct-stream.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/oct-stream.cc Fri Aug 26 13:40:10 2011 -0500 @@ -1379,7 +1379,9 @@ tmp[n++] = static_cast (c); \ \ if (n > 0 && c == EOF) \ - is.clear () + is.clear (); \ + \ + tmp.resize (n) // For a `%s' format, skip initial whitespace and then read until the // next whitespace character or until WIDTH characters have been read. @@ -2860,38 +2862,60 @@ { clearerr (); + // Find current position so we can return to it if needed. + long orig_pos = rep->tell (); - status = rep->seek (offset, origin); + // Move to end of file. If successful, find the offset of the end. + + status = rep->seek (0, SEEK_END); if (status == 0) { - long save_pos = rep->tell (); - - rep->seek (0, SEEK_END); - - long pos_eof = rep->tell (); - - // I don't think save_pos can be less than zero, but we'll - // check anyway... - - if (save_pos > pos_eof || save_pos < 0) + long eof_pos = rep->tell (); + + if (origin == SEEK_CUR) + { + // Move back to original position, otherwise we will be + // seeking from the end of file which is probably not the + // original location. + + rep->seek (orig_pos, SEEK_SET); + } + + // Attempt to move to desired position; may be outside bounds + // of existing file. + + status = rep->seek (offset, origin); + + if (status == 0) { - // Seek outside bounds of file. Failure should leave - // position unchanged. + // Where are we after moving to desired position? + + long desired_pos = rep->tell (); + + // I don't think save_pos can be less than zero, but we'll + // check anyway... + + if (desired_pos > eof_pos || desired_pos < 0) + { + // Seek outside bounds of file. Failure should leave + // position unchanged. + + rep->seek (orig_pos, SEEK_SET); + + status = -1; + } + } + else + { + // Seeking to the desired position failed. Move back to + // original position and return failure status. rep->seek (orig_pos, SEEK_SET); status = -1; } - else - { - // Is it possible for this to fail? We are just - // returning to a position after the first successful - // seek. - - rep->seek (save_pos, SEEK_SET); - } } } diff -r c67f7d390a1a -r 7df7650492e8 src/ov-builtin.cc --- a/src/ov-builtin.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/ov-builtin.cc Fri Aug 26 13:40:10 2011 -0500 @@ -126,7 +126,7 @@ try { - profile_data_accumulator::enter pe (profiler, profiler_name ()); + BEGIN_PROFILER_BLOCK (profiler_name ()) retval = (*f) (args, nargout); // Do not allow null values to be returned from functions. @@ -140,6 +140,8 @@ // the idiom is very common, so we solve that here. if (retval.length () == 1 && retval.xelem (0).is_undefined ()) retval.clear (); + + END_PROFILER_BLOCK } catch (octave_execution_exception) { diff -r c67f7d390a1a -r 7df7650492e8 src/ov-mex-fcn.cc --- a/src/ov-mex-fcn.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/ov-mex-fcn.cc Fri Aug 26 13:40:10 2011 -0500 @@ -148,8 +148,9 @@ try { - profile_data_accumulator::enter pe (profiler, profiler_name ()); + BEGIN_PROFILER_BLOCK (profiler_name ()) retval = call_mex (have_fmex, mex_fcn_ptr, args, nargout, this); + END_PROFILER_BLOCK } catch (octave_execution_exception) { diff -r c67f7d390a1a -r 7df7650492e8 src/ov-usr-fcn.cc --- a/src/ov-usr-fcn.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/ov-usr-fcn.cc Fri Aug 26 13:40:10 2011 -0500 @@ -134,11 +134,9 @@ frame.protect_var (tree_evaluator::statement_context); tree_evaluator::statement_context = tree_evaluator::script; - { - profile_data_accumulator::enter pe (profiler, - profiler_name ()); - cmd_list->accept (*current_evaluator); - } + BEGIN_PROFILER_BLOCK (profiler_name ()) + cmd_list->accept (*current_evaluator); + END_PROFILER_BLOCK if (tree_return_command::returning) tree_return_command::returning = 0; @@ -455,26 +453,26 @@ bool special_expr = (is_inline_function () || cmd_list->is_anon_function_body ()); - { - profile_data_accumulator::enter pe (profiler, profiler_name ()); + BEGIN_PROFILER_BLOCK (profiler_name ()) - if (special_expr) - { - assert (cmd_list->length () == 1); + if (special_expr) + { + assert (cmd_list->length () == 1); - tree_statement *stmt = 0; + tree_statement *stmt = 0; - if ((stmt = cmd_list->front ()) - && stmt->is_expression ()) - { - tree_expression *expr = stmt->expression (); + if ((stmt = cmd_list->front ()) + && stmt->is_expression ()) + { + tree_expression *expr = stmt->expression (); - retval = expr->rvalue (nargout); - } - } - else - cmd_list->accept (*current_evaluator); - } + retval = expr->rvalue (nargout); + } + } + else + cmd_list->accept (*current_evaluator); + + END_PROFILER_BLOCK if (echo_commands) print_code_function_trailer (); diff -r c67f7d390a1a -r 7df7650492e8 src/profiler.cc --- a/src/profiler.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/profiler.cc Fri Aug 26 13:40:10 2011 -0500 @@ -24,6 +24,7 @@ #include #endif +#include #include #include "defun.h" @@ -56,11 +57,8 @@ parents (), children () {} -// With the help of a mapping name -> index, convert a function_set list -// to an Octave array of indices. octave_value -profile_data_accumulator::stats::function_set_value (const function_set& list, - const fcn_index_map& idx) +profile_data_accumulator::stats::function_set_value (const function_set& list) { const octave_idx_type n = list.size (); @@ -68,9 +66,7 @@ octave_idx_type i = 0; for (function_set::const_iterator p = list.begin (); p != list.end (); ++p) { - fcn_index_map::const_iterator q = idx.find (*p); - assert (q != idx.end ()); - retval (i) = q->second; + retval(i) = *p; ++i; } assert (i == n); @@ -78,19 +74,144 @@ return retval; } +profile_data_accumulator::tree_node::tree_node (tree_node* p, octave_idx_type f) + : parent (p), fcn_id (f), children (), time (0.0), calls (0) +{} + +profile_data_accumulator::tree_node::~tree_node () +{ + for (child_map::iterator i = children.begin (); i != children.end (); ++i) + delete i->second; +} + +profile_data_accumulator::tree_node* +profile_data_accumulator::tree_node::enter (octave_idx_type fcn) +{ + tree_node* retval; + + child_map::iterator pos = children.find (fcn); + if (pos == children.end ()) + { + retval = new tree_node (this, fcn); + children[fcn] = retval; + } + else + retval = pos->second; + + ++retval->calls; + return retval; +} + +profile_data_accumulator::tree_node* +profile_data_accumulator::tree_node::exit (octave_idx_type fcn) +{ + assert (parent); + assert (fcn_id == fcn); + + return parent; +} + +void +profile_data_accumulator::tree_node::build_flat (flat_profile& data) const +{ + // If this is not the top-level node, update profile entry for this function. + if (fcn_id != 0) + { + stats& entry = data[fcn_id - 1]; + + entry.time += time; + entry.calls += calls; + + assert (parent); + if (parent->fcn_id != 0) + { + entry.parents.insert (parent->fcn_id); + data[parent->fcn_id - 1].children.insert (fcn_id); + } + + if (!entry.recursive) + for (const tree_node* i = parent; i; i = i->parent) + if (i->fcn_id == fcn_id) + { + entry.recursive = true; + break; + } + } + + // Recurse on children. + for (child_map::const_iterator i = children.begin (); + i != children.end (); ++i) + i->second->build_flat (data); +} + +octave_value +profile_data_accumulator::tree_node::get_hierarchical (void) const +{ + /* Note that we don't generate the entry just for this node, but rather + a struct-array with entries for all children. This way, the top-node + (for which we don't want a real entry) generates already the final + hierarchical profile data. */ + + const octave_idx_type n = children.size (); + + Cell rv_indices (n, 1); + Cell rv_times (n, 1); + Cell rv_calls (n, 1); + Cell rv_children (n, 1); + + octave_idx_type i = 0; + for (child_map::const_iterator p = children.begin (); + p != children.end (); ++p) + { + const tree_node& entry = *p->second; + + rv_indices(i) = octave_value (p->first); + rv_times(i) = octave_value (entry.time); + rv_calls(i) = octave_value (entry.calls); + rv_children(i) = entry.get_hierarchical (); + + ++i; + } + assert (i == n); + + Octave_map retval; + + retval.assign ("Index", rv_indices); + retval.assign ("SelfTime", rv_times); + retval.assign ("NumCalls", rv_calls); + retval.assign ("Children", rv_children); + + return retval; +} + profile_data_accumulator::profile_data_accumulator () - : enabled (false), call_stack (), data (), last_time (-1.0) + : known_functions (), fcn_index (), + enabled (false), call_tree (NULL), last_time (-1.0) {} +profile_data_accumulator::~profile_data_accumulator () +{ + if (call_tree) + delete call_tree; +} + void profile_data_accumulator::set_active (bool value) { - // If we enable, clear the call-stack. This ensures we freshly start - // with collecting times now. if (value) { - while (!call_stack.empty ()) - call_stack.pop_back (); + // Create a call-tree top-node if there isn't yet one. + if (!call_tree) + call_tree = new tree_node (NULL, 0); + + // Let the top-node be the active one. This ensures we have a clean + // fresh start collecting times. + active_fcn = call_tree; + } + else + { + // Make sure we start with fresh timing if we're re-enabled later. + last_time = -1.0; } enabled = value; @@ -101,39 +222,34 @@ { // The enter class will check and only call us if the profiler is active. assert (is_active ()); + assert (call_tree); // If there is already an active function, add to its time before // pushing the new one. - if (!call_stack.empty ()) + if (active_fcn != call_tree) add_current_time (); - // Update non-timing related data for the function entered. - stats& entry = data[fcn]; - ++entry.calls; - if (!call_stack.empty ()) + // Map the function's name to its index. + octave_idx_type fcn_idx; + fcn_index_map::iterator pos = fcn_index.find (fcn); + if (pos == fcn_index.end ()) { - const std::string parent_name = call_stack.back (); - entry.parents.insert (parent_name); - data[parent_name].children.insert (fcn); + known_functions.push_back (fcn); + fcn_idx = known_functions.size (); + fcn_index[fcn] = fcn_idx; } - if (!entry.recursive) - for (call_stack_type::iterator i = call_stack.begin (); - i != call_stack.end (); ++i) - if (*i == fcn) - { - entry.recursive = true; - break; - } + else + fcn_idx = pos->second; - call_stack.push_back (fcn); + active_fcn = active_fcn->enter (fcn_idx); last_time = query_time (); } void profile_data_accumulator::exit_function (const std::string& fcn) { - assert (!call_stack.empty ()); - assert (fcn == call_stack.back ()); + assert (call_tree); + assert (active_fcn != call_tree); // Usually, if we are disabled this function is not even called. But the // call disabling the profiler is an exception. So also check here @@ -141,7 +257,9 @@ if (is_active ()) add_current_time (); - call_stack.pop_back (); + fcn_index_map::iterator pos = fcn_index.find (fcn); + assert (pos != fcn_index.end ()); + active_fcn = active_fcn->exit (pos->second); // If this was an "inner call", we resume executing the parent function // up the stack. So note the start-time for this! @@ -157,26 +275,26 @@ return; } - data.clear (); + known_functions.clear (); + fcn_index.clear (); + + if (call_tree) + { + delete call_tree; + call_tree = NULL; + } + last_time = -1.0; } octave_value -profile_data_accumulator::get_data (void) const +profile_data_accumulator::get_flat (void) const { - const octave_idx_type n = data.size (); + const octave_idx_type n = known_functions.size (); - // For the parent/child data, we need to map function key-names - // to the indices they correspond to in the output array. Find them out - // in a preparation step. - fcn_index_map fcn_indices; - octave_idx_type i = 0; - for (stats_map::const_iterator p = data.begin (); p != data.end (); ++p) - { - fcn_indices[p->first] = i + 1; - ++i; - } - assert (i == n); + flat_profile flat (n); + assert (call_tree); + call_tree->build_flat (flat); Cell rv_names (n, 1); Cell rv_times (n, 1); @@ -185,21 +303,15 @@ Cell rv_parents (n, 1); Cell rv_children (n, 1); - i = 0; - for (stats_map::const_iterator p = data.begin (); p != data.end (); ++p) + for (octave_idx_type i = 0; i != n; ++i) { - const stats& entry = p->second; - - rv_names (i) = octave_value (p->first); - rv_times (i) = octave_value (entry.time); - rv_calls (i) = octave_value (entry.calls); - rv_recursive (i) = octave_value (entry.recursive); - rv_parents (i) = stats::function_set_value (entry.parents, fcn_indices); - rv_children (i) = stats::function_set_value (entry.children, fcn_indices); - - ++i; + rv_names(i) = octave_value (known_functions[i]); + rv_times(i) = octave_value (flat[i].time); + rv_calls(i) = octave_value (flat[i].calls); + rv_recursive(i) = octave_value (flat[i].recursive); + rv_parents(i) = stats::function_set_value (flat[i].parents); + rv_children(i) = stats::function_set_value (flat[i].children); } - assert (i == n); Octave_map retval; @@ -213,6 +325,13 @@ return retval; } +octave_value +profile_data_accumulator::get_hierarchical (void) const +{ + assert (call_tree); + return call_tree->get_hierarchical (); +} + double profile_data_accumulator::query_time (void) const { @@ -226,20 +345,14 @@ const double t = query_time (); assert (last_time >= 0.0 && last_time <= t); - assert (!call_stack.empty ()); - const std::string name = call_stack.back (); - - // The entry for this function should already be created; namely - // when entering the function via the non-timing data collection! - stats_map::iterator pos = data.find (name); - assert (pos != data.end ()); - pos->second.time += t - last_time; + assert (call_tree && active_fcn != call_tree); + active_fcn->add_time (t - last_time); } profile_data_accumulator profiler; // Enable or disable the profiler data collection. -DEFUN (__profiler_enable, args, , +DEFUN (__profiler_enable__, args, , "-*- texinfo -*-\n\ @deftypefn {Function File} __profiler_enable ()\n\ Undocumented internal function.\n\ @@ -265,7 +378,7 @@ } // Clear all collected profiling data. -DEFUN (__profiler_reset, args, , +DEFUN (__profiler_reset__, args, , "-*- texinfo -*-\n\ @deftypefn {Function File} __profiler_reset ()\n\ Undocumented internal function.\n\ @@ -283,7 +396,7 @@ } // Query the timings collected by the profiler. -DEFUN (__profiler_data, args, , +DEFUN (__profiler_data__, args, nargout, "-*- texinfo -*-\n\ @deftypefn {Function File} __profiler_data ()\n\ Undocumented internal function.\n\ @@ -295,7 +408,9 @@ if (nargin > 0) warning ("profiler_data: ignoring extra arguments"); - retval(0) = profiler.get_data (); + retval(0) = profiler.get_flat (); + if (nargout > 1) + retval(1) = profiler.get_hierarchical (); return retval; } diff -r c67f7d390a1a -r 7df7650492e8 src/profiler.h --- a/src/profiler.h Thu Aug 25 20:12:31 2011 +0200 +++ b/src/profiler.h Fri Aug 26 13:40:10 2011 -0500 @@ -40,72 +40,113 @@ // functions in a manner protected from stack unwinding. class enter { - private: - - profile_data_accumulator& acc; + private: - std::string fcn; + profile_data_accumulator& acc; + std::string fcn; - public: - - enter (profile_data_accumulator&, const std::string&); + public: - virtual ~enter (void); - - private: + enter (profile_data_accumulator&, const std::string&); + virtual ~enter (void); - // No copying! + private: - enter (const enter&); - - enter& operator = (const enter&); + // No copying! + enter (const enter&); + enter& operator = (const enter&); }; profile_data_accumulator (void); + virtual ~profile_data_accumulator (); bool is_active (void) const { return enabled; } - void set_active (bool); void reset (void); - octave_value get_data (void) const; + octave_value get_flat (void) const; + octave_value get_hierarchical (void) const; private: - typedef std::set function_set; + // One entry in the flat profile (i.e., a collection of data for a single + // function). This is filled in when building the flat profile from the + // hierarchical call tree. + struct stats + { + stats (); + + double time; + unsigned calls; + + bool recursive; + + typedef std::set function_set; + function_set parents; + function_set children; + + // Convert a function_set list to an Octave array of indices. + static octave_value function_set_value (const function_set&); + }; + + typedef std::vector flat_profile; + + // Store data for one node in the call-tree of the hierarchical profiler + // data we collect. + class tree_node + { + public: + + tree_node (tree_node*, octave_idx_type); + virtual ~tree_node (); + + void add_time (double dt) { time += dt; } + + // Enter a child function. It is created in the list of children if it + // wasn't already there. The now-active child node is returned. + tree_node* enter (octave_idx_type); + + // Exit function. As a sanity-check, it is verified that the currently + // active function actually is the one handed in here. Returned is the + // then-active node, which is our parent. + tree_node* exit (octave_idx_type); + + void build_flat (flat_profile&) const; + octave_value get_hierarchical (void) const; + + private: + + tree_node* parent; + octave_idx_type fcn_id; + + typedef std::map child_map; + child_map children; + + // This is only time spent *directly* on this level, excluding children! + double time; + + unsigned calls; + + // No copying! + tree_node (const tree_node&); + tree_node& operator = (const tree_node&); + }; + + // Each function we see in the profiler is given a unique index (which + // simply counts starting from 1). We thus have to map profiler-names to + // those indices. For all other stuff, we identify functions by their index. + + typedef std::vector function_set; typedef std::map fcn_index_map; - // Store some statistics data collected for a function. - class stats - { - private: - - double time; - unsigned calls; - - bool recursive; - - function_set parents; - function_set children; - - public: - - stats (); - - static octave_value - function_set_value (const function_set&, const fcn_index_map&); - - friend class profile_data_accumulator; - }; + function_set known_functions; + fcn_index_map fcn_index; bool enabled; - typedef std::vector call_stack_type; - call_stack_type call_stack; - - typedef std::map stats_map; - stats_map data; + tree_node* call_tree; + tree_node* active_fcn; // Store last timestamp we had, when the currently active function was called. double last_time; @@ -117,23 +158,28 @@ // Query a timestamp, used for timing calls (obviously). // This is not static because in the future, maybe we want a flag - // in the profiler or something to choose between cputime, wall-time + // in the profiler or something to choose between cputime, wall-time, // user-time, system-time, ... double query_time () const; - // Add the time elapsed since last_time to the function on the top - // of our call-stack. This is called from two different positions, - // thus it is useful to have it as a seperate function. + // Add the time elapsed since last_time to the function we're currently in. + // This is called from two different positions, thus it is useful to have + // it as a seperate function. void add_current_time (void); // No copying! - profile_data_accumulator (const profile_data_accumulator&); - profile_data_accumulator& operator = (const profile_data_accumulator&); }; // The instance used. extern profile_data_accumulator profiler; +// Helper macro to profile a block of code. +#define BEGIN_PROFILER_BLOCK(name) \ + { \ + profile_data_accumulator::enter pe (profiler, (name)); +#define END_PROFILER_BLOCK \ + } + #endif diff -r c67f7d390a1a -r 7df7650492e8 src/pt-binop.cc --- a/src/pt-binop.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/pt-binop.cc Fri Aug 26 13:40:10 2011 -0500 @@ -121,8 +121,7 @@ if (! error_state && b.is_defined ()) { - profile_data_accumulator::enter pe (profiler, - "binary " + oper ()); + BEGIN_PROFILER_BLOCK ("binary " + oper ()) // Note: The profiler does not catch the braindead // short-circuit evaluation code above, but that should be @@ -134,6 +133,8 @@ if (error_state) retval = octave_value (); + + END_PROFILER_BLOCK } } } diff -r c67f7d390a1a -r 7df7650492e8 src/pt-unop.cc --- a/src/pt-unop.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/pt-unop.cc Fri Aug 26 13:40:10 2011 -0500 @@ -73,13 +73,14 @@ if (! error_state) { - profile_data_accumulator::enter pe (profiler, - "prefix " + oper ()); + BEGIN_PROFILER_BLOCK ("prefix " + oper ()) ref.do_unary_op (etype); if (! error_state) retval = ref.value (); + + END_PROFILER_BLOCK } } else @@ -88,8 +89,7 @@ if (! error_state && val.is_defined ()) { - profile_data_accumulator::enter pe (profiler, - "prefix " + oper ()); + BEGIN_PROFILER_BLOCK ("prefix " + oper ()) // Attempt to do the operation in-place if it is unshared // (a temporary expression). @@ -100,6 +100,8 @@ if (error_state) retval = octave_value (); + + END_PROFILER_BLOCK } } } @@ -160,10 +162,9 @@ { retval = ref.value (); - profile_data_accumulator::enter pe (profiler, - "postfix " + oper ()); - + BEGIN_PROFILER_BLOCK ("postfix " + oper ()) ref.do_unary_op (etype); + END_PROFILER_BLOCK } } else @@ -172,13 +173,14 @@ if (! error_state && val.is_defined ()) { - profile_data_accumulator::enter pe (profiler, - "postfix " + oper ()); + BEGIN_PROFILER_BLOCK ("postfix " + oper ()) retval = ::do_unary_op (etype, val); if (error_state) retval = octave_value (); + + END_PROFILER_BLOCK } } } diff -r c67f7d390a1a -r 7df7650492e8 src/toplev.cc --- a/src/toplev.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/toplev.cc Fri Aug 26 13:40:10 2011 -0500 @@ -39,6 +39,7 @@ #include #include "cmd-edit.h" +#include "cmd-hist.h" #include "file-ops.h" #include "lo-error.h" #include "lo-mappers.h" @@ -1053,7 +1054,7 @@ SAFE_CALL (octave_history_write_timestamp, ()) - if (Vsaving_history) + if (! command_history::ignoring_entries ()) SAFE_CALL (command_history::clean_up_and_save, ()) SAFE_CALL (close_files, ()) diff -r c67f7d390a1a -r 7df7650492e8 src/txt-eng-ft.cc --- a/src/txt-eng-ft.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/txt-eng-ft.cc Fri Aug 26 13:40:10 2011 -0500 @@ -202,7 +202,8 @@ ft_render::ft_render (void) : text_processor (), face (0), bbox (1, 4, 0.0), - xoffset (0), yoffset (0), mode (MODE_BBOX), + xoffset (0), yoffset (0), multiline_halign (0), + multiline_align_xoffsets(), mode (MODE_BBOX), red (0), green (0), blue (0) { } @@ -270,15 +271,23 @@ { if (face) { + int line_index = 0; + FT_UInt box_line_width = 0; std::string str = e.string_value (); FT_UInt glyph_index, previous = 0; + if (mode == MODE_BBOX) + multiline_align_xoffsets.clear(); + else if (mode == MODE_RENDER) + xoffset += multiline_align_xoffsets[line_index]; + for (size_t i = 0; i < str.length (); i++) { glyph_index = FT_Get_Char_Index (face, str[i]); - if (! glyph_index - || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)) + if (str[i] != '\n' + && (! glyph_index + || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))) ::warning ("ft_render: skipping missing glyph for character `%c'", str[i]); else @@ -286,7 +295,21 @@ switch (mode) { case MODE_RENDER: - if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL)) + if (str[i] == '\n') + { + glyph_index = FT_Get_Char_Index(face, ' '); + if (!glyph_index || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)) + { + ::warning ("ft_render: skipping missing glyph for character ` '"); + } + else + { + line_index++; + xoffset = multiline_align_xoffsets[line_index]; + yoffset -= (face->size->metrics.height >> 6); + } + } + else if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL)) ::warning ("ft_render: unable to render glyph for character `%c'", str[i]); else @@ -304,6 +327,14 @@ x0 = xoffset+face->glyph->bitmap_left; y0 = yoffset+face->glyph->bitmap_top; + + // 'w' seems to have a negative -1 + // face->glyph->bitmap_left, this is so we don't + // index out of bound, and assumes we we allocated + // the right amount of horizontal space in the bbox. + if (x0 < 0) + x0 = 0; + for (int r = 0; r < bitmap.rows; r++) for (int c = 0; c < bitmap.width; c++) { @@ -327,43 +358,89 @@ break; case MODE_BBOX: - // width - if (previous) + if (str[i] == '\n') { - FT_Vector delta; - - FT_Get_Kerning (face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); - bbox(2) += (delta.x >> 6); - } - bbox(2) += (face->glyph->advance.x >> 6); - - int asc, desc; - - if (false /*tight*/) + glyph_index = FT_Get_Char_Index(face, ' '); + if (! glyph_index + || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)) + { + ::warning ("ft_render: skipping missing glyph for character ` '"); + } + else + { + multiline_align_xoffsets.push_back(box_line_width); + // Reset the pixel width for this newline, so we don't + // allocate a bounding box larger than the horizontal + // width of the multi-line + box_line_width = 0; + bbox(1) -= (face->size->metrics.height >> 6); + } + } + else { - desc = face->glyph->metrics.horiBearingY - face->glyph->metrics.height; - asc = face->glyph->metrics.horiBearingY; - } - else - { - asc = face->size->metrics.ascender; - desc = face->size->metrics.descender; - } + // width + if (previous) + { + FT_Vector delta; + + FT_Get_Kerning (face, previous, glyph_index, + FT_KERNING_DEFAULT, &delta); + + box_line_width += (delta.x >> 6); + } + + box_line_width += (face->glyph->advance.x >> 6); + + int asc, desc; - asc = yoffset + (asc >> 6); - desc = yoffset + (desc >> 6); + if (false /*tight*/) + { + desc = face->glyph->metrics.horiBearingY - face->glyph->metrics.height; + asc = face->glyph->metrics.horiBearingY; + } + else + { + asc = face->size->metrics.ascender; + desc = face->size->metrics.descender; + } - if (desc < bbox(1)) - { - bbox(3) += (bbox(1) - desc); - bbox(1) = desc; - } - if (asc > (bbox(3)+bbox(1))) - bbox(3) = asc-bbox(1); + asc = yoffset + (asc >> 6); + desc = yoffset + (desc >> 6); + + if (desc < bbox(1)) + { + bbox(3) += (bbox(1) - desc); + bbox(1) = desc; + } + if (asc > (bbox(3)+bbox(1))) + bbox(3) = asc-bbox(1); + if (bbox(2) < box_line_width) + bbox(2) = box_line_width; + } break; } + if (str[i] == '\n') + previous = 0; + else + previous = glyph_index; + } + } + if (mode == MODE_BBOX) + { + /* Push last the width associated with the last line */ + multiline_align_xoffsets.push_back(box_line_width); - previous = glyph_index; + for (unsigned int i = 0; i < multiline_align_xoffsets.size(); i++) + { + /* Center align */ + if (multiline_halign == 1) + multiline_align_xoffsets[i] = (bbox(2) - multiline_align_xoffsets[i])/2; + /* Right align */ + else if (multiline_halign == 2) + multiline_align_xoffsets[i] = (bbox(2) - multiline_align_xoffsets[i]); + /* Left align */ + else + multiline_align_xoffsets[i] = 0; } } } @@ -506,6 +583,8 @@ { // FIXME: clip "rotation" between 0 and 360 int rot_mode = rotation_to_mode (rotation); + + multiline_halign = halign; text_element *elt = text_parser_none ().parse (txt); pixels_ = render (elt, box, rot_mode); diff -r c67f7d390a1a -r 7df7650492e8 src/txt-eng-ft.h --- a/src/txt-eng-ft.h Thu Aug 25 20:12:31 2011 +0200 +++ b/src/txt-eng-ft.h Fri Aug 26 13:40:10 2011 -0500 @@ -25,6 +25,8 @@ #if HAVE_FREETYPE +#include + #include #include FT_FREETYPE_H @@ -94,6 +96,8 @@ uint8NDArray pixels; int xoffset; int yoffset; + int multiline_halign; + std::vector multiline_align_xoffsets; int mode; uint8_t red, green, blue; }; diff -r c67f7d390a1a -r 7df7650492e8 src/xdiv.cc --- a/src/xdiv.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/xdiv.cc Fri Aug 26 13:40:10 2011 -0500 @@ -64,14 +64,14 @@ template bool -mx_leftdiv_conform (const T1& a, const T2& b) +mx_leftdiv_conform (const T1& a, const T2& b, blas_trans_type blas_trans) { - octave_idx_type a_nr = a.rows (); + octave_idx_type a_nr = blas_trans == blas_no_trans ? a.rows () : a.cols (); octave_idx_type b_nr = b.rows (); if (a_nr != b_nr) { - octave_idx_type a_nc = a.cols (); + octave_idx_type a_nc = blas_trans == blas_no_trans ? a.cols () : a.rows (); octave_idx_type b_nc = b.cols (); gripe_nonconformant ("operator \\", a_nr, a_nc, b_nr, b_nc); @@ -82,7 +82,7 @@ } #define INSTANTIATE_MX_LEFTDIV_CONFORM(T1, T2) \ - template bool mx_leftdiv_conform (const T1&, const T2&) + template bool mx_leftdiv_conform (const T1&, const T2&, blas_trans_type) INSTANTIATE_MX_LEFTDIV_CONFORM (Matrix, Matrix); INSTANTIATE_MX_LEFTDIV_CONFORM (Matrix, ComplexMatrix); @@ -352,7 +352,7 @@ Matrix xleftdiv (const Matrix& a, const Matrix& b, MatrixType &typ, blas_trans_type transt) { - if (! mx_leftdiv_conform (a, b)) + if (! mx_leftdiv_conform (a, b, transt)) return Matrix (); octave_idx_type info; @@ -364,7 +364,7 @@ ComplexMatrix xleftdiv (const Matrix& a, const ComplexMatrix& b, MatrixType &typ, blas_trans_type transt) { - if (! mx_leftdiv_conform (a, b)) + if (! mx_leftdiv_conform (a, b, transt)) return ComplexMatrix (); octave_idx_type info; @@ -377,7 +377,7 @@ ComplexMatrix xleftdiv (const ComplexMatrix& a, const Matrix& b, MatrixType &typ, blas_trans_type transt) { - if (! mx_leftdiv_conform (a, b)) + if (! mx_leftdiv_conform (a, b, transt)) return ComplexMatrix (); octave_idx_type info; @@ -389,7 +389,7 @@ ComplexMatrix xleftdiv (const ComplexMatrix& a, const ComplexMatrix& b, MatrixType &typ, blas_trans_type transt) { - if (! mx_leftdiv_conform (a, b)) + if (! mx_leftdiv_conform (a, b, transt)) return ComplexMatrix (); octave_idx_type info; @@ -650,7 +650,7 @@ FloatMatrix xleftdiv (const FloatMatrix& a, const FloatMatrix& b, MatrixType &typ, blas_trans_type transt) { - if (! mx_leftdiv_conform (a, b)) + if (! mx_leftdiv_conform (a, b, transt)) return FloatMatrix (); octave_idx_type info; @@ -662,7 +662,7 @@ FloatComplexMatrix xleftdiv (const FloatMatrix& a, const FloatComplexMatrix& b, MatrixType &typ, blas_trans_type transt) { - if (! mx_leftdiv_conform (a, b)) + if (! mx_leftdiv_conform (a, b, transt)) return FloatComplexMatrix (); octave_idx_type info; @@ -675,7 +675,7 @@ FloatComplexMatrix xleftdiv (const FloatComplexMatrix& a, const FloatMatrix& b, MatrixType &typ, blas_trans_type transt) { - if (! mx_leftdiv_conform (a, b)) + if (! mx_leftdiv_conform (a, b, transt)) return FloatComplexMatrix (); octave_idx_type info; @@ -687,7 +687,7 @@ FloatComplexMatrix xleftdiv (const FloatComplexMatrix& a, const FloatComplexMatrix& b, MatrixType &typ, blas_trans_type transt) { - if (! mx_leftdiv_conform (a, b)) + if (! mx_leftdiv_conform (a, b, transt)) return FloatComplexMatrix (); octave_idx_type info; @@ -782,7 +782,7 @@ MT dmm_leftdiv_impl (const DMT& d, const MT& a) { - if (! mx_leftdiv_conform (d, a)) + if (! mx_leftdiv_conform (d, a, blas_no_trans)) return MT (); octave_idx_type m = d.cols (), n = a.cols (), k = a.rows (), l = d.length (); @@ -931,7 +931,7 @@ MT dmdm_leftdiv_impl (const DMT& d, const MT& a) { - if (! mx_leftdiv_conform (d, a)) + if (! mx_leftdiv_conform (d, a, blas_no_trans)) return MT (); octave_idx_type m = d.cols (), n = a.cols (), k = d.rows (); diff -r c67f7d390a1a -r 7df7650492e8 src/xpow.cc --- a/src/xpow.cc Thu Aug 25 20:12:31 2011 +0200 +++ b/src/xpow.cc Fri Aug 26 13:40:10 2011 -0500 @@ -49,6 +49,8 @@ #include "utils.h" #include "xpow.h" +#include "bsxfun.h" + #ifdef _OPENMP #include #endif @@ -1243,8 +1245,21 @@ if (a_dims != b_dims) { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); + if (is_valid_bsxfun (a_dims, b_dims)) + { + //Potentially complex results + NDArray xa = octave_value_extract (a); + NDArray xb = octave_value_extract (b); + if (! xb.all_integers () && xa.any_element_is_negative ()) + return octave_value (bsxfun_pow (ComplexNDArray (xa), xb)); + else + return octave_value (bsxfun_pow (xa, xb)); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } } int len = a.length (); @@ -1318,8 +1333,15 @@ if (a_dims != b_dims) { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); + if (is_valid_bsxfun (a_dims, b_dims)) + { + return bsxfun_pow (a, b); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } } ComplexNDArray result (a_dims); @@ -1410,8 +1432,15 @@ if (a_dims != b_dims) { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); + if (is_valid_bsxfun (a_dims, b_dims)) + { + return bsxfun_pow (a, b); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } } ComplexNDArray result (a_dims); @@ -1453,8 +1482,15 @@ if (a_dims != b_dims) { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); + if (is_valid_bsxfun (a_dims, b_dims)) + { + return bsxfun_pow (a, b); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } } ComplexNDArray result (a_dims); diff -r c67f7d390a1a -r 7df7650492e8 test/test_io.m --- a/test/test_io.m Thu Aug 25 20:12:31 2011 +0200 +++ b/test/test_io.m Fri Aug 26 13:40:10 2011 -0500 @@ -242,6 +242,30 @@ %% test/octave.test/io/puts-4.m %!error puts (1, 2); +%!assert (sscanf ('123456', '%10c'), '123456') +%!assert (sscanf ('123456', '%10s'), '123456') + +%!test +%! [val, count, msg, pos] = sscanf ("3I2", "%f"); +%! assert (val, 3); +%! assert (count, 1); +%! assert (msg, ""); +%! assert (pos, 2); + +%!test +%! [val, count, msg, pos] = sscanf ("3In2", "%f"); +%! assert (val, 3); +%! assert (count, 1); +%! assert (msg, ""); +%! assert (pos, 2); + +%!test +%! [val, count, msg, pos] = sscanf ("3Inf2", "%f"); +%! assert (val, [3; Inf; 2]); +%! assert (count, 3); +%! assert (msg, ""); +%! assert (pos, 6); + %% test/octave.test/io/sscanf-1.m %!test %! [a, b, c] = sscanf ("1.2 3 foo", "%f%d%s", "C");