# HG changeset patch # User John W. Eaton # Date 1344031518 14400 # Node ID b9b6a310ad97d0056726e965855ce11534cb4de1 # Parent a132d206a36a512544d5aa0804aa5c8ef27bfd68# Parent 909a2797935bbf1e59690da056a9b850360a0e26 maint: periodic merge of default to gui diff -r a132d206a36a -r b9b6a310ad97 src/Cell.cc --- a/src/Cell.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,320 +0,0 @@ -/* - -Copyright (C) 1999-2012 John W. Eaton -Copyright (C) 2009-2010 VZLU Prague - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "idx-vector.h" - -#include "Cell.h" -#include "error.h" -#include "gripes.h" -#include "oct-obj.h" - -Cell::Cell (const octave_value_list& ovl) - : Array (ovl.cell_value ()) -{ -} - -Cell::Cell (const string_vector& sv, bool trim) - : Array () -{ - octave_idx_type n = sv.length (); - - if (n > 0) - { - resize (dim_vector (n, 1)); - - for (octave_idx_type i = 0; i < n; i++) - { - std::string s = sv[i]; - - if (trim) - { - size_t pos = s.find_last_not_of (' '); - - s = (pos == std::string::npos) ? "" : s.substr (0, pos+1); - } - - elem(i,0) = s; - } - } -} - -Cell::Cell (const std::list& lst) - : Array () -{ - size_t n = lst.size (); - - if (n > 0) - { - resize (dim_vector (n, 1)); - - octave_idx_type i = 0; - - for (std::list::const_iterator it = lst.begin (); - it != lst.end (); it++) - { - elem(i++,0) = *it; - } - } -} - -Cell::Cell (const Array& sa) - : Array (sa.dims ()) -{ - octave_idx_type n = sa.numel (); - - octave_value *dst = fortran_vec (); - const std::string *src = sa.data (); - - for (octave_idx_type i = 0; i < n; i++) - dst[i] = src[i]; -} - -// Set size to DV, filling with []. Then fill with as many elements of -// SV as possible. - -Cell::Cell (const dim_vector& dv, const string_vector& sv, bool trim) - : Array (dv, Matrix ()) -{ - octave_idx_type n = sv.length (); - - if (n > 0) - { - octave_idx_type m = numel (); - - octave_idx_type len = n > m ? m : n; - - for (octave_idx_type i = 0; i < len; i++) - { - std::string s = sv[i]; - - if (trim) - { - size_t pos = s.find_last_not_of (' '); - - s = (pos == std::string::npos) ? "" : s.substr (0, pos+1); - } - - elem(i) = s; - } - } -} - -bool -Cell::is_cellstr (void) const -{ - bool retval = true; - - octave_idx_type n = numel (); - - for (octave_idx_type i = 0; i < n; i++) - { - if (! elem(i).is_string ()) - { - retval = false; - break; - } - } - - return retval; -} - -Array -Cell::cellstr_value (void) const -{ - Array retval (dims ()); - - octave_idx_type n = numel (); - - for (octave_idx_type i = 0; i < n; i++) - retval.xelem (i) = elem (i).string_value (); - - return retval; -} - -Cell -Cell::index (const octave_value_list& idx_arg, bool resize_ok) const -{ - Cell retval; - - octave_idx_type n = idx_arg.length (); - - switch (n) - { - case 0: - retval = *this; - break; - - case 1: - { - idx_vector i = idx_arg(0).index_vector (); - - if (! error_state) - retval = Array::index (i, resize_ok, Matrix ()); - } - break; - - case 2: - { - idx_vector i = idx_arg(0).index_vector (); - - if (! error_state) - { - idx_vector j = idx_arg(1).index_vector (); - - if (! error_state) - retval = Array::index (i, j, resize_ok, Matrix ()); - } - } - break; - - default: - { - Array iv (dim_vector (n, 1)); - - for (octave_idx_type i = 0; i < n; i++) - { - iv(i) = idx_arg(i).index_vector (); - - if (error_state) - break; - } - - if (!error_state) - retval = Array::index (iv, resize_ok, Matrix ()); - } - break; - } - - return retval; -} - -void -Cell::assign (const octave_value_list& idx_arg, const Cell& rhs, - const octave_value& fill_val) - -{ - octave_idx_type len = idx_arg.length (); - - Array ra_idx (dim_vector (len, 1)); - - for (octave_idx_type i = 0; i < len; i++) - ra_idx(i) = idx_arg(i).index_vector (); - - Array::assign (ra_idx, rhs, fill_val); -} - -void -Cell::delete_elements (const octave_value_list& idx_arg) - -{ - octave_idx_type len = idx_arg.length (); - - Array ra_idx (dim_vector (len, 1)); - - for (octave_idx_type i = 0; i < len; i++) - ra_idx.xelem (i) = idx_arg(i).index_vector (); - - Array::delete_elements (ra_idx); -} - -octave_idx_type -Cell::nnz (void) const -{ - gripe_wrong_type_arg ("nnz", "cell array"); - return -1; -} - -Cell -Cell::column (octave_idx_type i) const -{ - Cell retval; - - if (ndims () < 3) - { - if (i < 0 || i >= cols ()) - error ("invalid column selection"); - else - { - octave_idx_type nr = rows (); - - retval.resize (dim_vector (nr, 1)); - - for (octave_idx_type j = 0; j < nr; j++) - retval.xelem (j) = elem (j, i); - } - } - else - error ("Cell::column: requires 2-d cell array"); - - return retval; -} - -Cell -Cell::concat (const Cell& rb, const Array& ra_idx) -{ - return insert (rb, ra_idx); -} - -Cell& -Cell::insert (const Cell& a, octave_idx_type r, octave_idx_type c) -{ - Array::insert (a, r, c); - return *this; -} - -Cell& -Cell::insert (const Cell& a, const Array& ra_idx) -{ - Array::insert (a, ra_idx); - return *this; -} - -Cell -Cell::map (ctype_mapper fcn) const -{ - Cell retval (dims ()); - octave_value *r = retval.fortran_vec (); - - const octave_value *p = data (); - - for (octave_idx_type i = 0; i < numel (); i++) - r[i] = ((p++)->*fcn) (); - - return retval; -} - -Cell -Cell::diag (octave_idx_type k) const -{ - return Array::diag (k); -} - -Cell -Cell::diag (octave_idx_type m, octave_idx_type n) const -{ - return Array::diag (m, n); -} diff -r a132d206a36a -r b9b6a310ad97 src/Cell.h --- a/src/Cell.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -/* - -Copyright (C) 1999-2012 John W. Eaton -Copyright (C) 2009-2010 VZLU Prague - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (Cell_h) -#define Cell_h 1 - -#include - -#include "Array.h" -#include "oct-alloc.h" -#include "str-vec.h" -#include "ov.h" - -class octave_value_list; - -class -OCTINTERP_API -Cell : public Array -{ -public: - - Cell (void) - : Array (dim_vector (0, 0)) { } - - Cell (const octave_value& val) - : Array (dim_vector (1, 1), val) { } - - Cell (const octave_value_list& ovl); - - Cell (octave_idx_type n, octave_idx_type m, - const octave_value& val = Matrix ()) - : Array (dim_vector (n, m), val) { } - - Cell (const dim_vector& dv, const octave_value& val = Matrix ()) - : Array (dv, val) { } - - Cell (const Array& c) - : Array (c) { } - - Cell (const Array& c, octave_idx_type nr, octave_idx_type nc) - : Array (c, dim_vector (nr, nc)) { } - - Cell (const string_vector& sv, bool trim = false); - - Cell (const std::list& lst); - - Cell (const Array& sa); - - Cell (const dim_vector& dv, const string_vector& sv, bool trim = false); - - Cell (const Cell& c) - : Array (c) { } - - bool is_cellstr (void) const; - - Array cellstr_value (void) const; - - using Array::index; - - Cell index (const octave_value_list& idx, bool resize_ok = false) const; - - using Array::delete_elements; - - void delete_elements (const octave_value_list& idx); - - using Array::assign; - - void assign (const octave_value_list& idx, const Cell& rhs, - const octave_value& fill_val = Matrix ()); - - Cell reshape (const dim_vector& new_dims) const - { return Array::reshape (new_dims); } - - octave_idx_type nnz (void) const; - - Cell column (octave_idx_type i) const; - - // FIXME - boolMatrix all (int /* dim */ = 0) const { return boolMatrix (); } - - // FIXME - boolMatrix any (int /* dim */ = 0) const { return boolMatrix (); } - - Cell concat (const Cell& rb, const Array& ra_idx); - - Cell& insert (const Cell& a, octave_idx_type r, octave_idx_type c); - Cell& insert (const Cell& a, const Array& ra_idx); - - // FIXME - bool any_element_is_nan (void) const { return false; } - bool is_true (void) const { return false; } - - octave_value resize_fill_value (void) const - { - static Matrix rfv; - return rfv; - } - - Cell diag (octave_idx_type k = 0) const; - - Cell diag (octave_idx_type m, octave_idx_type n) const; - - Cell xisalnum (void) const { return map (&octave_value::xisalnum); } - Cell xisalpha (void) const { return map (&octave_value::xisalpha); } - Cell xisascii (void) const { return map (&octave_value::xisascii); } - Cell xiscntrl (void) const { return map (&octave_value::xiscntrl); } - Cell xisdigit (void) const { return map (&octave_value::xisdigit); } - Cell xisgraph (void) const { return map (&octave_value::xisgraph); } - Cell xislower (void) const { return map (&octave_value::xislower); } - Cell xisprint (void) const { return map (&octave_value::xisprint); } - Cell xispunct (void) const { return map (&octave_value::xispunct); } - Cell xisspace (void) const { return map (&octave_value::xisspace); } - Cell xisupper (void) const { return map (&octave_value::xisupper); } - Cell xisxdigit (void) const { return map (&octave_value::xisxdigit); } - Cell xtoascii (void) const { return map (&octave_value::xtoascii); } - Cell xtolower (void) const { return map (&octave_value::xtolower); } - Cell xtoupper (void) const { return map (&octave_value::xtoupper); } - -private: - - typedef octave_value (octave_value::*ctype_mapper) (void) const; - - Cell map (ctype_mapper) const; -}; - -template<> -inline Cell octave_value_extract (const octave_value& v) - { return v.cell_value (); } - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/Makefile.am --- a/src/Makefile.am Fri Aug 03 14:59:40 2012 -0400 +++ b/src/Makefile.am Fri Aug 03 18:05:18 2012 -0400 @@ -1,4 +1,4 @@ -# Makefile for octave's src directory +# Makefile for Octave's src directory # # Copyright (C) 1993-2012 John W. Eaton # @@ -24,10 +24,12 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/libcruft/misc \ -I../liboctave -I$(top_srcdir)/liboctave \ + -Ioctave-value -I$(srcdir)/octave-value \ + -Iparse-tree -I$(srcdir)/parse-tree \ + -Ioperators -I$(srcdir)/operators \ + -Iinterp-core -I$(srcdir)/interp-core \ -Iinterpfcn -I$(srcdir)/interpfcn \ -Icorefcn \ - -Ioctave-value -I$(srcdir)/octave-value \ - -Iparse-tree -I$(srcdir)/parse-tree \ -I. -I$(srcdir) \ -I../libgnu -I$(top_srcdir)/libgnu \ @CPPFLAGS@ @@ -66,33 +68,33 @@ ## $(DEF_FILES), and building those requires all the sources ## (except builtins.cc) to be available. BUILT_SOURCES = \ - $(BUILT_SOURCES_EXTRA) \ + interp-core/mxarray.h \ + interp-core/oct-errno.cc \ interpfcn/defaults.h \ + interpfcn/graphics-props.cc \ interpfcn/graphics.h \ - interpfcn/graphics-props.cc \ + operators/ops.cc \ parse-tree/lex.cc \ - mxarray.h \ + parse-tree/oct-gperf.h \ + parse-tree/oct-parse.cc \ oct-conf.h \ - oct-errno.cc \ - oct-gperf.h \ - parse-tree/oct-parse.cc \ - ops.cc \ version.h \ + $(BUILT_SOURCES_EXTRA) \ builtins.cc BUILT_DISTFILES = \ - oct-gperf.h \ + parse-tree/oct-gperf.h \ parse-tree/oct-parse.h ## Files that are created during build process and installed, ## BUT not distributed in tarball. BUILT_NODISTFILES = \ + interp-core/mxarray.h \ + interp-core/oct-errno.cc \ interpfcn/defaults.h \ interpfcn/graphics.h \ + operators/ops.cc \ oct-conf.h \ - oct-errno.cc \ - ops.cc \ - mxarray.h \ version.h \ $(OPT_HANDLERS) \ $(OPT_INC) \ @@ -101,13 +103,10 @@ EXTRA_DIST = \ Makefile.in \ - defaults.in.h \ DOCSTRINGS \ find-defun-files.sh \ gendoc.pl \ genprops.awk \ - gl2ps.c \ - graphics.in.h \ mk-errno-list \ mk-pkg-add \ mkbuiltins \ @@ -115,136 +114,36 @@ mkoctfile.in.cc \ mkoctfile.in.sh \ mkops \ - mxarray.in.h \ oct-conf.in.h \ - oct-errno.in.cc \ octave-config.in.cc \ octave-config.in.sh \ - octave.gperf \ version.in.h \ $(BUILT_DISTFILES) -JIT_INCLUDES = \ - jit-util.h \ - jit-typeinfo.h \ - jit-ir.h \ - pt-jit.h - octinclude_HEADERS = \ - Cell.h \ - builtins.h \ - c-file-ptr-stream.h \ - comment-list.h \ - cutils.h \ - defun-dld.h \ - defun-int.h \ - display.h \ - dynamic-ld.h \ - gl-render.h \ - gl2ps.h \ - gl2ps-renderer.h \ interpfcn/graphics-props.cc \ - gripes.h \ - ls-ascii-helper.h \ - ls-hdf5.h \ - ls-mat-ascii.h \ - ls-mat4.h \ - ls-mat5.h \ - ls-oct-binary.h \ - ls-utils.h \ - mex.h \ - mexproto.h \ - oct-errno.h \ - oct-fstrm.h \ - oct-gperf.h \ - oct-hdf5.h \ - oct-iostrm.h \ - oct-lvalue.h \ - oct-map.h \ - oct-obj.h \ - oct-prcstrm.h \ - oct-procbuf.h \ - oct-stdstrm.h \ - oct-stream.h \ - oct-strstrm.h \ - oct.h \ + parse-tree/oct-gperf.h \ + builtins.h \ octave.h \ - ops.h \ - procstream.h \ - siglist.h \ - sparse-xdiv.h \ - sparse-xpow.h \ - token.h \ - txt-eng-ft.h \ - txt-eng.h \ - unwind-prot.h \ - xdiv.h \ - xnorm.h \ - xpow.h \ - zfstream.h \ $(OV_INCLUDES) \ $(OV_SPARSE_INCLUDES) \ $(PT_INCLUDES) \ - $(INTERPFCN_INCLUDES) \ - $(JIT_INCLUDES) + $(OPERATOR_INCLUDES) \ + $(INTERP_CORE_INCLUDES) \ + $(INTERPFCN_INCLUDES) nodist_octinclude_HEADERS = \ + interp-core/mxarray.h \ interpfcn/defaults.h \ interpfcn/graphics.h \ oct-conf.h \ - mxarray.h \ version.h -JIT_SRC = \ - jit-util.cc \ - jit-typeinfo.cc \ - jit-ir.cc \ - pt-jit.cc - DIST_SRC = \ - Cell.cc \ - c-file-ptr-stream.cc \ - comment-list.cc \ - cutils.c \ - display.cc \ - dynamic-ld.cc \ - gl-render.cc \ - gl2ps-renderer.cc \ - gripes.cc \ - ls-ascii-helper.cc \ - ls-hdf5.cc \ - ls-mat-ascii.cc \ - ls-mat4.cc \ - ls-mat5.cc \ - ls-oct-binary.cc \ - ls-utils.cc \ - matherr.c \ - mex.cc \ - oct-fstrm.cc \ - oct-iostrm.cc \ - oct-lvalue.cc \ - oct-map.cc \ - oct-obj.cc \ - oct-prcstrm.cc \ - oct-procbuf.cc \ - oct-stream.cc \ - oct-strstrm.cc \ octave.cc \ - procstream.cc \ - siglist.c \ - sparse-xdiv.cc \ - sparse-xpow.cc \ - token.cc \ - txt-eng-ft.cc \ - unwind-prot.cc \ - xdiv.cc \ - xgl2ps.c \ - xnorm.cc \ - xpow.cc \ - zfstream.cc \ $(OCTAVE_VALUE_SRC) \ $(PARSE_TREE_SRC) \ - $(JIT_SRC) \ + $(INTERP_CORE_SRC) \ $(INTERPFCN_SRC) \ $(COREFCN_SRC) @@ -254,6 +153,7 @@ include octave-value/module.mk include operators/module.mk include template-inst/module.mk +include interp-core/module.mk include interpfcn/module.mk include corefcn/module.mk include dldfcn/module.mk @@ -277,13 +177,13 @@ $(TEMPLATE_INST_SRC) nodist_liboctinterp_la_SOURCES = \ - builtins.cc \ + interp-core/mxarray.h \ + interp-core/oct-errno.cc \ interpfcn/defaults.h \ interpfcn/graphics.h \ - mxarray.h \ + operators/ops.cc \ + builtins.cc \ oct-conf.h \ - oct-errno.cc \ - ops.cc \ version.h \ $(OPT_INC) @@ -309,8 +209,6 @@ -bindir $(bindir) \ $(LIBOCTINTERP_LINK_OPTS) -display.df display.lo: CPPFLAGS += $(X11_FLAGS) - ## FIXME: Does this rule need to be uncommented? #fft.df fft.lo fft2.df fft2.lo fftn.df fftn.lo: CPPFLAGS += $(FFTW_XCPPFLAGS) @@ -358,27 +256,12 @@ ## Special rules: ## Mostly for sources which must be built before rest of compilation. -## defaults.h and oct-conf.h must depend on Makefile. Calling configure +## oct-conf.h must depend on Makefile. Calling configure ## may change default/config values. However, calling configure will also ## regenerate the Makefiles from Makefile.am and trigger the rules below. oct-conf.h: oct-conf.in.h Makefile @$(do_subst_config_vals) -## Don't use a pipeline to process gperf output since if gperf -## is missing but sed is not, the exit status of the pipeline -## will still be success and we will end up creating an empty -## oct-gperf.h file. -oct-gperf.h: octave.gperf - $(GPERF) -t -C -D -G -L C++ -Z octave_kw_hash $< > $@-t1 - $(SED) 's,lookup\[,gperf_lookup[,' < $@-t1 > $@-t - mv $@-t $@ - rm -f $@-t1 - -mxarray.h: mxarray.in.h Makefile - $(SED) < $< \ - -e "s|%OCTAVE_IDX_TYPE%|${OCTAVE_IDX_TYPE}|" > $@-t - mv $@-t $@ - version.h: version.in.h Makefile $(SED) < $< \ -e "s|%OCTAVE_API_VERSION_NUMBER%|${OCTAVE_API_VERSION_NUMBER}|" \ @@ -392,20 +275,6 @@ $(srcdir)/mkbuiltins $(DEF_FILES) > $@-t mv $@-t $@ -ops.cc: $(OPERATORS_SRC) mkops - $(srcdir)/mkops $(OPERATORS_SRC) > $@-t - mv $@-t $@ - -oct-errno.cc: oct-errno.in.cc Makefile - if test -n "$(PERL)"; then \ - $(srcdir)/mk-errno-list --perl "$(PERL)" < $< > $@-t; \ - elif test -n "$(PYTHON)"; then \ - $(srcdir)/mk-errno-list --python "$(PYTHON)" < $< > $@-t; \ - else \ - $(SED) '/@SYSDEP_ERRNO_LIST@/D' $< > $@-t; \ - fi - mv $@-t $@ - if AMCOND_ENABLE_DYNAMIC_LINKING DLDFCN_PKG_ADD_FILE = dldfcn/PKG_ADD @@ -414,12 +283,6 @@ mv $@-t $@ endif -__fltk_uigetfile__.lo __fltk_uigetfile__.o: \ - AM_CXXFLAGS := $(filter-out $(DLL_CXXDEFS), $(AM_CXXFLAGS) $(GRAPHICS_CFLAGS)) - -__init_fltk__.lo __init_fltk__.o: \ - AM_CXXFLAGS := $(filter-out $(DLL_CXXDEFS), $(AM_CXXFLAGS) $(GRAPHICS_CFLAGS)) - if AMCOND_BUILD_DOCS .DOCSTRINGS: $(ALL_DEF_FILES) gendoc.pl if [ "x$(srcdir)" != "x." ] && [ -f $(srcdir)/DOCSTRINGS ] && [ ! -f DOCSTRINGS ]; then \ diff -r a132d206a36a -r b9b6a310ad97 src/c-file-ptr-stream.cc --- a/src/c-file-ptr-stream.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,362 +0,0 @@ -/* - -Copyright (C) 2000-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "c-file-ptr-stream.h" - -#ifndef SEEK_SET -#define SEEK_SET 0 -#endif - -#ifndef SEEK_CUR -#define SEEK_CUR 1 -#endif - -#ifndef SEEK_END -#define SEEK_END 2 -#endif - -c_file_ptr_buf::~c_file_ptr_buf (void) -{ - buf_close (); -} - -// FIXME -- I'm sure there is room for improvement here... - -c_file_ptr_buf::int_type -c_file_ptr_buf::overflow (int_type c) -{ -#if defined (CXX_ISO_COMPLIANT_LIBRARY) - if (f) - return (c != traits_type::eof ()) ? gnulib::fputc (c, f) : flush (); - else - return traits_type::not_eof (c); -#else - if (f) - return (c != EOF) ? gnulib::fputc (c, f) : flush (); - else - return EOF; -#endif -} - -c_file_ptr_buf::int_type -c_file_ptr_buf::underflow_common (bool bump) -{ - if (f) - { - int_type c = gnulib::fgetc (f); - - if (! bump -#if defined (CXX_ISO_COMPLIANT_LIBRARY) - && c != traits_type::eof ()) -#else - && c != EOF) -#endif - ungetc (c, f); - - return c; - } - else -#if defined (CXX_ISO_COMPLIANT_LIBRARY) - return traits_type::eof (); -#else - return EOF; -#endif -} - -c_file_ptr_buf::int_type -c_file_ptr_buf::pbackfail (int_type c) -{ -#if defined (CXX_ISO_COMPLIANT_LIBRARY) - return (c != traits_type::eof () && f) ? ungetc (c, f) : - traits_type::not_eof (c); -#else - return (c != EOF && f) ? ungetc (c, f) : EOF; -#endif -} - -std::streamsize -c_file_ptr_buf::xsputn (const char* s, std::streamsize n) -{ - if (f) - return gnulib::fwrite (s, 1, n, f); - else - return 0; -} - -std::streamsize -c_file_ptr_buf::xsgetn (char *s, std::streamsize n) -{ - if (f) - return gnulib::fread (s, 1, n, f); - else - return 0; -} - -static inline int -seekdir_to_whence (std::ios::seekdir dir) -{ - return ((dir == std::ios::beg) ? SEEK_SET : - (dir == std::ios::cur) ? SEEK_CUR : - (dir == std::ios::end) ? SEEK_END : - dir); -} - -std::streampos -c_file_ptr_buf::seekoff (std::streamoff /* offset */, - std::ios::seekdir /* dir */, - std::ios::openmode) -{ - // FIXME -#if 0 - if (f) - { - fseek (f, offset, seekdir_to_whence (dir)); - - return ftell (f); - } - else - return 0; -#endif - return -1; -} - -std::streampos -c_file_ptr_buf::seekpos (std::streampos /* offset */, std::ios::openmode) -{ - // FIXME -#if 0 - if (f) - { - fseek (f, offset, SEEK_SET); - - return ftell (f); - } - else - return 0; -#endif - return -1; -} - -int -c_file_ptr_buf::sync (void) -{ - flush (); - - return 0; -} - -int -c_file_ptr_buf::flush (void) -{ - return f ? gnulib::fflush (f) : EOF; -} - -int -c_file_ptr_buf::buf_close (void) -{ - int retval = -1; - - flush (); - - if (f) - { - retval = cf (f); - f = 0; - } - - return retval; -} - -int -c_file_ptr_buf::seek (long offset, int origin) -{ - return f ? gnulib::fseek (f, offset, origin) : -1; -} - -long -c_file_ptr_buf::tell (void) -{ - return f ? gnulib::ftell (f) : -1; -} - -int -c_file_ptr_buf::file_close (FILE *f) -{ - return gnulib::fclose (f); -} - -#ifdef HAVE_ZLIB - -c_zfile_ptr_buf::~c_zfile_ptr_buf (void) -{ - buf_close (); -} - -// FIXME -- I'm sure there is room for improvement here... - -c_zfile_ptr_buf::int_type -c_zfile_ptr_buf::overflow (int_type c) -{ -#if defined (CXX_ISO_COMPLIANT_LIBRARY) - if (f) - return (c != traits_type::eof ()) ? gzputc (f, c) : flush (); - else - return traits_type::not_eof (c); -#else - if (f) - return (c != EOF) ? gzputc (f, c) : flush (); - else - return EOF; -#endif -} - -c_zfile_ptr_buf::int_type -c_zfile_ptr_buf::underflow_common (bool bump) -{ - if (f) - { - int_type c = gzgetc (f); - - if (! bump -#if defined (CXX_ISO_COMPLIANT_LIBRARY) - && c != traits_type::eof ()) -#else - && c != EOF) -#endif - gzungetc (c, f); - - return c; - } - else -#if defined (CXX_ISO_COMPLIANT_LIBRARY) - return traits_type::eof (); -#else - return EOF; -#endif -} - -c_zfile_ptr_buf::int_type -c_zfile_ptr_buf::pbackfail (int_type c) -{ -#if defined (CXX_ISO_COMPLIANT_LIBRARY) - return (c != traits_type::eof () && f) ? gzungetc (c, f) : - traits_type::not_eof (c); -#else - return (c != EOF && f) ? gzungetc (c, f) : EOF; -#endif -} - -std::streamsize -c_zfile_ptr_buf::xsputn (const char* s, std::streamsize n) -{ - if (f) - return gzwrite (f, s, n); - else - return 0; -} - -std::streamsize -c_zfile_ptr_buf::xsgetn (char *s, std::streamsize n) -{ - if (f) - return gzread (f, s, n); - else - return 0; -} - -std::streampos -c_zfile_ptr_buf::seekoff (std::streamoff /* offset */, - std::ios::seekdir /* dir */, - std::ios::openmode) -{ - // FIXME -#if 0 - if (f) - { - gzseek (f, offset, seekdir_to_whence (dir)); - - return gztell (f); - } - else - return 0; -#endif - return -1; -} - -std::streampos -c_zfile_ptr_buf::seekpos (std::streampos /* offset */, std::ios::openmode) -{ - // FIXME -#if 0 - if (f) - { - gzseek (f, offset, SEEK_SET); - - return gztell (f); - } - else - return 0; -#endif - return -1; -} - -int -c_zfile_ptr_buf::sync (void) -{ - flush (); - - return 0; -} - -int -c_zfile_ptr_buf::flush (void) -{ - // FIXME -- do we need something more complex here, passing - // something other than 0 for the second argument to gzflush and - // checking the return value, etc.? - - return f ? gzflush (f, 0) : EOF; -} - -int -c_zfile_ptr_buf::buf_close (void) -{ - int retval = -1; - - flush (); - - if (f) - { - retval = cf (f); - f = 0; - } - - return retval; -} - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/c-file-ptr-stream.h --- a/src/c-file-ptr-stream.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,227 +0,0 @@ -/* - -Copyright (C) 2000-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_c_file_ptr_stream_h) -#define octave_c_file_ptr_stream_h 1 - -#include - -#include - -class -c_file_ptr_buf : public std::streambuf -{ -public: - -#if !defined (CXX_ISO_COMPLIANT_LIBRARY) - typedef int int_type; -#else - typedef std::streambuf::int_type int_type; -#endif - - typedef int (*close_fcn) (FILE *); - - FILE* stdiofile (void) { return f; } - - c_file_ptr_buf (FILE *f_arg, close_fcn cf_arg = file_close) - : std::streambuf (), f (f_arg), cf (cf_arg) - { } - - ~c_file_ptr_buf (void); - - int_type overflow (int_type); - - int_type underflow (void) { return underflow_common (false); } - - int_type uflow (void) { return underflow_common (true); } - - int_type pbackfail (int_type); - - std::streamsize xsputn (const char*, std::streamsize); - - std::streamsize xsgetn (char *, std::streamsize); - - std::streampos seekoff (std::streamoff, std::ios::seekdir, - std::ios::openmode = std::ios::in | std::ios::out); - - std::streampos seekpos (std::streampos, - std::ios::openmode = std::ios::in | std::ios::out); - - int sync (void); - - int flush (void); - - int buf_close (void); - - int file_number () const { return f ? fileno (f) : -1; } - - int seek (long offset, int origin); - - long tell (void); - - void clear (void) { if (f) clearerr (f); } - - static int file_close (FILE *f); - -protected: - - FILE *f; - - close_fcn cf; - -private: - - int_type underflow_common (bool); - - // No copying! - - c_file_ptr_buf (const c_file_ptr_buf&); - - c_file_ptr_buf& operator = (const c_file_ptr_buf&); -}; - -// FIXME -- the following three classes could probably share -// some code... - -template -class -c_file_ptr_stream : public STREAM_T -{ -public: - - c_file_ptr_stream (FILE_T f, typename BUF_T::close_fcn cf = BUF_T::file_close) - : STREAM_T (0), buf (new BUF_T (f, cf)) { STREAM_T::init (buf); } - - ~c_file_ptr_stream (void) { delete buf; buf = 0; } - - BUF_T *rdbuf (void) { return buf; } - - void stream_close (void) { if (buf) buf->buf_close (); } - - int seek (long offset, int origin) - { return buf ? buf->seek (offset, origin) : -1; } - - long tell (void) { return buf ? buf->tell () : -1; } - - void clear (void) { if (buf) buf->clear (); STREAM_T::clear (); } - -private: - - BUF_T *buf; - - // No copying! - - c_file_ptr_stream (const c_file_ptr_stream&); - - c_file_ptr_stream& operator = (const c_file_ptr_stream&); -}; - -typedef c_file_ptr_stream i_c_file_ptr_stream; -typedef c_file_ptr_stream o_c_file_ptr_stream; -typedef c_file_ptr_stream io_c_file_ptr_stream; - -#ifdef HAVE_ZLIB - -#ifdef HAVE_ZLIB_H -#include -#endif - -class -c_zfile_ptr_buf : public std::streambuf -{ -public: - -#if !defined (CXX_ISO_COMPLIANT_LIBRARY) - typedef int int_type; -#else - typedef std::streambuf::int_type int_type; -#endif - - typedef int (*close_fcn) (gzFile); - - gzFile stdiofile (void) { return f; } - - c_zfile_ptr_buf (gzFile f_arg, close_fcn cf_arg = file_close) - : std::streambuf (), f (f_arg), cf (cf_arg) - { } - - ~c_zfile_ptr_buf (void); - - int_type overflow (int_type); - - int_type underflow (void) { return underflow_common (false); } - - int_type uflow (void) { return underflow_common (true); } - - int_type pbackfail (int_type); - - std::streamsize xsputn (const char*, std::streamsize); - - std::streamsize xsgetn (char *, std::streamsize); - - std::streampos seekoff (std::streamoff, std::ios::seekdir, - std::ios::openmode = std::ios::in | std::ios::out); - - std::streampos seekpos (std::streampos, - std::ios::openmode = std::ios::in | std::ios::out); - - int sync (void); - - int flush (void); - - int buf_close (void); - - int file_number () const { return -1; } - - int seek (long offset, int origin) - { return f ? gzseek (f, offset, origin) : -1; } - - long tell (void) { return f ? gztell (f) : -1; } - - void clear (void) { if (f) gzclearerr (f); } - - static int file_close (gzFile f) { return ::gzclose (f); } - -protected: - - gzFile f; - - close_fcn cf; - -private: - - int_type underflow_common (bool); - - // No copying! - - c_zfile_ptr_buf (const c_zfile_ptr_buf&); - - c_zfile_ptr_buf& operator = (const c_zfile_ptr_buf&); -}; - -typedef c_file_ptr_stream i_c_zfile_ptr_stream; -typedef c_file_ptr_stream o_c_zfile_ptr_stream; -typedef c_file_ptr_stream io_c_zfile_ptr_stream; - -#endif - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/comment-list.cc --- a/src/comment-list.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/* - -Copyright (C) 2000-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "lo-utils.h" -#include "singleton-cleanup.h" - -#include "comment-list.h" -#include "error.h" - -octave_comment_buffer *octave_comment_buffer::instance = 0; - -octave_comment_list * -octave_comment_list::dup (void) const -{ - octave_comment_list *new_cl = new octave_comment_list (); - - for (const_iterator p = begin (); p != end (); p++) - { - const octave_comment_elt elt = *p; - - new_cl->append (elt); - } - - return new_cl; -} - -bool -octave_comment_buffer::instance_ok (void) -{ - bool retval = true; - - if (! instance) - { - instance = new octave_comment_buffer (); - - if (instance) - singleton_cleanup_list::add (cleanup_instance); - } - - if (! instance) - { - ::error ("unable to create comment buffer object"); - - retval = false; - } - - return retval; -} - -void -octave_comment_buffer::append (const std::string& s, - octave_comment_elt::comment_type t) -{ - if (instance_ok ()) - instance->do_append (s, t); -} - -octave_comment_list * -octave_comment_buffer::get_comment (void) -{ - return (instance_ok ()) ? instance->do_get_comment () : 0; -} - -void -octave_comment_buffer::do_append (const std::string& s, - octave_comment_elt::comment_type t) -{ - comment_list->append (s, t); -} - -octave_comment_list * -octave_comment_buffer::do_get_comment (void) -{ - octave_comment_list *retval = 0; - - if (comment_list && comment_list->length () > 0) - { - retval = comment_list; - comment_list = new octave_comment_list (); - } - - return retval; -} diff -r a132d206a36a -r b9b6a310ad97 src/comment-list.h --- a/src/comment-list.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -/* - -Copyright (C) 2000-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_comment_list_h) -#define octave_comment_list_h 1 - -#include - -#include - -extern std::string get_comment_text (void); - -extern char *get_comment_text_c_str (void); - -extern void save_comment_text (const std::string& text); - -class -octave_comment_elt -{ -public: - - enum comment_type - { - unknown, - block, - end_of_line, - doc_string, - copyright - }; - - octave_comment_elt (const std::string& s = std::string (), - comment_type t = unknown) - : txt (s), typ (t) { } - - octave_comment_elt (const octave_comment_elt& oc) - : txt (oc.txt), typ (oc.typ) { } - - octave_comment_elt& operator = (const octave_comment_elt& oc) - { - if (this != &oc) - { - txt = oc.txt; - typ = oc.typ; - } - - return *this; - } - - std::string text (void) const { return txt; } - - comment_type type (void) const { return typ; } - - ~octave_comment_elt (void) { } - -private: - - // The text of the comment. - std::string txt; - - // The type of comment. - comment_type typ; -}; - -class -octave_comment_list : public octave_base_list -{ -public: - - octave_comment_list (void) { } - - void append (const octave_comment_elt& elt) - { octave_base_list::append (elt); } - - void append (const std::string& s, - octave_comment_elt::comment_type t = octave_comment_elt::unknown) - { append (octave_comment_elt (s, t)); } - - octave_comment_list *dup (void) const; -}; - -class -octave_comment_buffer -{ -public: - - octave_comment_buffer (void) - : comment_list (new octave_comment_list ()) { } - - ~octave_comment_buffer (void) { delete comment_list; } - - static bool instance_ok (void); - - static void append - (const std::string& s, - octave_comment_elt::comment_type t = octave_comment_elt::unknown); - - static octave_comment_list *get_comment (void); - -private: - - void do_append (const std::string& s, octave_comment_elt::comment_type t); - - octave_comment_list *do_get_comment (void); - - octave_comment_list *comment_list; - - static octave_comment_buffer *instance; - - static void cleanup_instance (void) { delete instance; instance = 0; } -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/cutils.c --- a/src/cutils.c Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,60 +0,0 @@ -/* - -Copyright (C) 1999-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include -#include - -#include "cutils.h" - -void -octave_sleep (unsigned int seconds) -{ - sleep (seconds); -} - -void -octave_usleep (unsigned int useconds) -{ - struct timespec delay; - struct timespec remaining; - - unsigned int sec = useconds / 1000000; - unsigned int usec = useconds % 1000000; - - delay.tv_sec = sec; - delay.tv_nsec = usec * 1000; - - nanosleep (&delay, &remaining); -} - -int -octave_raw_vsnprintf (char *buf, size_t n, const char *fmt, va_list args) -{ - return vsnprintf (buf, n, fmt, args); -} diff -r a132d206a36a -r b9b6a310ad97 src/cutils.h --- a/src/cutils.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/* - -Copyright (C) 2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_cutils_h) -#define octave_cutils_h 1 - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -OCTINTERP_API void octave_sleep (unsigned int seconds); - -OCTINTERP_API void octave_usleep (unsigned int useconds); - -OCTINTERP_API int -octave_raw_vsnprintf (char *buf, size_t n, const char *fmt, va_list args); - -#ifdef __cplusplus -} -#endif - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/defun-dld.h --- a/src/defun-dld.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - -Copyright (C) 1994-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_defun_dld_h) -#define octave_defun_dld_h 1 - -#if defined (octave_defun_h) -#error defun.h and defun-dld.h both included in same file! -#endif - -#include "defun-int.h" - -// Define a builtin function that may be loaded dynamically at run -// time. -// -// If Octave is not configured for dynamic linking of builtin -// functions, this is the same as DEFUN, except that it will generate -// an extra externally visible function. -// -// The first DECLARE_FUN is for the benefit of the installer function -// and the second is for the definition of the function. - -#if defined (MAKE_BUILTINS) - -#define DEFUN_DLD(name, args_name, nargout_name, doc) \ - DEFUN_DLD_INTERNAL (name, args_name, nargout_name, doc) - -// This one can be used when `name' cannot be used directly (if it is -// already defined as a macro). In that case, name is already a -// quoted string, and the internal name of the function must be passed -// too (the convention is to use a prefix of "F", so "foo" becomes -// "Ffoo") as well as the name of the generated installer function -// (the convention is to use a prefix of "G", so "foo" becomes "Gfoo"). - -#define DEFUNX_DLD(name, fname, gname, args_name, nargout_name, doc) \ - DEFUNX_DLD_INTERNAL (name, fname, args_name, nargout_name, doc) - -#else - -#define DEFUN_DLD(name, args_name, nargout_name, doc) \ - DECLARE_FUN (name, args_name, nargout_name); \ - DEFINE_FUN_INSTALLER_FUN (name, doc) \ - DECLARE_FUN (name, args_name, nargout_name) - -#define DEFUNX_DLD(name, fname, gname, args_name, nargout_name, doc) \ - DECLARE_FUNX (fname, args_name, nargout_name); \ - DEFINE_FUNX_INSTALLER_FUN (name, fname, gname, doc) \ - DECLARE_FUNX (fname, args_name, nargout_name) - -#endif - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/defun-int.h --- a/src/defun-int.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,187 +0,0 @@ -/* - -Copyright (C) 1994-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_defun_int_h) -#define octave_defun_int_h 1 - -#include - -#include "ov-builtin.h" -#include "ov-dld-fcn.h" -#include "symtab.h" -#include "version.h" - -class octave_value; - -extern OCTINTERP_API void print_usage (void); -extern OCTINTERP_API void print_usage (const std::string&); - -extern OCTINTERP_API void check_version (const std::string& version, const std::string& fcn); - -extern OCTINTERP_API void -install_builtin_function (octave_builtin::fcn f, const std::string& name, - const std::string& file, const std::string& doc, - bool can_hide_function = true); - -extern OCTINTERP_API void -install_dld_function (octave_dld_function::fcn f, const std::string& name, - const octave_shlib& shl, const std::string& doc, - bool relative = false); - -extern OCTINTERP_API void -install_mex_function (void *fptr, bool fmex, const std::string& name, - const octave_shlib& shl, bool relative = false); - -extern OCTINTERP_API void -alias_builtin (const std::string& alias, const std::string& name); - -// Gets the shlib of the currently executing DLD function, if any. -extern OCTINTERP_API octave_shlib -get_current_shlib (void); - -// This is a convenience class that calls the above function automatically at -// construction time. When deriving new classes, you can either use it as a field -// or as a parent (with multiple inheritance). - -class octave_auto_shlib : public octave_shlib -{ -public: - octave_auto_shlib (void) - : octave_shlib (get_current_shlib ()) { } - octave_auto_shlib (const octave_shlib& shl) - : octave_shlib (shl) { } -}; - -extern OCTINTERP_API bool -defun_isargout (int, int); - -extern OCTINTERP_API void -defun_isargout (int, int, bool *); - -#define DECLARE_FUNX(name, args_name, nargout_name) \ - OCTAVE_EXPORT octave_value_list \ - name (const octave_value_list& args_name, int nargout_name) - -#define DECLARE_FUN(name, args_name, nargout_name) \ - DECLARE_FUNX (F ## name, args_name, nargout_name) - -// Define the code that will be used to insert the new function into -// the symbol table. We look for this name instead of the actual -// function so that we can easily install the doc std::string too. - -typedef bool (*octave_dld_fcn_installer) (const octave_shlib&, bool relative); - -typedef octave_function * (*octave_dld_fcn_getter) (const octave_shlib&, bool relative); - -#define DEFINE_FUN_INSTALLER_FUN(name, doc) \ - DEFINE_FUNX_INSTALLER_FUN(#name, F ## name, G ## name, doc) - -#define DEFINE_FUNX_INSTALLER_FUN(name, fname, gname, doc) \ - extern "C" \ - OCTAVE_EXPORT \ - octave_function * \ - gname (const octave_shlib& shl, bool relative) \ - { \ - octave_function *retval = 0; \ - \ - check_version (OCTAVE_API_VERSION, name); \ - \ - if (! error_state) \ - { \ - octave_dld_function *fcn = octave_dld_function::create (fname, shl, name, doc); \ - \ - if (relative) \ - fcn->mark_relative (); \ - \ - retval = fcn; \ - } \ - \ - return retval; \ - } - -// MAKE_BUILTINS is defined to extract function names and related -// information and create the *.df files that are eventually used to -// create the builtins.cc file. - -#if defined (MAKE_BUILTINS) - -// Generate code to install name in the symbol table. The script -// mkdefs will create a .def file for every .cc file that uses DEFUN, -// or DEFCMD. - -#define DEFUN_INTERNAL(name, args_name, nargout_name, doc) \ - BEGIN_INSTALL_BUILTIN \ - XDEFUN_INTERNAL (name, args_name, nargout_name, doc) \ - END_INSTALL_BUILTIN - -#define DEFCONSTFUN_INTERNAL(name, args_name, nargout_name, doc) \ - BEGIN_INSTALL_BUILTIN \ - XDEFCONSTFUN_INTERNAL (name, args_name, nargout_name, doc) \ - END_INSTALL_BUILTIN - -#define DEFUNX_INTERNAL(name, fname, args_name, nargout_name, doc) \ - BEGIN_INSTALL_BUILTIN \ - XDEFUNX_INTERNAL (name, fname, args_name, nargout_name, doc) \ - END_INSTALL_BUILTIN - -// Generate code to install name in the symbol table. The script -// mkdefs will create a .def file for every .cc file that uses -// DEFUN_DLD. - -#define DEFUN_DLD_INTERNAL(name, args_name, nargout_name, doc) \ - BEGIN_INSTALL_BUILTIN \ - XDEFUN_DLD_INTERNAL (name, args_name, nargout_name, doc) \ - END_INSTALL_BUILTIN - -#define DEFUNX_DLD_INTERNAL(name, fname, args_name, nargout_name, doc) \ - BEGIN_INSTALL_BUILTIN \ - XDEFUNX_DLD_INTERNAL (name, fname, args_name, nargout_name, doc) \ - END_INSTALL_BUILTIN - -// Generate code for making another name for an existing function. - -#define DEFALIAS_INTERNAL(alias, name) \ - BEGIN_INSTALL_BUILTIN \ - XDEFALIAS_INTERNAL(alias, name) \ - END_INSTALL_BUILTIN - -#else /* ! MAKE_BUILTINS */ - -// Generate the first line of the function definition. This ensures -// that the internal functions all have the same signature. - -#define DEFUN_INTERNAL(name, args_name, nargout_name, doc) \ - DECLARE_FUN (name, args_name, nargout_name) - -#define DEFCONSTFUN_INTERNAL(name, args_name, nargout_name, doc) \ - DECLARE_FUN (name, args_name, nargout_name) - -#define DEFUNX_INTERNAL(name, fname, args_name, nargout_name, doc) \ - DECLARE_FUNX (fname, args_name, nargout_name) - -// No definition is required for an alias. - -#define DEFALIAS_INTERNAL(alias, name) - -#endif /* ! MAKE_BUILTINS */ - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/display.cc --- a/src/display.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,182 +0,0 @@ -/* - -Copyright (C) 2009-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#if defined (OCTAVE_USE_WINDOWS_API) -#include -#elif defined (HAVE_FRAMEWORK_CARBON) -#include -#elif defined (HAVE_X_WINDOWS) -#include -#endif - -#include "singleton-cleanup.h" - -#include "display.h" -#include "error.h" - -display_info *display_info::instance = 0; - -#if defined (HAVE_FRAMEWORK_CARBON) && ! defined (HAVE_CARBON_CGDISPLAYBITSPERPIXEL) -// FIXME - This will only work for MacOS > 10.5. For earlier versions -// this code is not needed (use CGDisplayBitsPerPixel instead). -size_t DisplayBitsPerPixel (CGDirectDisplayID display) -{ - CGDisplayModeRef mode = CGDisplayCopyDisplayMode (display); - CFStringRef pixelEncoding = CGDisplayModeCopyPixelEncoding (mode); - - if (CFStringCompare (pixelEncoding, CFSTR (IO32BitDirectPixels), 0) == 0) - return 32; - else if (CFStringCompare (pixelEncoding, CFSTR (IO16BitDirectPixels), 0) == 0) - return 16; - else - return 8; -} -#endif - -void -display_info::init (bool query) -{ - if (query) - { -#if defined (OCTAVE_USE_WINDOWS_API) - - HDC hdc = GetDC (0); - - if (hdc) - { - dp = GetDeviceCaps (hdc, BITSPIXEL); - - ht = GetDeviceCaps (hdc, VERTRES); - wd = GetDeviceCaps (hdc, HORZRES); - - double ht_mm = GetDeviceCaps (hdc, VERTSIZE); - double wd_mm = GetDeviceCaps (hdc, HORZSIZE); - - rx = wd * 25.4 / wd_mm; - ry = ht * 25.4 / ht_mm; - } - else - warning ("no graphical display found"); - -#elif defined (HAVE_FRAMEWORK_CARBON) - - CGDirectDisplayID display = CGMainDisplayID (); - - if (display) - { -# if defined (HAVE_CARBON_CGDISPLAYBITSPERPIXEL) - // For MacOS < 10.7 use the line below - dp = CGDisplayBitsPerPixel (display); -# else - // For MacOS > 10.5 use the line below - dp = DisplayBitsPerPixel (display); -# endif - - ht = CGDisplayPixelsHigh (display); - wd = CGDisplayPixelsWide (display); - - CGSize sz_mm = CGDisplayScreenSize (display); - // For MacOS >= 10.6, CGSize is a struct keeping 2 CGFloat values, - // but the CGFloat typedef is not present on older systems, - // so use double instead. - double ht_mm = sz_mm.height; - double wd_mm = sz_mm.width; - - rx = wd * 25.4 / wd_mm; - ry = ht * 25.4 / ht_mm; - } - else - warning ("no graphical display found"); - -#elif defined (HAVE_X_WINDOWS) - - const char *display_name = getenv ("DISPLAY"); - - if (display_name && *display_name) - { - Display *display = XOpenDisplay (display_name); - - if (display) - { - Screen *screen = DefaultScreenOfDisplay (display); - - if (screen) - { - dp = DefaultDepthOfScreen (screen); - - ht = HeightOfScreen (screen); - wd = WidthOfScreen (screen); - - int screen_number = XScreenNumberOfScreen (screen); - - double ht_mm = DisplayHeightMM (display, screen_number); - double wd_mm = DisplayWidthMM (display, screen_number); - - rx = wd * 25.4 / wd_mm; - ry = ht * 25.4 / ht_mm; - } - else - warning ("X11 display has no default screen"); - - XCloseDisplay (display); - } - else - warning ("unable to open X11 DISPLAY"); - } - else - warning ("X11 DISPLAY environment variable not set"); -#else - - warning ("no graphical display found"); - -#endif - } -} - -bool -display_info::instance_ok (bool query) -{ - bool retval = true; - - if (! instance) - { - instance = new display_info (query); - - if (instance) - singleton_cleanup_list::add (cleanup_instance); - } - - if (! instance) - { - ::error ("unable to create display_info object!"); - - retval = false; - } - - return retval; -} diff -r a132d206a36a -r b9b6a310ad97 src/display.h --- a/src/display.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - -Copyright (C) 2009-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_display_h) -#define octave_display_h 1 - -class Matrix; - -class display_info -{ -protected: - - display_info (bool query = true) - : ht (1), wd (1), dp (0), rx (72), ry (72) - { - init (query); - } - -public: - - static int height (void) - { - return instance_ok () ? instance->do_height () : 0; - } - - static int width (void) - { - return instance_ok () ? instance->do_width () : 0; - } - - static int depth (void) - { - return instance_ok () ? instance->do_depth () : 0; - } - - static double x_dpi (void) - { - return instance_ok () ? instance->do_x_dpi () : 0; - } - - static double y_dpi (void) - { - return instance_ok () ? instance->do_y_dpi () : 0; - } - - // To disable querying the window system for defaults, this function - // must be called before any other display_info function. - static void no_window_system (void) - { - instance_ok (false); - } - -private: - - static display_info *instance; - - static void cleanup_instance (void) { delete instance; instance = 0; } - - // Height, width, and depth of the display. - int ht; - int wd; - int dp; - - // X- and Y- Resolution of the display in dots (pixels) per inch. - double rx; - double ry; - - int do_height (void) const { return ht; } - int do_width (void) const { return wd; } - int do_depth (void) const { return dp; } - - double do_x_dpi (void) const { return rx; } - double do_y_dpi (void) const { return ry; } - - void init (bool query = true); - - static bool instance_ok (bool query = true); -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/dynamic-ld.cc --- a/src/dynamic-ld.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,582 +0,0 @@ -/* - -Copyright (C) 1993-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "file-stat.h" -#include "oct-env.h" -#include "oct-time.h" -#include "singleton-cleanup.h" - -#include - -#include "defun.h" -#include "dynamic-ld.h" -#include "ov-fcn.h" -#include "ov-dld-fcn.h" -#include "ov-mex-fcn.h" -#include "parse.h" -#include "unwind-prot.h" -#include "utils.h" -#include "variables.h" - -#define STRINGIFY(s) STRINGIFY1(s) -#define STRINGIFY1(s) #s - -class -octave_shlib_list -{ -public: - - typedef std::list::iterator iterator; - typedef std::list::const_iterator const_iterator; - - static void append (const octave_shlib& shl); - - static void remove (octave_shlib& shl, octave_shlib::close_hook cl_hook = 0); - - static octave_shlib find_file (const std::string& file_name); - - static void display (void); - -private: - - octave_shlib_list (void) : lib_list () { } - - ~octave_shlib_list (void) { } - - void do_append (const octave_shlib& shl); - - void do_remove (octave_shlib& shl, octave_shlib::close_hook cl_hook = 0); - - octave_shlib do_find_file (const std::string& file_name) const; - - void do_display (void) const; - - static octave_shlib_list *instance; - - static void cleanup_instance (void) { delete instance; instance = 0; } - - static bool instance_ok (void); - - // List of libraries we have loaded. - std::list lib_list; - - // No copying! - - octave_shlib_list (const octave_shlib_list&); - - octave_shlib_list& operator = (const octave_shlib_list&); -}; - -octave_shlib_list *octave_shlib_list::instance = 0; - -void -octave_shlib_list::do_append (const octave_shlib& shl) -{ - lib_list.push_back (shl); -} - -void -octave_shlib_list::do_remove (octave_shlib& shl, - octave_shlib::close_hook cl_hook) -{ - for (iterator p = lib_list.begin (); p != lib_list.end (); p++) - { - if (*p == shl) - { - // Erase first to avoid potentially invalidating the pointer by the - // following hooks. - lib_list.erase (p); - - shl.close (cl_hook); - - break; - } - } -} - -octave_shlib -octave_shlib_list::do_find_file (const std::string& file_name) const -{ - octave_shlib retval; - - for (const_iterator p = lib_list.begin (); p != lib_list.end (); p++) - { - if (p->file_name () == file_name) - { - retval = *p; - break; - } - } - - return retval; -} - -void -octave_shlib_list::do_display (void) const -{ - std::cerr << "current shared libraries:" << std::endl; - for (const_iterator p = lib_list.begin (); p != lib_list.end (); p++) - std::cerr << " " << p->file_name () << std::endl; -} - -bool -octave_shlib_list::instance_ok (void) -{ - bool retval = true; - - if (! instance) - { - instance = new octave_shlib_list (); - - if (instance) - singleton_cleanup_list::add (cleanup_instance); - } - - if (! instance) - { - ::error ("unable to create shared library list object!"); - - retval = false; - } - - return retval; -} - -void -octave_shlib_list::append (const octave_shlib& shl) -{ - if (instance_ok ()) - instance->do_append (shl); -} - -void -octave_shlib_list::remove (octave_shlib& shl, - octave_shlib::close_hook cl_hook) -{ - if (instance_ok ()) - instance->do_remove (shl, cl_hook); -} - -octave_shlib -octave_shlib_list::find_file (const std::string& file_name) -{ - return (instance_ok ()) - ? instance->do_find_file (file_name) : octave_shlib (); -} - -void -octave_shlib_list::display (void) -{ - if (instance_ok ()) - instance->do_display (); -} - -class -octave_mex_file_list -{ -public: - - typedef std::list::iterator iterator; - typedef std::list::const_iterator const_iterator; - - static void append (const octave_shlib& shl); - - static void remove (octave_shlib& shl, octave_shlib::close_hook cl_hook = 0); - -private: - - octave_mex_file_list (void) : file_list () { } - - ~octave_mex_file_list (void) { } - - void do_append (const octave_shlib& shl); - - void do_remove (octave_shlib& shl, octave_shlib::close_hook cl_hook = 0); - - static octave_mex_file_list *instance; - - static void cleanup_instance (void) { delete instance; instance = 0; } - - static bool instance_ok (void); - - // List of libraries we have loaded. - std::list file_list; - - // No copying! - - octave_mex_file_list (const octave_mex_file_list&); - - octave_mex_file_list& operator = (const octave_mex_file_list&); -}; - -octave_mex_file_list *octave_mex_file_list::instance = 0; - -void -octave_mex_file_list::do_append (const octave_shlib& shl) -{ - file_list.push_back (shl); -} - -void -octave_mex_file_list::do_remove (octave_shlib& shl, - octave_shlib::close_hook cl_hook) -{ - for (iterator p = file_list.begin (); p != file_list.end (); p++) - { - if (*p == shl) - { - // Erase first to avoid potentially invalidating the pointer by the - // following hooks. - file_list.erase (p); - - shl.close (cl_hook); - - break; - } - } -} - -bool -octave_mex_file_list::instance_ok (void) -{ - bool retval = true; - - if (! instance) - { - instance = new octave_mex_file_list (); - - if (instance) - singleton_cleanup_list::add (cleanup_instance); - } - - if (! instance) - { - ::error ("unable to create shared library list object!"); - - retval = false; - } - - return retval; -} - -void -octave_mex_file_list::append (const octave_shlib& shl) -{ - if (instance_ok ()) - instance->do_append (shl); -} - -void -octave_mex_file_list::remove (octave_shlib& shl, - octave_shlib::close_hook cl_hook) -{ - if (instance_ok ()) - instance->do_remove (shl, cl_hook); -} - -octave_dynamic_loader *octave_dynamic_loader::instance = 0; - -bool octave_dynamic_loader::doing_load = false; - -bool -octave_dynamic_loader::instance_ok (void) -{ - bool retval = true; - - if (! instance) - { - instance = new octave_dynamic_loader (); - - if (instance) - singleton_cleanup_list::add (cleanup_instance); - } - - if (! instance) - { - ::error ("unable to create dynamic loader object!"); - - retval = false; - } - - return retval; -} - -static void -do_clear_function (const std::string& fcn_name) -{ - warning_with_id ("Octave:reload-forces-clear", " %s", fcn_name.c_str ()); - - symbol_table::clear_dld_function (fcn_name); -} - -static void -clear (octave_shlib& oct_file) -{ - if (oct_file.number_of_functions_loaded () > 1) - { - warning_with_id ("Octave:reload-forces-clear", - "reloading %s clears the following functions:", - oct_file.file_name ().c_str ()); - - octave_shlib_list::remove (oct_file, do_clear_function); - } - else - octave_shlib_list::remove (oct_file, symbol_table::clear_dld_function); -} - -octave_function * -octave_dynamic_loader::do_load_oct (const std::string& fcn_name, - const std::string& file_name, - bool relative) -{ - octave_function *retval = 0; - - unwind_protect frame; - - frame.protect_var (octave_dynamic_loader::doing_load); - - doing_load = true; - - octave_shlib oct_file = octave_shlib_list::find_file (file_name); - - if (oct_file && oct_file.is_out_of_date ()) - clear (oct_file); - - if (! oct_file) - { - oct_file.open (file_name); - - if (! error_state && oct_file) - octave_shlib_list::append (oct_file); - } - - if (! error_state) - { - if (oct_file) - { - void *function = oct_file.search (fcn_name, name_mangler); - - if (! function) - { - // FIXME -- can we determine this C mangling scheme - // automatically at run time or configure time? - - function = oct_file.search (fcn_name, name_uscore_mangler); - } - - if (function) - { - octave_dld_fcn_getter f - = FCN_PTR_CAST (octave_dld_fcn_getter, function); - - retval = f (oct_file, relative); - - if (! retval) - ::error ("failed to install .oct file function `%s'", - fcn_name.c_str ()); - } - } - else - ::error ("%s is not a valid shared library", - file_name.c_str ()); - } - - return retval; -} - -octave_function * -octave_dynamic_loader::do_load_mex (const std::string& fcn_name, - const std::string& file_name, - bool /*relative*/) -{ - octave_function *retval = 0; - - unwind_protect frame; - - frame.protect_var (octave_dynamic_loader::doing_load); - - doing_load = true; - - octave_shlib mex_file = octave_shlib_list::find_file (file_name); - - if (mex_file && mex_file.is_out_of_date ()) - clear (mex_file); - - if (! mex_file) - { - mex_file.open (file_name); - - if (! error_state && mex_file) - octave_shlib_list::append (mex_file); - } - - if (! error_state) - { - if (mex_file) - { - void *function = 0; - - bool have_fmex = false; - - octave_mex_file_list::append (mex_file); - - function = mex_file.search (fcn_name, mex_mangler); - - if (! function) - { - // FIXME -- can we determine this C mangling scheme - // automatically at run time or configure time? - - function = mex_file.search (fcn_name, mex_uscore_mangler); - - if (! function) - { - function = mex_file.search (fcn_name, mex_f77_mangler); - - if (function) - have_fmex = true; - } - } - - if (function) - retval = new octave_mex_function (function, have_fmex, - mex_file, fcn_name); - else - ::error ("failed to install .mex file function `%s'", - fcn_name.c_str ()); - } - else - ::error ("%s is not a valid shared library", - file_name.c_str ()); - } - - return retval; -} - -bool -octave_dynamic_loader::do_remove_oct (const std::string& fcn_name, - octave_shlib& shl) -{ - bool retval = false; - - // We don't need to do anything if this is called because we are in - // the process of reloading a .oct file that has changed. - - if (! doing_load) - { - retval = shl.remove (fcn_name); - - if (shl.number_of_functions_loaded () == 0) - octave_shlib_list::remove (shl); - } - - return retval; -} - -bool -octave_dynamic_loader::do_remove_mex (const std::string& fcn_name, - octave_shlib& shl) -{ - bool retval = false; - - // We don't need to do anything if this is called because we are in - // the process of reloading a .oct file that has changed. - - if (! doing_load) - { - retval = shl.remove (fcn_name); - - if (shl.number_of_functions_loaded () == 0) - octave_mex_file_list::remove (shl); - } - - return retval; -} - -octave_function * -octave_dynamic_loader::load_oct (const std::string& fcn_name, - const std::string& file_name, - bool relative) -{ - return (instance_ok ()) - ? instance->do_load_oct (fcn_name, file_name, relative) : 0; -} - -octave_function * -octave_dynamic_loader::load_mex (const std::string& fcn_name, - const std::string& file_name, - bool relative) -{ - return (instance_ok ()) - ? instance->do_load_mex (fcn_name, file_name, relative) : 0; -} - -bool -octave_dynamic_loader::remove_oct (const std::string& fcn_name, - octave_shlib& shl) -{ - return (instance_ok ()) ? instance->do_remove_oct (fcn_name, shl) : false; -} - -bool -octave_dynamic_loader::remove_mex (const std::string& fcn_name, - octave_shlib& shl) -{ - return (instance_ok ()) ? instance->do_remove_mex (fcn_name, shl) : false; -} - -std::string -octave_dynamic_loader::name_mangler (const std::string& name) -{ - return "G" + name; -} - -std::string -octave_dynamic_loader::name_uscore_mangler (const std::string& name) -{ - return "_G" + name; -} - -std::string -octave_dynamic_loader::mex_mangler (const std::string&) -{ - return "mexFunction"; -} - -std::string -octave_dynamic_loader::mex_uscore_mangler (const std::string&) -{ - return "_mexFunction"; -} - -std::string -octave_dynamic_loader::mex_f77_mangler (const std::string&) -{ - return STRINGIFY (F77_FUNC (mexfunction, MEXFUNCTION)); -} diff -r a132d206a36a -r b9b6a310ad97 src/dynamic-ld.h --- a/src/dynamic-ld.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,100 +0,0 @@ -/* - -Copyright (C) 1993-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_dynamic_ld_h) -#define octave_dynamic_ld_h 1 - -#include - -#include "oct-shlib.h" - -class octave_function; - -class -octave_dynamic_loader -{ -protected: - - octave_dynamic_loader (void) { } - -public: - - virtual ~octave_dynamic_loader (void) { } - - static octave_function * - load_oct (const std::string& fcn_name, - const std::string& file_name = std::string (), - bool relative = false); - - static octave_function * - load_mex (const std::string& fcn_name, - const std::string& file_name = std::string (), - bool relative = false); - - static bool remove_oct (const std::string& fcn_name, octave_shlib& shl); - - static bool remove_mex (const std::string& fcn_name, octave_shlib& shl); - -private: - - // No copying! - - octave_dynamic_loader (const octave_dynamic_loader&); - - octave_dynamic_loader& operator = (const octave_dynamic_loader&); - - static octave_dynamic_loader *instance; - - static void cleanup_instance (void) { delete instance; instance = 0; } - - static bool instance_ok (void); - - octave_function * - do_load_oct (const std::string& fcn_name, - const std::string& file_name = std::string (), - bool relative = false); - - octave_function * - do_load_mex (const std::string& fcn_name, - const std::string& file_name = std::string (), - bool relative = false); - - bool do_remove_oct (const std::string& fcn_name, octave_shlib& shl); - - bool do_remove_mex (const std::string& fcn_name, octave_shlib& shl); - - static bool doing_load; - -protected: - - static std::string name_mangler (const std::string& name); - - static std::string name_uscore_mangler (const std::string& name); - - static std::string mex_mangler (const std::string& name); - - static std::string mex_uscore_mangler (const std::string& name); - - static std::string mex_f77_mangler (const std::string& name); -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/gl-render.cc --- a/src/gl-render.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3039 +0,0 @@ -/* - -Copyright (C) 2008-2012 Michael Goffioul - -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 -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#if defined (HAVE_OPENGL) - -#include - -#include -#include "oct-locbuf.h" -#include "oct-refcount.h" -#include "gl-render.h" -#include "txt-eng.h" -#include "txt-eng-ft.h" - -#define LIGHT_MODE GL_FRONT_AND_BACK - -// Win32 API requires the CALLBACK attributes for -// GLU callback functions. Define it to empty on -// other platforms. -#ifndef CALLBACK -#define CALLBACK -#endif - -static octave_idx_type -xmin (octave_idx_type x, octave_idx_type y) -{ - return x < y ? x : y; -} - -class -opengl_texture -{ -protected: - class texture_rep - { - public: - texture_rep (void) - : id (), w (), h (), tw (), th (), tx (), ty (), - valid (false), count (1) - { } - - texture_rep (GLuint id_arg, int w_arg, int h_arg, int tw_arg, int th_arg) - : id (id_arg), w (w_arg), h (h_arg), tw (tw_arg), th (th_arg), - tx (double(w)/tw), ty (double(h)/th), valid (true), - count (1) { } - - ~texture_rep (void) - { - if (valid) - glDeleteTextures (1, &id); - } - - void bind (int mode) const - { if (valid) glBindTexture (mode, id); } - - void tex_coord (double q, double r) const - { if (valid) glTexCoord2d (q*tx, r*ty); } - - GLuint id; - int w, h; - int tw, th; - double tx, ty; - bool valid; - octave_refcount count; - }; - - texture_rep *rep; - -private: - opengl_texture (texture_rep *_rep) : rep (_rep) { } - -public: - opengl_texture (void) : rep (new texture_rep ()) { } - - opengl_texture (const opengl_texture& tx) - : rep (tx.rep) - { - rep->count++; - } - - ~opengl_texture (void) - { - if (--rep->count == 0) - delete rep; - } - - opengl_texture& operator = (const opengl_texture& tx) - { - if (--rep->count == 0) - delete rep; - - rep = tx.rep; - rep->count++; - - return *this; - } - - static opengl_texture create (const octave_value& data); - - void bind (int mode = GL_TEXTURE_2D) const - { rep->bind (mode); } - - void tex_coord (double q, double r) const - { rep->tex_coord (q, r); } - - bool is_valid (void) const - { return rep->valid; } -}; - -static int -next_power_of_2 (int n) -{ - int m = 1; - - while (m < n && m < INT_MAX) - m <<= 1; - - return m; -} - -opengl_texture -opengl_texture::create (const octave_value& data) -{ - opengl_texture retval; - - dim_vector dv (data.dims ()); - - // Expect RGB data - if (dv.length () == 3 && dv(2) == 3) - { - // FIXME -- dim_vectors hold octave_idx_type values. Should we - // check for dimensions larger than intmax? - int h = dv(0), w = dv(1), tw, th; - GLuint id; - bool ok = true; - - tw = next_power_of_2 (w); - th = next_power_of_2 (w); - - glGenTextures (1, &id); - glBindTexture (GL_TEXTURE_2D, id); - - if (data.is_double_type ()) - { - const NDArray xdata = data.array_value (); - - OCTAVE_LOCAL_BUFFER (float, a, (3*tw*th)); - - for (int i = 0; i < h; i++) - { - for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3) - { - a[idx] = xdata(i,j,0); - a[idx+1] = xdata(i,j,1); - a[idx+2] = xdata(i,j,2); - } - } - - glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0, - GL_RGB, GL_FLOAT, a); - } - else if (data.is_uint8_type ()) - { - const uint8NDArray xdata = data.uint8_array_value (); - - OCTAVE_LOCAL_BUFFER (octave_uint8, a, (3*tw*th)); - - for (int i = 0; i < h; i++) - { - for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3) - { - a[idx] = xdata(i,j,0); - a[idx+1] = xdata(i,j,1); - a[idx+2] = xdata(i,j,2); - } - } - - glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0, - GL_RGB, GL_UNSIGNED_BYTE, a); - } - else - { - ok = false; - warning ("opengl_texture::create: invalid texture data type (expected double or uint8)"); - } - - if (ok) - { - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - if (glGetError () != GL_NO_ERROR) - warning ("opengl_texture::create: OpenGL error while generating texture data"); - else - retval = opengl_texture (new texture_rep (id, w, h, tw, th)); - } - } - else - warning ("opengl_texture::create: invalid texture data size"); - - return retval; -} - -class -opengl_tesselator -{ -public: -#if defined (HAVE_FRAMEWORK_OPENGL) && defined (HAVE_GLUTESSCALLBACK_THREEDOTS) - typedef GLvoid (CALLBACK *fcn) (...); -#else - typedef void (CALLBACK *fcn) (void); -#endif - -public: - - opengl_tesselator (void) : glu_tess (0), fill () { init (); } - - virtual ~opengl_tesselator (void) - { if (glu_tess) gluDeleteTess (glu_tess); } - - void begin_polygon (bool filled = true) - { - gluTessProperty (glu_tess, GLU_TESS_BOUNDARY_ONLY, - (filled ? GL_FALSE : GL_TRUE)); - fill = filled; - gluTessBeginPolygon (glu_tess, this); - } - - void end_polygon (void) const - { gluTessEndPolygon (glu_tess); } - - void begin_contour (void) const - { gluTessBeginContour (glu_tess); } - - void end_contour (void) const - { gluTessEndContour (glu_tess); } - - void add_vertex (double *loc, void *data) const - { gluTessVertex (glu_tess, loc, data); } - -protected: - virtual void begin (GLenum /*type*/) { } - - virtual void end (void) { } - - virtual void vertex (void */*data*/) { } - - virtual void combine (GLdouble /*c*/[3], void */*data*/[4], - GLfloat /*w*/[4], void **/*out_data*/) { } - - virtual void edge_flag (GLboolean /*flag*/) { } - - virtual void error (GLenum err) - { ::error ("OpenGL tesselation error (%d)", err); } - - virtual void init (void) - { - glu_tess = gluNewTess (); - - gluTessCallback (glu_tess, GLU_TESS_BEGIN_DATA, - reinterpret_cast (tess_begin)); - gluTessCallback (glu_tess, GLU_TESS_END_DATA, - reinterpret_cast (tess_end)); - gluTessCallback (glu_tess, GLU_TESS_VERTEX_DATA, - reinterpret_cast (tess_vertex)); - gluTessCallback (glu_tess, GLU_TESS_COMBINE_DATA, - reinterpret_cast (tess_combine)); - gluTessCallback (glu_tess, GLU_TESS_EDGE_FLAG_DATA, - reinterpret_cast (tess_edge_flag)); - gluTessCallback (glu_tess, GLU_TESS_ERROR_DATA, - reinterpret_cast (tess_error)); - } - - bool is_filled (void) const { return fill; } - -private: - static void CALLBACK tess_begin (GLenum type, void *t) - { reinterpret_cast (t)->begin (type); } - - static void CALLBACK tess_end (void *t) - { reinterpret_cast (t)->end (); } - - static void CALLBACK tess_vertex (void *v, void *t) - { reinterpret_cast (t)->vertex (v); } - - static void CALLBACK tess_combine (GLdouble c[3], void *v[4], GLfloat w[4], - void **out, void *t) - { reinterpret_cast (t)->combine (c, v, w, out); } - - static void CALLBACK tess_edge_flag (GLboolean flag, void *t) - { reinterpret_cast (t)->edge_flag (flag); } - - static void CALLBACK tess_error (GLenum err, void *t) - { reinterpret_cast (t)->error (err); } - -private: - - // No copying! - - opengl_tesselator (const opengl_tesselator&); - - opengl_tesselator operator = (const opengl_tesselator&); - - GLUtesselator *glu_tess; - bool fill; -}; - -class -vertex_data -{ -public: - class vertex_data_rep - { - public: - Matrix coords; - Matrix color; - Matrix normal; - double alpha; - float ambient; - float diffuse; - float specular; - float specular_exp; - - // reference counter - octave_refcount count; - - vertex_data_rep (void) - : coords (), color (), normal (), alpha (), - ambient (), diffuse (), specular (), specular_exp (),count (1) { } - - vertex_data_rep (const Matrix& c, const Matrix& col, const Matrix& n, - double a, float as, float ds, float ss, float se) - : coords (c), color (col), normal (n), alpha (a), - ambient (as), diffuse (ds), specular (ss), specular_exp (se), - count (1) { } - }; - -private: - vertex_data_rep *rep; - - vertex_data_rep *nil_rep (void) const - { - static vertex_data_rep *nr = new vertex_data_rep (); - - return nr; - } - -public: - vertex_data (void) : rep (nil_rep ()) - { rep->count++; } - - vertex_data (const vertex_data& v) : rep (v.rep) - { rep->count++; } - - vertex_data (const Matrix& c, const Matrix& col, const Matrix& n, - double a, float as, float ds, float ss, float se) - : rep (new vertex_data_rep (c, col, n, a, as, ds, ss, se)) - { } - - vertex_data (vertex_data_rep *new_rep) - : rep (new_rep) { } - - ~vertex_data (void) - { - if (--rep->count == 0) - delete rep; - } - - vertex_data& operator = (const vertex_data& v) - { - if (--rep->count == 0) - delete rep; - - rep = v.rep; - rep->count++; - - return *this; - } - - vertex_data_rep *get_rep (void) const { return rep; } -}; - -class -opengl_renderer::patch_tesselator : public opengl_tesselator -{ -public: - patch_tesselator (opengl_renderer *r, int cmode, int lmode, int idx = 0) - : opengl_tesselator (), renderer (r), - color_mode (cmode), light_mode (lmode), index (idx), - first (true), tmp_vdata () - { } - -protected: - void begin (GLenum type) - { - //printf ("patch_tesselator::begin (%d)\n", type); - first = true; - - if (color_mode == 2 || light_mode == 2) - glShadeModel (GL_SMOOTH); - else - glShadeModel (GL_FLAT); - - if (is_filled ()) - renderer->set_polygon_offset (true, 1+index); - - glBegin (type); - } - - void end (void) - { - //printf ("patch_tesselator::end\n"); - glEnd (); - renderer->set_polygon_offset (false); - } - - void vertex (void *data) - { - vertex_data::vertex_data_rep *v - = reinterpret_cast (data); - //printf ("patch_tesselator::vertex (%g, %g, %g)\n", v->coords(0), v->coords(1), v->coords(2)); - - // FIXME: why did I need to keep the first vertex of the face - // in JHandles? I think it's related to the fact that the - // tessellation process might re-order the vertices, such that - // the first one you get here might not be the first one of the face; - // but I can't figure out the actual reason. - if (color_mode > 0 && (first || color_mode == 2)) - { - Matrix col = v->color; - - if (col.numel () == 3) - { - glColor3dv (col.data ()); - if (light_mode > 0) - { - float buf[4] = { 0, 0, 0, 1 }; - - for (int k = 0; k < 3; k++) - buf[k] = (v->ambient * col(k)); - glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf); - - for (int k = 0; k < 3; k++) - buf[k] = (v->diffuse * col(k)); - glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf); - } - } - } - - if (light_mode > 0 && (first || light_mode == 2)) - glNormal3dv (v->normal.data ()); - - glVertex3dv (v->coords.data ()); - - first = false; - } - - void combine (GLdouble xyz[3], void *data[4], GLfloat w[4], - void **out_data) - { - //printf ("patch_tesselator::combine\n"); - - vertex_data::vertex_data_rep *v[4]; - int vmax = 4; - - for (int i = 0; i < 4; i++) - { - v[i] = reinterpret_cast (data[i]); - - if (vmax == 4 && ! v[i]) - vmax = i; - } - - Matrix vv (1, 3, 0.0); - Matrix cc; - Matrix nn (1, 3, 0.0); - double aa = 0.0; - - vv(0) = xyz[0]; - vv(1) = xyz[1]; - vv(2) = xyz[2]; - - if (v[0]->color.numel ()) - { - cc.resize (1, 3, 0.0); - for (int ic = 0; ic < 3; ic++) - for (int iv = 0; iv < vmax; iv++) - cc(ic) += (w[iv] * v[iv]->color (ic)); - } - - if (v[0]->normal.numel () > 0) - { - for (int in = 0; in < 3; in++) - for (int iv = 0; iv < vmax; iv++) - nn(in) += (w[iv] * v[iv]->normal (in)); - } - - for (int iv = 0; iv < vmax; iv++) - aa += (w[iv] * v[iv]->alpha); - - vertex_data new_v (vv, cc, nn, aa, v[0]->ambient, v[0]->diffuse, - v[0]->specular, v[0]->specular_exp); - tmp_vdata.push_back (new_v); - - *out_data = new_v.get_rep (); - } - -private: - - // No copying! - - patch_tesselator (const patch_tesselator&); - - patch_tesselator& operator = (const patch_tesselator&); - - opengl_renderer *renderer; - int color_mode; // 0: uni, 1: flat, 2: interp - int light_mode; // 0: none, 1: flat, 2: gouraud - int index; - bool first; - std::list tmp_vdata; -}; - -void -opengl_renderer::draw (const graphics_object& go, bool toplevel) -{ - if (! go.valid_object ()) - return; - - const base_properties& props = go.get_properties (); - - if (! toolkit) - toolkit = props.get_toolkit (); - - if (go.isa ("figure")) - draw_figure (dynamic_cast (props)); - else if (go.isa ("axes")) - draw_axes (dynamic_cast (props)); - else if (go.isa ("line")) - draw_line (dynamic_cast (props)); - else if (go.isa ("surface")) - draw_surface (dynamic_cast (props)); - else if (go.isa ("patch")) - draw_patch (dynamic_cast (props)); - else if (go.isa ("hggroup")) - draw_hggroup (dynamic_cast (props)); - else if (go.isa ("text")) - draw_text (dynamic_cast (props)); - else if (go.isa ("image")) - draw_image (dynamic_cast (props)); - else if (go.isa ("uimenu") || go.isa ("uicontrol") - || go.isa ("uicontextmenu") || go.isa ("uitoolbar") - || go.isa ("uipushtool") || go.isa ("uitoggletool")) - /* SKIP */; - else if (go.isa ("uipanel")) - { - if (toplevel) - draw_uipanel (dynamic_cast (props), go); - } - else - { - warning ("opengl_renderer: cannot render object of type `%s'", - props.graphics_object_name ().c_str ()); - } -} - -void -opengl_renderer::draw_figure (const figure::properties& props) -{ - // Initialize OpenGL context - - init_gl_context (props.is___enhanced__ (), props.get_color_rgb ()); - - // Draw children - - draw (props.get_all_children (), false); -} - -void -opengl_renderer::draw_uipanel (const uipanel::properties& props, - const graphics_object& go) -{ - graphics_object fig = go.get_ancestor ("figure"); - const figure::properties& figProps = - dynamic_cast (fig.get_properties ()); - - // Initialize OpenGL context - - init_gl_context (figProps.is___enhanced__ (), - props.get_backgroundcolor_rgb ()); - - // Draw children - - draw (props.get_all_children (), false); -} - -void -opengl_renderer::init_gl_context (bool enhanced, const Matrix& c) -{ - // Initialize OpenGL context - - glEnable (GL_DEPTH_TEST); - glDepthFunc (GL_LEQUAL); - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glAlphaFunc (GL_GREATER, 0.0f); - glEnable (GL_NORMALIZE); - - if (enhanced) - { - glEnable (GL_BLEND); - glEnable (GL_LINE_SMOOTH); - } - else - { - glDisable (GL_BLEND); - glDisable (GL_LINE_SMOOTH); - } - - // Clear background - - if (c.length () >= 3) - { - glClearColor (c(0), c(1), c(2), 1); - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } -} - -void -opengl_renderer::render_grid (const std::string& gridstyle, - const Matrix& ticks, double lim1, double lim2, - double p1, double p1N, double p2, double p2N, - int xyz, bool is_3D) -{ - set_linestyle (gridstyle, true); - glBegin (GL_LINES); - for (int i = 0; i < ticks.numel (); i++) - { - double val = ticks(i); - if (lim1 <= val && val <= lim2) - { - if (xyz == 0) // X - { - glVertex3d (val, p1N, p2); - glVertex3d (val, p1, p2); - if (is_3D) - { - glVertex3d (val, p1, p2N); - glVertex3d (val, p1, p2); - } - } - else if (xyz == 1) // Y - { - glVertex3d (p1N, val, p2); - glVertex3d (p1, val, p2); - if (is_3D) - { - glVertex3d (p1, val, p2N); - glVertex3d (p1, val, p2); - } - } - else if (xyz == 2) // Z - { - glVertex3d (p1N, p2, val); - glVertex3d (p1, p2, val); - glVertex3d (p1, p2N, val); - glVertex3d (p1, p2, val); - } - } - } - glEnd (); - set_linestyle ("-", true); -} - -void -opengl_renderer::render_tickmarks (const Matrix& ticks, - double lim1, double lim2, - double p1, double p1N, - double p2, double p2N, - double dx, double dy, double dz, - int xyz, bool mirror) -{ - glBegin (GL_LINES); - - for (int i = 0; i < ticks.numel (); i++) - { - double val = ticks(i); - - if (lim1 <= val && val <= lim2) - { - if (xyz == 0) // X - { - glVertex3d (val, p1, p2); - glVertex3d (val, p1+dy, p2+dz); - if (mirror) - { - glVertex3d (val, p1N, p2N); - glVertex3d (val, p1N-dy, p2N-dz); - } - } - else if (xyz == 1) // Y - { - glVertex3d (p1, val, p2); - glVertex3d (p1+dx, val, p2+dz); - if (mirror) - { - glVertex3d (p1N, val, p2N); - glVertex3d (p1N-dx, val, p2N-dz); - } - } - else if (xyz == 2) // Z - { - glVertex3d (p1, p2, val); - glVertex3d (p1+dx, p2+dy, val); - if (mirror) - { - glVertex3d (p1N, p2N, val); - glVertex3d (p1N-dx, p2N-dy, val); - } - } - } - } - - glEnd (); -} - -void -opengl_renderer::render_ticktexts (const Matrix& ticks, - const string_vector& ticklabels, - double lim1, double lim2, - double p1, double p2, - int xyz, int ha, int va, - int& wmax, int& hmax) -{ - int n = std::min (ticklabels.numel (), ticks.numel ()); - - for (int i = 0; i < n; i++) - { - double val = ticks(i); - - if (lim1 <= val && val <= lim2) - { - Matrix b; - // FIXME: as tick text is transparent, shouldn't be - // drawn after axes object, for correct rendering? - if (xyz == 0) // X - { - b = render_text (ticklabels(i), val, p1, p2, ha, va); - } - else if (xyz == 1) // Y - { - b = render_text (ticklabels(i), p1, val, p2, ha, va); - } - else if (xyz == 2) // Z - { - b = render_text (ticklabels(i), p1, p2, val, ha, va); - } - - wmax = std::max (wmax, static_cast (b(2))); - hmax = std::max (hmax, static_cast (b(3))); - } - } -} - -void -opengl_renderer::setup_opengl_transformation (const axes::properties& props) -{ - // setup OpenGL transformation - - Matrix x_zlim = props.get_transform_zlim (); - - xZ1 = x_zlim(0)-(x_zlim(1)-x_zlim(0))/2; - xZ2 = x_zlim(1)+(x_zlim(1)-x_zlim(0))/2; - - Matrix x_mat1 = props.get_opengl_matrix_1 (); - Matrix x_mat2 = props.get_opengl_matrix_2 (); - -#if defined (HAVE_FRAMEWORK_OPENGL) - GLint vw[4]; -#else - int vw[4]; -#endif - - glGetIntegerv (GL_VIEWPORT, vw); - - glMatrixMode (GL_MODELVIEW); - glLoadIdentity (); - glScaled (1, 1, -1); - glMultMatrixd (x_mat1.data ()); - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); - glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2); - glMultMatrixd (x_mat2.data ()); - glMatrixMode (GL_MODELVIEW); - - glClear (GL_DEPTH_BUFFER_BIT); - - glDisable (GL_LINE_SMOOTH); - - // store axes transformation data - - xform = props.get_transform (); -} - -void -opengl_renderer::draw_axes_planes (const axes::properties& props) -{ - double xPlane = props.get_xPlane (); - double yPlane = props.get_yPlane (); - double zPlane = props.get_zPlane (); - double xPlaneN = props.get_xPlaneN (); - double yPlaneN = props.get_yPlaneN (); - double zPlaneN = props.get_zPlaneN (); - - // Axes planes - Matrix axe_color = props.get_color_rgb (); - if (axe_color.numel () > 0 && props.is_visible ()) - { - set_color (axe_color); - set_polygon_offset (true, 2.5); - - glBegin (GL_QUADS); - - // X plane - glVertex3d (xPlane, yPlaneN, zPlaneN); - glVertex3d (xPlane, yPlane, zPlaneN); - glVertex3d (xPlane, yPlane, zPlane); - glVertex3d (xPlane, yPlaneN, zPlane); - - // Y plane - glVertex3d (xPlaneN, yPlane, zPlaneN); - glVertex3d (xPlane, yPlane, zPlaneN); - glVertex3d (xPlane, yPlane, zPlane); - glVertex3d (xPlaneN, yPlane, zPlane); - - // Z plane - glVertex3d (xPlaneN, yPlaneN, zPlane); - glVertex3d (xPlane, yPlaneN, zPlane); - glVertex3d (xPlane, yPlane, zPlane); - glVertex3d (xPlaneN, yPlane, zPlane); - - glEnd (); - - set_polygon_offset (false); - } -} - -void -opengl_renderer::draw_axes_boxes (const axes::properties& props) -{ - bool xySym = props.get_xySym (); - double xPlane = props.get_xPlane (); - double yPlane = props.get_yPlane (); - double zPlane = props.get_zPlane (); - double xPlaneN = props.get_xPlaneN (); - double yPlaneN = props.get_yPlaneN (); - double zPlaneN = props.get_zPlaneN (); - double xpTick = props.get_xpTick (); - double ypTick = props.get_ypTick (); - double zpTick = props.get_zpTick (); - double xpTickN = props.get_xpTickN (); - double ypTickN = props.get_ypTickN (); - double zpTickN = props.get_zpTickN (); - - bool plotyy = (props.has_property ("__plotyy_axes__")); - - // Axes box - - set_linestyle ("-", true); - set_linewidth (props.get_linewidth ()); - - if (props.is_visible ()) - { - glBegin (GL_LINES); - - // X box - set_color (props.get_xcolor_rgb ()); - glVertex3d (xPlaneN, ypTick, zpTick); - glVertex3d (xPlane, ypTick, zpTick); - - if (props.is_box ()) - { - glVertex3d (xPlaneN, ypTickN, zpTick); - glVertex3d (xPlane, ypTickN, zpTick); - glVertex3d (xPlaneN, ypTickN, zpTickN); - glVertex3d (xPlane, ypTickN, zpTickN); - glVertex3d (xPlaneN, ypTick, zpTickN); - glVertex3d (xPlane, ypTick, zpTickN); - } - - // Y box - set_color (props.get_ycolor_rgb ()); - glVertex3d (xpTick, yPlaneN, zpTick); - glVertex3d (xpTick, yPlane, zpTick); - - if (props.is_box () && ! plotyy) - { - glVertex3d (xpTickN, yPlaneN, zpTick); - glVertex3d (xpTickN, yPlane, zpTick); - glVertex3d (xpTickN, yPlaneN, zpTickN); - glVertex3d (xpTickN, yPlane, zpTickN); - glVertex3d (xpTick, yPlaneN, zpTickN); - glVertex3d (xpTick, yPlane, zpTickN); - } - - // Z box - set_color (props.get_zcolor_rgb ()); - - if (xySym) - { - glVertex3d (xPlaneN, yPlane, zPlaneN); - glVertex3d (xPlaneN, yPlane, zPlane); - } - else - { - glVertex3d (xPlane, yPlaneN, zPlaneN); - glVertex3d (xPlane, yPlaneN, zPlane); - } - - if (props.is_box ()) - { - glVertex3d (xPlane, yPlane, zPlaneN); - glVertex3d (xPlane, yPlane, zPlane); - - if (xySym) - { - glVertex3d (xPlane, yPlaneN, zPlaneN); - glVertex3d (xPlane, yPlaneN, zPlane); - } - else - { - glVertex3d (xPlaneN, yPlane, zPlaneN); - glVertex3d (xPlaneN, yPlane, zPlane); - } - - glVertex3d (xPlaneN, yPlaneN, zPlaneN); - glVertex3d (xPlaneN, yPlaneN, zPlane); - } - - glEnd (); - } -} - -void -opengl_renderer::draw_axes_x_grid (const axes::properties& props) -{ - int xstate = props.get_xstate (); - int zstate = props.get_zstate (); - bool x2Dtop = props.get_x2Dtop (); - bool layer2Dtop = props.get_layer2Dtop (); - bool xyzSym = props.get_xyzSym (); - bool nearhoriz = props.get_nearhoriz (); - double xticklen = props.get_xticklen (); - double xtickoffset = props.get_xtickoffset (); - double fy = props.get_fy (); - double fz = props.get_fz (); - double x_min = props.get_x_min (); - double x_max = props.get_x_max (); - double yPlane = props.get_yPlane (); - double yPlaneN = props.get_yPlaneN (); - double ypTick = props.get_ypTick (); - double ypTickN = props.get_ypTickN (); - double zPlane = props.get_zPlane (); - double zPlaneN = props.get_zPlaneN (); - double zpTick = props.get_zpTick (); - double zpTickN = props.get_zpTickN (); - - // X grid - - if (props.is_visible () && xstate != AXE_DEPTH_DIR) - { - std::string gridstyle = props.get_gridlinestyle (); - std::string minorgridstyle = props.get_minorgridlinestyle (); - bool do_xgrid = (props.is_xgrid () && (gridstyle != "none")); - bool do_xminorgrid = (props.is_xminorgrid () && (minorgridstyle != "none")); - bool do_xminortick = props.is_xminortick (); - Matrix xticks = xform.xscale (props.get_xtick ().matrix_value ()); - Matrix xmticks = xform.xscale (props.get_xmtick ().matrix_value ()); - string_vector xticklabels = props.get_xticklabel ().all_strings (); - int wmax = 0, hmax = 0; - bool tick_along_z = nearhoriz || xisinf (fy); - bool mirror = props.is_box () && xstate != AXE_ANY_DIR; - - set_color (props.get_xcolor_rgb ()); - - // grid lines - if (do_xgrid) - render_grid (gridstyle, xticks, x_min, x_max, - yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane, - zPlaneN, 0, (zstate != AXE_DEPTH_DIR)); - - // tick marks - if (tick_along_z) - { - render_tickmarks (xticks, x_min, x_max, ypTick, ypTick, - zpTick, zpTickN, 0., 0., - signum (zpTick-zpTickN)*fz*xticklen, - 0, mirror); - } - else - { - render_tickmarks (xticks, x_min, x_max, ypTick, ypTickN, - zpTick, zpTick, 0., - signum (ypTick-ypTickN)*fy*xticklen, - 0., 0, mirror); - } - - // tick texts - if (xticklabels.numel () > 0) - { - int halign = (xstate == AXE_HORZ_DIR ? 1 : (xyzSym ? 0 : 2)); - int valign = (xstate == AXE_VERT_DIR ? 1 : (x2Dtop ? 0 : 2)); - - if (tick_along_z) - render_ticktexts (xticks, xticklabels, x_min, x_max, ypTick, - zpTick+signum (zpTick-zpTickN)*fz*xtickoffset, - 0, halign, valign, wmax, hmax); - else - render_ticktexts (xticks, xticklabels, x_min, x_max, - ypTick+signum (ypTick-ypTickN)*fy*xtickoffset, - zpTick, 0, halign, valign, wmax, hmax); - } - - // minor grid lines - if (do_xminorgrid) - render_grid (minorgridstyle, xmticks, x_min, x_max, - yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane, - zPlaneN, 0, (zstate != AXE_DEPTH_DIR)); - - // minor tick marks - if (do_xminortick) - { - if (tick_along_z) - render_tickmarks (xmticks, x_min, x_max, ypTick, ypTick, - zpTick, zpTickN, 0., 0., - signum (zpTick-zpTickN)*fz*xticklen/2, - 0, mirror); - else - render_tickmarks (xmticks, x_min, x_max, ypTick, ypTickN, - zpTick, zpTick, 0., - signum (ypTick-ypTickN)*fy*xticklen/2, - 0., 0, mirror); - } - - gh_manager::get_object (props.get_xlabel ()).set ("visible", "on"); - } - else - gh_manager::get_object (props.get_xlabel ()).set ("visible", "off"); -} - -void -opengl_renderer::draw_axes_y_grid (const axes::properties& props) -{ - int ystate = props.get_ystate (); - int zstate = props.get_zstate (); - bool y2Dright = props.get_y2Dright (); - bool layer2Dtop = props.get_layer2Dtop (); - bool xyzSym = props.get_xyzSym (); - bool nearhoriz = props.get_nearhoriz (); - double yticklen = props.get_yticklen (); - double ytickoffset = props.get_ytickoffset (); - double fx = props.get_fx (); - double fz = props.get_fz (); - double xPlane = props.get_xPlane (); - double xPlaneN = props.get_xPlaneN (); - double xpTick = props.get_xpTick (); - double xpTickN = props.get_xpTickN (); - double y_min = props.get_y_min (); - double y_max = props.get_y_max (); - double zPlane = props.get_zPlane (); - double zPlaneN = props.get_zPlaneN (); - double zpTick = props.get_zpTick (); - double zpTickN = props.get_zpTickN (); - - // Y grid - - if (ystate != AXE_DEPTH_DIR && props.is_visible ()) - { - std::string gridstyle = props.get_gridlinestyle (); - std::string minorgridstyle = props.get_minorgridlinestyle (); - bool do_ygrid = (props.is_ygrid () && (gridstyle != "none")); - bool do_yminorgrid = (props.is_yminorgrid () && (minorgridstyle != "none")); - bool do_yminortick = props.is_yminortick (); - Matrix yticks = xform.yscale (props.get_ytick ().matrix_value ()); - Matrix ymticks = xform.yscale (props.get_ymtick ().matrix_value ()); - string_vector yticklabels = props.get_yticklabel ().all_strings (); - int wmax = 0, hmax = 0; - bool tick_along_z = nearhoriz || xisinf (fx); - bool mirror = props.is_box () && ystate != AXE_ANY_DIR - && (! props.has_property ("__plotyy_axes__")); - - set_color (props.get_ycolor_rgb ()); - - // grid lines - if (do_ygrid) - render_grid (gridstyle, yticks, y_min, y_max, - xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane, - zPlaneN, 1, (zstate != AXE_DEPTH_DIR)); - - // tick marks - if (tick_along_z) - render_tickmarks (yticks, y_min, y_max, xpTick, xpTick, - zpTick, zpTickN, 0., 0., - signum (zpTick-zpTickN)*fz*yticklen, - 1, mirror); - else - render_tickmarks (yticks, y_min, y_max, xpTick, xpTickN, - zpTick, zpTick, - signum (xPlaneN-xPlane)*fx*yticklen, - 0., 0., 1, mirror); - - // tick texts - if (yticklabels.numel () > 0) - { - int halign = (ystate == AXE_HORZ_DIR - ? 1 : (!xyzSym || y2Dright ? 0 : 2)); - int valign = (ystate == AXE_VERT_DIR ? 1 : 2); - - if (tick_along_z) - render_ticktexts (yticks, yticklabels, y_min, y_max, xpTick, - zpTick+signum (zpTick-zpTickN)*fz*ytickoffset, - 1, halign, valign, wmax, hmax); - else - render_ticktexts (yticks, yticklabels, y_min, y_max, - xpTick+signum (xpTick-xpTickN)*fx*ytickoffset, - zpTick, 1, halign, valign, wmax, hmax); - } - - // minor grid lines - if (do_yminorgrid) - render_grid (minorgridstyle, ymticks, y_min, y_max, - xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane, - zPlaneN, 1, (zstate != AXE_DEPTH_DIR)); - - // minor tick marks - if (do_yminortick) - { - if (tick_along_z) - render_tickmarks (ymticks, y_min, y_max, xpTick, xpTick, - zpTick, zpTickN, 0., 0., - signum (zpTick-zpTickN)*fz*yticklen/2, - 1, mirror); - else - render_tickmarks (ymticks, y_min, y_max, xpTick, xpTickN, - zpTick, zpTick, - signum (xpTick-xpTickN)*fx*yticklen/2, - 0., 0., 1, mirror); - } - - gh_manager::get_object (props.get_ylabel ()).set ("visible", "on"); - } - else - gh_manager::get_object (props.get_ylabel ()).set ("visible", "off"); -} - -void -opengl_renderer::draw_axes_z_grid (const axes::properties& props) -{ - int zstate = props.get_zstate (); - bool xySym = props.get_xySym (); - bool zSign = props.get_zSign (); - double zticklen = props.get_zticklen (); - double ztickoffset = props.get_ztickoffset (); - double fx = props.get_fx (); - double fy = props.get_fy (); - double xPlane = props.get_xPlane (); - double xPlaneN = props.get_xPlaneN (); - double yPlane = props.get_yPlane (); - double yPlaneN = props.get_yPlaneN (); - double z_min = props.get_z_min (); - double z_max = props.get_z_max (); - - // Z Grid - - if (zstate != AXE_DEPTH_DIR && props.is_visible ()) - { - std::string gridstyle = props.get_gridlinestyle (); - std::string minorgridstyle = props.get_minorgridlinestyle (); - bool do_zgrid = (props.is_zgrid () && (gridstyle != "none")); - bool do_zminorgrid = (props.is_zminorgrid () && (minorgridstyle != "none")); - bool do_zminortick = props.is_zminortick (); - Matrix zticks = xform.zscale (props.get_ztick ().matrix_value ()); - Matrix zmticks = xform.zscale (props.get_zmtick ().matrix_value ()); - string_vector zticklabels = props.get_zticklabel ().all_strings (); - int wmax = 0, hmax = 0; - bool mirror = props.is_box () && zstate != AXE_ANY_DIR; - - set_color (props.get_zcolor_rgb ()); - - // grid lines - if (do_zgrid) - render_grid (gridstyle, zticks, z_min, z_max, - xPlane, xPlaneN, yPlane, yPlaneN, 2, true); - - // tick marks - if (xySym) - { - if (xisinf (fy)) - render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane, - yPlane, yPlane, - signum (xPlaneN-xPlane)*fx*zticklen, - 0., 0., 2, mirror); - else - render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlaneN, - yPlane, yPlane, 0., - signum (yPlane-yPlaneN)*fy*zticklen, - 0., 2, false); - } - else - { - if (xisinf (fx)) - render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane, - yPlaneN, yPlane, 0., - signum (yPlaneN-yPlane)*fy*zticklen, - 0., 2, mirror); - else - render_tickmarks (zticks, z_min, z_max, xPlane, xPlane, - yPlaneN, yPlane, - signum (xPlane-xPlaneN)*fx*zticklen, - 0., 0., 2, false); - } - - // FIXME: tick texts - if (zticklabels.numel () > 0) - { - int halign = 2; - int valign = (zstate == AXE_VERT_DIR ? 1 : (zSign ? 3 : 2)); - - if (xySym) - { - if (xisinf (fy)) - render_ticktexts (zticks, zticklabels, z_min, z_max, - xPlaneN+signum (xPlaneN-xPlane)*fx*ztickoffset, - yPlane, 2, halign, valign, wmax, hmax); - else - render_ticktexts (zticks, zticklabels, z_min, z_max, xPlaneN, - yPlane+signum (yPlane-yPlaneN)*fy*ztickoffset, - 2, halign, valign, wmax, hmax); - } - else - { - if (xisinf (fx)) - render_ticktexts (zticks, zticklabels, z_min, z_max, xPlane, - yPlaneN+signum (yPlaneN-yPlane)*fy*ztickoffset, - 2, halign, valign, wmax, hmax); - else - render_ticktexts (zticks, zticklabels, z_min, z_max, - xPlane+signum (xPlane-xPlaneN)*fx*ztickoffset, - yPlaneN, 2, halign, valign, wmax, hmax); - } - } - - // minor grid lines - if (do_zminorgrid) - render_grid (minorgridstyle, zmticks, z_min, z_max, - xPlane, xPlaneN, yPlane, yPlaneN, 2, true); - - // minor tick marks - if (do_zminortick) - { - if (xySym) - { - if (xisinf (fy)) - render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlane, - yPlane, yPlane, - signum (xPlaneN-xPlane)*fx*zticklen/2, - 0., 0., 2, mirror); - else - render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlaneN, - yPlane, yPlane, 0., - signum (yPlane-yPlaneN)*fy*zticklen/2, - 0., 2, false); - } - else - { - if (xisinf (fx)) - render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane, - yPlaneN, yPlane, 0., - signum (yPlaneN-yPlane)*fy*zticklen/2, - 0., 2, mirror); - else - render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane, - yPlaneN, yPlaneN, - signum (xPlane-xPlaneN)*fx*zticklen/2, - 0., 0., 2, false); - } - } - - gh_manager::get_object (props.get_zlabel ()).set ("visible", "on"); - } - else - gh_manager::get_object (props.get_zlabel ()).set ("visible", "off"); -} - -void -opengl_renderer::draw_axes_children (const axes::properties& props) -{ - // Children - - GLboolean antialias; - glGetBooleanv (GL_LINE_SMOOTH, &antialias); - - if (antialias == GL_TRUE) - glEnable (GL_LINE_SMOOTH); - - Matrix children = props.get_all_children (); - std::list obj_list; - std::list::iterator it; - - // 1st pass: draw light objects - - // Start with the last element of the array of child objects to - // display them in the oder they were added to the array. - - for (octave_idx_type i = children.numel () - 1; i >= 0; i--) - { - graphics_object go = gh_manager::get_object (children (i)); - - if (go.get_properties ().is_visible ()) - { - if (go.isa ("light")) - draw (go); - else - obj_list.push_back (go); - } - } - - // 2nd pass: draw other objects (with units set to "data") - - it = obj_list.begin (); - while (it != obj_list.end ()) - { - graphics_object go = (*it); - - // FIXME: check whether object has "units" property and it is set - // to "data" - if (! go.isa ("text") || go.get ("units").string_value () == "data") - { - set_clipping (go.get_properties ().is_clipping ()); - draw (go); - - it = obj_list.erase (it); - } - else - it++; - } - - // 3rd pass: draw remaining objects - - glDisable (GL_DEPTH_TEST); - - for (it = obj_list.begin (); it != obj_list.end (); it++) - { - graphics_object go = (*it); - - set_clipping (go.get_properties ().is_clipping ()); - draw (go); - } - - glEnable (GL_DEPTH_TEST); - - set_clipping (false); - - // FIXME: finalize rendering (transparency processing) - // FIXME: draw zoom box, if needed -} - -void -opengl_renderer::draw_axes (const axes::properties& props) -{ - double x_min = props.get_x_min (); - double x_max = props.get_x_max (); - double y_min = props.get_y_min (); - double y_max = props.get_y_max (); - double z_min = props.get_z_min (); - double z_max = props.get_z_max (); - - setup_opengl_transformation (props); - - // draw axes object - - draw_axes_planes (props); - draw_axes_boxes (props); - - set_font (props); - - draw_axes_x_grid (props); - draw_axes_y_grid (props); - draw_axes_z_grid (props); - - set_linestyle ("-"); - - set_clipbox (x_min, x_max, y_min, y_max, z_min, z_max); - - draw_axes_children (props); -} - -void -opengl_renderer::draw_line (const line::properties& props) -{ - Matrix x = xform.xscale (props.get_xdata ().matrix_value ()); - Matrix y = xform.yscale (props.get_ydata ().matrix_value ()); - Matrix z = xform.zscale (props.get_zdata ().matrix_value ()); - - bool has_z = (z.numel () > 0); - int n = static_cast (::xmin (::xmin (x.numel (), y.numel ()), (has_z ? z.numel () : INT_MAX))); - octave_uint8 clip_mask = (props.is_clipping () ? 0x7F : 0x40), clip_ok (0x40); - - std::vector clip (n); - - if (has_z) - for (int i = 0; i < n; i++) - clip[i] = (clip_code (x(i), y(i), z(i)) & clip_mask); - else - { - double z_mid = (zmin+zmax)/2; - - for (int i = 0; i < n; i++) - clip[i] = (clip_code (x(i), y(i), z_mid) & clip_mask); - } - - if (! props.linestyle_is ("none")) - { - set_color (props.get_color_rgb ()); - set_linestyle (props.get_linestyle (), false); - set_linewidth (props.get_linewidth ()); - - if (has_z) - { - bool flag = false; - - for (int i = 1; i < n; i++) - { - if ((clip[i-1] & clip[i]) == clip_ok) - { - if (! flag) - { - flag = true; - glBegin (GL_LINE_STRIP); - glVertex3d (x(i-1), y(i-1), z(i-1)); - } - glVertex3d (x(i), y(i), z(i)); - } - else if (flag) - { - flag = false; - glEnd (); - } - } - - if (flag) - glEnd (); - } - else - { - bool flag = false; - - for (int i = 1; i < n; i++) - { - if ((clip[i-1] & clip[i]) == clip_ok) - { - if (! flag) - { - flag = true; - glBegin (GL_LINE_STRIP); - glVertex2d (x(i-1), y(i-1)); - } - glVertex2d (x(i), y(i)); - } - else if (flag) - { - flag = false; - glEnd (); - } - } - - if (flag) - glEnd (); - } - - set_linewidth (0.5); - set_linestyle ("-"); - } - - set_clipping (false); - - if (! props.marker_is ("none") && - ! (props.markeredgecolor_is ("none") - && props.markerfacecolor_is ("none"))) - { - Matrix lc, fc; - - if (props.markeredgecolor_is ("auto")) - lc = props.get_color_rgb (); - else if (! props.markeredgecolor_is ("none")) - lc = props.get_markeredgecolor_rgb (); - - if (props.markerfacecolor_is ("auto")) - fc = props.get_color_rgb (); - else if (! props.markerfacecolor_is ("none")) - fc = props.get_markerfacecolor_rgb (); - - init_marker (props.get_marker (), props.get_markersize (), - props.get_linewidth ()); - - for (int i = 0; i < n; i++) - { - if (clip[i] == clip_ok) - draw_marker (x(i), y(i), - has_z ? z(i) : static_cast (i) / n, - lc, fc); - } - - end_marker (); - } - - set_clipping (props.is_clipping ()); -} - -void -opengl_renderer::draw_surface (const surface::properties& props) -{ - const Matrix x = xform.xscale (props.get_xdata ().matrix_value ()); - const Matrix y = xform.yscale (props.get_ydata ().matrix_value ()); - const Matrix z = xform.zscale (props.get_zdata ().matrix_value ()); - - int zr = z.rows (), zc = z.columns (); - - NDArray c; - const NDArray n = props.get_vertexnormals ().array_value (); - - // FIXME: handle transparency - Matrix a; - - if (props.facelighting_is ("phong") || props.edgelighting_is ("phong")) - warning ("opengl_renderer::draw: phong light model not supported"); - - int fc_mode = (props.facecolor_is_rgb () ? 0 : - (props.facecolor_is ("flat") ? 1 : - (props.facecolor_is ("interp") ? 2 : - (props.facecolor_is ("texturemap") ? 3 : -1)))); - int fl_mode = (props.facelighting_is ("none") ? 0 : - (props.facelighting_is ("flat") ? 1 : 2)); - int fa_mode = (props.facealpha_is_double () ? 0 : - (props.facealpha_is ("flat") ? 1 : 2)); - int ec_mode = (props.edgecolor_is_rgb () ? 0 : - (props.edgecolor_is ("flat") ? 1 : - (props.edgecolor_is ("interp") ? 2 : -1))); - int el_mode = (props.edgelighting_is ("none") ? 0 : - (props.edgelighting_is ("flat") ? 1 : 2)); - int ea_mode = (props.edgealpha_is_double () ? 0 : - (props.edgealpha_is ("flat") ? 1 : 2)); - - Matrix fcolor = (fc_mode == 3 ? Matrix (1, 3, 1.0) : props.get_facecolor_rgb ()); - Matrix ecolor = props.get_edgecolor_rgb (); - - float as = props.get_ambientstrength (); - float ds = props.get_diffusestrength (); - float ss = props.get_specularstrength (); - float se = props.get_specularexponent (); - float cb[4] = { 0.0, 0.0, 0.0, 1.0 }; - double d = 1.0; - - opengl_texture tex; - - int i1, i2, j1, j2; - bool x_mat = (x.rows () == z.rows ()); - bool y_mat = (y.columns () == z.columns ()); - - i1 = i2 = j1 = j2 = 0; - - boolMatrix clip (z.dims (), false); - - for (int i = 0; i < zr; i++) - { - if (x_mat) - i1 = i; - - for (int j = 0; j < zc; j++) - { - if (y_mat) - j1 = j; - - clip(i,j) = is_nan_or_inf (x(i1,j), y(i,j1), z(i,j)); - } - } - - if ((fc_mode > 0 && fc_mode < 3) || ec_mode > 0) - c = props.get_color_data ().array_value (); - - if (fa_mode > 0 || ea_mode > 0) - { - // FIXME: implement alphadata conversion - //a = props.get_alpha_data (); - } - - if (fl_mode > 0 || el_mode > 0) - { - float buf[4] = { ss, ss, ss, 1 }; - - glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf); - glMaterialf (LIGHT_MODE, GL_SHININESS, se); - } - - // FIXME: good candidate for caching, transfering pixel - // data to OpenGL is time consuming. - if (fc_mode == 3) - tex = opengl_texture::create (props.get_color_data ()); - - if (! props.facecolor_is ("none")) - { - if (props.get_facealpha_double () == 1) - { - if (fc_mode == 0 || fc_mode == 3) - { - glColor3dv (fcolor.data ()); - if (fl_mode > 0) - { - for (int i = 0; i < 3; i++) - cb[i] = as * fcolor(i); - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int i = 0; i < 3; i++) - cb[i] = ds * fcolor(i); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - - if (fl_mode > 0) - glEnable (GL_LIGHTING); - glShadeModel ((fc_mode == 2 || fl_mode == 2) ? GL_SMOOTH : GL_FLAT); - set_polygon_offset (true, 1); - if (fc_mode == 3) - glEnable (GL_TEXTURE_2D); - - for (int i = 1; i < zc; i++) - { - if (y_mat) - { - i1 = i-1; - i2 = i; - } - - for (int j = 1; j < zr; j++) - { - if (clip(j-1, i-1) || clip (j, i-1) - || clip (j-1, i) || clip (j, i)) - continue; - - if (x_mat) - { - j1 = j-1; - j2 = j; - } - - glBegin (GL_QUADS); - - // Vertex 1 - if (fc_mode == 3) - tex.tex_coord (double (i-1) / (zc-1), double (j-1) / (zr-1)); - else if (fc_mode > 0) - { - // FIXME: is there a smarter way to do this? - for (int k = 0; k < 3; k++) - cb[k] = c(j-1, i-1, k); - glColor3fv (cb); - - if (fl_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] *= as; - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int k = 0; k < 3; k++) - cb[k] = ds * c(j-1, i-1, k); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - if (fl_mode > 0) - { - d = sqrt (n(j-1,i-1,0) * n(j-1,i-1,0) - + n(j-1,i-1,1) * n(j-1,i-1,1) - + n(j-1,i-1,2) * n(j-1,i-1,2)); - glNormal3d (n(j-1,i-1,0)/d, n(j-1,i-1,1)/d, n(j-1,i-1,2)/d); - } - glVertex3d (x(j1,i-1), y(j-1,i1), z(j-1,i-1)); - - // Vertex 2 - if (fc_mode == 3) - tex.tex_coord (double (i) / (zc-1), double (j-1) / (zr-1)); - else if (fc_mode == 2) - { - for (int k = 0; k < 3; k++) - cb[k] = c(j-1, i, k); - glColor3fv (cb); - - if (fl_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] *= as; - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int k = 0; k < 3; k++) - cb[k] = ds * c(j-1, i, k); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - - if (fl_mode == 2) - { - d = sqrt (n(j-1,i,0) * n(j-1,i,0) - + n(j-1,i,1) * n(j-1,i,1) - + n(j-1,i,2) * n(j-1,i,2)); - glNormal3d (n(j-1,i,0)/d, n(j-1,i,1)/d, n(j-1,i,2)/d); - } - - glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i)); - - // Vertex 3 - if (fc_mode == 3) - tex.tex_coord (double (i) / (zc-1), double (j) / (zr-1)); - else if (fc_mode == 2) - { - for (int k = 0; k < 3; k++) - cb[k] = c(j, i, k); - glColor3fv (cb); - - if (fl_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] *= as; - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int k = 0; k < 3; k++) - cb[k] = ds * c(j, i, k); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - if (fl_mode == 2) - { - d = sqrt (n(j,i,0) * n(j,i,0) - + n(j,i,1) * n(j,i,1) - + n(j,i,2) * n(j,i,2)); - glNormal3d (n(j,i,0)/d, n(j,i,1)/d, n(j,i,2)/d); - } - glVertex3d (x(j2,i), y(j,i2), z(j,i)); - - // Vertex 4 - if (fc_mode == 3) - tex.tex_coord (double (i-1) / (zc-1), double (j) / (zr-1)); - else if (fc_mode == 2) - { - for (int k = 0; k < 3; k++) - cb[k] = c(j, i-1, k); - glColor3fv (cb); - - if (fl_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] *= as; - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int k = 0; k < 3; k++) - cb[k] = ds * c(j, i-1, k); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - if (fl_mode == 2) - { - d = sqrt (n(j,i-1,0) * n(j,i-1,0) - + n(j,i-1,1) * n(j,i-1,1) - + n(j,i-1,2) * n(j,i-1,2)); - glNormal3d (n(j,i-1,0)/d, n(j,i-1,1)/d, n(j,i-1,2)/d); - } - glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1)); - - glEnd (); - } - } - - set_polygon_offset (false); - if (fc_mode == 3) - glDisable (GL_TEXTURE_2D); - - if (fl_mode > 0) - glDisable (GL_LIGHTING); - } - else - { - // FIXME: implement transparency - } - } - - if (! props.edgecolor_is ("none")) - { - if (props.get_edgealpha_double () == 1) - { - if (ec_mode == 0) - { - glColor3dv (ecolor.data ()); - if (fl_mode > 0) - { - for (int i = 0; i < 3; i++) - cb[i] = as * ecolor(i); - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int i = 0; i < 3; i++) - cb[i] = ds * ecolor(i); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - - if (el_mode > 0) - glEnable (GL_LIGHTING); - glShadeModel ((ec_mode == 2 || el_mode == 2) ? GL_SMOOTH : GL_FLAT); - - set_linestyle (props.get_linestyle (), false); - set_linewidth (props.get_linewidth ()); - - // Mesh along Y-axis - - if (props.meshstyle_is ("both") || props.meshstyle_is ("column")) - { - for (int i = 0; i < zc; i++) - { - if (y_mat) - { - i1 = i-1; - i2 = i; - } - - for (int j = 1; j < zr; j++) - { - if (clip(j-1,i) || clip(j,i)) - continue; - - if (x_mat) - { - j1 = j-1; - j2 = j; - } - - glBegin (GL_LINES); - - // Vertex 1 - if (ec_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] = c(j-1, i, k); - glColor3fv (cb); - - if (fl_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] *= as; - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int k = 0; k < 3; k++) - cb[k] = ds * c(j-1, i, k); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - if (el_mode > 0) - { - d = sqrt (n(j-1,i,0) * n(j-1,i,0) - + n(j-1,i,1) * n(j-1,i,1) - + n(j-1,i,2) * n(j-1,i,2)); - glNormal3d (n(j-1,i,0)/d, n(j-1,i,1)/d, n(j-1,i,2)/d); - } - glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i)); - - // Vertex 2 - if (ec_mode == 2) - { - for (int k = 0; k < 3; k++) - cb[k] = c(j, i, k); - glColor3fv (cb); - - if (fl_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] *= as; - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int k = 0; k < 3; k++) - cb[k] = ds * c(j, i, k); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - if (el_mode == 2) - { - d = sqrt (n(j,i,0) * n(j,i,0) - + n(j,i,1) * n(j,i,1) - + n(j,i,2) * n(j,i,2)); - glNormal3d (n(j,i,0)/d, n(j,i,1)/d, n(j,i,2)/d); - } - glVertex3d (x(j2,i), y(j,i2), z(j,i)); - - glEnd (); - } - } - } - - // Mesh along X-axis - - if (props.meshstyle_is ("both") || props.meshstyle_is ("row")) - { - for (int j = 0; j < zr; j++) - { - if (x_mat) - { - j1 = j-1; - j2 = j; - } - - for (int i = 1; i < zc; i++) - { - if (clip(j,i-1) || clip(j,i)) - continue; - - if (y_mat) - { - i1 = i-1; - i2 = i; - } - - glBegin (GL_LINES); - - // Vertex 1 - if (ec_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] = c(j, i-1, k); - glColor3fv (cb); - - if (fl_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] *= as; - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int k = 0; k < 3; k++) - cb[k] = ds * c(j, i-1, k); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - if (el_mode > 0) - { - d = sqrt (n(j,i-1,0) * n(j,i-1,0) - + n(j,i-1,1) * n(j,i-1,1) - + n(j,i-1,2) * n(j,i-1,2)); - glNormal3d (n(j,i-1,0)/d, n(j,i-1,1)/d, n(j,i-1,2)/d); - } - glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1)); - - // Vertex 2 - if (ec_mode == 2) - { - for (int k = 0; k < 3; k++) - cb[k] = c(j, i, k); - glColor3fv (cb); - - if (fl_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] *= as; - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int k = 0; k < 3; k++) - cb[k] = ds * c(j, i, k); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - if (el_mode == 2) - { - d = sqrt (n(j,i,0) * n(j,i,0) - + n(j,i,1) * n(j,i,1) - + n(j,i,2) * n(j,i,2)); - glNormal3d (n(j,i,0)/d, n(j,i,1)/d, n(j,i,2)/d); - } - glVertex3d (x(j2,i), y(j,i2), z(j,i)); - - glEnd (); - } - } - } - - set_linestyle ("-"); - set_linewidth (0.5); - - if (el_mode > 0) - glDisable (GL_LIGHTING); - } - else - { - // FIXME: implement transparency - } - } - - if (! props.marker_is ("none") && - ! (props.markeredgecolor_is ("none") - && props.markerfacecolor_is ("none"))) - { - // FIXME: check how transparency should be handled in markers - // FIXME: check what to do with marker facecolor set to auto - // and facecolor set to none. - - bool do_edge = ! props.markeredgecolor_is ("none"); - bool do_face = ! props.markerfacecolor_is ("none"); - - Matrix mecolor = props.get_markeredgecolor_rgb (); - Matrix mfcolor = props.get_markerfacecolor_rgb (); - Matrix cc (1, 3, 0.0); - - if (mecolor.numel () == 0 && props.markeredgecolor_is ("auto")) - { - mecolor = props.get_edgecolor_rgb (); - do_edge = ! props.edgecolor_is ("none"); - } - - if (mfcolor.numel () == 0 && props.markerfacecolor_is ("auto")) - { - mfcolor = props.get_facecolor_rgb (); - do_face = ! props.facecolor_is ("none"); - } - - if ((mecolor.numel () == 0 || mfcolor.numel () == 0) - && c.numel () == 0) - c = props.get_color_data ().array_value (); - - init_marker (props.get_marker (), props.get_markersize (), - props.get_linewidth ()); - - for (int i = 0; i < zc; i++) - { - if (y_mat) - i1 = i; - - for (int j = 0; j < zr; j++) - { - if (clip(j,i)) - continue; - - if (x_mat) - j1 = j; - - if ((do_edge && mecolor.numel () == 0) - || (do_face && mfcolor.numel () == 0)) - { - for (int k = 0; k < 3; k++) - cc(k) = c(j,i,k); - } - - Matrix lc = (do_edge ? (mecolor.numel () == 0 ? cc : mecolor) : Matrix ()); - Matrix fc = (do_face ? (mfcolor.numel () == 0 ? cc : mfcolor) : Matrix ()); - - draw_marker (x(j1,i), y(j,i1), z(j,i), lc, fc); - } - } - - end_marker (); - } -} - -// FIXME: global optimization (rendering, data structures...), there -// is probably a smarter/faster/less-memory-consuming way to do this. -void -opengl_renderer::draw_patch (const patch::properties &props) -{ - const Matrix f = props.get_faces ().matrix_value (); - const Matrix v = xform.scale (props.get_vertices ().matrix_value ()); - Matrix c; - const Matrix n = props.get_vertexnormals ().matrix_value (); - Matrix a; - - int nv = v.rows (); - // int vmax = v.columns (); - int nf = f.rows (); - int fcmax = f.columns (); - - bool has_z = (v.columns () > 2); - bool has_facecolor = false; - bool has_facealpha = false; - - int fc_mode = ((props.facecolor_is ("none") - || props.facecolor_is_rgb ()) ? 0 : - (props.facecolor_is ("flat") ? 1 : 2)); - int fl_mode = (props.facelighting_is ("none") ? 0 : - (props.facelighting_is ("flat") ? 1 : 2)); - int fa_mode = (props.facealpha_is_double () ? 0 : - (props.facealpha_is ("flat") ? 1 : 2)); - int ec_mode = ((props.edgecolor_is ("none") - || props.edgecolor_is_rgb ()) ? 0 : - (props.edgecolor_is ("flat") ? 1 : 2)); - int el_mode = (props.edgelighting_is ("none") ? 0 : - (props.edgelighting_is ("flat") ? 1 : 2)); - int ea_mode = (props.edgealpha_is_double () ? 0 : - (props.edgealpha_is ("flat") ? 1 : 2)); - - Matrix fcolor = props.get_facecolor_rgb (); - Matrix ecolor = props.get_edgecolor_rgb (); - - float as = props.get_ambientstrength (); - float ds = props.get_diffusestrength (); - float ss = props.get_specularstrength (); - float se = props.get_specularexponent (); - - boolMatrix clip (1, nv, false); - - if (has_z) - for (int i = 0; i < nv; i++) - clip(i) = is_nan_or_inf (v(i,0), v(i,1), v(i,2)); - else - for (int i = 0; i < nv; i++) - clip(i) = is_nan_or_inf (v(i,0), v(i,1), 0); - - boolMatrix clip_f (1, nf, false); - Array count_f (dim_vector (nf, 1), 0); - - for (int i = 0; i < nf; i++) - { - bool fclip = false; - int count = 0; - - for (int j = 0; j < fcmax && ! xisnan (f(i,j)); j++, count++) - fclip = (fclip || clip(int (f(i,j) - 1))); - - clip_f(i) = fclip; - count_f(i) = count; - } - - if (fc_mode > 0 || ec_mode > 0) - { - c = props.get_color_data ().matrix_value (); - - if (c.rows () == 1) - { - // Single color specifications, we can simplify a little bit - - if (fc_mode > 0) - { - fcolor = c; - fc_mode = 0; - } - - if (ec_mode > 0) - { - ecolor = c; - ec_mode = 0; - } - - c = Matrix (); - } - else - has_facecolor = ((c.numel () > 0) && (c.rows () == f.rows ())); - } - - if (fa_mode > 0 || ea_mode > 0) - { - // FIXME: retrieve alpha data from patch object - //a = props.get_alpha_data (); - has_facealpha = ((a.numel () > 0) && (a.rows () == f.rows ())); - } - - octave_idx_type fr = f.rows (); - std::vector vdata (f.numel ()); - - for (int i = 0; i < nf; i++) - for (int j = 0; j < count_f(i); j++) - { - int idx = int (f(i,j) - 1); - - Matrix vv (1, 3, 0.0); - Matrix cc; - Matrix nn(1, 3, 0.0); - double aa = 1.0; - - vv(0) = v(idx,0); vv(1) = v(idx,1); - if (has_z) - vv(2) = v(idx,2); - // FIXME: uncomment when patch object has normal computation - //nn(0) = n(idx,0); nn(1) = n(idx,1); nn(2) = n(idx,2); - if (c.numel () > 0) - { - cc.resize (1, 3); - if (has_facecolor) - cc(0) = c(i,0), cc(1) = c(i,1), cc(2) = c(i,2); - else - cc(0) = c(idx,0), cc(1) = c(idx,1), cc(2) = c(idx,2); - } - if (a.numel () > 0) - { - if (has_facealpha) - aa = a(i); - else - aa = a(idx); - } - - vdata[i+j*fr] = - vertex_data (vv, cc, nn, aa, as, ds, ss, se); - } - - if (fl_mode > 0 || el_mode > 0) - { - float buf[4] = { ss, ss, ss, 1 }; - - glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf); - glMaterialf (LIGHT_MODE, GL_SHININESS, se); - } - - if (! props.facecolor_is ("none")) - { - // FIXME: adapt to double-radio property - if (props.get_facealpha_double () == 1) - { - if (fc_mode == 0) - { - glColor3dv (fcolor.data ()); - if (fl_mode > 0) - { - float cb[4] = { 0, 0, 0, 1 }; - - for (int i = 0; i < 3; i++) - cb[i] = (as * fcolor(i)); - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int i = 0; i < 3; i++) - cb[i] = ds * fcolor(i); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - - if (fl_mode > 0) - glEnable (GL_LIGHTING); - - // FIXME: use __index__ property from patch object - patch_tesselator tess (this, fc_mode, fl_mode, 0); - - for (int i = 0; i < nf; i++) - { - if (clip_f(i)) - continue; - - tess.begin_polygon (true); - tess.begin_contour (); - - for (int j = 0; j < count_f(i); j++) - { - vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep (); - - tess.add_vertex (vv->coords.fortran_vec (), vv); - } - - tess.end_contour (); - tess.end_polygon (); - } - - if (fl_mode > 0) - glDisable (GL_LIGHTING); - } - else - { - // FIXME: implement transparency - } - } - - if (! props.edgecolor_is ("none")) - { - // FIXME: adapt to double-radio property - if (props.get_edgealpha_double () == 1) - { - if (ec_mode == 0) - { - glColor3dv (ecolor.data ()); - if (el_mode > 0) - { - float cb[4] = { 0, 0, 0, 1 }; - - for (int i = 0; i < 3; i++) - cb[i] = (as * ecolor(i)); - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int i = 0; i < 3; i++) - cb[i] = ds * ecolor(i); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - - if (el_mode > 0) - glEnable (GL_LIGHTING); - - set_linestyle (props.get_linestyle (), false); - set_linewidth (props.get_linewidth ()); - - - // FIXME: use __index__ property from patch object; should we - // offset patch contour as well? - patch_tesselator tess (this, ec_mode, el_mode); - - for (int i = 0; i < nf; i++) - { - if (clip_f(i)) - { - // This is an unclosed contour. Draw it as a line - bool flag = false; - - for (int j = 0; j < count_f(i); j++) - { - if (! clip(int (f(i,j) - 1))) - { - vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep (); - const Matrix m = vv->coords; - if (! flag) - { - flag = true; - glBegin (GL_LINE_STRIP); - } - glVertex3d (m(0), m(1), m(2)); - } - else if (flag) - { - flag = false; - glEnd (); - } - } - - if (flag) - glEnd (); - } - else - { - tess.begin_polygon (false); - tess.begin_contour (); - - for (int j = 0; j < count_f(i); j++) - { - vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep (); - tess.add_vertex (vv->coords.fortran_vec (), vv); - } - - tess.end_contour (); - tess.end_polygon (); - } - } - - set_linestyle ("-"); - set_linewidth (0.5); - - if (el_mode > 0) - glDisable (GL_LIGHTING); - } - else - { - // FIXME: implement transparency - } - } - - if (! props.marker_is ("none") && - ! (props.markeredgecolor_is ("none") && props.markerfacecolor_is ("none"))) - { - bool do_edge = ! props.markeredgecolor_is ("none"); - bool do_face = ! props.markerfacecolor_is ("none"); - - Matrix mecolor = props.get_markeredgecolor_rgb (); - Matrix mfcolor = props.get_markerfacecolor_rgb (); - - bool has_markerfacecolor = false; - - if ((mecolor.numel () == 0 && ! props.markeredgecolor_is ("none")) - || (mfcolor.numel () == 0 && ! props.markerfacecolor_is ("none"))) - { - Matrix mc = props.get_color_data ().matrix_value (); - - if (mc.rows () == 1) - { - // Single color specifications, we can simplify a little bit - - if (mfcolor.numel () == 0 - && ! props.markerfacecolor_is ("none")) - mfcolor = mc; - - if (mecolor.numel () == 0 - && ! props.markeredgecolor_is ("none")) - mecolor = mc; - } - else - { - if (c.numel () == 0) - c = props.get_color_data ().matrix_value (); - has_markerfacecolor = ((c.numel () > 0) - && (c.rows () == f.rows ())); - } - } - - - init_marker (props.get_marker (), props.get_markersize (), - props.get_linewidth ()); - - for (int i = 0; i < nf; i++) - for (int j = 0; j < count_f(i); j++) - { - int idx = int (f(i,j) - 1); - - if (clip(idx)) - continue; - - Matrix cc; - if (c.numel () > 0) - { - cc.resize (1, 3); - if (has_markerfacecolor) - cc(0) = c(i,0), cc(1) = c(i,1), cc(2) = c(i,2); - else - cc(0) = c(idx,0), cc(1) = c(idx,1), cc(2) = c(idx,2); - } - - Matrix lc = (do_edge ? (mecolor.numel () == 0 ? cc : mecolor) - : Matrix ()); - Matrix fc = (do_face ? (mfcolor.numel () == 0 ? cc : mfcolor) - : Matrix ()); - - draw_marker (v(idx,0), v(idx,1), (has_z ? v(idx,2) : 0), lc, fc); - } - - end_marker (); - } -} - -void -opengl_renderer::draw_hggroup (const hggroup::properties &props) -{ - draw (props.get_children ()); -} - -void -opengl_renderer::draw_text (const text::properties& props) -{ - if (props.get_string ().is_empty ()) - return; - - Matrix pos = xform.scale (props.get_data_position ()); - const Matrix bbox = props.get_extent_matrix (); - - // FIXME: handle margin and surrounding box - bool blend = glIsEnabled (GL_BLEND); - - glEnable (GL_BLEND); - glEnable (GL_ALPHA_TEST); - glRasterPos3d (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0); - glBitmap (0, 0, 0, 0, bbox(0), bbox(1), 0); - glDrawPixels (bbox(2), bbox(3), - GL_RGBA, GL_UNSIGNED_BYTE, props.get_pixels ().data ()); - glDisable (GL_ALPHA_TEST); - if (! blend) - glDisable (GL_BLEND); - -} - -void -opengl_renderer::draw_image (const image::properties& props) -{ - octave_value cdata = props.get_color_data (); - dim_vector dv (cdata.dims ()); - int h = dv(0), w = dv(1); - - Matrix x = props.get_xdata ().matrix_value (); - Matrix y = props.get_ydata ().matrix_value (); - - // Someone wants us to draw an empty image? No way. - if (x.is_empty () || y.is_empty ()) - return; - - if (w > 1 && x(1) == x(0)) - x(1) = x(1) + (w-1); - - if (h > 1 && y(1) == y(0)) - y(1) = y(1) + (h-1); - - const ColumnVector p0 = xform.transform (x(0), y(0), 0); - const ColumnVector p1 = xform.transform (x(1), y(1), 0); - - // image pixel size in screen pixel units - float pix_dx, pix_dy; - // image pixel size in normalized units - float nor_dx, nor_dy; - - if (w > 1) - { - pix_dx = (p1(0) - p0(0))/(w-1); - nor_dx = (x(1) - x(0))/(w-1); - } - else - { - const ColumnVector p1w = xform.transform (x(1) + 1, y(1), 0); - pix_dx = p1w(0) - p0(0); - nor_dx = 1; - } - - if (h > 1) - { - pix_dy = (p1(1) - p0(1))/(h-1); - nor_dy = (y(1) - y(0))/(h-1); - } - else - { - const ColumnVector p1h = xform.transform (x(1), y(1) + 1, 0); - pix_dy = p1h(1) - p0(1); - nor_dy = 1; - } - - - // OpenGL won't draw the image if it's origin is outside the - // viewport/clipping plane so we must do the clipping - // ourselfes - only draw part of the image - - int j0 = 0, j1 = w; - int i0 = 0, i1 = h; - - float im_xmin = x(0) - nor_dx/2; - float im_xmax = x(1) + nor_dx/2; - float im_ymin = y(0) - nor_dy/2; - float im_ymax = y(1) + nor_dy/2; - if (props.is_clipping ()) // clip to axes - { - if (im_xmin < xmin) - j0 += (xmin - im_xmin)/nor_dx + 1; - if (im_xmax > xmax) - j1 -= (im_xmax - xmax)/nor_dx ; - - if (im_ymin < ymin) - i0 += (ymin - im_ymin)/nor_dy + 1; - if (im_ymax > ymax) - i1 -= (im_ymax - ymax)/nor_dy; - } - else // clip to viewport - { - GLfloat vp[4]; - glGetFloatv (GL_VIEWPORT, vp); - // FIXME -- actually add the code to do it! - - } - - if (i0 >= i1 || j0 >= j1) - return; - - glPixelZoom (pix_dx, -pix_dy); - glRasterPos3d (im_xmin + nor_dx*j0, im_ymin + nor_dy*i0, 0); - - // by default this is 4 - glPixelStorei (GL_UNPACK_ALIGNMENT,1); - - // Expect RGB data - if (dv.length () == 3 && dv(2) == 3) - { - if (cdata.is_double_type ()) - { - const NDArray xcdata = cdata.array_value (); - - OCTAVE_LOCAL_BUFFER (GLfloat, a, 3*(j1-j0)*(i1-i0)); - - for (int i = i0; i < i1; i++) - { - for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3) - { - a[idx] = xcdata(i,j,0); - a[idx+1] = xcdata(i,j,1); - a[idx+2] = xcdata(i,j,2); - } - } - - draw_pixels (j1-j0, i1-i0, GL_RGB, GL_FLOAT, a); - - } - else if (cdata.is_uint16_type ()) - { - const uint16NDArray xcdata = cdata.uint16_array_value (); - - OCTAVE_LOCAL_BUFFER (GLushort, a, 3*(j1-j0)*(i1-i0)); - - for (int i = i0; i < i1; i++) - { - for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3) - { - a[idx] = xcdata(i,j,0); - a[idx+1] = xcdata(i,j,1); - a[idx+2] = xcdata(i,j,2); - } - } - - draw_pixels (j1-j0, i1-i0, GL_RGB, GL_UNSIGNED_SHORT, a); - - } - else if (cdata.is_uint8_type ()) - { - const uint8NDArray xcdata = cdata.uint8_array_value (); - - OCTAVE_LOCAL_BUFFER (GLubyte, a, 3*(j1-j0)*(i1-i0)); - - for (int i = i0; i < i1; i++) - { - for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3) - { - a[idx] = xcdata(i,j,0); - a[idx+1] = xcdata(i,j,1); - a[idx+2] = xcdata(i,j,2); - } - } - - draw_pixels (j1-j0, i1-i0, GL_RGB, GL_UNSIGNED_BYTE, a); - } - else - warning ("opengl_texture::draw: invalid image data type (expected double, uint16, or uint8)"); - } - else - warning ("opengl_texture::draw: invalid image size (expected n*m*3 or n*m)"); - - glPixelZoom (1, 1); -} - -void -opengl_renderer::set_viewport (int w, int h) -{ - glViewport (0, 0, w, h); -} - -void -opengl_renderer::draw_pixels (GLsizei width, GLsizei height, GLenum format, - GLenum type, const GLvoid *data) -{ - glDrawPixels (width, height, format, type, data); -} - -void -opengl_renderer::set_color (const Matrix& c) -{ - glColor3dv (c.data ()); -#if HAVE_FREETYPE - text_renderer.set_color (c); -#endif -} - -void -opengl_renderer::set_font (const base_properties& props) -{ -#if HAVE_FREETYPE - text_renderer.set_font (props.get ("fontname").string_value (), - props.get ("fontweight").string_value (), - props.get ("fontangle").string_value (), - props.get ("fontsize").double_value ()); -#endif -} - -void -opengl_renderer::set_polygon_offset (bool on, double offset) -{ - if (on) - { - glPolygonOffset (offset, offset); - glEnable (GL_POLYGON_OFFSET_FILL); - glEnable (GL_POLYGON_OFFSET_LINE); - } - else - { - glDisable (GL_POLYGON_OFFSET_FILL); - glDisable (GL_POLYGON_OFFSET_LINE); - } -} - -void -opengl_renderer::set_linewidth (float w) -{ - glLineWidth (w); -} - -void -opengl_renderer::set_linestyle (const std::string& s, bool use_stipple) -{ - bool solid = false; - - if (s == "-") - { - glLineStipple (1, static_cast (0xFFFF)); - solid = true; - } - else if (s == ":") - glLineStipple (1, static_cast (0x8888)); - else if (s == "--") - glLineStipple (1, static_cast (0x0FFF)); - else if (s == "-.") - glLineStipple (1, static_cast (0x020F)); - else - glLineStipple (1, static_cast (0x0000)); - - if (solid && ! use_stipple) - glDisable (GL_LINE_STIPPLE); - else - glEnable (GL_LINE_STIPPLE); -} - -void -opengl_renderer::set_clipbox (double x1, double x2, double y1, double y2, - double z1, double z2) -{ - double dx = (x2-x1); - double dy = (y2-y1); - double dz = (z2-z1); - - x1 -= 0.001*dx; x2 += 0.001*dx; - y1 -= 0.001*dy; y2 += 0.001*dy; - z1 -= 0.001*dz; z2 += 0.001*dz; - - ColumnVector p (4, 0.0); - - p(0) = -1; p(3) = x2; - glClipPlane (GL_CLIP_PLANE0, p.data ()); - p(0) = 1; p(3) = -x1; - glClipPlane (GL_CLIP_PLANE1, p.data ()); - p(0) = 0; p(1) = -1; p(3) = y2; - glClipPlane (GL_CLIP_PLANE2, p.data ()); - p(1) = 1; p(3) = -y1; - glClipPlane (GL_CLIP_PLANE3, p.data ()); - p(1) = 0; p(2) = -1; p(3) = z2; - glClipPlane (GL_CLIP_PLANE4, p.data ()); - p(2) = 1; p(3) = -z1; - glClipPlane (GL_CLIP_PLANE5, p.data ()); - - xmin = x1; xmax = x2; - ymin = y1; ymax = y2; - zmin = z1; zmax = z2; -} - -void -opengl_renderer::set_clipping (bool enable) -{ - bool has_clipping = (glIsEnabled (GL_CLIP_PLANE0) == GL_TRUE); - - if (enable != has_clipping) - { - if (enable) - for (int i = 0; i < 6; i++) - glEnable (GL_CLIP_PLANE0+i); - else - for (int i = 0; i < 6; i++) - glDisable (GL_CLIP_PLANE0+i); - } -} - -void -opengl_renderer::init_marker (const std::string& m, double size, float width) -{ -#if defined (HAVE_FRAMEWORK_OPENGL) - GLint vw[4]; -#else - int vw[4]; -#endif - - glGetIntegerv (GL_VIEWPORT, vw); - - glMatrixMode (GL_PROJECTION); - glPushMatrix (); - glLoadIdentity (); - glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2); - glMatrixMode (GL_MODELVIEW); - glPushMatrix (); - - set_clipping (false); - set_linewidth (width); - - marker_id = make_marker_list (m, size, false); - filled_marker_id = make_marker_list (m, size, true); -} - -void -opengl_renderer::end_marker (void) -{ - glDeleteLists (marker_id, 1); - glDeleteLists (filled_marker_id, 1); - - glMatrixMode (GL_MODELVIEW); - glPopMatrix (); - glMatrixMode (GL_PROJECTION); - glPopMatrix (); - set_linewidth (0.5f); -} - -void -opengl_renderer::draw_marker (double x, double y, double z, - const Matrix& lc, const Matrix& fc) -{ - ColumnVector tmp = xform.transform (x, y, z, false); - - glLoadIdentity (); - glTranslated (tmp(0), tmp(1), -tmp(2)); - - if (filled_marker_id > 0 && fc.numel () > 0) - { - glColor3dv (fc.data ()); - set_polygon_offset (true, -1.0); - glCallList (filled_marker_id); - if (lc.numel () > 0) - { - glColor3dv (lc.data ()); - glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); - glEdgeFlag (GL_TRUE); - set_polygon_offset (true, -2.0); - glCallList (filled_marker_id); - glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); - } - set_polygon_offset (false); - } - else if (marker_id > 0 && lc.numel () > 0) - { - glColor3dv (lc.data ()); - glCallList (marker_id); - } -} - -unsigned int -opengl_renderer::make_marker_list (const std::string& marker, double size, - bool filled) const -{ - char c = marker[0]; - - if (filled && (c == '+' || c == 'x' || c == '*' || c == '.')) - return 0; - - unsigned int ID = glGenLists (1); - double sz = size * toolkit.get_screen_resolution () / 72.0; - - // constants for the * marker - const double sqrt2d4 = 0.35355339059327; - double tt = sz*sqrt2d4; - - glNewList (ID, GL_COMPILE); - - switch (marker[0]) - { - case '+': - glBegin (GL_LINES); - glVertex2f (-sz/2, 0); - glVertex2f (sz/2, 0); - glVertex2f (0, -sz/2); - glVertex2f (0, sz/2); - glEnd (); - break; - case 'x': - glBegin (GL_LINES); - glVertex2f (-sz/2, -sz/2); - glVertex2f (sz/2, sz/2); - glVertex2f (-sz/2, sz/2); - glVertex2f (sz/2, -sz/2); - glEnd (); - break; - case '*': - glBegin (GL_LINES); - glVertex2f (-sz/2, 0); - glVertex2f (sz/2, 0); - glVertex2f (0, -sz/2); - glVertex2f (0, sz/2); - glVertex2f (-tt, -tt); - glVertex2f (+tt, +tt); - glVertex2f (-tt, +tt); - glVertex2f (+tt, -tt); - glEnd (); - break; - case '.': - { - double ang_step = M_PI / 5; - - glBegin (GL_POLYGON); - for (double ang = 0; ang < (2*M_PI); ang += ang_step) - glVertex2d (sz*cos (ang)/3, sz*sin (ang)/3); - glEnd (); - } - break; - case 's': - glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); - glVertex2d (-sz/2, -sz/2); - glVertex2d (-sz/2, sz/2); - glVertex2d (sz/2, sz/2); - glVertex2d (sz/2, -sz/2); - glEnd (); - break; - case 'o': - { - double ang_step = M_PI / 5; - - glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); - for (double ang = 0; ang < (2*M_PI); ang += ang_step) - glVertex2d (sz*cos (ang)/2, sz*sin (ang)/2); - glEnd (); - } - break; - case 'd': - glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); - glVertex2d (0, -sz/2); - glVertex2d (sz/2, 0); - glVertex2d (0, sz/2); - glVertex2d (-sz/2, 0); - glEnd (); - break; - case 'v': - glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); - glVertex2f (0, sz/2); - glVertex2f (sz/2, -sz/2); - glVertex2f (-sz/2, -sz/2); - glEnd (); - break; - case '^': - glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); - glVertex2f (0, -sz/2); - glVertex2f (-sz/2, sz/2); - glVertex2f (sz/2, sz/2); - glEnd (); - break; - case '>': - glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); - glVertex2f (sz/2, 0); - glVertex2f (-sz/2, sz/2); - glVertex2f (-sz/2, -sz/2); - glEnd (); - break; - case '<': - glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); - glVertex2f (-sz/2, 0); - glVertex2f (sz/2, -sz/2); - glVertex2f (sz/2, sz/2); - glEnd (); - break; - case 'p': - { - double ang; - double r; - double dr = 1.0 - sin (M_PI/10)/sin (3*M_PI/10)*1.02; - - glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); - for (int i = 0; i < 2*5; i++) - { - ang = (-0.5 + double(i+1)/5) * M_PI; - r = 1.0 - (dr * fmod (double(i+1), 2.0)); - glVertex2d (sz*r*cos (ang)/2, sz*r*sin (ang)/2); - } - glEnd (); - } - break; - case 'h': - { - double ang; - double r; - double dr = 1.0 - 0.5/sin (M_PI/3)*1.02; - - glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); - for (int i = 0; i < 2*6; i++) - { - ang = (0.5 + double(i+1)/6.0) * M_PI; - r = 1.0 - (dr * fmod (double(i+1), 2.0)); - glVertex2d (sz*r*cos (ang)/2, sz*r*sin (ang)/2); - } - glEnd (); - } - break; - default: - warning ("opengl_renderer: unsupported marker `%s'", - marker.c_str ()); - break; - } - - glEndList (); - - return ID; -} - -void -opengl_renderer::text_to_pixels (const std::string& txt, - uint8NDArray& pixels, - Matrix& bbox, - int halign, int valign, double rotation) -{ -#if HAVE_FREETYPE - text_renderer.text_to_pixels (txt, pixels, bbox, - halign, valign, rotation); -#endif -} - -Matrix -opengl_renderer::render_text (const std::string& txt, - double x, double y, double z, - int halign, int valign, double rotation) -{ -#if HAVE_FREETYPE - if (txt.empty ()) - return Matrix (1, 4, 0.0); - - uint8NDArray pixels; - Matrix bbox; - text_to_pixels (txt, pixels, bbox, halign, valign, rotation); - - bool blend = glIsEnabled (GL_BLEND); - - glEnable (GL_BLEND); - glEnable (GL_ALPHA_TEST); - glRasterPos3d (x, y, z); - glBitmap(0, 0, 0, 0, bbox(0), bbox(1), 0); - glDrawPixels (bbox(2), bbox(3), - GL_RGBA, GL_UNSIGNED_BYTE, pixels.data ()); - glDisable (GL_ALPHA_TEST); - if (! blend) - glDisable (GL_BLEND); - - return bbox; -#else - ::warning ("render_text: cannot render text, Freetype library not available"); - return Matrix (1, 4, 0.0); -#endif -} - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/gl-render.h --- a/src/gl-render.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,211 +0,0 @@ -/* - -Copyright (C) 2008-2012 Michael Goffioul - -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 (gl_render_h) -#define gl_render_h 1 - -#ifdef HAVE_WINDOWS_H -#define WIN32_LEAN_AND_MEAN -#include -#endif - -#ifdef HAVE_GL_GL_H -#include -#elif defined HAVE_OPENGL_GL_H || defined HAVE_FRAMEWORK_OPENGL -#include -#endif - -#ifdef HAVE_GL_GLU_H -#include -#elif defined HAVE_OPENGL_GLU_H || defined HAVE_FRAMEWORK_OPENGL -#include -#endif - -#include "graphics.h" -#include "txt-eng-ft.h" - -class -OCTINTERP_API -opengl_renderer -{ -public: - opengl_renderer (void) - : toolkit (), xform (), xmin (), xmax (), ymin (), ymax (), - zmin (), zmax (), xZ1 (), xZ2 (), marker_id (), filled_marker_id (), - camera_pos (), camera_dir () -#if HAVE_FREETYPE - , text_renderer () -#endif - { } - - virtual ~opengl_renderer (void) { } - - virtual void draw (const graphics_object& go, bool toplevel = true); - - virtual void draw (const Matrix& hlist, bool toplevel = false) - { - int len = hlist.length (); - - for (int i = len-1; i >= 0; i--) - { - graphics_object obj = gh_manager::get_object (hlist(i)); - - if (obj) - draw (obj, toplevel); - } - } - - virtual void set_viewport (int w, int h); - virtual graphics_xform get_transform (void) const { return xform; } - -protected: - virtual void draw_figure (const figure::properties& props); - virtual void draw_axes (const axes::properties& props); - virtual void draw_line (const line::properties& props); - virtual void draw_surface (const surface::properties& props); - virtual void draw_patch (const patch::properties& props); - virtual void draw_hggroup (const hggroup::properties& props); - virtual void draw_text (const text::properties& props); - virtual void draw_image (const image::properties& props); - virtual void draw_uipanel (const uipanel::properties& props, - const graphics_object& go); - - virtual void init_gl_context (bool enhanced, const Matrix& backgroundColor); - virtual void setup_opengl_transformation (const axes::properties& props); - - virtual void set_color (const Matrix& c); - virtual void set_polygon_offset (bool on, double offset = 0.0); - virtual void set_linewidth (float w); - virtual void set_linestyle (const std::string& s, bool stipple = false); - virtual void set_clipbox (double x1, double x2, double y1, double y2, - double z1, double z2); - virtual void set_clipping (bool on); - virtual void set_font (const base_properties& props); - - virtual void init_marker (const std::string& m, double size, float width); - virtual void end_marker (void); - virtual void draw_marker (double x, double y, double z, - const Matrix& lc, const Matrix& fc); - - virtual void text_to_pixels (const std::string& txt, - uint8NDArray& pixels, - Matrix& bbox, - int halign = 0, int valign = 0, - double rotation = 0.0); - - virtual Matrix render_text (const std::string& txt, - double x, double y, double z, - int halign, int valign, double rotation = 0.0); - - virtual void draw_pixels (GLsizei w, GLsizei h, GLenum format, - GLenum type, const GLvoid *data); - - virtual void render_grid (const std::string& gridstyle, const Matrix& ticks, - double lim1, double lim2, - double p1, double p1N, double p2, double p2N, - int xyz, bool is_3D); - - virtual void render_tickmarks (const Matrix& ticks, double lim1, double lim2, - double p1, double p1N, double p2, double p2N, - double dx, double dy, double dz, - int xyz, bool doubleside); - - virtual void render_ticktexts (const Matrix& ticks, - const string_vector& ticklabels, - double lim1, double lim2, - double p1, double p2, - int xyz, int ha, int va, - int& wmax, int& hmax); - -private: - opengl_renderer (const opengl_renderer&) - : toolkit (), xform (), xmin (), xmax (), ymin (), ymax (), - zmin (), zmax (), xZ1 (), xZ2 (), marker_id (), filled_marker_id (), - camera_pos (), camera_dir () -#if HAVE_FREETYPE - , text_renderer () -#endif - { } - - opengl_renderer& operator = (const opengl_renderer&) - { return *this; } - - bool is_nan_or_inf (double x, double y, double z) const - { - return (xisnan (x) || xisnan (y) || xisnan (z) - || xisinf (x) || xisinf (y) || xisinf (z)); - } - - octave_uint8 clip_code (double x, double y, double z) const - { - return ((x < xmin ? 1 : 0) - | (x > xmax ? 1 : 0) << 1 - | (y < ymin ? 1 : 0) << 2 - | (y > ymax ? 1 : 0) << 3 - | (z < zmin ? 1 : 0) << 4 - | (z > zmax ? 1 : 0) << 5 - | (is_nan_or_inf (x, y, z) ? 0 : 1) << 6); - } - - unsigned int make_marker_list (const std::string& m, double size, - bool filled) const; - - void draw_axes_planes (const axes::properties& props); - void draw_axes_boxes (const axes::properties& props); - - void draw_axes_x_grid (const axes::properties& props); - void draw_axes_y_grid (const axes::properties& props); - void draw_axes_z_grid (const axes::properties& props); - - void draw_axes_children (const axes::properties& props); - -private: - // The graphics toolkit associated with the figure being rendered. - graphics_toolkit toolkit; - - // axes transformation data - graphics_xform xform; - - // axis limits in model scaled coordinate - double xmin, xmax; - double ymin, ymax; - double zmin, zmax; - - // Z projection limits in windows coordinate - double xZ1, xZ2; - - // call lists identifiers for markers - unsigned int marker_id, filled_marker_id; - - // camera information for primitive sorting - ColumnVector camera_pos, camera_dir; - -#if HAVE_FREETYPE - // freetype render, used for text rendering - ft_render text_renderer; -#endif - -private: - class patch_tesselator; -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/gl2ps-renderer.cc --- a/src/gl2ps-renderer.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,232 +0,0 @@ -/* - -Copyright (C) 2009-2012 Shai Ayal - -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 -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#if defined (HAVE_OPENGL) - -#include - -#include "lo-mappers.h" -#include "oct-locbuf.h" - -#include "gl2ps-renderer.h" -#include "gl2ps.h" - -void -glps_renderer::draw (const graphics_object& go) -{ - static bool in_draw = false; - - if (!in_draw) - { - in_draw = true; - - GLint buffsize = 0, state = GL2PS_OVERFLOW; - GLint viewport[4]; - - glGetIntegerv (GL_VIEWPORT, viewport); - - GLint gl2ps_term; - if (term.find ("eps") != std::string::npos) gl2ps_term = GL2PS_EPS; - else if (term.find ("pdf") != std::string::npos) gl2ps_term = GL2PS_PDF; - else if (term.find ("svg") != std::string::npos) gl2ps_term = GL2PS_SVG; - else if (term.find ("ps") != std::string::npos) gl2ps_term = GL2PS_PS; - else if (term.find ("pgf") != std::string::npos) gl2ps_term = GL2PS_PGF; - else if (term.find ("tex") != std::string::npos) gl2ps_term = GL2PS_TEX; - else - { - error ("gl2ps-renderer:: Unknown terminal"); - return; - } - - GLint gl2ps_text = 0; - if (term.find ("notxt") != std::string::npos) gl2ps_text = GL2PS_NO_TEXT; - - // Default sort order optimizes for 3D plots - GLint gl2ps_sort = GL2PS_BSP_SORT; - if (term.find ("is2D") != std::string::npos) gl2ps_sort = GL2PS_NO_SORT; - - while (state == GL2PS_OVERFLOW) - { - buffsize += 1024*1024; - gl2psBeginPage ("glps_renderer figure", "Octave", viewport, - gl2ps_term, gl2ps_sort, - (GL2PS_SILENT | GL2PS_SIMPLE_LINE_OFFSET - | GL2PS_NO_BLENDING | GL2PS_OCCLUSION_CULL - | GL2PS_BEST_ROOT | gl2ps_text - | GL2PS_NO_PS3_SHADING), - GL_RGBA, 0, NULL, 0, 0, 0, - buffsize, fp, "" ); - - opengl_renderer::draw (go); - state = gl2psEndPage (); - } - - in_draw = 0; - } - else - opengl_renderer::draw (go); -} - -int -glps_renderer::alignment_to_mode (int ha, int va) const -{ - int gl2psa=GL2PS_TEXT_BL; - if (ha == 0) - { - if (va == 0 || va == 3) - gl2psa=GL2PS_TEXT_BL; - else if (va == 2) - gl2psa=GL2PS_TEXT_TL; - else if (va == 1) - gl2psa=GL2PS_TEXT_CL; - } - else if (ha == 2) - { - if (va == 0 || va == 3) - gl2psa=GL2PS_TEXT_BR; - else if (va == 2) - gl2psa=GL2PS_TEXT_TR; - else if (va == 1) - gl2psa=GL2PS_TEXT_CR; - } - else if (ha == 1) - { - if (va == 0 || va == 3) - gl2psa=GL2PS_TEXT_B; - else if (va == 2) - gl2psa=GL2PS_TEXT_T; - else if (va == 1) - gl2psa=GL2PS_TEXT_C; - } - return gl2psa; -} - -Matrix -glps_renderer::render_text (const std::string& txt, - double x, double y, double z, - int ha, int va, double rotation) -{ - if (txt.empty ()) - return Matrix (1, 4, 0.0); - - glRasterPos3d (x, y, z); - gl2psTextOpt (txt.c_str (), fontname.c_str (), fontsize, - alignment_to_mode (ha, va), rotation); - - // FIXME? -- we have no way of getting a bounding box from gl2ps, so - // we use freetype - Matrix bbox; - uint8NDArray pixels; - text_to_pixels (txt, pixels, bbox, 0, 0, rotation); - return bbox; -} - -void -glps_renderer::set_font (const base_properties& props) -{ - opengl_renderer::set_font (props); - - fontsize = props.get ("fontsize").double_value (); - - caseless_str fn = props.get ("fontname").string_value (); - fontname = ""; - if (fn == "times" || fn == "times-roman") - fontname = "Times-Roman"; - else if (fn == "courier") - fontname = "Courier"; - else if (fn == "symbol") - fontname = "Symbol"; - else if (fn == "zapfdingbats") - fontname = "ZapfDingbats"; - else - fontname = "Helvetica"; - - // FIXME -- add support for bold and italic -} - -template -static void -draw_pixels (GLsizei w, GLsizei h, GLenum format, const T *data) -{ - OCTAVE_LOCAL_BUFFER (GLfloat, a, 3*w*h); - - for (int i = 0; i < 3*w*h; i++) - a[i] = data[i]; - - gl2psDrawPixels (w, h, 0, 0, format, GL_FLOAT, a); -} - -void -glps_renderer::draw_pixels (GLsizei w, GLsizei h, GLenum format, - GLenum type, const GLvoid *data) -{ - if (type == GL_UNSIGNED_SHORT) - ::draw_pixels (w, h, format, static_cast (data)); - else if (type == GL_UNSIGNED_BYTE) - ::draw_pixels (w, h, format, static_cast (data)); - else - gl2psDrawPixels (w, h, 0, 0, format, type, data); -} - -void -glps_renderer::draw_text (const text::properties& props) -{ - if (props.get_string ().is_empty ()) - return; - - set_font (props); - set_color (props.get_color_rgb ()); - - const Matrix pos = get_transform ().scale (props.get_data_position ()); - int halign = 0, valign = 0; - - if (props.horizontalalignment_is ("center")) - halign = 1; - else if (props.horizontalalignment_is ("right")) - halign = 2; - - if (props.verticalalignment_is ("top")) - valign = 2; - else if (props.verticalalignment_is ("baseline")) - valign = 3; - else if (props.verticalalignment_is ("middle")) - valign = 1; - - // FIXME: handle margin and surrounding box - - glRasterPos3d (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0); - - 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 a132d206a36a -r b9b6a310ad97 src/gl2ps-renderer.h --- a/src/gl2ps-renderer.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - -Copyright (C) 2009-2012 Shai Ayal - -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 (gl2ps_renderer_h) -#define gl2ps_renderer_h 1 - -#include "gl-render.h" -#include "gl2ps.h" - -class -OCTINTERP_API -glps_renderer : public opengl_renderer -{ -public: - glps_renderer (FILE *_fp, const std::string& _term) - : opengl_renderer () , fp (_fp), term (_term), - fontsize (), fontname () { } - - ~glps_renderer (void) { } - - void draw (const graphics_object& go); - -protected: - - Matrix render_text (const std::string& txt, - double x, double y, double z, - int halign, int valign, double rotation = 0.0); - - - void set_font (const base_properties& props); - - void draw_text (const text::properties& props); - void draw_pixels (GLsizei w, GLsizei h, GLenum format, - GLenum type, const GLvoid *data); - - void set_linestyle (const std::string& s, bool use_stipple = false) - { - opengl_renderer::set_linestyle (s, use_stipple); - - if (s == "-" && ! use_stipple) - gl2psDisable (GL2PS_LINE_STIPPLE); - else - gl2psEnable (GL2PS_LINE_STIPPLE); - } - - void set_polygon_offset (bool on, double offset = 0.0) - { - opengl_renderer::set_polygon_offset (on, offset); - if (on) - gl2psEnable (GL2PS_POLYGON_OFFSET_FILL); - else - gl2psDisable (GL2PS_POLYGON_OFFSET_FILL); - } - - void set_linewidth (float w) - { - gl2psLineWidth (w); - } - -private: - int alignment_to_mode (int ha, int va) const; - FILE *fp; - caseless_str term; - double fontsize; - std::string fontname; -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/gl2ps.c --- a/src/gl2ps.c Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6078 +0,0 @@ -/* - * GL2PS, an OpenGL to PostScript Printing Library - * Copyright (C) 1999-2011 C. Geuzaine - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of either: - * - * a) the GNU Library General Public License as published by the Free - * Software Foundation, either version 2 of the License, or (at your - * option) any later version; or - * - * b) the GL2PS License as published by Christophe Geuzaine, either - * version 2 of the License, or (at your option) any later version. - * - * This program 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 either - * the GNU Library General Public License or the GL2PS License for - * more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library in the file named "COPYING.LGPL"; - * if not, write to the Free Software Foundation, Inc., 675 Mass Ave, - * Cambridge, MA 02139, USA. - * - * You should have received a copy of the GL2PS License with this - * library in the file named "COPYING.GL2PS"; if not, I will be glad - * to provide one. - * - * For the latest info about gl2ps and a full list of contributors, - * see http://www.geuz.org/gl2ps/. - * - * Please report all bugs and problems to . - */ - -#include "gl2ps.h" - -#include -#include -#include -#include -#include -#include - -#if defined(GL2PS_HAVE_ZLIB) -#include -#endif - -#if defined(GL2PS_HAVE_LIBPNG) -#include -#endif - -/********************************************************************* - * - * Private definitions, data structures and prototypes - * - *********************************************************************/ - -/* Magic numbers (assuming that the order of magnitude of window - coordinates is 10^3) */ - -#define GL2PS_EPSILON 5.0e-3F -#define GL2PS_ZSCALE 1000.0F -#define GL2PS_ZOFFSET 5.0e-2F -#define GL2PS_ZOFFSET_LARGE 20.0F -#define GL2PS_ZERO(arg) (fabs(arg) < 1.e-20) - -/* Primitive types */ - -#define GL2PS_NO_TYPE -1 -#define GL2PS_TEXT 1 -#define GL2PS_POINT 2 -#define GL2PS_LINE 3 -#define GL2PS_QUADRANGLE 4 -#define GL2PS_TRIANGLE 5 -#define GL2PS_PIXMAP 6 -#define GL2PS_IMAGEMAP 7 -#define GL2PS_IMAGEMAP_WRITTEN 8 -#define GL2PS_IMAGEMAP_VISIBLE 9 -#define GL2PS_SPECIAL 10 - -/* BSP tree primitive comparison */ - -#define GL2PS_COINCIDENT 1 -#define GL2PS_IN_FRONT_OF 2 -#define GL2PS_IN_BACK_OF 3 -#define GL2PS_SPANNING 4 - -/* 2D BSP tree primitive comparison */ - -#define GL2PS_POINT_COINCIDENT 0 -#define GL2PS_POINT_INFRONT 1 -#define GL2PS_POINT_BACK 2 - -/* Internal feedback buffer pass-through tokens */ - -#define GL2PS_BEGIN_OFFSET_TOKEN 1 -#define GL2PS_END_OFFSET_TOKEN 2 -#define GL2PS_BEGIN_BOUNDARY_TOKEN 3 -#define GL2PS_END_BOUNDARY_TOKEN 4 -#define GL2PS_BEGIN_STIPPLE_TOKEN 5 -#define GL2PS_END_STIPPLE_TOKEN 6 -#define GL2PS_POINT_SIZE_TOKEN 7 -#define GL2PS_LINE_WIDTH_TOKEN 8 -#define GL2PS_BEGIN_BLEND_TOKEN 9 -#define GL2PS_END_BLEND_TOKEN 10 -#define GL2PS_SRC_BLEND_TOKEN 11 -#define GL2PS_DST_BLEND_TOKEN 12 -#define GL2PS_IMAGEMAP_TOKEN 13 -#define GL2PS_DRAW_PIXELS_TOKEN 14 -#define GL2PS_TEXT_TOKEN 15 - -typedef enum { - T_UNDEFINED = -1, - T_CONST_COLOR = 1, - T_VAR_COLOR = 1<<1, - T_ALPHA_1 = 1<<2, - T_ALPHA_LESS_1 = 1<<3, - T_VAR_ALPHA = 1<<4 -} GL2PS_TRIANGLE_PROPERTY; - -typedef GLfloat GL2PSxyz[3]; -typedef GLfloat GL2PSplane[4]; - -typedef struct _GL2PSbsptree2d GL2PSbsptree2d; - -struct _GL2PSbsptree2d { - GL2PSplane plane; - GL2PSbsptree2d *front, *back; -}; - -typedef struct { - GLint nmax, size, incr, n; - char *array; -} GL2PSlist; - -typedef struct _GL2PSbsptree GL2PSbsptree; - -struct _GL2PSbsptree { - GL2PSplane plane; - GL2PSlist *primitives; - GL2PSbsptree *front, *back; -}; - -typedef struct { - GL2PSxyz xyz; - GL2PSrgba rgba; -} GL2PSvertex; - -typedef struct { - GL2PSvertex vertex[3]; - int prop; -} GL2PStriangle; - -typedef struct { - GLshort fontsize; - char *str, *fontname; - /* Note: for a 'special' string, 'alignment' holds the format - (PostScript, PDF, etc.) of the special string */ - GLint alignment; - GLfloat angle; -} GL2PSstring; - -typedef struct { - GLsizei width, height; - /* Note: for an imagemap, 'type' indicates if it has already been - 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; - -typedef struct _GL2PSimagemap GL2PSimagemap; - -struct _GL2PSimagemap { - GL2PSimage *image; - GL2PSimagemap *next; -}; - -typedef struct { - GLshort type, numverts; - GLushort pattern; - char boundary, offset, culled; - GLint factor; - GLfloat width; - GL2PSvertex *verts; - union { - GL2PSstring *text; - GL2PSimage *image; - } data; -} GL2PSprimitive; - -typedef struct { -#if defined(GL2PS_HAVE_ZLIB) - Bytef *dest, *src, *start; - uLongf destLen, srcLen; -#else - int dummy; -#endif -} GL2PScompress; - -typedef struct{ - GL2PSlist* ptrlist; - int gsno, fontno, imno, shno, maskshno, trgroupno; - int gsobjno, fontobjno, imobjno, shobjno, maskshobjno, trgroupobjno; -} GL2PSpdfgroup; - -typedef struct { - /* General */ - GLint format, sort, options, colorsize, colormode, buffersize; - char *title, *producer, *filename; - GLboolean boundary, blending; - GLfloat *feedback, offset[2], lastlinewidth; - GLint viewport[4], blendfunc[2], lastfactor; - GL2PSrgba *colormap, lastrgba, threshold, bgcolor; - GLushort lastpattern; - GL2PSvertex lastvertex; - GL2PSlist *primitives, *auxprimitives; - FILE *stream; - GL2PScompress *compress; - GLboolean header; - - /* BSP-specific */ - GLint maxbestroot; - - /* Occlusion culling-specific */ - GLboolean zerosurfacearea; - GL2PSbsptree2d *imagetree; - GL2PSprimitive *primitivetoadd; - - /* PDF-specific */ - int streamlength; - GL2PSlist *pdfprimlist, *pdfgrouplist; - int *xreflist; - int objects_stack; /* available objects */ - int extgs_stack; /* graphics state object number */ - int font_stack; /* font object number */ - int im_stack; /* image object number */ - int trgroupobjects_stack; /* xobject numbers */ - int shader_stack; /* shader object numbers */ - int mshader_stack; /* mask shader object numbers */ - - /* for image map list */ - GL2PSimagemap *imagemap_head; - GL2PSimagemap *imagemap_tail; -} GL2PScontext; - -typedef struct { - void (*printHeader)(void); - void (*printFooter)(void); - void (*beginViewport)(GLint viewport[4]); - GLint (*endViewport)(void); - void (*printPrimitive)(void *data); - void (*printFinalPrimitive)(void); - const char *file_extension; - const char *description; -} GL2PSbackend; - -/* The gl2ps context. gl2ps is not thread safe (we should create a - local GL2PScontext during gl2psBeginPage) */ - -static GL2PScontext *gl2ps = NULL; - -/* Need to forward-declare this one */ - -static GLint gl2psPrintPrimitives(void); - -/********************************************************************* - * - * Utility routines - * - *********************************************************************/ - -static void gl2psMsg(GLint level, const char *fmt, ...) -{ - va_list args; - - if(!(gl2ps->options & GL2PS_SILENT)){ - switch(level){ - case GL2PS_INFO : fprintf(stderr, "GL2PS info: "); break; - case GL2PS_WARNING : fprintf(stderr, "GL2PS warning: "); break; - case GL2PS_ERROR : fprintf(stderr, "GL2PS error: "); break; - } - va_start(args, fmt); - vfprintf(stderr, fmt, args); - va_end(args); - fprintf(stderr, "\n"); - } - /* if(level == GL2PS_ERROR) exit(1); */ -} - -static void *gl2psMalloc(size_t size) -{ - void *ptr; - - if(!size) return NULL; - ptr = malloc(size); - if(!ptr){ - gl2psMsg(GL2PS_ERROR, "Couldn't allocate requested memory"); - return NULL; - } - return ptr; -} - -static void *gl2psRealloc(void *ptr, size_t size) -{ - void *orig = ptr; - if(!size) return NULL; - ptr = realloc(orig, size); - if(!ptr){ - gl2psMsg(GL2PS_ERROR, "Couldn't reallocate requested memory"); - free(orig); - return NULL; - } - return ptr; -} - -static void gl2psFree(void *ptr) -{ - if(!ptr) return; - free(ptr); -} - -static int gl2psWriteBigEndian(unsigned long data, int bytes) -{ - int i; - int size = sizeof(unsigned long); - for(i = 1; i <= bytes; ++i){ - fputc(0xff & (data >> (size - i) * 8), gl2ps->stream); - } - return bytes; -} - -/* zlib compression helper routines */ - -#if defined(GL2PS_HAVE_ZLIB) - -static void gl2psSetupCompress(void) -{ - gl2ps->compress = (GL2PScompress*)gl2psMalloc(sizeof(GL2PScompress)); - gl2ps->compress->src = NULL; - gl2ps->compress->start = NULL; - gl2ps->compress->dest = NULL; - gl2ps->compress->srcLen = 0; - gl2ps->compress->destLen = 0; -} - -static void gl2psFreeCompress(void) -{ - if(!gl2ps->compress) - return; - gl2psFree(gl2ps->compress->start); - gl2psFree(gl2ps->compress->dest); - gl2ps->compress->src = NULL; - gl2ps->compress->start = NULL; - gl2ps->compress->dest = NULL; - gl2ps->compress->srcLen = 0; - gl2ps->compress->destLen = 0; -} - -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; -} - -static void *gl2psReallocCompress(unsigned int srcsize) -{ - 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->srcLen); - gl2ps->compress->start = gl2ps->compress->src; - gl2ps->compress->dest = (Bytef*)gl2psRealloc(gl2ps->compress->dest, - gl2ps->compress->destLen); - - return gl2ps->compress->start; -} - -static int gl2psWriteBigEndianCompress(unsigned long data, int bytes) -{ - int i; - int size = sizeof(unsigned long); - for(i = 1; i <= bytes; ++i){ - *gl2ps->compress->src = (Bytef)(0xff & (data >> (size-i) * 8)); - ++gl2ps->compress->src; - } - return bytes; -} - -static int gl2psDeflate(void) -{ - /* 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); -} - -#endif - -static int gl2psPrintf(const char* fmt, ...) -{ - int ret; - va_list args; - -#if defined(GL2PS_HAVE_ZLIB) - unsigned int oldsize = 0; - static char buf[1000]; - if(gl2ps->options & GL2PS_COMPRESS){ - va_start(args, fmt); - ret = vsprintf(buf, fmt, args); - va_end(args); - oldsize = gl2ps->compress->srcLen; - gl2ps->compress->start = (Bytef*)gl2psReallocCompress(oldsize + ret); - memcpy(gl2ps->compress->start+oldsize, buf, ret); - ret = 0; - } - else{ -#endif - va_start(args, fmt); - ret = vfprintf(gl2ps->stream, fmt, args); - va_end(args); -#if defined(GL2PS_HAVE_ZLIB) - } -#endif - return ret; -} - -static void gl2psPrintGzipHeader(void) -{ -#if defined(GL2PS_HAVE_ZLIB) - char tmp[10] = {'\x1f', '\x8b', /* magic numbers: 0x1f, 0x8b */ - 8, /* compression method: Z_DEFLATED */ - 0, /* flags */ - 0, 0, 0, 0, /* time */ - 2, /* extra flags: max compression */ - '\x03'}; /* OS code: 0x03 (Unix) */ - - if(gl2ps->options & GL2PS_COMPRESS){ - gl2psSetupCompress(); - /* add the gzip file header */ - fwrite(tmp, 10, 1, gl2ps->stream); - } -#endif -} - -static void gl2psPrintGzipFooter(void) -{ -#if defined(GL2PS_HAVE_ZLIB) - int n; - uLong crc, len; - char tmp[8]; - - if(gl2ps->options & GL2PS_COMPRESS){ - if(Z_OK != gl2psDeflate()){ - gl2psMsg(GL2PS_ERROR, "Zlib deflate error"); - } - else{ - /* determine the length of the header in the zlib stream */ - n = 2; /* CMF+FLG */ - if(gl2ps->compress->dest[1] & (1<<5)){ - n += 4; /* DICTID */ - } - /* write the data, without the zlib header and footer */ - 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); - for(n = 0; n < 4; ++n){ - tmp[n] = (char)(crc & 0xff); - crc >>= 8; - } - len = gl2ps->compress->srcLen; - for(n = 4; n < 8; ++n){ - tmp[n] = (char)(len & 0xff); - len >>= 8; - } - fwrite(tmp, 8, 1, gl2ps->stream); - } - gl2psFreeCompress(); - gl2psFree(gl2ps->compress); - gl2ps->compress = NULL; - } -#endif -} - -/* The list handling routines */ - -static void gl2psListRealloc(GL2PSlist *list, GLint n) -{ - if(!list){ - gl2psMsg(GL2PS_ERROR, "Cannot reallocate NULL list"); - return; - } - if(n <= 0) return; - if(!list->array){ - list->nmax = n; - list->array = (char*)gl2psMalloc(list->nmax * list->size); - } - else{ - if(n > list->nmax){ - list->nmax = ((n - 1) / list->incr + 1) * list->incr; - list->array = (char*)gl2psRealloc(list->array, - list->nmax * list->size); - } - } -} - -static GL2PSlist *gl2psListCreate(GLint n, GLint incr, GLint size) -{ - GL2PSlist *list; - - if(n < 0) n = 0; - if(incr <= 0) incr = 1; - list = (GL2PSlist*)gl2psMalloc(sizeof(GL2PSlist)); - list->nmax = 0; - list->incr = incr; - list->size = size; - list->n = 0; - list->array = NULL; - gl2psListRealloc(list, n); - return list; -} - -static void gl2psListReset(GL2PSlist *list) -{ - if(!list) return; - list->n = 0; -} - -static void gl2psListDelete(GL2PSlist *list) -{ - if(!list) return; - gl2psFree(list->array); - gl2psFree(list); -} - -static void gl2psListAdd(GL2PSlist *list, void *data) -{ - if(!list){ - gl2psMsg(GL2PS_ERROR, "Cannot add into unallocated list"); - return; - } - list->n++; - gl2psListRealloc(list, list->n); - memcpy(&list->array[(list->n - 1) * list->size], data, list->size); -} - -static int gl2psListNbr(GL2PSlist *list) -{ - if(!list) - return 0; - return list->n; -} - -static void *gl2psListPointer(GL2PSlist *list, GLint index) -{ - if(!list){ - gl2psMsg(GL2PS_ERROR, "Cannot point into unallocated list"); - return NULL; - } - if((index < 0) || (index >= list->n)){ - gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListPointer"); - return NULL; - } - return &list->array[index * list->size]; -} - -static void gl2psListSort(GL2PSlist *list, - int (*fcmp)(const void *a, const void *b)) -{ - if(!list) - return; - qsort(list->array, list->n, list->size, fcmp); -} - -static void gl2psListAction(GL2PSlist *list, void (*action)(void *data)) -{ - GLint i; - - for(i = 0; i < gl2psListNbr(list); i++){ - (*action)(gl2psListPointer(list, i)); - } -} - -static void gl2psListActionInverse(GL2PSlist *list, void (*action)(void *data)) -{ - GLint i; - - for(i = gl2psListNbr(list); i > 0; i--){ - (*action)(gl2psListPointer(list, i-1)); - } -} - -#if defined(GL2PS_HAVE_LIBPNG) - -static void gl2psListRead(GL2PSlist *list, int index, void *data) -{ - if((index < 0) || (index >= list->n)) - gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListRead"); - memcpy(data, &list->array[index * list->size], list->size); -} - -static void gl2psEncodeBase64Block(unsigned char in[3], unsigned char out[4], int len) -{ - static const char cb64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - out[0] = cb64[ in[0] >> 2 ]; - out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ]; - out[2] = (len > 1) ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '='; - out[3] = (len > 2) ? cb64[ in[2] & 0x3f ] : '='; -} - -static void gl2psListEncodeBase64(GL2PSlist *list) -{ - unsigned char *buffer, in[3], out[4]; - int i, n, index, len; - - n = list->n * list->size; - buffer = (unsigned char*)gl2psMalloc(n * sizeof(unsigned char)); - memcpy(buffer, list->array, n * sizeof(unsigned char)); - gl2psListReset(list); - - index = 0; - while(index < n) { - len = 0; - for(i = 0; i < 3; i++) { - if(index < n){ - in[i] = buffer[index]; - len++; - } - else{ - in[i] = 0; - } - index++; - } - if(len) { - gl2psEncodeBase64Block(in, out, len); - for(i = 0; i < 4; i++) - gl2psListAdd(list, &out[i]); - } - } - gl2psFree(buffer); -} - -#endif - -/* Helpers for rgba colors */ - -static GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2) -{ - if(!GL2PS_ZERO(rgba1[0] - rgba2[0]) || - !GL2PS_ZERO(rgba1[1] - rgba2[1]) || - !GL2PS_ZERO(rgba1[2] - rgba2[2])) - return GL_FALSE; - return GL_TRUE; -} - -static GLboolean gl2psVertsSameColor(const GL2PSprimitive *prim) -{ - int i; - - for(i = 1; i < prim->numverts; i++){ - if(!gl2psSameColor(prim->verts[0].rgba, prim->verts[i].rgba)){ - return GL_FALSE; - } - } - return GL_TRUE; -} - -static GLboolean gl2psSameColorThreshold(int n, GL2PSrgba rgba[], - GL2PSrgba threshold) -{ - 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; - for(i = 0; i < 3; ++i){ - gl2ps->lastrgba[i] = rgba[i]; - } -} - -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 */ - switch(im->format){ - case GL_RGBA: - pimag = pixels + 4 * (width * (height - 1 - y) + x); - break; - case GL_RGB: - default: - pimag = pixels + 3 * (width * (height - 1 - y) + x); - break; - } - *red = *pimag; pimag++; - *green = *pimag; pimag++; - *blue = *pimag; pimag++; - - return (im->format == GL_RGBA) ? *pimag : 1.0F; -} - -/* Helper routines for pixmaps */ - -static GL2PSimage *gl2psCopyPixmap(GL2PSimage *im) -{ - 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: - size = image->height * image->width * 4 * sizeof(GLfloat); - break; - case GL_RGB: - default: - size = image->height * image->width * 3 * sizeof(GLfloat); - break; - } - - image->pixels = (GLfloat*)gl2psMalloc(size); - memcpy(image->pixels, im->pixels, size); - - return image; -} - -static void gl2psFreePixmap(GL2PSimage *im) -{ - if(!im) - return; - gl2psFree(im->pixels); - gl2psFree(im); -} - -#if defined(GL2PS_HAVE_LIBPNG) - -#if !defined(png_jmpbuf) -# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) -#endif - -static void gl2psUserWritePNG(png_structp png_ptr, png_bytep data, png_size_t length) -{ - unsigned int i; - GL2PSlist *png = (GL2PSlist*)png_get_io_ptr(png_ptr); - for(i = 0; i < length; i++) - gl2psListAdd(png, &data[i]); -} - -static void gl2psUserFlushPNG(png_structp png_ptr) -{ - (void) png_ptr; /* not used */ -} - -static void gl2psConvertPixmapToPNG(GL2PSimage *pixmap, GL2PSlist *png) -{ - png_structp png_ptr; - png_infop info_ptr; - unsigned char *row_data; - GLfloat dr, dg, db; - int row, col; - - 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_FILTER_TYPE_BASE); - png_write_info(png_ptr, info_ptr); - - row_data = (unsigned char*)gl2psMalloc(3 * pixmap->width * sizeof(unsigned char)); - for(row = 0; row < pixmap->height; row++){ - for(col = 0; col < pixmap->width; col++){ - gl2psGetRGB(pixmap, col, row, &dr, &dg, &db); - row_data[3*col] = (unsigned char)(255. * dr); - row_data[3*col+1] = (unsigned char)(255. * dg); - row_data[3*col+2] = (unsigned char)(255. * db); - } - png_write_row(png_ptr, (png_bytep)row_data); - } - gl2psFree(row_data); - - png_write_end(png_ptr, info_ptr); - png_destroy_write_struct(&png_ptr, &info_ptr); -} - -#endif - -/* Helper routines for text strings */ - -static GLint gl2psAddText(GLint type, const char *str, const char *fontname, - GLshort fontsize, GLint alignment, GLfloat angle) -{ - GLfloat pos[4]; - GL2PSprimitive *prim; - GLboolean valid; - - if(!gl2ps || !str || !fontname) return GL2PS_UNINITIALIZED; - - if(gl2ps->options & GL2PS_NO_TEXT) return GL2PS_SUCCESS; - - glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid); - if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */ - - glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); - - prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); - prim->type = type; - prim->boundary = 0; - prim->numverts = 1; - prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex)); - prim->verts[0].xyz[0] = pos[0]; - prim->verts[0].xyz[1] = pos[1]; - prim->verts[0].xyz[2] = pos[2]; - prim->culled = 0; - prim->offset = 0; - prim->pattern = 0; - prim->factor = 0; - prim->width = 1; - 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); - prim->data.text->fontname = (char*)gl2psMalloc((strlen(fontname)+1)*sizeof(char)); - strcpy(prim->data.text->fontname, fontname); - prim->data.text->fontsize = fontsize; - prim->data.text->alignment = alignment; - prim->data.text->angle = angle; - - gl2psListAdd(gl2ps->auxprimitives, &prim); - glPassThrough(GL2PS_TEXT_TOKEN); - - return GL2PS_SUCCESS; -} - -static GL2PSstring *gl2psCopyText(GL2PSstring *t) -{ - GL2PSstring *text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring)); - text->str = (char*)gl2psMalloc((strlen(t->str)+1)*sizeof(char)); - 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; -} - -static void gl2psFreeText(GL2PSstring *text) -{ - if(!text) - return; - gl2psFree(text->str); - gl2psFree(text->fontname); - gl2psFree(text); -} - -/* Helpers for blending modes */ - -static GLboolean gl2psSupportedBlendMode(GLenum sfactor, GLenum dfactor) -{ - /* 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) || - (sfactor == GL_ONE && dfactor == GL_ZERO) ) - return GL_TRUE; - return GL_FALSE; -} - -static void gl2psAdaptVertexForBlending(GL2PSvertex *v) -{ - /* Transforms vertex depending on the actual blending function - - currently the vertex v is considered as source vertex and his - alpha value is changed to 1.0 if source blending GL_ONE is - active. This might be extended in the future */ - - if(!v || !gl2ps) - return; - - if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){ - v->rgba[3] = 1.0F; - return; - } - - switch(gl2ps->blendfunc[0]){ - case GL_ONE: - v->rgba[3] = 1.0F; - break; - default: - break; - } -} - -static void gl2psAssignTriangleProperties(GL2PStriangle *t) -{ - /* int i; */ - - t->prop = T_VAR_COLOR; - - /* Uncommenting the following lines activates an even more fine - grained distinction between triangle types - please don't delete, - a remarkable amount of PDF handling code inside this file depends - on it if activated */ - /* - t->prop = T_CONST_COLOR; - for(i = 0; i < 3; ++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; - } - } - */ - - 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; - } - else{ - if(t->vertex[0].rgba[3] < 1) - t->prop |= T_ALPHA_LESS_1; - else - t->prop |= T_ALPHA_1; - } -} - -static void gl2psFillTriangleFromPrimitive(GL2PStriangle *t, GL2PSprimitive *p, - GLboolean assignprops) -{ - t->vertex[0] = p->verts[0]; - t->vertex[1] = p->verts[1]; - t->vertex[2] = p->verts[2]; - if(GL_TRUE == assignprops) - gl2psAssignTriangleProperties(t); -} - -static void gl2psInitTriangle(GL2PStriangle *t) -{ - int i; - GL2PSvertex vertex = { {-1.0F, -1.0F, -1.0F}, {-1.0F, -1.0F, -1.0F, -1.0F} }; - for(i = 0; i < 3; i++) - t->vertex[i] = vertex; - t->prop = T_UNDEFINED; -} - -/* Miscellaneous helper routines */ - -static GL2PSprimitive *gl2psCopyPrimitive(GL2PSprimitive *p) -{ - GL2PSprimitive *prim; - - if(!p){ - gl2psMsg(GL2PS_ERROR, "Trying to copy an empty primitive"); - return NULL; - } - - prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); - - prim->type = p->type; - prim->numverts = p->numverts; - prim->boundary = p->boundary; - prim->offset = p->offset; - prim->pattern = p->pattern; - prim->factor = p->factor; - prim->culled = p->culled; - prim->width = p->width; - prim->verts = (GL2PSvertex*)gl2psMalloc(p->numverts*sizeof(GL2PSvertex)); - memcpy(prim->verts, p->verts, p->numverts * sizeof(GL2PSvertex)); - - switch(prim->type){ - case GL2PS_PIXMAP : - prim->data.image = gl2psCopyPixmap(p->data.image); - break; - case GL2PS_TEXT : - case GL2PS_SPECIAL : - prim->data.text = gl2psCopyText(p->data.text); - break; - default: - break; - } - - return prim; -} - -static GLboolean gl2psSamePosition(GL2PSxyz p1, GL2PSxyz p2) -{ - if(!GL2PS_ZERO(p1[0] - p2[0]) || - !GL2PS_ZERO(p1[1] - p2[1]) || - !GL2PS_ZERO(p1[2] - p2[2])) - return GL_FALSE; - return GL_TRUE; -} - -/********************************************************************* - * - * 3D sorting routines - * - *********************************************************************/ - -static GLfloat gl2psComparePointPlane(GL2PSxyz point, GL2PSplane plane) -{ - return (plane[0] * point[0] + - plane[1] * point[1] + - plane[2] * point[2] + - plane[3]); -} - -static GLfloat gl2psPsca(GLfloat *a, GLfloat *b) -{ - return (a[0]*b[0] + a[1]*b[1] + a[2]*b[2]); -} - -static void gl2psPvec(GLfloat *a, GLfloat *b, GLfloat *c) -{ - c[0] = a[1]*b[2] - a[2]*b[1]; - c[1] = a[2]*b[0] - a[0]*b[2]; - c[2] = a[0]*b[1] - a[1]*b[0]; -} - -static GLfloat gl2psNorm(GLfloat *a) -{ - return (GLfloat)sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]); -} - -static void gl2psGetNormal(GLfloat *a, GLfloat *b, GLfloat *c) -{ - GLfloat norm; - - gl2psPvec(a, b, c); - if(!GL2PS_ZERO(norm = gl2psNorm(c))){ - c[0] = c[0] / norm; - c[1] = c[1] / norm; - c[2] = c[2] / norm; - } - else{ - /* The plane is still wrong despite our tests in gl2psGetPlane. - Let's return a dummy value for now (this is a hack: we should - do more intelligent tests in GetPlane) */ - c[0] = c[1] = 0.0F; - c[2] = 1.0F; - } -} - -static void gl2psGetPlane(GL2PSprimitive *prim, GL2PSplane plane) -{ - GL2PSxyz v = {0.0F, 0.0F, 0.0F}, w = {0.0F, 0.0F, 0.0F}; - - 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])) || - (GL2PS_ZERO(w[0]) && GL2PS_ZERO(w[1]) && GL2PS_ZERO(w[2]))){ - plane[0] = plane[1] = 0.0F; - plane[2] = 1.0F; - plane[3] = -prim->verts[0].xyz[2]; - } - else{ - gl2psGetNormal(v, w, plane); - 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]; - if(GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])){ - plane[0] = plane[1] = 0.0F; - plane[2] = 1.0F; - plane[3] = -prim->verts[0].xyz[2]; - } - else{ - if(GL2PS_ZERO(v[0])) w[0] = 1.0F; - 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[2] * prim->verts[0].xyz[2]; - } - break; - case GL2PS_POINT : - case GL2PS_PIXMAP : - case GL2PS_TEXT : - case GL2PS_SPECIAL : - case GL2PS_IMAGEMAP: - plane[0] = plane[1] = 0.0F; - plane[2] = 1.0F; - plane[3] = -prim->verts[0].xyz[2]; - break; - default : - gl2psMsg(GL2PS_ERROR, "Unknown primitive type in BSP tree"); - plane[0] = plane[1] = plane[3] = 0.0F; - plane[2] = 1.0F; - break; - } -} - -static void gl2psCutEdge(GL2PSvertex *a, GL2PSvertex *b, GL2PSplane plane, - GL2PSvertex *c) -{ - GL2PSxyz v; - GLfloat sect, psca; - - v[0] = b->xyz[0] - a->xyz[0]; - v[1] = b->xyz[1] - a->xyz[1]; - v[2] = b->xyz[2] - a->xyz[2]; - - if(!GL2PS_ZERO(psca = gl2psPsca(plane, v))) - 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]; - c->rgba[3] = (1 - sect) * a->rgba[3] + sect * b->rgba[3]; -} - -static void gl2psCreateSplitPrimitive(GL2PSprimitive *parent, GL2PSplane plane, - GL2PSprimitive *child, GLshort numverts, - GLshort *index0, GLshort *index1) -{ - GLshort i; - - if(parent->type == GL2PS_IMAGEMAP){ - child->type = GL2PS_IMAGEMAP; - child->data.image = parent->data.image; - } - else{ - if(numverts > 4){ - gl2psMsg(GL2PS_WARNING, "%d vertices in polygon", numverts); - 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; - default: child->type = GL2PS_NO_TYPE; break; - } - } - - child->boundary = 0; /* FIXME: not done! */ - child->culled = parent->culled; - child->offset = parent->offset; - child->pattern = parent->pattern; - child->factor = parent->factor; - child->width = parent->width; - child->numverts = numverts; - child->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex)); - - for(i = 0; i < numverts; i++){ - if(index1[i] < 0){ - child->verts[i] = parent->verts[index0[i]]; - } - else{ - gl2psCutEdge(&parent->verts[index0[i]], &parent->verts[index1[i]], - plane, &child->verts[i]); - } - } -} - -static void gl2psAddIndex(GLshort *index0, GLshort *index1, GLshort *nb, - GLshort i, GLshort j) -{ - GLint k; - - for(k = 0; k < *nb; k++){ - if((index0[k] == i && index1[k] == j) || - (index1[k] == i && index0[k] == j)) return; - } - index0[*nb] = i; - index1[*nb] = j; - (*nb)++; -} - -static GLshort gl2psGetIndex(GLshort i, GLshort num) -{ - return (i < num - 1) ? i + 1 : 0; -} - -static GLint gl2psTestSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane) -{ - GLint type = GL2PS_COINCIDENT; - GLshort i, j; - GLfloat d[5]; - - for(i = 0; i < prim->numverts; i++){ - d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane); - } - - if(prim->numverts < 2){ - return 0; - } - else{ - for(i = 0; i < prim->numverts; i++){ - 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; - if(d[i] < -GL2PS_EPSILON) return 1; - } - else if(d[j] < -GL2PS_EPSILON){ - 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; - } - } - } - return 0; -} - -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]; - - type = GL2PS_COINCIDENT; - - for(i = 0; i < prim->numverts; i++){ - d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane); - } - - switch(prim->type){ - case GL2PS_POINT : - if(d[0] > GL2PS_EPSILON) type = GL2PS_IN_BACK_OF; - else if(d[0] < -GL2PS_EPSILON) type = GL2PS_IN_FRONT_OF; - else type = GL2PS_COINCIDENT; - break; - default : - for(i = 0; i < prim->numverts; i++){ - 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; - if(d[i] < -GL2PS_EPSILON){ - gl2psAddIndex(in0, in1, &in, i, j); - gl2psAddIndex(out0, out1, &out, i, j); - type = GL2PS_SPANNING; - } - gl2psAddIndex(out0, out1, &out, j, -1); - } - else if(d[j] < -GL2PS_EPSILON){ - 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); - gl2psAddIndex(out0, out1, &out, i, j); - type = GL2PS_SPANNING; - } - gl2psAddIndex(in0, in1, &in, j, -1); - } - else{ - gl2psAddIndex(in0, in1, &in, j, -1); - gl2psAddIndex(out0, out1, &out, j, -1); - } - } - break; - } - - if(type == GL2PS_SPANNING){ - *back = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); - *front = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); - gl2psCreateSplitPrimitive(prim, plane, *back, out, out0, out1); - gl2psCreateSplitPrimitive(prim, plane, *front, in, in0, in1); - } - - return type; -} - -static void gl2psDivideQuad(GL2PSprimitive *quad, - GL2PSprimitive **t1, GL2PSprimitive **t2) -{ - *t1 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); - *t2 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); - (*t1)->type = (*t2)->type = GL2PS_TRIANGLE; - (*t1)->numverts = (*t2)->numverts = 3; - (*t1)->culled = (*t2)->culled = quad->culled; - (*t1)->offset = (*t2)->offset = quad->offset; - (*t1)->pattern = (*t2)->pattern = quad->pattern; - (*t1)->factor = (*t2)->factor = quad->factor; - (*t1)->width = (*t2)->width = quad->width; - (*t1)->verts = (GL2PSvertex*)gl2psMalloc(3 * sizeof(GL2PSvertex)); - (*t2)->verts = (GL2PSvertex*)gl2psMalloc(3 * sizeof(GL2PSvertex)); - (*t1)->verts[0] = quad->verts[0]; - (*t1)->verts[1] = quad->verts[1]; - (*t1)->verts[2] = quad->verts[2]; - (*t1)->boundary = ((quad->boundary & 1) ? 1 : 0) | ((quad->boundary & 2) ? 2 : 0); - (*t2)->verts[0] = quad->verts[0]; - (*t2)->verts[1] = quad->verts[2]; - (*t2)->verts[2] = quad->verts[3]; - (*t2)->boundary = ((quad->boundary & 4) ? 2 : 0) | ((quad->boundary & 8) ? 4 : 0); -} - -static int gl2psCompareDepth(const void *a, const void *b) -{ - const GL2PSprimitive *q, *w; - GLfloat dq = 0.0F, dw = 0.0F, diff; - int i; - - q = *(const GL2PSprimitive* const*)a; - w = *(const GL2PSprimitive* const*)b; - - for(i = 0; i < q->numverts; i++){ - dq += q->verts[i].xyz[2]; - } - dq /= (GLfloat)q->numverts; - - for(i = 0; i < w->numverts; i++){ - dw += w->verts[i].xyz[2]; - } - dw /= (GLfloat)w->numverts; - - diff = dq - dw; - if(diff > 0.){ - return -1; - } - else if(diff < 0.){ - return 1; - } - else{ - return 0; - } -} - -static int gl2psTrianglesFirst(const void *a, const void *b) -{ - const GL2PSprimitive *q, *w; - - q = *(const GL2PSprimitive* const*)a; - w = *(const GL2PSprimitive* const*)b; - return (q->type < w->type ? 1 : -1); -} - -static GLint gl2psFindRoot(GL2PSlist *primitives, GL2PSprimitive **root) -{ - GLint i, j, count, best = 1000000, index = 0; - GL2PSprimitive *prim1, *prim2; - GL2PSplane plane; - GLint maxp; - - if(!gl2psListNbr(primitives)){ - gl2psMsg(GL2PS_ERROR, "Cannot fint root in empty primitive list"); - return 0; - } - - *root = *(GL2PSprimitive**)gl2psListPointer(primitives, 0); - - if(gl2ps->options & GL2PS_BEST_ROOT){ - maxp = gl2psListNbr(primitives); - if(maxp > gl2ps->maxbestroot){ - maxp = gl2ps->maxbestroot; - } - for(i = 0; i < maxp; i++){ - prim1 = *(GL2PSprimitive**)gl2psListPointer(primitives, i); - gl2psGetPlane(prim1, plane); - count = 0; - for(j = 0; j < gl2psListNbr(primitives); j++){ - if(j != i){ - prim2 = *(GL2PSprimitive**)gl2psListPointer(primitives, j); - count += gl2psTestSplitPrimitive(prim2, plane); - } - if(count > best) break; - } - if(count < best){ - best = count; - index = i; - *root = prim1; - if(!count) return index; - } - } - /* if(index) gl2psMsg(GL2PS_INFO, "GL2PS_BEST_ROOT was worth it: %d", index); */ - return index; - } - else{ - return 0; - } -} - -static void gl2psFreeImagemap(GL2PSimagemap *list) -{ - GL2PSimagemap *next; - while(list != NULL){ - next = list->next; - gl2psFree(list->image->pixels); - gl2psFree(list->image); - gl2psFree(list); - list = next; - } -} - -static void gl2psFreePrimitive(void *data) -{ - GL2PSprimitive *q; - - q = *(GL2PSprimitive**)data; - gl2psFree(q->verts); - if(q->type == GL2PS_TEXT || q->type == GL2PS_SPECIAL){ - gl2psFreeText(q->data.text); - } - else if(q->type == GL2PS_PIXMAP){ - gl2psFreePixmap(q->data.image); - } - gl2psFree(q); -} - -static void gl2psAddPrimitiveInList(GL2PSprimitive *prim, GL2PSlist *list) -{ - GL2PSprimitive *t1, *t2; - - if(prim->type != GL2PS_QUADRANGLE){ - gl2psListAdd(list, &prim); - } - else{ - gl2psDivideQuad(prim, &t1, &t2); - gl2psListAdd(list, &t1); - gl2psListAdd(list, &t2); - gl2psFreePrimitive(&prim); - } - -} - -static void gl2psFreeBspTree(GL2PSbsptree **tree) -{ - if(*tree){ - if((*tree)->back) gl2psFreeBspTree(&(*tree)->back); - if((*tree)->primitives){ - gl2psListAction((*tree)->primitives, gl2psFreePrimitive); - gl2psListDelete((*tree)->primitives); - } - if((*tree)->front) gl2psFreeBspTree(&(*tree)->front); - gl2psFree(*tree); - *tree = NULL; - } -} - -static GLboolean gl2psGreater(GLfloat f1, GLfloat f2) -{ - if(f1 > f2) return GL_TRUE; - else return GL_FALSE; -} - -static GLboolean gl2psLess(GLfloat f1, GLfloat f2) -{ - if(f1 < f2) return GL_TRUE; - else return GL_FALSE; -} - -static void gl2psBuildBspTree(GL2PSbsptree *tree, GL2PSlist *primitives) -{ - GL2PSprimitive *prim, *frontprim = NULL, *backprim = NULL; - GL2PSlist *frontlist, *backlist; - GLint i, index; - - tree->front = NULL; - tree->back = NULL; - tree->primitives = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); - index = gl2psFindRoot(primitives, &prim); - gl2psGetPlane(prim, tree->plane); - gl2psAddPrimitiveInList(prim, tree->primitives); - - frontlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); - backlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); - - for(i = 0; i < gl2psListNbr(primitives); i++){ - if(i != index){ - prim = *(GL2PSprimitive**)gl2psListPointer(primitives,i); - switch(gl2psSplitPrimitive(prim, tree->plane, &frontprim, &backprim)){ - case GL2PS_COINCIDENT: - gl2psAddPrimitiveInList(prim, tree->primitives); - break; - case GL2PS_IN_BACK_OF: - gl2psAddPrimitiveInList(prim, backlist); - break; - case GL2PS_IN_FRONT_OF: - gl2psAddPrimitiveInList(prim, frontlist); - break; - case GL2PS_SPANNING: - gl2psAddPrimitiveInList(backprim, backlist); - gl2psAddPrimitiveInList(frontprim, frontlist); - gl2psFreePrimitive(&prim); - break; - } - } - } - - if(gl2psListNbr(tree->primitives)){ - gl2psListSort(tree->primitives, gl2psTrianglesFirst); - } - - if(gl2psListNbr(frontlist)){ - gl2psListSort(frontlist, gl2psTrianglesFirst); - tree->front = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree)); - gl2psBuildBspTree(tree->front, frontlist); - } - else{ - gl2psListDelete(frontlist); - } - - if(gl2psListNbr(backlist)){ - gl2psListSort(backlist, gl2psTrianglesFirst); - tree->back = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree)); - gl2psBuildBspTree(tree->back, backlist); - } - else{ - gl2psListDelete(backlist); - } - - gl2psListDelete(primitives); -} - -static void gl2psTraverseBspTree(GL2PSbsptree *tree, GL2PSxyz eye, GLfloat epsilon, - GLboolean (*compare)(GLfloat f1, GLfloat f2), - void (*action)(void *data), int inverse) -{ - GLfloat result; - - if(!tree) return; - - result = gl2psComparePointPlane(eye, tree->plane); - - if(GL_TRUE == compare(result, epsilon)){ - gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse); - if(inverse){ - gl2psListActionInverse(tree->primitives, action); - } - else{ - gl2psListAction(tree->primitives, action); - } - gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); - } - else if(GL_TRUE == compare(-epsilon, result)){ - gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); - if(inverse){ - gl2psListActionInverse(tree->primitives, action); - } - else{ - gl2psListAction(tree->primitives, action); - } - gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse); - } - else{ - gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); - gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse); - } -} - -static void gl2psRescaleAndOffset(void) -{ - GL2PSprimitive *prim; - GLfloat minZ, maxZ, rangeZ, scaleZ; - GLfloat factor, units, area, dZ, dZdX, dZdY, maxdZ; - int i, j; - - if(!gl2psListNbr(gl2ps->primitives)) - return; - - /* get z-buffer range */ - prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, 0); - minZ = maxZ = prim->verts[0].xyz[2]; - for(i = 1; i < prim->numverts; i++){ - if(prim->verts[i].xyz[2] < minZ) minZ = prim->verts[i].xyz[2]; - if(prim->verts[i].xyz[2] > maxZ) maxZ = prim->verts[i].xyz[2]; - } - for(i = 1; i < gl2psListNbr(gl2ps->primitives); i++){ - prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, i); - for(j = 0; j < prim->numverts; j++){ - if(prim->verts[j].xyz[2] < minZ) minZ = prim->verts[j].xyz[2]; - if(prim->verts[j].xyz[2] > maxZ) maxZ = prim->verts[j].xyz[2]; - } - } - rangeZ = (maxZ - minZ); - - /* rescale z-buffer coordinate in [0,GL2PS_ZSCALE], to make it of - the same order of magnitude as the x and y coordinates */ - scaleZ = GL2PS_ZERO(rangeZ) ? GL2PS_ZSCALE : (GL2PS_ZSCALE / rangeZ); - /* avoid precision loss (we use floats!) */ - if(scaleZ > 100000.F) scaleZ = 100000.F; - - /* apply offsets */ - for(i = 0; i < gl2psListNbr(gl2ps->primitives); i++){ - prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, i); - for(j = 0; j < prim->numverts; j++){ - prim->verts[j].xyz[2] = (prim->verts[j].xyz[2] - minZ) * scaleZ; - } - if((gl2ps->options & GL2PS_SIMPLE_LINE_OFFSET) && - (prim->type == GL2PS_LINE)){ - if(gl2ps->sort == GL2PS_SIMPLE_SORT){ - prim->verts[0].xyz[2] -= GL2PS_ZOFFSET_LARGE; - prim->verts[1].xyz[2] -= GL2PS_ZOFFSET_LARGE; - } - else{ - prim->verts[0].xyz[2] -= GL2PS_ZOFFSET; - prim->verts[1].xyz[2] -= GL2PS_ZOFFSET; - } - } - 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]) * - (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]); - if(!GL2PS_ZERO(area)){ - 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 = - ((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]) * - (prim->verts[1].xyz[2] - prim->verts[0].xyz[2])) / area; - maxdZ = (GLfloat)sqrt(dZdX * dZdX + dZdY * dZdY); - } - else{ - maxdZ = 0.0F; - } - dZ = factor * maxdZ + units; - prim->verts[0].xyz[2] += dZ; - prim->verts[1].xyz[2] += dZ; - prim->verts[2].xyz[2] += dZ; - } - } -} - -/********************************************************************* - * - * 2D sorting routines (for occlusion culling) - * - *********************************************************************/ - -static GLint gl2psGetPlaneFromPoints(GL2PSxyz a, GL2PSxyz b, GL2PSplane plane) -{ - GLfloat n; - - plane[0] = b[1] - a[1]; - plane[1] = a[0] - b[0]; - n = (GLfloat)sqrt(plane[0]*plane[0] + plane[1]*plane[1]); - plane[2] = 0.0F; - if(!GL2PS_ZERO(n)){ - plane[0] /= n; - plane[1] /= n; - plane[3] = -plane[0]*a[0]-plane[1]*a[1]; - return 1; - } - else{ - plane[0] = -1.0F; - plane[1] = 0.0F; - plane[3] = a[0]; - return 0; - } -} - -static void gl2psFreeBspImageTree(GL2PSbsptree2d **tree) -{ - if(*tree){ - if((*tree)->back) gl2psFreeBspImageTree(&(*tree)->back); - if((*tree)->front) gl2psFreeBspImageTree(&(*tree)->front); - gl2psFree(*tree); - *tree = NULL; - } -} - -static GLint gl2psCheckPoint(GL2PSxyz point, GL2PSplane plane) -{ - GLfloat pt_dis; - - pt_dis = gl2psComparePointPlane(point, plane); - if(pt_dis > GL2PS_EPSILON) return GL2PS_POINT_INFRONT; - else if(pt_dis < -GL2PS_EPSILON) return GL2PS_POINT_BACK; - else return GL2PS_POINT_COINCIDENT; -} - -static void gl2psAddPlanesInBspTreeImage(GL2PSprimitive *prim, - GL2PSbsptree2d **tree) -{ - GLint ret = 0; - GLint i; - GLint offset = 0; - GL2PSbsptree2d *head = NULL, *cur = NULL; - - if((*tree == NULL) && (prim->numverts > 2)){ - /* don't cull if transparent - for(i = 0; i < prim->numverts - 1; i++) - if(prim->verts[i].rgba[3] < 1.0F) return; - */ - head = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); - for(i = 0; i < prim->numverts-1; i++){ - if(!gl2psGetPlaneFromPoints(prim->verts[i].xyz, - prim->verts[i+1].xyz, - head->plane)){ - if(prim->numverts-i > 3){ - offset++; - } - else{ - gl2psFree(head); - return; - } - } - else{ - break; - } - } - head->back = NULL; - head->front = NULL; - for(i = 2+offset; i < prim->numverts; i++){ - ret = gl2psCheckPoint(prim->verts[i].xyz, head->plane); - if(ret != GL2PS_POINT_COINCIDENT) break; - } - switch(ret){ - case GL2PS_POINT_INFRONT : - cur = head; - for(i = 1+offset; i < prim->numverts-1; i++){ - if(cur->front == NULL){ - cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); - } - if(gl2psGetPlaneFromPoints(prim->verts[i].xyz, - prim->verts[i+1].xyz, - cur->front->plane)){ - cur = cur->front; - cur->front = NULL; - cur->back = NULL; - } - } - if(cur->front == NULL){ - cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); - } - if(gl2psGetPlaneFromPoints(prim->verts[i].xyz, - prim->verts[offset].xyz, - cur->front->plane)){ - cur->front->front = NULL; - cur->front->back = NULL; - } - else{ - gl2psFree(cur->front); - cur->front = NULL; - } - break; - case GL2PS_POINT_BACK : - for(i = 0; i < 4; i++){ - head->plane[i] = -head->plane[i]; - } - cur = head; - for(i = 1+offset; i < prim->numverts-1; i++){ - if(cur->front == NULL){ - cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); - } - if(gl2psGetPlaneFromPoints(prim->verts[i+1].xyz, - prim->verts[i].xyz, - cur->front->plane)){ - cur = cur->front; - cur->front = NULL; - cur->back = NULL; - } - } - if(cur->front == NULL){ - cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); - } - if(gl2psGetPlaneFromPoints(prim->verts[offset].xyz, - prim->verts[i].xyz, - cur->front->plane)){ - cur->front->front = NULL; - cur->front->back = NULL; - } - else{ - gl2psFree(cur->front); - cur->front = NULL; - } - break; - default: - gl2psFree(head); - return; - } - (*tree) = head; - } -} - -static GLint gl2psCheckPrimitive(GL2PSprimitive *prim, GL2PSplane plane) -{ - GLint i; - GLint pos; - - pos = gl2psCheckPoint(prim->verts[0].xyz, plane); - for(i = 1; i < prim->numverts; i++){ - pos |= gl2psCheckPoint(prim->verts[i].xyz, plane); - if(pos == (GL2PS_POINT_INFRONT | GL2PS_POINT_BACK)) return GL2PS_SPANNING; - } - if(pos & GL2PS_POINT_INFRONT) return GL2PS_IN_FRONT_OF; - else if(pos & GL2PS_POINT_BACK) return GL2PS_IN_BACK_OF; - else return GL2PS_COINCIDENT; -} - -static GL2PSprimitive *gl2psCreateSplitPrimitive2D(GL2PSprimitive *parent, - GLshort numverts, - GL2PSvertex *vertx) -{ - GLint i; - GL2PSprimitive *child = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); - - if(parent->type == GL2PS_IMAGEMAP){ - child->type = GL2PS_IMAGEMAP; - child->data.image = parent->data.image; - } - else { - 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; - default: child->type = GL2PS_NO_TYPE; break; /* FIXME */ - } - } - child->boundary = 0; /* FIXME: not done! */ - child->culled = parent->culled; - child->offset = parent->offset; - child->pattern = parent->pattern; - child->factor = parent->factor; - child->width = parent->width; - child->numverts = numverts; - child->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex)); - for(i = 0; i < numverts; i++){ - child->verts[i] = vertx[i]; - } - return child; -} - -static void gl2psSplitPrimitive2D(GL2PSprimitive *prim, - GL2PSplane plane, - GL2PSprimitive **front, - GL2PSprimitive **back) -{ - /* cur will hold the position of the current vertex - prev will hold the position of the previous vertex - prev0 will hold the position of the vertex number 0 - 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; - - for(i = 0; i <= prim->numverts; i++){ - v1 = i; - if(v1 == prim->numverts){ - if(prim->numverts < 3) break; - v1 = 0; - v2 = prim->numverts - 1; - cur = prev0; - } - else if(flag){ - cur = gl2psCheckPoint(prim->verts[v1].xyz, plane); - if(i == 0){ - prev0 = cur; - } - } - if(((prev == -1) || (prev == cur) || (prev == 0) || (cur == 0)) && - (i < prim->numverts)){ - if(cur == GL2PS_POINT_INFRONT){ - front_count++; - front_list = (GL2PSvertex*)gl2psRealloc(front_list, - sizeof(GL2PSvertex)*front_count); - front_list[front_count-1] = prim->verts[v1]; - } - else if(cur == GL2PS_POINT_BACK){ - back_count++; - back_list = (GL2PSvertex*)gl2psRealloc(back_list, - sizeof(GL2PSvertex)*back_count); - back_list[back_count-1] = prim->verts[v1]; - } - else{ - front_count++; - front_list = (GL2PSvertex*)gl2psRealloc(front_list, - sizeof(GL2PSvertex)*front_count); - front_list[front_count-1] = prim->verts[v1]; - back_count++; - back_list = (GL2PSvertex*)gl2psRealloc(back_list, - sizeof(GL2PSvertex)*back_count); - back_list[back_count-1] = prim->verts[v1]; - } - flag = 1; - } - else if((prev != cur) && (cur != 0) && (prev != 0)){ - if(v1 != 0){ - v2 = v1-1; - i--; - } - front_count++; - front_list = (GL2PSvertex*)gl2psRealloc(front_list, - sizeof(GL2PSvertex)*front_count); - gl2psCutEdge(&prim->verts[v2], &prim->verts[v1], - plane, &front_list[front_count-1]); - back_count++; - back_list = (GL2PSvertex*)gl2psRealloc(back_list, - sizeof(GL2PSvertex)*back_count); - back_list[back_count-1] = front_list[front_count-1]; - flag = 0; - } - prev = cur; - } - *front = gl2psCreateSplitPrimitive2D(prim, front_count, front_list); - *back = gl2psCreateSplitPrimitive2D(prim, back_count, back_list); - gl2psFree(front_list); - gl2psFree(back_list); -} - -static GLint gl2psAddInBspImageTree(GL2PSprimitive *prim, GL2PSbsptree2d **tree) -{ - 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 || - prim->type == GL2PS_SPECIAL){ - return 1; - } - - if(*tree == NULL){ - if((prim->type != GL2PS_IMAGEMAP) && (GL_FALSE == gl2ps->zerosurfacearea)){ - gl2psAddPlanesInBspTreeImage(gl2ps->primitivetoadd, tree); - } - return 1; - } - else{ - switch(gl2psCheckPrimitive(prim, (*tree)->plane)){ - case GL2PS_IN_BACK_OF: return gl2psAddInBspImageTree(prim, &(*tree)->back); - case GL2PS_IN_FRONT_OF: - if((*tree)->front != NULL) return gl2psAddInBspImageTree(prim, &(*tree)->front); - else return 0; - case GL2PS_SPANNING: - gl2psSplitPrimitive2D(prim, (*tree)->plane, &frontprim, &backprim); - ret = gl2psAddInBspImageTree(backprim, &(*tree)->back); - if((*tree)->front != NULL){ - if(gl2psAddInBspImageTree(frontprim, &(*tree)->front)){ - ret = 1; - } - } - gl2psFree(frontprim->verts); - gl2psFree(frontprim); - gl2psFree(backprim->verts); - gl2psFree(backprim); - return ret; - case GL2PS_COINCIDENT: - if((*tree)->back != NULL){ - gl2ps->zerosurfacearea = GL_TRUE; - ret = gl2psAddInBspImageTree(prim, &(*tree)->back); - gl2ps->zerosurfacearea = GL_FALSE; - if(ret) return ret; - } - if((*tree)->front != NULL){ - gl2ps->zerosurfacearea = GL_TRUE; - ret = gl2psAddInBspImageTree(prim, &(*tree)->front); - gl2ps->zerosurfacearea = GL_FALSE; - if(ret) return ret; - } - if(prim->type == GL2PS_LINE) return 1; - else return 0; - } - } - return 0; -} - -static void gl2psAddInImageTree(void *data) -{ - GL2PSprimitive *prim = *(GL2PSprimitive **)data; - gl2ps->primitivetoadd = prim; - if(prim->type == GL2PS_IMAGEMAP && prim->data.image->format == GL2PS_IMAGEMAP_VISIBLE){ - prim->culled = 1; - } - else if(!gl2psAddInBspImageTree(prim, &gl2ps->imagetree)){ - prim->culled = 1; - } - else if(prim->type == GL2PS_IMAGEMAP){ - prim->data.image->format = GL2PS_IMAGEMAP_VISIBLE; - } -} - -/* Boundary construction */ - -static void gl2psAddBoundaryInList(GL2PSprimitive *prim, GL2PSlist *list) -{ - GL2PSprimitive *b; - GLshort i; - GL2PSxyz c; - - c[0] = c[1] = c[2] = 0.0F; - for(i = 0; i < prim->numverts; i++){ - c[0] += prim->verts[i].xyz[0]; - c[1] += prim->verts[i].xyz[1]; - } - c[0] /= prim->numverts; - c[1] /= prim->numverts; - - for(i = 0; i < prim->numverts; i++){ - if(prim->boundary & (GLint)pow(2., i)){ - b = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); - b->type = GL2PS_LINE; - b->offset = prim->offset; - b->pattern = prim->pattern; - b->factor = prim->factor; - b->culled = prim->culled; - b->width = prim->width; - b->boundary = 0; - b->numverts = 2; - b->verts = (GL2PSvertex*)gl2psMalloc(2 * sizeof(GL2PSvertex)); - -#if 0 /* FIXME: need to work on boundary offset... */ - v[0] = c[0] - prim->verts[i].xyz[0]; - v[1] = c[1] - prim->verts[i].xyz[1]; - v[2] = 0.0F; - norm = gl2psNorm(v); - v[0] /= norm; - v[1] /= norm; - b->verts[0].xyz[0] = prim->verts[i].xyz[0] +0.1*v[0]; - b->verts[0].xyz[1] = prim->verts[i].xyz[1] +0.1*v[1]; - b->verts[0].xyz[2] = prim->verts[i].xyz[2]; - v[0] = c[0] - prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0]; - v[1] = c[1] - prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1]; - norm = gl2psNorm(v); - v[0] /= norm; - v[1] /= norm; - b->verts[1].xyz[0] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0] +0.1*v[0]; - b->verts[1].xyz[1] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1] +0.1*v[1]; - b->verts[1].xyz[2] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[2]; -#else - b->verts[0].xyz[0] = prim->verts[i].xyz[0]; - b->verts[0].xyz[1] = prim->verts[i].xyz[1]; - b->verts[0].xyz[2] = prim->verts[i].xyz[2]; - b->verts[1].xyz[0] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0]; - b->verts[1].xyz[1] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1]; - b->verts[1].xyz[2] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[2]; -#endif - - b->verts[0].rgba[0] = 0.0F; - b->verts[0].rgba[1] = 0.0F; - b->verts[0].rgba[2] = 0.0F; - b->verts[0].rgba[3] = 0.0F; - b->verts[1].rgba[0] = 0.0F; - b->verts[1].rgba[1] = 0.0F; - b->verts[1].rgba[2] = 0.0F; - b->verts[1].rgba[3] = 0.0F; - gl2psListAdd(list, &b); - } - } - -} - -static void gl2psBuildPolygonBoundary(GL2PSbsptree *tree) -{ - GLint i; - GL2PSprimitive *prim; - - if(!tree) return; - gl2psBuildPolygonBoundary(tree->back); - for(i = 0; i < gl2psListNbr(tree->primitives); i++){ - prim = *(GL2PSprimitive**)gl2psListPointer(tree->primitives, i); - if(prim->boundary) gl2psAddBoundaryInList(prim, tree->primitives); - } - gl2psBuildPolygonBoundary(tree->front); -} - -/********************************************************************* - * - * Feedback buffer parser - * - *********************************************************************/ - -static void gl2psAddPolyPrimitive(GLshort type, GLshort numverts, - GL2PSvertex *verts, GLint offset, - GLushort pattern, GLint factor, - GLfloat width, char boundary) -{ - GL2PSprimitive *prim; - - prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); - prim->type = type; - prim->numverts = numverts; - prim->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex)); - memcpy(prim->verts, verts, numverts * sizeof(GL2PSvertex)); - prim->boundary = boundary; - prim->offset = offset; - prim->pattern = pattern; - prim->factor = factor; - prim->width = width; - prim->culled = 0; - - /* FIXME: here we should have an option to split stretched - tris/quads to enhance SIMPLE_SORT */ - - gl2psListAdd(gl2ps->primitives, &prim); -} - -static GLint gl2psGetVertex(GL2PSvertex *v, GLfloat *p) -{ - GLint i; - - v->xyz[0] = p[0]; - v->xyz[1] = p[1]; - v->xyz[2] = p[2]; - - if(gl2ps->colormode == GL_COLOR_INDEX && gl2ps->colorsize > 0){ - i = (GLint)(p[3] + 0.5); - v->rgba[0] = gl2ps->colormap[i][0]; - v->rgba[1] = gl2ps->colormap[i][1]; - v->rgba[2] = gl2ps->colormap[i][2]; - v->rgba[3] = gl2ps->colormap[i][3]; - return 4; - } - else{ - v->rgba[0] = p[3]; - v->rgba[1] = p[4]; - v->rgba[2] = p[5]; - v->rgba[3] = p[6]; - return 7; - } -} - -static void gl2psParseFeedbackBuffer(GLint used) -{ - char flag; - GLushort pattern = 0; - GLboolean boundary; - GLint i, sizeoffloat, count, v, vtot, offset = 0, factor = 0, auxindex = 0; - GLfloat lwidth = 1.0F, psize = 1.0F; - GLfloat *current; - GL2PSvertex vertices[3]; - GL2PSprimitive *prim; - GL2PSimagemap *node; - - current = gl2ps->feedback; - boundary = gl2ps->boundary = GL_FALSE; - - while(used > 0){ - - if(GL_TRUE == boundary) gl2ps->boundary = GL_TRUE; - - switch((GLint)*current){ - case GL_POINT_TOKEN : - current ++; - used --; - i = gl2psGetVertex(&vertices[0], current); - current += i; - used -= i; - gl2psAddPolyPrimitive(GL2PS_POINT, 1, vertices, 0, - pattern, factor, psize, 0); - break; - case GL_LINE_TOKEN : - case GL_LINE_RESET_TOKEN : - current ++; - used --; - i = gl2psGetVertex(&vertices[0], current); - current += i; - used -= i; - i = gl2psGetVertex(&vertices[1], current); - current += i; - used -= i; - gl2psAddPolyPrimitive(GL2PS_LINE, 2, vertices, 0, - pattern, factor, lwidth, 0); - break; - case GL_POLYGON_TOKEN : - count = (GLint)current[1]; - current += 2; - used -= 2; - v = vtot = 0; - while(count > 0 && used > 0){ - i = gl2psGetVertex(&vertices[v], current); - gl2psAdaptVertexForBlending(&vertices[v]); - current += i; - used -= i; - count --; - vtot++; - if(v == 2){ - if(GL_TRUE == boundary){ - if(!count && vtot == 2) flag = 1|2|4; - else if(!count) flag = 2|4; - else if(vtot == 2) flag = 1|2; - else flag = 2; - } - else - flag = 0; - gl2psAddPolyPrimitive(GL2PS_TRIANGLE, 3, vertices, offset, - pattern, factor, 1, flag); - vertices[1] = vertices[2]; - } - else - v ++; - } - break; - case GL_BITMAP_TOKEN : - case GL_DRAW_PIXEL_TOKEN : - case GL_COPY_PIXEL_TOKEN : - current ++; - used --; - i = gl2psGetVertex(&vertices[0], current); - current += i; - used -= i; - break; - case GL_PASS_THROUGH_TOKEN : - switch((GLint)current[1]){ - case GL2PS_BEGIN_OFFSET_TOKEN : offset = 1; break; - case GL2PS_END_OFFSET_TOKEN : offset = 0; break; - case GL2PS_BEGIN_BOUNDARY_TOKEN : boundary = GL_TRUE; break; - case GL2PS_END_BOUNDARY_TOKEN : boundary = GL_FALSE; break; - 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 : - current += 2; - used -= 2; - pattern = (GLushort)current[1]; - current += 2; - used -= 2; - factor = (GLint)current[1]; - break; - 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; - gl2ps->blendfunc[1] = (GLint)current[1]; - break; - case GL2PS_POINT_SIZE_TOKEN : - current += 2; - used -= 2; - psize = current[1]; - break; - case GL2PS_LINE_WIDTH_TOKEN : - current += 2; - used -= 2; - lwidth = current[1]; - break; - case GL2PS_IMAGEMAP_TOKEN : - prim = (GL2PSprimitive *)gl2psMalloc(sizeof(GL2PSprimitive)); - prim->type = GL2PS_IMAGEMAP; - prim->boundary = 0; - prim->numverts = 4; - prim->verts = (GL2PSvertex *)gl2psMalloc(4 * sizeof(GL2PSvertex)); - prim->culled = 0; - prim->offset = 0; - 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]; - prim->verts[0].xyz[0] = prim->verts[0].xyz[0] - (int)(node->image->width / 2) + 0.5F; - prim->verts[0].xyz[1] = prim->verts[0].xyz[1] - (int)(node->image->height / 2) + 0.5F; - for(i = 1; i < 4; i++){ - for(v = 0; v < 3; v++){ - prim->verts[i].xyz[v] = prim->verts[0].xyz[v]; - prim->verts[i].rgba[v] = prim->verts[0].rgba[v]; - } - prim->verts[i].rgba[v] = prim->verts[0].rgba[v]; - } - prim->verts[1].xyz[0] = prim->verts[1].xyz[0] + node->image->width; - prim->verts[2].xyz[0] = prim->verts[1].xyz[0]; - prim->verts[2].xyz[1] = prim->verts[2].xyz[1] + node->image->height; - prim->verts[3].xyz[1] = prim->verts[2].xyz[1]; - - sizeoffloat = sizeof(GLfloat); - v = 2 * sizeoffloat; - 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) - memcpy(&(((char*)(node->image->pixels))[i + v]), &(current[2]), sizeoffloat); - else - memcpy(&(((char*)(node->image->pixels))[i + v]), &(current[2]), vtot - i); - } - current++; used--; - gl2psListAdd(gl2ps->primitives, &prim); - break; - case GL2PS_DRAW_PIXELS_TOKEN : - case GL2PS_TEXT_TOKEN : - if(auxindex < gl2psListNbr(gl2ps->auxprimitives)) - gl2psListAdd(gl2ps->primitives, - gl2psListPointer(gl2ps->auxprimitives, auxindex++)); - else - gl2psMsg(GL2PS_ERROR, "Wrong number of auxiliary tokens in buffer"); - break; - } - current += 2; - used -= 2; - break; - default : - gl2psMsg(GL2PS_WARNING, "Unknown token in buffer"); - current ++; - used --; - break; - } - } - - gl2psListReset(gl2ps->auxprimitives); -} - -/********************************************************************* - * - * PostScript routines - * - *********************************************************************/ - -static void gl2psWriteByte(unsigned char byte) -{ - unsigned char h = byte / 16; - unsigned char l = byte % 16; - gl2psPrintf("%x%x", h, l); -} - -static void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GL2PSimage *im) -{ - GLuint nbhex, nbyte, nrgb, nbits; - GLuint row, col, ibyte, icase; - GLfloat dr, dg, db, fgrey; - unsigned char red = 0, green = 0, blue = 0, b, grey; - GLuint width = (GLuint)im->width; - GLuint height = (GLuint)im->height; - - /* FIXME: should we define an option for these? Or just keep the - 8-bit per component case? */ - int greyscale = 0; /* set to 1 to output greyscale image */ - int nbit = 8; /* number of bits per color compoment (2, 4 or 8) */ - - 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); - - 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("{ currentfile picstr readhexstring pop }\n"); - gl2psPrintf("image\n"); - for(row = 0; row < height; row++){ - 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); - gl2psWriteByte(grey); - } - gl2psPrintf("\n"); - } - 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; - nbits = nrgb * nbit; - nbyte = nbits / 8; - 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); - gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n"); - gl2psPrintf("false 3\n"); - gl2psPrintf("colorimage\n"); - for(row = 0; row < height; row++){ - icase = 1; - col = 0; - b = 0; - for(ibyte = 0; ibyte < nbyte; ibyte++){ - if(icase == 1) { - if(col < width) { - gl2psGetRGB(im, col, row, &dr, &dg, &db); - } - else { - dr = dg = db = 0; - } - col++; - red = (unsigned char)(3. * dr); - green = (unsigned char)(3. * dg); - blue = (unsigned char)(3. * db); - b = red; - b = (b<<2) + green; - b = (b<<2) + blue; - if(col < width) { - gl2psGetRGB(im, col, row, &dr, &dg, &db); - } - else { - dr = dg = db = 0; - } - col++; - red = (unsigned char)(3. * dr); - green = (unsigned char)(3. * dg); - blue = (unsigned char)(3. * db); - b = (b<<2) + red; - gl2psWriteByte(b); - b = 0; - icase++; - } - else if(icase == 2) { - b = green; - b = (b<<2) + blue; - if(col < width) { - gl2psGetRGB(im, col, row, &dr, &dg, &db); - } - else { - dr = dg = db = 0; - } - col++; - red = (unsigned char)(3. * dr); - green = (unsigned char)(3. * dg); - blue = (unsigned char)(3. * db); - b = (b<<2) + red; - b = (b<<2) + green; - gl2psWriteByte(b); - b = 0; - icase++; - } - else if(icase == 3) { - b = blue; - if(col < width) { - gl2psGetRGB(im, col, row, &dr, &dg, &db); - } - else { - dr = dg = db = 0; - } - col++; - red = (unsigned char)(3. * dr); - green = (unsigned char)(3. * dg); - blue = (unsigned char)(3. * db); - b = (b<<2) + red; - b = (b<<2) + green; - b = (b<<2) + blue; - gl2psWriteByte(b); - b = 0; - icase = 1; - } - } - gl2psPrintf("\n"); - } - } - else if(nbit == 4){ /* color, 4 bits for r and g and b; rgbs following each other */ - nrgb = width * 3; - nbits = nrgb * nbit; - nbyte = nbits / 8; - 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); - gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n"); - gl2psPrintf("false 3\n"); - gl2psPrintf("colorimage\n"); - for(row = 0; row < height; row++){ - col = 0; - icase = 1; - for(ibyte = 0; ibyte < nbyte; ibyte++){ - if(icase == 1) { - if(col < width) { - gl2psGetRGB(im, col, row, &dr, &dg, &db); - } - else { - dr = dg = db = 0; - } - col++; - red = (unsigned char)(15. * dr); - 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; - } - col++; - red = (unsigned char)(15. * dr); - gl2psPrintf("%x%x", blue, red); - icase++; - } - else if(icase == 3) { - green = (unsigned char)(15. * dg); - blue = (unsigned char)(15. * db); - gl2psPrintf("%x%x", green, blue); - icase = 1; - } - } - gl2psPrintf("\n"); - } - } - else{ /* 8 bit for r and g and b */ - 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("{ currentfile rgbstr readhexstring pop }\n"); - gl2psPrintf("false 3\n"); - gl2psPrintf("colorimage\n"); - for(row = 0; row < height; row++){ - for(col = 0; col < width; col++){ - gl2psGetRGB(im, col, row, &dr, &dg, &db); - red = (unsigned char)(255. * dr); - gl2psWriteByte(red); - green = (unsigned char)(255. * dg); - gl2psWriteByte(green); - blue = (unsigned char)(255. * db); - gl2psWriteByte(blue); - } - gl2psPrintf("\n"); - } - } - - gl2psPrintf("grestore\n"); -} - -static void gl2psPrintPostScriptImagemap(GLfloat x, GLfloat y, - 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 0 0 -%d 0 %d ] {<", width, height); - for(i = 0; i < size; i++){ - gl2psWriteByte(*imagemap); - imagemap++; - } - gl2psPrintf(">} imagemask\ngrestore\n"); -} - -static void gl2psPrintPostScriptHeader(void) -{ - time_t now; - - /* Since compression is not part of the PostScript standard, - compressed PostScript files are just gzipped PostScript files - ("ps.gz" or "eps.gz") */ - gl2psPrintGzipHeader(); - - time(&now); - - if(gl2ps->format == GL2PS_PS){ - gl2psPrintf("%%!PS-Adobe-3.0\n"); - } - else{ - gl2psPrintf("%%!PS-Adobe-3.0 EPSF-3.0\n"); - } - - gl2psPrintf("%%%%Title: %s\n" - "%%%%Creator: GL2PS %d.%d.%d%s, %s\n" - "%%%%For: %s\n" - "%%%%CreationDate: %s" - "%%%%LanguageLevel: 3\n" - "%%%%DocumentData: Clean7Bit\n" - "%%%%Pages: 1\n", - gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, - GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, - gl2ps->producer, ctime(&now)); - - if(gl2ps->format == GL2PS_PS){ - gl2psPrintf("%%%%Orientation: %s\n" - "%%%%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[3]); - } - - gl2psPrintf("%%%%BoundingBox: %d %d %d %d\n" - "%%%%EndComments\n", - (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] : - (int)gl2ps->viewport[2], - (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] : - (int)gl2ps->viewport[3]); - - /* RGB color: r g b C (replace C by G in output to change from rgb to gray) - Grayscale: r g b G - Font choose: size fontname FC - Text string: (string) x y size fontname S?? - Rotated text string: (string) angle x y size fontname S??R - Point primitive: x y size P - Line width: width W - Line start: x y LS - Line joining last point: x y L - Line end: x y LE - Flat-shaded triangle: x3 y3 x2 y2 x1 y1 T - Smooth-shaded triangle: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 ST */ - - gl2psPrintf("%%%%BeginProlog\n" - "/gl2psdict 64 dict def gl2psdict begin\n" - "0 setlinecap 0 setlinejoin\n" - "/tryPS3shading %s def %% set to false to force subdivision\n" - "/rThreshold %g def %% red component subdivision threshold\n" - "/gThreshold %g def %% green component subdivision threshold\n" - "/bThreshold %g def %% blue component subdivision threshold\n", - (gl2ps->options & GL2PS_NO_PS3_SHADING) ? "false" : "true", - gl2ps->threshold[0], gl2ps->threshold[1], gl2ps->threshold[2]); - - gl2psPrintf("/BD { bind def } bind def\n" - "/C { setrgbcolor } BD\n" - "/G { 0.082 mul exch 0.6094 mul add exch 0.3086 mul add neg 1.0 add setgray } BD\n" - "/W { setlinewidth } BD\n"); - - gl2psPrintf("/FC { findfont exch /SH exch def SH scalefont setfont } BD\n" - "/SW { dup stringwidth pop } BD\n" - "/S { FC moveto show } BD\n" - "/SBC{ FC moveto SW -2 div 0 rmoveto show } BD\n" - "/SBR{ FC moveto SW neg 0 rmoveto show } BD\n" - "/SCL{ FC moveto 0 SH -2 div rmoveto show } BD\n" - "/SCC{ FC moveto SW -2 div SH -2 div rmoveto show } BD\n" - "/SCR{ FC moveto SW neg SH -2 div rmoveto show } BD\n" - "/STL{ FC moveto 0 SH neg rmoveto show } BD\n" - "/STC{ FC moveto SW -2 div SH neg rmoveto show } BD\n" - "/STR{ FC moveto SW neg SH neg rmoveto show } BD\n"); - - /* 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" - "/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"); - gl2psPrintf("/SCCR{ gsave FCT moveto rotate SW -2 div SH -2 div rmoveto show grestore} BD\n" - "/SCRR{ gsave FCT moveto rotate SW neg SH -2 div rmoveto show grestore} BD\n" - "/STLR{ gsave FCT moveto rotate 0 SH neg rmoveto show grestore } BD\n" - "/STCR{ gsave FCT moveto rotate SW -2 div SH neg rmoveto show grestore } BD\n" - "/STRR{ gsave FCT moveto rotate SW neg SH neg rmoveto show grestore } BD\n"); - - gl2psPrintf("/P { newpath 0.0 360.0 arc closepath fill } BD\n" - "/LS { newpath moveto } BD\n" - "/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 */ - - gl2psPrintf("/STshfill {\n" - " /b1 exch def /g1 exch def /r1 exch def /y1 exch def /x1 exch def\n" - " /b2 exch def /g2 exch def /r2 exch def /y2 exch def /x2 exch def\n" - " /b3 exch def /g3 exch def /r3 exch def /y3 exch def /x3 exch def\n" - " gsave << /ShadingType 4 /ColorSpace [/DeviceRGB]\n" - " /DataSource [ 0 x1 y1 r1 g1 b1 0 x2 y2 r2 g2 b2 0 x3 y3 r3 g3 b3 ] >>\n" - " shfill grestore } BD\n"); - - /* Flat-shaded triangle with middle color: - x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 Tm */ - - gl2psPrintf(/* stack : x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 */ - "/Tm { 3 -1 roll 8 -1 roll 13 -1 roll add add 3 div\n" /* r = (r1+r2+r3)/3 */ - /* stack : x3 y3 g3 b3 x2 y2 g2 b2 x1 y1 g1 b1 r */ - " 3 -1 roll 7 -1 roll 11 -1 roll add add 3 div\n" /* g = (g1+g2+g3)/3 */ - /* stack : x3 y3 b3 x2 y2 b2 x1 y1 b1 r g b */ - " 3 -1 roll 6 -1 roll 9 -1 roll add add 3 div" /* b = (b1+b2+b3)/3 */ - /* stack : x3 y3 x2 y2 x1 y1 r g b */ - " C T } BD\n"); - - /* Split triangle in four sub-triangles (at sides middle points) and call the - STnoshfill procedure on each, interpolating the colors in RGB space: - x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STsplit - (in procedure comments key: (Vi) = xi yi ri gi bi) */ - - gl2psPrintf("/STsplit {\n" - " 4 index 15 index add 0.5 mul\n" /* x13 = (x1+x3)/2 */ - " 4 index 15 index add 0.5 mul\n" /* y13 = (y1+y3)/2 */ - " 4 index 15 index add 0.5 mul\n" /* r13 = (r1+r3)/2 */ - " 4 index 15 index add 0.5 mul\n" /* g13 = (g1+g3)/2 */ - " 4 index 15 index add 0.5 mul\n" /* b13 = (b1+b3)/2 */ - " 5 copy 5 copy 25 15 roll\n"); - - /* at his point, stack = (V3) (V13) (V13) (V13) (V2) (V1) */ - - gl2psPrintf(" 9 index 30 index add 0.5 mul\n" /* x23 = (x2+x3)/2 */ - " 9 index 30 index add 0.5 mul\n" /* y23 = (y2+y3)/2 */ - " 9 index 30 index add 0.5 mul\n" /* r23 = (r2+r3)/2 */ - " 9 index 30 index add 0.5 mul\n" /* g23 = (g2+g3)/2 */ - " 9 index 30 index add 0.5 mul\n" /* b23 = (b2+b3)/2 */ - " 5 copy 5 copy 35 5 roll 25 5 roll 15 5 roll\n"); - - /* stack = (V3) (V13) (V23) (V13) (V23) (V13) (V23) (V2) (V1) */ - - gl2psPrintf(" 4 index 10 index add 0.5 mul\n" /* x12 = (x1+x2)/2 */ - " 4 index 10 index add 0.5 mul\n" /* y12 = (y1+y2)/2 */ - " 4 index 10 index add 0.5 mul\n" /* r12 = (r1+r2)/2 */ - " 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 */ - - gl2psPrintf("/STnoshfill {\n" - " 2 index 8 index sub abs rThreshold gt\n" /* |r1-r2|>rth */ - " { STsplit }\n" - " { 1 index 7 index sub abs gThreshold gt\n" /* |g1-g2|>gth */ - " { STsplit }\n" - " { dup 6 index sub abs bThreshold gt\n" /* |b1-b2|>bth */ - " { STsplit }\n" - " { 2 index 13 index sub abs rThreshold gt\n" /* |r1-r3|>rht */ - " { STsplit }\n" - " { 1 index 12 index sub abs gThreshold gt\n" /* |g1-g3|>gth */ - " { STsplit }\n" - " { dup 11 index sub abs bThreshold gt\n" /* |b1-b3|>bth */ - " { STsplit }\n" - " { 7 index 13 index sub abs rThreshold gt\n"); /* |r2-r3|>rht */ - gl2psPrintf(" { STsplit }\n" - " { 6 index 12 index sub abs gThreshold gt\n" /* |g2-g3|>gth */ - " { STsplit }\n" - " { 5 index 11 index sub abs bThreshold gt\n" /* |b2-b3|>bth */ - " { STsplit }\n" - " { Tm }\n" /* all colors sufficiently similar */ - " ifelse }\n" - " ifelse }\n" - " ifelse }\n" - " ifelse }\n" - " ifelse }\n" - " ifelse }\n" - " ifelse }\n" - " ifelse }\n" - " ifelse } BD\n"); - - gl2psPrintf("tryPS3shading\n" - "{ /shfill where\n" - " { /ST { STshfill } BD }\n" - " { /ST { STnoshfill } BD }\n" - " ifelse }\n" - "{ /ST { STnoshfill } BD }\n" - "ifelse\n"); - - gl2psPrintf("end\n" - "%%%%EndProlog\n" - "%%%%BeginSetup\n" - "/DeviceRGB setcolorspace\n" - "gl2psdict begin\n" - "%%%%EndSetup\n" - "%%%%Page: 1 1\n" - "%%%%BeginPageSetup\n"); - - if(gl2ps->options & GL2PS_LANDSCAPE){ - gl2psPrintf("%d 0 translate 90 rotate\n", - (int)gl2ps->viewport[3]); - } - - gl2psPrintf("%%%%EndPageSetup\n" - "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], - (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]); - } -} - -static void gl2psPrintPostScriptColor(GL2PSrgba rgba) -{ - if(!gl2psSameColor(gl2ps->lastrgba, rgba)){ - gl2psSetLastColor(rgba); - gl2psPrintf("%g %g %g C\n", rgba[0], rgba[1], rgba[2]); - } -} - -static void gl2psResetPostScriptColor(void) -{ - gl2ps->lastrgba[0] = gl2ps->lastrgba[1] = gl2ps->lastrgba[2] = -1.; -} - -static void gl2psEndPostScriptLine(void) -{ - int i; - if(gl2ps->lastvertex.rgba[0] >= 0.){ - gl2psPrintf("%g %g LE\n", gl2ps->lastvertex.xyz[0], gl2ps->lastvertex.xyz[1]); - for(i = 0; i < 3; i++) - gl2ps->lastvertex.xyz[i] = -1.; - for(i = 0; i < 4; i++) - gl2ps->lastvertex.rgba[i] = -1.; - } -} - -static void gl2psParseStipplePattern(GLushort pattern, GLint factor, - int *nb, int array[10]) -{ - int i, n; - int on[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - int off[8] = {0, 0, 0, 0, 0, 0, 0, 0}; - char tmp[16]; - - /* extract the 16 bits from the OpenGL stipple pattern */ - for(n = 15; n >= 0; n--){ - tmp[n] = (char)(pattern & 0x01); - pattern >>= 1; - } - /* compute the on/off pixel sequence */ - n = 0; - for(i = 0; i < 8; i++){ - while(n < 16 && !tmp[n]){ off[i]++; n++; } - while(n < 16 && tmp[n]){ on[i]++; n++; } - if(n >= 15){ i++; break; } - } - - /* store the on/off array from right to left, starting with off - pixels. The PostScript specification allows for at most 11 - elements in the on/off array, so we limit ourselves to 5 on/off - couples (our longest possible array is thus [on4 off4 on3 off3 - on2 off2 on1 off1 on0 off0]) */ - *nb = 0; - for(n = i - 1; n >= 0; n--){ - array[(*nb)++] = factor * on[n]; - array[(*nb)++] = factor * off[n]; - if(*nb == 10) break; - } -} - -static int gl2psPrintPostScriptDash(GLushort pattern, GLint factor, const char *str) -{ - int len = 0, i, n, array[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); - } - else{ - gl2psParseStipplePattern(pattern, factor, &n, array); - len += gl2psPrintf("["); - for(i = 0; i < n; i++){ - if(i) len += gl2psPrintf(" "); - len += gl2psPrintf("%d", array[i]); - } - len += gl2psPrintf("] 0 %s\n", str); - } - - return len; -} - -static void gl2psPrintPostScriptPrimitive(void *data) -{ - int newline; - GL2PSprimitive *prim; - - prim = *(GL2PSprimitive**)data; - - if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return; - - /* Every effort is made to draw lines as connected segments (i.e., - using a single PostScript path): this is the only way to get nice - line joins and to not restart the stippling for every line - segment. So if the primitive to print is not a line we must first - finish the current line (if any): */ - if(prim->type != GL2PS_LINE) gl2psEndPostScriptLine(); - - switch(prim->type){ - case GL2PS_POINT : - gl2psPrintPostScriptColor(prim->verts[0].rgba); - gl2psPrintf("%g %g %g P\n", - prim->verts[0].xyz[0], prim->verts[0].xyz[1], 0.5 * prim->width); - break; - case GL2PS_LINE : - if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) || - !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) || - gl2ps->lastlinewidth != prim->width || - gl2ps->lastpattern != prim->pattern || - gl2ps->lastfactor != prim->factor){ - /* End the current line if the new segment does not start where - the last one ended, or if the color, the width or the - stippling have changed (multi-stroking lines with changing - colors is necessary until we use /shfill for lines; - unfortunately this means that at the moment we can screw up - line stippling for smooth-shaded lines) */ - gl2psEndPostScriptLine(); - newline = 1; - } - else{ - newline = 0; - } - if(gl2ps->lastlinewidth != prim->width){ - gl2ps->lastlinewidth = prim->width; - gl2psPrintf("%g W\n", gl2ps->lastlinewidth); - } - gl2psPrintPostScriptDash(prim->pattern, prim->factor, "setdash"); - gl2psPrintPostScriptColor(prim->verts[0].rgba); - gl2psPrintf("%g %g %s\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1], - newline ? "LS" : "L"); - gl2ps->lastvertex = prim->verts[1]; - break; - case GL2PS_TRIANGLE : - if(!gl2psVertsSameColor(prim)){ - gl2psResetPostScriptColor(); - gl2psPrintf("%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g ST\n", - prim->verts[2].xyz[0], prim->verts[2].xyz[1], - prim->verts[2].rgba[0], prim->verts[2].rgba[1], - prim->verts[2].rgba[2], prim->verts[1].xyz[0], - prim->verts[1].xyz[1], prim->verts[1].rgba[0], - prim->verts[1].rgba[1], prim->verts[1].rgba[2], - prim->verts[0].xyz[0], prim->verts[0].xyz[1], - prim->verts[0].rgba[0], prim->verts[0].rgba[1], - prim->verts[0].rgba[2]); - } - else{ - gl2psPrintPostScriptColor(prim->verts[0].rgba); - gl2psPrintf("%g %g %g %g %g %g T\n", - prim->verts[2].xyz[0], prim->verts[2].xyz[1], - prim->verts[1].xyz[0], prim->verts[1].xyz[1], - prim->verts[0].xyz[0], prim->verts[0].xyz[1]); - } - break; - case GL2PS_QUADRANGLE : - gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print"); - break; - case GL2PS_PIXMAP : - gl2psPrintPostScriptPixmap(prim->verts[0].xyz[0], prim->verts[0].xyz[1], - prim->data.image); - break; - case GL2PS_IMAGEMAP : - if(prim->data.image->type != GL2PS_IMAGEMAP_WRITTEN){ - gl2psPrintPostScriptColor(prim->verts[0].rgba); - gl2psPrintPostScriptImagemap(prim->data.image->pixels[0], - prim->data.image->pixels[1], - prim->data.image->width, prim->data.image->height, - (const unsigned char*)(&(prim->data.image->pixels[2]))); - prim->data.image->type = GL2PS_IMAGEMAP_WRITTEN; - } - break; - case GL2PS_TEXT : - gl2psPrintPostScriptColor(prim->verts[0].rgba); - gl2psPrintf("(%s) ", prim->data.text->str); - if(prim->data.text->angle) - gl2psPrintf("%g ", prim->data.text->angle); - gl2psPrintf("%g %g %d /%s ", - prim->verts[0].xyz[0], prim->verts[0].xyz[1], - prim->data.text->fontsize, prim->data.text->fontname); - switch(prim->data.text->alignment){ - case GL2PS_TEXT_C: - gl2psPrintf(prim->data.text->angle ? "SCCR\n" : "SCC\n"); - break; - case GL2PS_TEXT_CL: - gl2psPrintf(prim->data.text->angle ? "SCLR\n" : "SCL\n"); - break; - case GL2PS_TEXT_CR: - gl2psPrintf(prim->data.text->angle ? "SCRR\n" : "SCR\n"); - break; - case GL2PS_TEXT_B: - gl2psPrintf(prim->data.text->angle ? "SBCR\n" : "SBC\n"); - break; - case GL2PS_TEXT_BR: - gl2psPrintf(prim->data.text->angle ? "SBRR\n" : "SBR\n"); - break; - case GL2PS_TEXT_T: - gl2psPrintf(prim->data.text->angle ? "STCR\n" : "STC\n"); - break; - case GL2PS_TEXT_TL: - gl2psPrintf(prim->data.text->angle ? "STLR\n" : "STL\n"); - break; - case GL2PS_TEXT_TR: - gl2psPrintf(prim->data.text->angle ? "STRR\n" : "STR\n"); - break; - case GL2PS_TEXT_BL: - default: - gl2psPrintf(prim->data.text->angle ? "SR\n" : "S\n"); - break; - } - break; - case GL2PS_SPECIAL : - /* alignment contains the format for which the special output text - is intended */ - if(prim->data.text->alignment == GL2PS_PS || - prim->data.text->alignment == GL2PS_EPS) - gl2psPrintf("%s\n", prim->data.text->str); - break; - default : - break; - } -} - -static void gl2psPrintPostScriptFooter(void) -{ - gl2psPrintf("grestore\n" - "showpage\n" - "cleartomark\n" - "%%%%PageTrailer\n" - "%%%%Trailer\n" - "end\n" - "%%%%EOF\n"); - - gl2psPrintGzipFooter(); -} - -static void gl2psPrintPostScriptBeginViewport(GLint viewport[4]) -{ - GLint index; - GLfloat rgba[4]; - int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; - - glRenderMode(GL_FEEDBACK); - - if(gl2ps->header){ - gl2psPrintPostScriptHeader(); - gl2ps->header = GL_FALSE; - } - - gl2psPrintf("gsave\n" - "1.0 1.0 scale\n"); - - if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ - if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ - glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); - } - else{ - glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); - rgba[0] = gl2ps->colormap[index][0]; - rgba[1] = gl2ps->colormap[index][1]; - rgba[2] = gl2ps->colormap[index][2]; - rgba[3] = 1.0F; - } - 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], - 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) -{ - GLint res; - - res = gl2psPrintPrimitives(); - gl2psPrintf("grestore\n"); - return res; -} - -static void gl2psPrintPostScriptFinalPrimitive(void) -{ - /* End any remaining line, if any */ - gl2psEndPostScriptLine(); -} - -/* definition of the PostScript and Encapsulated PostScript backends */ - -static GL2PSbackend gl2psPS = { - gl2psPrintPostScriptHeader, - gl2psPrintPostScriptFooter, - gl2psPrintPostScriptBeginViewport, - gl2psPrintPostScriptEndViewport, - gl2psPrintPostScriptPrimitive, - gl2psPrintPostScriptFinalPrimitive, - "ps", - "Postscript" -}; - -static GL2PSbackend gl2psEPS = { - gl2psPrintPostScriptHeader, - gl2psPrintPostScriptFooter, - gl2psPrintPostScriptBeginViewport, - gl2psPrintPostScriptEndViewport, - gl2psPrintPostScriptPrimitive, - gl2psPrintPostScriptFinalPrimitive, - "eps", - "Encapsulated Postscript" -}; - -/********************************************************************* - * - * LaTeX routines - * - *********************************************************************/ - -static void gl2psPrintTeXHeader(void) -{ - char name[256]; - time_t now; - int i; - - if(gl2ps->filename && strlen(gl2ps->filename) < 256){ - for(i = (int)strlen(gl2ps->filename) - 1; i >= 0; i--){ - if(gl2ps->filename[i] == '.'){ - strncpy(name, gl2ps->filename, i); - name[i] = '\0'; - break; - } - } - if(i <= 0) strcpy(name, gl2ps->filename); - } - else{ - strcpy(name, "untitled"); - } - - time(&now); - - fprintf(gl2ps->stream, - "%% Title: %s\n" - "%% Creator: GL2PS %d.%d.%d%s, %s\n" - "%% For: %s\n" - "%% CreationDate: %s", - gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, - GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, - gl2ps->producer, ctime(&now)); - - fprintf(gl2ps->stream, - "\\setlength{\\unitlength}{1pt}\n" - "\\begin{picture}(0,0)\n" - "\\includegraphics{%s}\n" - "\\end{picture}%%\n" - "%s\\begin{picture}(%d,%d)(0,0)\n", - name, (gl2ps->options & GL2PS_LANDSCAPE) ? "\\rotatebox{90}{" : "", - (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); -} - -static void gl2psPrintTeXPrimitive(void *data) -{ - GL2PSprimitive *prim; - - prim = *(GL2PSprimitive**)data; - - switch(prim->type){ - case GL2PS_TEXT : - fprintf(gl2ps->stream, "\\fontsize{%d}{0}\n\\selectfont", - prim->data.text->fontsize); - fprintf(gl2ps->stream, "\\put(%g,%g)", - 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, "{"); - break; - case GL2PS_TEXT_CL: - fprintf(gl2ps->stream, "[l]{"); - break; - case GL2PS_TEXT_CR: - fprintf(gl2ps->stream, "[r]{"); - break; - case GL2PS_TEXT_B: - fprintf(gl2ps->stream, "[b]{"); - break; - case GL2PS_TEXT_BR: - fprintf(gl2ps->stream, "[br]{"); - break; - case GL2PS_TEXT_T: - fprintf(gl2ps->stream, "[t]{"); - break; - case GL2PS_TEXT_TL: - fprintf(gl2ps->stream, "[tl]{"); - break; - case GL2PS_TEXT_TR: - fprintf(gl2ps->stream, "[tr]{"); - break; - case GL2PS_TEXT_BL: - default: - fprintf(gl2ps->stream, "[bl]{"); - break; - } - 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); - if(prim->data.text->angle) - fprintf(gl2ps->stream, "}"); - fprintf(gl2ps->stream, "}}\n"); - break; - case GL2PS_SPECIAL : - /* alignment contains the format for which the special output text - is intended */ - if (prim->data.text->alignment == GL2PS_TEX) - fprintf(gl2ps->stream, "%s\n", prim->data.text->str); - break; - default : - break; - } -} - -static void gl2psPrintTeXFooter(void) -{ - fprintf(gl2ps->stream, "\\end{picture}%s\n", - (gl2ps->options & GL2PS_LANDSCAPE) ? "}" : ""); -} - -static void gl2psPrintTeXBeginViewport(GLint viewport[4]) -{ - (void) viewport; /* not used */ - glRenderMode(GL_FEEDBACK); - - if(gl2ps->header){ - gl2psPrintTeXHeader(); - gl2ps->header = GL_FALSE; - } -} - -static GLint gl2psPrintTeXEndViewport(void) -{ - return gl2psPrintPrimitives(); -} - -static void gl2psPrintTeXFinalPrimitive(void) -{ -} - -/* definition of the LaTeX backend */ - -static GL2PSbackend gl2psTEX = { - gl2psPrintTeXHeader, - gl2psPrintTeXFooter, - gl2psPrintTeXBeginViewport, - gl2psPrintTeXEndViewport, - gl2psPrintTeXPrimitive, - gl2psPrintTeXFinalPrimitive, - "tex", - "LaTeX text" -}; - -/********************************************************************* - * - * PDF routines - * - *********************************************************************/ - -static int gl2psPrintPDFCompressorType(void) -{ -#if defined(GL2PS_HAVE_ZLIB) - if(gl2ps->options & GL2PS_COMPRESS){ - return fprintf(gl2ps->stream, "/Filter [/FlateDecode]\n"); - } -#endif - return 0; -} - -static int gl2psPrintPDFStrokeColor(GL2PSrgba rgba) -{ - int i, offs = 0; - - gl2psSetLastColor(rgba); - for(i = 0; i < 3; ++i){ - if(GL2PS_ZERO(rgba[i])) - offs += gl2psPrintf("%.0f ", 0.); - else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting */ - offs += gl2psPrintf("%f ", rgba[i]); - else - offs += gl2psPrintf("%g ", rgba[i]); - } - offs += gl2psPrintf("RG\n"); - return offs; -} - -static int gl2psPrintPDFFillColor(GL2PSrgba rgba) -{ - int i, offs = 0; - - for(i = 0; i < 3; ++i){ - if(GL2PS_ZERO(rgba[i])) - offs += gl2psPrintf("%.0f ", 0.); - else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting */ - offs += gl2psPrintf("%f ", rgba[i]); - else - offs += gl2psPrintf("%g ", rgba[i]); - } - offs += gl2psPrintf("rg\n"); - return offs; -} - -static int gl2psPrintPDFLineWidth(GLfloat lw) -{ - if(GL2PS_ZERO(lw)) - return gl2psPrintf("%.0f w\n", 0.); - else if(lw < 1e-4 || lw > 1e6) /* avoid %e formatting */ - return gl2psPrintf("%f w\n", lw); - else - return gl2psPrintf("%g w\n", lw); -} - -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", - cnt, text->fontsize, x, y, text->str); - } - else{ - rad = (GLfloat)(M_PI * text->angle / 180.0F); - srad = (GLfloat)sin(rad); - crad = (GLfloat)cos(rad); - gl2ps->streamlength += gl2psPrintf - ("BT\n" - "/F%d %d Tf\n" - "%f %f %f %f %f %f Tm\n" - "(%s) Tj\n" - "ET\n", - cnt, text->fontsize, crad, srad, -srad, crad, x, y, text->str); - } -} - -static void gl2psPutPDFImage(GL2PSimage *image, int cnt, GLfloat x, GLfloat y) -{ - gl2ps->streamlength += gl2psPrintf - ("q\n" - "%d 0 0 %d %f %f cm\n" - "/Im%d Do\n" - "Q\n", - (int)image->width, (int)image->height, x, y, cnt); -} - -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; -} - -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->maskshobjno = gro->gsobjno = gro->trgroupobjno = -1; -} - -/* Build up group objects and assign name and object numbers */ - -static void gl2psPDFgroupListInit(void) -{ - int i; - GL2PSprimitive *p = NULL; - GL2PSpdfgroup gro; - int lasttype = GL2PS_NO_TYPE; - GL2PSrgba lastrgba = {-1.0F, -1.0F, -1.0F, -1.0F}; - GLushort lastpattern = 0; - GLint lastfactor = 0; - GLfloat lastwidth = 1; - GL2PStriangle lastt, tmpt; - int lastTriangleWasNotSimpleWithSameColor = 0; - - if(!gl2ps->pdfprimlist) - return; - - gl2ps->pdfgrouplist = gl2psListCreate(500, 500, sizeof(GL2PSpdfgroup)); - gl2psInitTriangle(&lastt); - - for(i = 0; i < gl2psListNbr(gl2ps->pdfprimlist); ++i){ - p = *(GL2PSprimitive**)gl2psListPointer(gl2ps->pdfprimlist, i); - switch(p->type){ - case GL2PS_PIXMAP: - gl2psPDFgroupObjectInit(&gro); - gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); - gro.imno = gl2ps->im_stack++; - gl2psListAdd(gro.ptrlist, &p); - gl2psListAdd(gl2ps->pdfgrouplist, &gro); - break; - case GL2PS_TEXT: - gl2psPDFgroupObjectInit(&gro); - gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); - gro.fontno = gl2ps->font_stack++; - gl2psListAdd(gro.ptrlist, &p); - gl2psListAdd(gl2ps->pdfgrouplist, &gro); - break; - case GL2PS_LINE: - if(lasttype != p->type || lastwidth != p->width || - lastpattern != p->pattern || lastfactor != p->factor || - !gl2psSameColor(p->verts[0].rgba, lastrgba)){ - gl2psPDFgroupObjectInit(&gro); - gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); - gl2psListAdd(gro.ptrlist, &p); - gl2psListAdd(gl2ps->pdfgrouplist, &gro); - } - else{ - gl2psListAdd(gro.ptrlist, &p); - } - lastpattern = p->pattern; - lastfactor = p->factor; - lastwidth = p->width; - lastrgba[0] = p->verts[0].rgba[0]; - lastrgba[1] = p->verts[0].rgba[1]; - lastrgba[2] = p->verts[0].rgba[2]; - break; - case GL2PS_POINT: - if(lasttype != p->type || lastwidth != p->width || - !gl2psSameColor(p->verts[0].rgba, lastrgba)){ - gl2psPDFgroupObjectInit(&gro); - gro.ptrlist = gl2psListCreate(1,2,sizeof(GL2PSprimitive*)); - gl2psListAdd(gro.ptrlist, &p); - gl2psListAdd(gl2ps->pdfgrouplist, &gro); - } - else{ - gl2psListAdd(gro.ptrlist, &p); - } - lastwidth = p->width; - lastrgba[0] = p->verts[0].rgba[0]; - lastrgba[1] = p->verts[0].rgba[1]; - lastrgba[2] = p->verts[0].rgba[2]; - break; - case GL2PS_TRIANGLE: - gl2psFillTriangleFromPrimitive(&tmpt, p, GL_TRUE); - 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 && - lastTriangleWasNotSimpleWithSameColor){ - /* TODO Check here for last alpha */ - gl2psListAdd(gro.ptrlist, &p); - } - else{ - gl2psPDFgroupObjectInit(&gro); - gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); - gl2psListAdd(gro.ptrlist, &p); - gl2psListAdd(gl2ps->pdfgrouplist, &gro); - } - lastt = tmpt; - break; - default: - break; - } - lasttype = p->type; - } -} - -static void gl2psSortOutTrianglePDFgroup(GL2PSpdfgroup *gro) -{ - GL2PStriangle t; - GL2PSprimitive *prim = NULL; - - if(!gro) - return; - - if(!gl2psListNbr(gro->ptrlist)) - return; - - prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); - - if(prim->type != GL2PS_TRIANGLE) - return; - - gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE); - - 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){ - gro->gsno = gl2ps->extgs_stack++; - gro->gsobjno = gl2ps->objects_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){ - gro->shno = gl2ps->shader_stack++; - gro->shobjno = gl2ps->objects_stack++; - } - 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->shobjno = gl2ps->objects_stack++; - } - 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->shobjno = gl2ps->objects_stack++; - gro->trgroupno = gl2ps->trgroupobjects_stack++; - gro->trgroupobjno = gl2ps->objects_stack++; - gro->maskshno = gl2ps->mshader_stack++; - gro->maskshobjno = gl2ps->objects_stack++; - } -} - -/* Main stream data */ - -static void gl2psPDFgroupListWriteMainStream(void) -{ - int i, j, lastel; - GL2PSprimitive *prim = NULL, *prev = NULL; - GL2PSpdfgroup *gro; - GL2PStriangle t; - - if(!gl2ps->pdfgrouplist) - return; - - for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ - gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); - - lastel = gl2psListNbr(gro->ptrlist) - 1; - if(lastel < 0) - continue; - - prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); - - switch(prim->type){ - case GL2PS_POINT: - gl2ps->streamlength += gl2psPrintf("1 J\n"); - gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width); - gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba); - 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("0 J\n"); - break; - case GL2PS_LINE: - /* We try to use as few paths as possible to draw lines, in - order to get nice stippling even when the individual segments - are smaller than the stipple */ - gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width); - 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", - prim->verts[0].xyz[0], prim->verts[0].xyz[1]); - - for(j = 1; j <= lastel; ++j){ - prev = prim; - prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); - if(!gl2psSamePosition(prim->verts[0].xyz, prev->verts[1].xyz)){ - /* 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", - prev->verts[1].xyz[0], prev->verts[1].xyz[1]); - 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 += - 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", - 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){ - prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); - gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); - gl2ps->streamlength - += gl2psPrintf("%f %f m\n" - "%f %f l\n" - "%f %f l\n" - "h f\n", - t.vertex[0].xyz[0], t.vertex[0].xyz[1], - t.vertex[1].xyz[0], t.vertex[1].xyz[1], - t.vertex[2].xyz[0], t.vertex[2].xyz[1]); - } - } - /* 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){ - gl2ps->streamlength += gl2psPrintf("q\n" - "/GS%d gs\n", - gro->gsno); - gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); - for(j = 0; j <= lastel; ++j){ - prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); - gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); - gl2ps->streamlength - += gl2psPrintf("%f %f m\n" - "%f %f l\n" - "%f %f l\n" - "h f\n", - t.vertex[0].xyz[0], t.vertex[0].xyz[1], - t.vertex[1].xyz[0], t.vertex[1].xyz[1], - t.vertex[2].xyz[0], t.vertex[2].xyz[1]); - } - gl2ps->streamlength += gl2psPrintf("Q\n"); - } - /* 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){ - 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){ - prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); - gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); - gl2ps->streamlength - += gl2psPrintf("%f %f m\n" - "%f %f l\n" - "%f %f l\n" - "h f\n", - t.vertex[0].xyz[0], t.vertex[0].xyz[1], - t.vertex[1].xyz[0], t.vertex[1].xyz[1], - t.vertex[2].xyz[0], t.vertex[2].xyz[1]); - } - gl2ps->streamlength += gl2psPrintf("Q\n"); - } - /* Variable color and no alpha: Shader Object for the colored - triangle(s) */ - 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 - for the alpha const */ - 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 - + Xobject + Shader object for the alpha mask */ - 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" - "/Sh%d sh\n" - "Q\n", - gro->gsno, gro->trgroupno, gro->shno); - } - break; - 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], - prim->verts[0].xyz[1]); - } - break; - case GL2PS_TEXT: - 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], - prim->verts[0].xyz[1]); - } - break; - default: - break; - } - } -} - -/* Graphics State names */ - -static int gl2psPDFgroupListWriteGStateResources(void) -{ - GL2PSpdfgroup *gro; - int offs = 0; - int i; - - offs += fprintf(gl2ps->stream, - "/ExtGState\n" - "<<\n" - "/GSa 7 0 R\n"); - 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"); - return offs; -} - -/* Main Shader names */ - -static int gl2psPDFgroupListWriteShaderResources(void) -{ - GL2PSpdfgroup *gro; - int offs = 0; - int i; - - offs += fprintf(gl2ps->stream, - "/Shading\n" - "<<\n"); - 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"); - return offs; -} - -/* Images & Mask Shader XObject names */ - -static int gl2psPDFgroupListWriteXObjectResources(void) -{ - int i; - GL2PSprimitive *p = NULL; - GL2PSpdfgroup *gro; - int offs = 0; - - offs += fprintf(gl2ps->stream, - "/XObject\n" - "<<\n"); - - 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); - switch(p->type){ - case GL2PS_PIXMAP: - gro->imobjno = gl2ps->objects_stack++; - if(GL_RGBA == p->data.image->format) /* reserve one object for image mask */ - gl2ps->objects_stack++; - offs += fprintf(gl2ps->stream, "/Im%d %d 0 R\n", gro->imno, gro->imobjno); - case GL2PS_TRIANGLE: - if(gro->trgroupno >=0) - offs += fprintf(gl2ps->stream, "/TrG%d %d 0 R\n", gro->trgroupno, gro->trgroupobjno); - break; - default: - break; - } - } - offs += fprintf(gl2ps->stream,">>\n"); - return offs; -} - -/* Font names */ - -static int gl2psPDFgroupListWriteFontResources(void) -{ - int i; - GL2PSpdfgroup *gro; - int offs = 0; - - offs += fprintf(gl2ps->stream, "/Font\n<<\n"); - - for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ - gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); - if(gro->fontno < 0) - continue; - gro->fontobjno = gl2ps->objects_stack++; - offs += fprintf(gl2ps->stream, "/F%d %d 0 R\n", gro->fontno, gro->fontobjno); - } - offs += fprintf(gl2ps->stream, ">>\n"); - - return offs; -} - -static void gl2psPDFgroupListDelete(void) -{ - int i; - GL2PSpdfgroup *gro = NULL; - - if(!gl2ps->pdfgrouplist) - return; - - for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ - gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist,i); - gl2psListDelete(gro->ptrlist); - } - - gl2psListDelete(gl2ps->pdfgrouplist); - gl2ps->pdfgrouplist = NULL; -} - -/* Print 1st PDF object - file info */ - -static int gl2psPrintPDFInfo(void) -{ - int offs; - time_t now; - struct tm *newtime; - - time(&now); - newtime = gmtime(&now); - - offs = fprintf(gl2ps->stream, - "1 0 obj\n" - "<<\n" - "/Title (%s)\n" - "/Creator (GL2PS %d.%d.%d%s, %s)\n" - "/Producer (%s)\n", - gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, - GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, - gl2ps->producer); - - if(!newtime){ - offs += fprintf(gl2ps->stream, - ">>\n" - "endobj\n"); - return offs; - } - - 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_mday, - newtime->tm_hour, - newtime->tm_min, - newtime->tm_sec); - return offs; -} - -/* Create catalog and page structure - 2nd and 3th PDF object */ - -static int gl2psPrintPDFCatalog(void) -{ - return fprintf(gl2ps->stream, - "2 0 obj\n" - "<<\n" - "/Type /Catalog\n" - "/Pages 3 0 R\n" - ">>\n" - "endobj\n"); -} - -static int gl2psPrintPDFPages(void) -{ - return fprintf(gl2ps->stream, - "3 0 obj\n" - "<<\n" - "/Type /Pages\n" - "/Kids [6 0 R]\n" - "/Count 1\n" - ">>\n" - "endobj\n"); -} - -/* Open stream for data - graphical objects, fonts etc. PDF object 4 */ - -static int gl2psOpenPDFDataStream(void) -{ - int offs = 0; - - offs += fprintf(gl2ps->stream, - "4 0 obj\n" - "<<\n" - "/Length 5 0 R\n" ); - offs += gl2psPrintPDFCompressorType(); - offs += fprintf(gl2ps->stream, - ">>\n" - "stream\n"); - return offs; -} - -/* Stream setup - Graphics state, fill background if allowed */ - -static int gl2psOpenPDFDataStreamWritePreface(void) -{ - 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"); - } - return offs; -} - -/* Use the functions above to create the first part of the PDF*/ - -static void gl2psPrintPDFHeader(void) -{ - int offs = 0; - gl2ps->pdfprimlist = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*)); - gl2psPDFstacksInit(); - - gl2ps->xreflist = (int*)gl2psMalloc(sizeof(int) * gl2ps->objects_stack); - -#if defined(GL2PS_HAVE_ZLIB) - if(gl2ps->options & GL2PS_COMPRESS){ - gl2psSetupCompress(); - } -#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(); -} - -/* The central primitive drawing */ - -static void gl2psPrintPDFPrimitive(void *data) -{ - GL2PSprimitive *prim = *(GL2PSprimitive**)data; - - if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) - return; - - prim = gl2psCopyPrimitive(prim); /* deep copy */ - gl2psListAdd(gl2ps->pdfprimlist, &prim); -} - -/* close stream and ... */ - -static int gl2psClosePDFDataStream(void) -{ - int offs = 0; - -#if defined(GL2PS_HAVE_ZLIB) - if(gl2ps->options & GL2PS_COMPRESS){ - if(Z_OK != gl2psDeflate()) - gl2psMsg(GL2PS_ERROR, "Zlib deflate error"); - 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, - "endstream\n" - "endobj\n"); - return offs; -} - -/* ... write the now known length object */ - -static int gl2psPrintPDFDataStreamLength(int val) -{ - return fprintf(gl2ps->stream, - "5 0 obj\n" - "%d\n" - "endobj\n", val); -} - -/* Put the info created before in PDF objects */ - -static int gl2psPrintPDFOpenPage(void) -{ - int offs; - - /* Write fixed part */ - - offs = fprintf(gl2ps->stream, - "6 0 obj\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" - "/ProcSet [/PDF /Text /ImageB /ImageC] %%/ImageI\n"); - - return offs; - - /* End fixed part, proceeds in gl2psPDFgroupListWriteVariableResources() */ -} - -static int gl2psPDFgroupListWriteVariableResources(void) -{ - int offs = 0; - - /* a) Graphics States for shader alpha masks*/ - 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" - ">>\n" - "endobj\n"); - return offs; -} - -/* Standard Graphics State */ - -static int gl2psPrintPDFGSObject(void) -{ - return fprintf(gl2ps->stream, - "7 0 obj\n" - "<<\n" - "/Type /ExtGState\n" - "/SA false\n" - "/SM 0.02\n" - "/OP false\n" - "/op false\n" - "/OPM 0\n" - "/BG2 /Default\n" - "/UCR2 /Default\n" - "/TR2 /Default\n" - ">>\n" - "endobj\n"); -} - -/* Put vertex' edge flag (8bit) and coordinates (32bit) in shader stream */ - -static int gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex *vertex, - int (*action)(unsigned long data, int size), - GLfloat dx, GLfloat dy, - GLfloat xmin, GLfloat ymin) -{ - int offs = 0; - unsigned long imap; - GLfloat diff; - double dmax = ~1UL; - char edgeflag = 0; - - /* FIXME: temp bux fix for 64 bit archs: */ - if(sizeof(unsigned long) == 8) dmax = dmax - 2048.; - - offs += (*action)(edgeflag, 1); - - /* 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); - } - else{ - diff = (vertex->xyz[0] - xmin) / dx; - if(diff > 1) - diff = 1.0F; - else if(diff < 0) - diff = 0.0F; - imap = (unsigned long)(diff * dmax); - offs += (*action)(imap, 4); - - diff = (vertex->xyz[1] - ymin) / dy; - if(diff > 1) - diff = 1.0F; - else if(diff < 0) - diff = 0.0F; - 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, - int (*action)(unsigned long data, int size)) -{ - int offs = 0; - unsigned long imap; - double dmax = ~1UL; - - /* FIXME: temp bux fix for 64 bit archs: */ - if(sizeof(unsigned long) == 8) dmax = dmax - 2048.; - - 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, - int (*action)(unsigned long data, int size), - int sigbyte) -{ - int offs = 0; - unsigned long imap; - double dmax = ~1UL; - - /* FIXME: temp bux fix for 64 bit archs: */ - if(sizeof(unsigned long) == 8) dmax = dmax - 2048.; - - 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, - GLfloat xmin, GLfloat ymin, - int (*action)(unsigned long data, int 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){ - v = triangle->vertex[i]; - 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, - GL2PStriangle *triangles, int cnt) -{ - int i, j; - - *xmin = triangles[0].vertex[0].xyz[0]; - *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]) - *xmin = triangles[i].vertex[j].xyz[0]; - if(*xmax < triangles[i].vertex[j].xyz[0]) - *xmax = triangles[i].vertex[j].xyz[0]; - if(*ymin > triangles[i].vertex[j].xyz[1]) - *ymin = triangles[i].vertex[j].xyz[1]; - if(*ymax < triangles[i].vertex[j].xyz[1]) - *ymax = triangles[i].vertex[j].xyz[1]; - } - } -} - -/* 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, - 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; - break; - case 8: - vertexbytes = 1+4+4+1; - break; - case 16: - vertexbytes = 1+4+4+2; - break; - default: - gray = 8; - vertexbytes = 1+4+4+1; - break; - } - - gl2psPDFRectHull(&xmin, &xmax, &ymin, &ymax, triangles, size); - - offs += fprintf(gl2ps->stream, - "%d 0 obj\n" - "<< " - "/ShadingType 4 " - "/ColorSpace %s " - "/BitsPerCoordinate 32 " - "/BitsPerComponent %d " - "/BitsPerFlag 8 " - "/Decode [%f %f %f %f 0 1 %s] ", - obj, - (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, - gl2psWriteBigEndianCompress, gray); - - if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){ - offs += gl2psPrintPDFCompressorType(); - offs += fprintf(gl2ps->stream, - "/Length %d " - ">>\n" - "stream\n", - (int)gl2ps->compress->destLen); - offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, - gl2ps->compress->destLen, - 1, gl2ps->stream); - done = 1; - } - gl2psFreeCompress(); - } -#endif - - if(!done){ - /* no compression, or too long after compression, or compress error - -> write non-compressed entry */ - offs += fprintf(gl2ps->stream, - "/Length %d " - ">>\n" - "stream\n", - vertexbytes * 3 * size); - for(i = 0; i < size; ++i) - offs += gl2psPrintPDFShaderStreamData(&triangles[i], - xmax-xmin, ymax-ymin, xmin, ymin, - gl2psWriteBigEndian, gray); - } - - offs += fprintf(gl2ps->stream, - "\nendstream\n" - "endobj\n"); - - return offs; -} - -/* Writes a XObject for a shaded triangle mask */ - -static int gl2psPrintPDFShaderMask(int obj, int childobj) -{ - int offs = 0, len; - - offs += fprintf(gl2ps->stream, - "%d 0 obj\n" - "<<\n" - "/Type /XObject\n" - "/Subtype /Form\n" - "/BBox [ %d %d %d %d ]\n" - "/Group \n<<\n/S /Transparency /CS /DeviceRGB\n" - ">>\n", - obj, - (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], - (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); - - len = (childobj>0) - ? strlen("/TrSh sh\n") + (int)log10((double)childobj)+1 - : strlen("/TrSh0 sh\n"); - - offs += fprintf(gl2ps->stream, - "/Length %d\n" - ">>\n" - "stream\n", - len); - offs += fprintf(gl2ps->stream, - "/TrSh%d sh\n", - childobj); - offs += fprintf(gl2ps->stream, - "endstream\n" - "endobj\n"); - - return offs; -} - -/* Writes a Extended graphics state for a shaded triangle mask if - simplealpha ist true the childobj argument is ignored and a /ca - statement will be written instead */ - -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"); - return offs; -} - -/* a simple graphics state */ - -static int gl2psPrintPDFShaderSimpleExtGS(int obj, GLfloat alpha) -{ - int offs = 0; - - offs += fprintf(gl2ps->stream, - "%d 0 obj\n" - "<<\n" - "/ca %g" - ">>\n" - "endobj\n", - obj, alpha); - return offs; -} - -/* Similar groups of functions for pixmaps and text */ - -static int gl2psPrintPDFPixmapStreamData(GL2PSimage *im, - int (*action)(unsigned long data, int size), - int gray) -{ - int x, y, shift; - GLfloat r, g, b, a; - - if(im->format != GL_RGBA && gray) - return 0; - - if(gray && gray != 8 && gray != 16) - gray = 8; - - gray /= 8; - - shift = (sizeof(unsigned long) - 1) * 8; - - for(y = 0; y < im->height; ++y){ - for(x = 0; x < im->width; ++x){ - a = gl2psGetRGB(im, x, y, &r, &g, &b); - if(im->format == GL_RGBA && gray){ - (*action)((unsigned long)(a * 255) << shift, gray); - } - else{ - (*action)((unsigned long)(r * 255) << shift, 1); - (*action)((unsigned long)(g * 255) << shift, 1); - (*action)((unsigned long)(b * 255) << shift, 1); - } - } - } - - switch(gray){ - case 0: return 3 * im->width * im->height; - case 1: return im->width * im->height; - case 2: return 2 * im->width * im->height; - default: return 3 * im->width * im->height; - } -} - -static int gl2psPrintPDFPixmap(int obj, int childobj, GL2PSimage *im, int gray) -{ - int offs = 0, done = 0, sigbytes = 3; - - if(gray && gray !=8 && gray != 16) - gray = 8; - - if(gray) - sigbytes = gray / 8; - - offs += fprintf(gl2ps->stream, - "%d 0 obj\n" - "<<\n" - "/Type /XObject\n" - "/Subtype /Image\n" - "/Width %d\n" - "/Height %d\n" - "/ColorSpace %s \n" - "/BitsPerComponent 8\n", - obj, - (int)im->width, (int)im->height, - (gray) ? "/DeviceGray" : "/DeviceRGB" ); - if(GL_RGBA == im->format && gray == 0){ - offs += fprintf(gl2ps->stream, - "/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, - "/Length %d " - ">>\n" - "stream\n", - (int)gl2ps->compress->destLen); - offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, gl2ps->compress->destLen, - 1, gl2ps->stream); - done = 1; - } - gl2psFreeCompress(); - } -#endif - - if(!done){ - /* no compression, or too long after compression, or compress error - -> write non-compressed entry */ - offs += fprintf(gl2ps->stream, - "/Length %d " - ">>\n" - "stream\n", - (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" - "/Type /Font\n" - "/Subtype /Type1\n" - "/Name /F%d\n" - "/BaseFont /%s\n" - "/Encoding /MacRomanEncoding\n" - ">>\n" - "endobj\n", - obj, fontnumber, s->fontname); - return offs; -} - -/* Write the physical objects */ - -static int gl2psPDFgroupListWriteObjects(int entryoffs) -{ - int i,j; - GL2PSprimitive *p = NULL; - GL2PSpdfgroup *gro; - int offs = entryoffs; - GL2PStriangle *triangles; - int size = 0; - - if(!gl2ps->pdfgrouplist) - return offs; - - 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); - switch(p->type){ - case GL2PS_POINT: - break; - case GL2PS_LINE: - break; - case GL2PS_TRIANGLE: - size = gl2psListNbr(gro->ptrlist); - triangles = (GL2PStriangle*)gl2psMalloc(sizeof(GL2PStriangle) * size); - for(j = 0; j < size; ++j){ - p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); - gl2psFillTriangleFromPrimitive(&triangles[j], p, GL_TRUE); - } - if(triangles[0].prop & T_VAR_COLOR){ - gl2ps->xreflist[gro->shobjno] = offs; - offs += gl2psPrintPDFShader(gro->shobjno, triangles, size, 0); - } - if(triangles[0].prop & T_ALPHA_LESS_1){ - gl2ps->xreflist[gro->gsobjno] = offs; - offs += gl2psPrintPDFShaderSimpleExtGS(gro->gsobjno, triangles[0].vertex[0].rgba[3]); - } - if(triangles[0].prop & T_VAR_ALPHA){ - gl2ps->xreflist[gro->gsobjno] = offs; - offs += gl2psPrintPDFShaderExtGS(gro->gsobjno, gro->trgroupobjno); - gl2ps->xreflist[gro->trgroupobjno] = offs; - offs += gl2psPrintPDFShaderMask(gro->trgroupobjno, gro->maskshno); - gl2ps->xreflist[gro->maskshobjno] = offs; - offs += gl2psPrintPDFShader(gro->maskshobjno, triangles, size, 8); - } - gl2psFree(triangles); - break; - case GL2PS_PIXMAP: - gl2ps->xreflist[gro->imobjno] = offs; - offs += gl2psPrintPDFPixmap(gro->imobjno, gro->imobjno+1, p->data.image, 0); - if(p->data.image->format == GL_RGBA){ - gl2ps->xreflist[gro->imobjno+1] = offs; - offs += gl2psPrintPDFPixmap(gro->imobjno+1, -1, p->data.image, 8); - } - break; - case GL2PS_TEXT: - gl2ps->xreflist[gro->fontobjno] = offs; - offs += gl2psPrintPDFText(gro->fontobjno,p->data.text,gro->fontno); - break; - case GL2PS_SPECIAL : - /* alignment contains the format for which the special output text - is intended */ - if(p->data.text->alignment == GL2PS_PDF) - offs += fprintf(gl2ps->stream, "%s\n", p->data.text->str); - break; - default: - break; - } - } - return offs; -} - -/* All variable data has been written at this point and all required - functioninality has been gathered, so we can write now file footer - with cross reference table and trailer */ - -static void gl2psPrintPDFFooter(void) -{ - int i, offs; - - gl2psPDFgroupListInit(); - gl2psPDFgroupListWriteMainStream(); - - 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] = - gl2psPDFgroupListWriteObjects(gl2ps->xreflist[8]); - - /* Start cross reference table. The file has to been opened in - binary mode to preserve the 20 digit string length! */ - fprintf(gl2ps->stream, - "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" - "/Size %d\n" - "/Info 1 0 R\n" - "/Root 2 0 R\n" - ">>\n" - "startxref\n%d\n" - "%%%%EOF\n", - gl2ps->objects_stack, gl2ps->xreflist[gl2ps->objects_stack]); - - /* 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(); - gl2psFree(gl2ps->compress); - gl2ps->compress = NULL; - } -#endif -} - -/* PDF begin viewport */ - -static void gl2psPrintPDFBeginViewport(GLint viewport[4]) -{ - int offs = 0; - 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); - } - else{ - glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); - rgba[0] = gl2ps->colormap[index][0]; - rgba[1] = gl2ps->colormap[index][1]; - rgba[2] = gl2ps->colormap[index][2]; - rgba[3] = 1.0F; - } - offs += gl2psPrintPDFFillColor(rgba); - offs += gl2psPrintf("%d %d %d %d re\n" - "W\n" - "f\n", - x, y, w, h); - } - else{ - offs += gl2psPrintf("%d %d %d %d re\n" - "W\n" - "n\n", - x, y, w, h); - } - - gl2ps->streamlength += offs; -} - -static GLint gl2psPrintPDFEndViewport(void) -{ - GLint res; - - res = gl2psPrintPrimitives(); - gl2ps->streamlength += gl2psPrintf("Q\n"); - return res; -} - -static void gl2psPrintPDFFinalPrimitive(void) -{ -} - -/* definition of the PDF backend */ - -static GL2PSbackend gl2psPDF = { - gl2psPrintPDFHeader, - gl2psPrintPDFFooter, - gl2psPrintPDFBeginViewport, - gl2psPrintPDFEndViewport, - gl2psPrintPDFPrimitive, - gl2psPrintPDFFinalPrimitive, - "pdf", - "Portable Document Format" -}; - -/********************************************************************* - * - * SVG routines - * - *********************************************************************/ - -static void gl2psSVGGetCoordsAndColors(int n, GL2PSvertex *verts, - GL2PSxyz *xyz, GL2PSrgba *rgba) -{ - int i, j; - - for(i = 0; i < n; i++){ - xyz[i][0] = verts[i].xyz[0]; - xyz[i][1] = gl2ps->viewport[3] - verts[i].xyz[1]; - xyz[i][2] = 0.0F; - for(j = 0; j < 4; j++) - rgba[i][j] = verts[i].rgba[j]; - } -} - -static void gl2psSVGGetColorString(GL2PSrgba rgba, char str[32]) -{ - int r = (int)(255. * rgba[0]); - int g = (int)(255. * rgba[1]); - int b = (int)(255. * rgba[2]); - int rc = (r < 0) ? 0 : (r > 255) ? 255 : r; - int gc = (g < 0) ? 0 : (g > 255) ? 255 : g; - int bc = (b < 0) ? 0 : (b > 255) ? 255 : b; - sprintf(str, "#%2.2x%2.2x%2.2x", rc, gc, bc); -} - -static void gl2psPrintSVGHeader(void) -{ - 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]; - width = (int)gl2ps->viewport[3]; - height = (int)gl2ps->viewport[2]; - } - else{ - x = (int)gl2ps->viewport[0]; - y = (int)gl2ps->viewport[1]; - width = (int)gl2ps->viewport[2]; - height = (int)gl2ps->viewport[3]; - } - - /* Compressed SVG files (.svgz) are simply gzipped SVG files */ - gl2psPrintGzipHeader(); - - gl2psPrintf("\n"); - gl2psPrintf("\n", - width, height, x, y, width, height); - gl2psPrintf("%s\n", gl2ps->title); - gl2psPrintf("\n"); - gl2psPrintf("Creator: GL2PS %d.%d.%d%s, %s\n" - "For: %s\n" - "CreationDate: %s", - GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION, - GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer, ctime(&now)); - gl2psPrintf("\n"); - gl2psPrintf("\n"); - gl2psPrintf("\n"); - - if(gl2ps->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[3]); - } - - /* group all the primitives and disable antialiasing */ - gl2psPrintf("\n"); -} - -static void gl2psPrintSVGSmoothTriangle(GL2PSxyz xyz[3], GL2PSrgba rgba[3]) -{ - int i; - GL2PSxyz xyz2[3]; - GL2PSrgba rgba2[3]; - char col[32]; - - /* Apparently there is no easy way to do Gouraud shading in SVG - without explicitly pre-defining gradients, so for now we just do - recursive subdivision */ - - if(gl2psSameColorThreshold(3, rgba, gl2ps->threshold)){ - gl2psSVGGetColorString(rgba[0], col); - gl2psPrintf("\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[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[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[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[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[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[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[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[2][i] = 0.5F * (rgba[0][i] + rgba[2][i]); - } - gl2psPrintSVGSmoothTriangle(xyz2, rgba2); - } -} - -static void gl2psPrintSVGDash(GLushort pattern, GLint factor) -{ - int i, n, array[10]; - - if(!pattern || !factor) return; /* solid line */ - - gl2psParseStipplePattern(pattern, factor, &n, array); - gl2psPrintf("stroke-dasharray=\""); - for(i = 0; i < n; i++){ - if(i) gl2psPrintf(","); - gl2psPrintf("%d", array[i]); - } - gl2psPrintf("\" "); -} - -static void gl2psEndSVGLine(void) -{ - int i; - if(gl2ps->lastvertex.rgba[0] >= 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.; - for(i = 0; i < 4; i++) - gl2ps->lastvertex.rgba[i] = -1.; - } -} - -static void gl2psPrintSVGPixmap(GLfloat x, GLfloat y, GL2PSimage *pixmap) -{ -#if defined(GL2PS_HAVE_LIBPNG) - GL2PSlist *png; - unsigned char c; - int i; - - /* The only image types supported by the SVG standard are JPEG, PNG - and SVG. Here we choose PNG, and since we want to embed the image - directly in the SVG stream (and not link to an external image - file), we need to encode the pixmap into PNG in memory, then - encode it into base64. */ - - png = gl2psListCreate(pixmap->width * pixmap->height * 3, 1000, - sizeof(unsigned char)); - gl2psConvertPixmapToPNG(pixmap, png); - gl2psListEncodeBase64(png); - gl2psPrintf("height, pixmap->width, pixmap->height); - gl2psPrintf("xlink:href=\"data:image/png;base64,"); - for(i = 0; i < gl2psListNbr(png); i++){ - gl2psListRead(png, i, &c); - gl2psPrintf("%c", c); - } - gl2psPrintf("\"/>\n"); - gl2psListDelete(png); -#else - (void) x; (void) y; (void) pixmap; /* not used */ - gl2psMsg(GL2PS_WARNING, "GL2PS must be compiled with PNG support in " - "order to embed images in SVG streams"); -#endif -} - -static void gl2psPrintSVGPrimitive(void *data) -{ - GL2PSprimitive *prim; - GL2PSxyz xyz[4]; - GL2PSrgba rgba[4]; - char col[32]; - int newline; - - prim = *(GL2PSprimitive**)data; - - if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return; - - /* We try to draw connected lines as a single path to get nice line - joins and correct stippling. So if the primitive to print is not - a line we must first finish the current line (if any): */ - if(prim->type != GL2PS_LINE) gl2psEndSVGLine(); - - gl2psSVGGetCoordsAndColors(prim->numverts, prim->verts, xyz, rgba); - - switch(prim->type){ - case GL2PS_POINT : - gl2psSVGGetColorString(rgba[0], col); - gl2psPrintf("\n", - xyz[0][0], xyz[0][1], 0.5 * prim->width); - break; - case GL2PS_LINE : - if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) || - !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) || - gl2ps->lastlinewidth != prim->width || - gl2ps->lastpattern != prim->pattern || - gl2ps->lastfactor != prim->factor){ - /* End the current line if the new segment does not start where - the last one ended, or if the color, the width or the - stippling have changed (we will need to use multi-point - gradients for smooth-shaded lines) */ - gl2psEndSVGLine(); - newline = 1; - } - else{ - newline = 0; - } - gl2ps->lastvertex = prim->verts[1]; - gl2psSetLastColor(prim->verts[0].rgba); - gl2ps->lastlinewidth = prim->width; - gl2ps->lastpattern = prim->pattern; - 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); - gl2psPrintf("points=\"%g,%g ", xyz[0][0], xyz[0][1]); - } - else{ - gl2psPrintf("%g,%g ", xyz[0][0], xyz[0][1]); - } - break; - case GL2PS_TRIANGLE : - gl2psPrintSVGSmoothTriangle(xyz, rgba); - break; - case GL2PS_QUADRANGLE : - gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print"); - break; - case GL2PS_PIXMAP : - gl2psPrintSVGPixmap(xyz[0][0], xyz[0][1], prim->data.image); - break; - case GL2PS_TEXT : - gl2psSVGGetColorString(prim->verts[0].rgba, col); - gl2psPrintf("data.text->fontsize); - 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")) - gl2psPrintf("font-family=\"Times\" font-weight=\"bold\">"); - else if(!strcmp(prim->data.text->fontname, "Times-Italic")) - gl2psPrintf("font-family=\"Times\" font-style=\"italic\">"); - else if(!strcmp(prim->data.text->fontname, "Times-BoldItalic")) - gl2psPrintf("font-family=\"Times\" font-style=\"italic\" font-weight=\"bold\">"); - else if(!strcmp(prim->data.text->fontname, "Helvetica-Bold")) - gl2psPrintf("font-family=\"Helvetica\" font-weight=\"bold\">"); - else if(!strcmp(prim->data.text->fontname, "Helvetica-Oblique")) - gl2psPrintf("font-family=\"Helvetica\" font-style=\"oblique\">"); - else if(!strcmp(prim->data.text->fontname, "Helvetica-BoldOblique")) - gl2psPrintf("font-family=\"Helvetica\" font-style=\"oblique\" font-weight=\"bold\">"); - else if(!strcmp(prim->data.text->fontname, "Courier-Bold")) - gl2psPrintf("font-family=\"Courier\" font-weight=\"bold\">"); - else if(!strcmp(prim->data.text->fontname, "Courier-Oblique")) - gl2psPrintf("font-family=\"Courier\" font-style=\"oblique\">"); - else if(!strcmp(prim->data.text->fontname, "Courier-BoldOblique")) - gl2psPrintf("font-family=\"Courier\" font-style=\"oblique\" font-weight=\"bold\">"); - else - gl2psPrintf("font-family=\"%s\">", prim->data.text->fontname); - gl2psPrintf("%s\n", prim->data.text->str); - break; - case GL2PS_SPECIAL : - /* alignment contains the format for which the special output text - is intended */ - if(prim->data.text->alignment == GL2PS_SVG) - gl2psPrintf("%s\n", prim->data.text->str); - break; - default : - break; - } -} - -static void gl2psPrintSVGFooter(void) -{ - gl2psPrintf("\n"); - gl2psPrintf("\n"); - - gl2psPrintGzipFooter(); -} - -static void gl2psPrintSVGBeginViewport(GLint viewport[4]) -{ - GLint index; - char col[32]; - GLfloat rgba[4]; - int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; - - glRenderMode(GL_FEEDBACK); - - if(gl2ps->header){ - gl2psPrintSVGHeader(); - gl2ps->header = GL_FALSE; - } - - if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ - if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ - glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); - } - else{ - glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); - rgba[0] = gl2ps->colormap[index][0]; - rgba[1] = gl2ps->colormap[index][1]; - rgba[2] = gl2ps->colormap[index][2]; - 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), - 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), - x, gl2ps->viewport[3] - (y + h)); - gl2psPrintf("\n"); - gl2psPrintf("\n", x, y, w, h); -} - -static GLint gl2psPrintSVGEndViewport(void) -{ - GLint res; - - res = gl2psPrintPrimitives(); - gl2psPrintf("\n"); - return res; -} - -static void gl2psPrintSVGFinalPrimitive(void) -{ - /* End any remaining line, if any */ - gl2psEndSVGLine(); -} - -/* definition of the SVG backend */ - -static GL2PSbackend gl2psSVG = { - gl2psPrintSVGHeader, - gl2psPrintSVGFooter, - gl2psPrintSVGBeginViewport, - gl2psPrintSVGEndViewport, - gl2psPrintSVGPrimitive, - gl2psPrintSVGFinalPrimitive, - "svg", - "Scalable Vector Graphics" -}; - -/********************************************************************* - * - * PGF routines - * - *********************************************************************/ - -static void gl2psPrintPGFColor(GL2PSrgba rgba) -{ - if(!gl2psSameColor(gl2ps->lastrgba, rgba)){ - gl2psSetLastColor(rgba); - fprintf(gl2ps->stream, "\\color[rgb]{%f,%f,%f}\n", rgba[0], rgba[1], rgba[2]); - } -} - -static void gl2psPrintPGFHeader(void) -{ - time_t now; - - time(&now); - - fprintf(gl2ps->stream, - "%% Title: %s\n" - "%% Creator: GL2PS %d.%d.%d%s, %s\n" - "%% For: %s\n" - "%% CreationDate: %s", - gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, - GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, - gl2ps->producer, ctime(&now)); - - fprintf(gl2ps->stream, "\\begin{pgfpicture}\n"); - if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ - gl2psPrintPGFColor(gl2ps->bgcolor); - fprintf(gl2ps->stream, - "\\pgfpathrectanglecorners{" - "\\pgfpoint{%dpt}{%dpt}}{\\pgfpoint{%dpt}{%dpt}}\n" - "\\pgfusepath{fill}\n", - (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], - (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); - } -} - -static void gl2psPrintPGFDash(GLushort pattern, GLint factor) -{ - int i, n, array[10]; - - if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor) - return; - - gl2ps->lastpattern = pattern; - gl2ps->lastfactor = factor; - - if(!pattern || !factor){ - /* solid line */ - fprintf(gl2ps->stream, "\\pgfsetdash{}{0pt}\n"); - } - else{ - gl2psParseStipplePattern(pattern, factor, &n, array); - fprintf(gl2ps->stream, "\\pgfsetdash{"); - for(i = 0; i < n; i++) fprintf(gl2ps->stream, "{%dpt}", array[i]); - fprintf(gl2ps->stream, "}{0pt}\n"); - } -} - -static const char *gl2psPGFTextAlignment(int align) -{ - switch(align){ - case GL2PS_TEXT_C : return "center"; - case GL2PS_TEXT_CL : return "west"; - case GL2PS_TEXT_CR : return "east"; - case GL2PS_TEXT_B : return "south"; - case GL2PS_TEXT_BR : return "south east"; - case GL2PS_TEXT_T : return "north"; - case GL2PS_TEXT_TL : return "north west"; - case GL2PS_TEXT_TR : return "north east"; - case GL2PS_TEXT_BL : - default : return "south west"; - } -} - -static void gl2psPrintPGFPrimitive(void *data) -{ - GL2PSprimitive *prim; - - prim = *(GL2PSprimitive**)data; - - switch(prim->type){ - case GL2PS_POINT : - /* Points in openGL are rectangular */ - gl2psPrintPGFColor(prim->verts[0].rgba); - fprintf(gl2ps->stream, - "\\pgfpathrectangle{\\pgfpoint{%fpt}{%fpt}}" - "{\\pgfpoint{%fpt}{%fpt}}\n\\pgfusepath{fill}\n", - prim->verts[0].xyz[0]-0.5*prim->width, - prim->verts[0].xyz[1]-0.5*prim->width, - prim->width,prim->width); - break; - case GL2PS_LINE : - gl2psPrintPGFColor(prim->verts[0].rgba); - if(gl2ps->lastlinewidth != prim->width){ - gl2ps->lastlinewidth = prim->width; - fprintf(gl2ps->stream, "\\pgfsetlinewidth{%fpt}\n", gl2ps->lastlinewidth); - } - gl2psPrintPGFDash(prim->pattern, prim->factor); - fprintf(gl2ps->stream, - "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n" - "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" - "\\pgfusepath{stroke}\n", - prim->verts[1].xyz[0], prim->verts[1].xyz[1], - prim->verts[0].xyz[0], prim->verts[0].xyz[1]); - break; - case GL2PS_TRIANGLE : - if(gl2ps->lastlinewidth != 0){ - gl2ps->lastlinewidth = 0; - fprintf(gl2ps->stream, "\\pgfsetlinewidth{0.01pt}\n"); - } - gl2psPrintPGFColor(prim->verts[0].rgba); - fprintf(gl2ps->stream, - "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n" - "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" - "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" - "\\pgfpathclose\n" - "\\pgfusepath{fill,stroke}\n", - prim->verts[2].xyz[0], prim->verts[2].xyz[1], - prim->verts[1].xyz[0], prim->verts[1].xyz[1], - prim->verts[0].xyz[0], prim->verts[0].xyz[1]); - break; - case GL2PS_TEXT : - fprintf(gl2ps->stream, "{\n\\pgftransformshift{\\pgfpoint{%fpt}{%fpt}}\n", - prim->verts[0].xyz[0], prim->verts[0].xyz[1]); - - if(prim->data.text->angle) - fprintf(gl2ps->stream, "\\pgftransformrotate{%f}{", prim->data.text->angle); - - fprintf(gl2ps->stream, "\\pgfnode{rectangle}{%s}{\\fontsize{%d}{0}\\selectfont", - gl2psPGFTextAlignment(prim->data.text->alignment), - prim->data.text->fontsize); - - 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); - - fprintf(gl2ps->stream, "}{}{\\pgfusepath{discard}}}\n"); - break; - case GL2PS_SPECIAL : - /* alignment contains the format for which the special output text - is intended */ - if (prim->data.text->alignment == GL2PS_PGF) - fprintf(gl2ps->stream, "%s\n", prim->data.text->str); - break; - default : - break; - } -} - -static void gl2psPrintPGFFooter(void) -{ - fprintf(gl2ps->stream, "\\end{pgfpicture}\n"); -} - -static void gl2psPrintPGFBeginViewport(GLint viewport[4]) -{ - GLint index; - GLfloat rgba[4]; - int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; - - glRenderMode(GL_FEEDBACK); - - if(gl2ps->header){ - gl2psPrintPGFHeader(); - gl2ps->header = GL_FALSE; - } - - fprintf(gl2ps->stream, "\\begin{pgfscope}\n"); - if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ - if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ - glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); - } - else{ - glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); - rgba[0] = gl2ps->colormap[index][0]; - rgba[1] = gl2ps->colormap[index][1]; - rgba[2] = gl2ps->colormap[index][2]; - rgba[3] = 1.0F; - } - gl2psPrintPGFColor(rgba); - fprintf(gl2ps->stream, - "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}" - "{\\pgfpoint{%dpt}{%dpt}}\n" - "\\pgfusepath{fill}\n", - x, y, w, h); - } - - fprintf(gl2ps->stream, - "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}" - "{\\pgfpoint{%dpt}{%dpt}}\n" - "\\pgfusepath{clip}\n", - x, y, w, h); -} - -static GLint gl2psPrintPGFEndViewport(void) -{ - GLint res; - res = gl2psPrintPrimitives(); - fprintf(gl2ps->stream, "\\end{pgfscope}\n"); - return res; -} - -static void gl2psPrintPGFFinalPrimitive(void) -{ -} - -/* definition of the PGF backend */ - -static GL2PSbackend gl2psPGF = { - gl2psPrintPGFHeader, - gl2psPrintPGFFooter, - gl2psPrintPGFBeginViewport, - gl2psPrintPGFEndViewport, - gl2psPrintPGFPrimitive, - gl2psPrintPGFFinalPrimitive, - "tex", - "PGF Latex Graphics" -}; - -/********************************************************************* - * - * General primitive printing routine - * - *********************************************************************/ - -/* Warning: the ordering of the backends must match the format - #defines in gl2ps.h */ - -static GL2PSbackend *gl2psbackends[] = { - &gl2psPS, /* 0 */ - &gl2psEPS, /* 1 */ - &gl2psTEX, /* 2 */ - &gl2psPDF, /* 3 */ - &gl2psSVG, /* 4 */ - &gl2psPGF /* 5 */ -}; - -static void gl2psComputeTightBoundingBox(void *data) -{ - GL2PSprimitive *prim; - int i; - - prim = *(GL2PSprimitive**)data; - - for(i = 0; i < prim->numverts; i++){ - if(prim->verts[i].xyz[0] < gl2ps->viewport[0]) - gl2ps->viewport[0] = (GLint)prim->verts[i].xyz[0]; - if(prim->verts[i].xyz[0] > gl2ps->viewport[2]) - gl2ps->viewport[2] = (GLint)(prim->verts[i].xyz[0] + 0.5F); - if(prim->verts[i].xyz[1] < gl2ps->viewport[1]) - gl2ps->viewport[1] = (GLint)prim->verts[i].xyz[1]; - if(prim->verts[i].xyz[1] > gl2ps->viewport[3]) - gl2ps->viewport[3] = (GLint)(prim->verts[i].xyz[1] + 0.5F); - } -} - -static GLint gl2psPrintPrimitives(void) -{ - GL2PSbsptree *root; - GL2PSxyz eye = {0.0F, 0.0F, 100.0F * GL2PS_ZSCALE}; - GLint used; - - used = glRenderMode(GL_RENDER); - - if(used < 0){ - gl2psMsg(GL2PS_INFO, "OpenGL feedback buffer overflow"); - return GL2PS_OVERFLOW; - } - - if(used > 0) - gl2psParseFeedbackBuffer(used); - - gl2psRescaleAndOffset(); - - if(gl2ps->header){ - if(gl2psListNbr(gl2ps->primitives) && - (gl2ps->options & GL2PS_TIGHT_BOUNDING_BOX)){ - gl2ps->viewport[0] = gl2ps->viewport[1] = 100000; - gl2ps->viewport[2] = gl2ps->viewport[3] = -100000; - gl2psListAction(gl2ps->primitives, gl2psComputeTightBoundingBox); - } - (gl2psbackends[gl2ps->format]->printHeader)(); - gl2ps->header = GL_FALSE; - } - - if(!gl2psListNbr(gl2ps->primitives)){ - /* empty feedback buffer and/or nothing else to print */ - return GL2PS_NO_FEEDBACK; - } - - switch(gl2ps->sort){ - case GL2PS_NO_SORT : - gl2psListAction(gl2ps->primitives, gl2psbackends[gl2ps->format]->printPrimitive); - gl2psListAction(gl2ps->primitives, gl2psFreePrimitive); - /* reset the primitive list, waiting for the next viewport */ - gl2psListReset(gl2ps->primitives); - break; - case GL2PS_SIMPLE_SORT : - gl2psListSort(gl2ps->primitives, gl2psCompareDepth); - if(gl2ps->options & GL2PS_OCCLUSION_CULL){ - gl2psListActionInverse(gl2ps->primitives, gl2psAddInImageTree); - gl2psFreeBspImageTree(&gl2ps->imagetree); - } - gl2psListAction(gl2ps->primitives, gl2psbackends[gl2ps->format]->printPrimitive); - gl2psListAction(gl2ps->primitives, gl2psFreePrimitive); - /* reset the primitive list, waiting for the next viewport */ - gl2psListReset(gl2ps->primitives); - break; - case GL2PS_BSP_SORT : - root = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree)); - gl2psBuildBspTree(root, gl2ps->primitives); - if(GL_TRUE == gl2ps->boundary) gl2psBuildPolygonBoundary(root); - if(gl2ps->options & GL2PS_OCCLUSION_CULL){ - gl2psTraverseBspTree(root, eye, -GL2PS_EPSILON, gl2psLess, - gl2psAddInImageTree, 1); - gl2psFreeBspImageTree(&gl2ps->imagetree); - } - gl2psTraverseBspTree(root, eye, GL2PS_EPSILON, gl2psGreater, - gl2psbackends[gl2ps->format]->printPrimitive, 0); - gl2psFreeBspTree(&root); - /* reallocate the primitive list (it's been deleted by - gl2psBuildBspTree) in case there is another viewport */ - gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*)); - break; - } - gl2psbackends[gl2ps->format]->printFinalPrimitive(); - - return GL2PS_SUCCESS; -} - -/********************************************************************* - * - * Public routines - * - *********************************************************************/ - -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 nr, GLint ng, GLint nb, GLint buffersize, - FILE *stream, const char *filename) -{ - GLint index; - int i; - - if(gl2ps){ - gl2psMsg(GL2PS_ERROR, "gl2psBeginPage called in wrong program state"); - return GL2PS_ERROR; - } - - gl2ps = (GL2PScontext*)gl2psMalloc(sizeof(GL2PScontext)); - - if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0]))){ - gl2ps->format = format; - } - else { - gl2psMsg(GL2PS_ERROR, "Unknown output format: %d", format); - gl2psFree(gl2ps); - gl2ps = NULL; - return GL2PS_ERROR; - } - - switch(sort){ - case GL2PS_NO_SORT : - case GL2PS_SIMPLE_SORT : - case GL2PS_BSP_SORT : - gl2ps->sort = sort; - break; - default : - gl2psMsg(GL2PS_ERROR, "Unknown sorting algorithm: %d", sort); - gl2psFree(gl2ps); - gl2ps = NULL; - return GL2PS_ERROR; - } - - if(stream){ - gl2ps->stream = stream; - } - else{ - gl2psMsg(GL2PS_ERROR, "Bad file pointer"); - gl2psFree(gl2ps); - gl2ps = NULL; - return GL2PS_ERROR; - } - - gl2ps->header = GL_TRUE; - gl2ps->maxbestroot = 10; - gl2ps->options = options; - gl2ps->compress = NULL; - gl2ps->imagemap_head = NULL; - gl2ps->imagemap_tail = NULL; - - if(gl2ps->options & GL2PS_USE_CURRENT_VIEWPORT){ - glGetIntegerv(GL_VIEWPORT, gl2ps->viewport); - } - else{ - for(i = 0; i < 4; i++){ - gl2ps->viewport[i] = viewport[i]; - } - } - - 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[2], gl2ps->viewport[3]); - gl2psFree(gl2ps); - gl2ps = NULL; - return GL2PS_ERROR; - } - - gl2ps->threshold[0] = nr ? 1.0F / (GLfloat)nr : 0.064F; - gl2ps->threshold[1] = ng ? 1.0F / (GLfloat)ng : 0.034F; - gl2ps->threshold[2] = nb ? 1.0F / (GLfloat)nb : 0.100F; - gl2ps->colormode = colormode; - gl2ps->buffersize = buffersize > 0 ? buffersize : 2048 * 2048; - for(i = 0; i < 3; i++){ - gl2ps->lastvertex.xyz[i] = -1.0F; - } - for(i = 0; i < 4; i++){ - gl2ps->lastvertex.rgba[i] = -1.0F; - gl2ps->lastrgba[i] = -1.0F; - } - gl2ps->lastlinewidth = -1.0F; - gl2ps->lastpattern = 0; - gl2ps->lastfactor = 0; - gl2ps->imagetree = NULL; - gl2ps->primitivetoadd = NULL; - 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); - glGetIntegerv(GL_BLEND_SRC, &gl2ps->blendfunc[0]); - glGetIntegerv(GL_BLEND_DST, &gl2ps->blendfunc[1]); - - if(gl2ps->colormode == GL_RGBA){ - gl2ps->colorsize = 0; - gl2ps->colormap = NULL; - glGetFloatv(GL_COLOR_CLEAR_VALUE, gl2ps->bgcolor); - } - else if(gl2ps->colormode == GL_COLOR_INDEX){ - if(!colorsize || !colormap){ - gl2psMsg(GL2PS_ERROR, "Missing colormap for GL_COLOR_INDEX rendering"); - gl2psFree(gl2ps); - gl2ps = NULL; - return GL2PS_ERROR; - } - gl2ps->colorsize = colorsize; - gl2ps->colormap = (GL2PSrgba*)gl2psMalloc(gl2ps->colorsize * sizeof(GL2PSrgba)); - memcpy(gl2ps->colormap, colormap, gl2ps->colorsize * sizeof(GL2PSrgba)); - glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); - gl2ps->bgcolor[0] = gl2ps->colormap[index][0]; - gl2ps->bgcolor[1] = gl2ps->colormap[index][1]; - gl2ps->bgcolor[2] = gl2ps->colormap[index][2]; - gl2ps->bgcolor[3] = 1.0F; - } - else{ - gl2psMsg(GL2PS_ERROR, "Unknown color mode in gl2psBeginPage"); - gl2psFree(gl2ps); - gl2ps = NULL; - return GL2PS_ERROR; - } - - if(!title){ - gl2ps->title = (char*)gl2psMalloc(sizeof(char)); - gl2ps->title[0] = '\0'; - } - else{ - 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'; - } - else{ - 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'; - } - else{ - gl2ps->filename = (char*)gl2psMalloc((strlen(filename)+1)*sizeof(char)); - strcpy(gl2ps->filename, filename); - } - - gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*)); - 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); - - return GL2PS_SUCCESS; -} - -GL2PSDLL_API GLint gl2psEndPage(void) -{ - GLint res; - - if(!gl2ps) return GL2PS_UNINITIALIZED; - - res = gl2psPrintPrimitives(); - - if(res != GL2PS_OVERFLOW) - (gl2psbackends[gl2ps->format]->printFooter)(); - - fflush(gl2ps->stream); - - gl2psListDelete(gl2ps->primitives); - gl2psListDelete(gl2ps->auxprimitives); - gl2psFreeImagemap(gl2ps->imagemap_head); - gl2psFree(gl2ps->colormap); - gl2psFree(gl2ps->title); - gl2psFree(gl2ps->producer); - gl2psFree(gl2ps->filename); - gl2psFree(gl2ps->feedback); - gl2psFree(gl2ps); - gl2ps = NULL; - - return res; -} - -GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4]) -{ - if(!gl2ps) return GL2PS_UNINITIALIZED; - - (gl2psbackends[gl2ps->format]->beginViewport)(viewport); - - return GL2PS_SUCCESS; -} - -GL2PSDLL_API GLint gl2psEndViewport(void) -{ - GLint res; - - if(!gl2ps) return GL2PS_UNINITIALIZED; - - res = (gl2psbackends[gl2ps->format]->endViewport)(); - - /* reset last used colors, line widths */ - gl2ps->lastlinewidth = -1.0F; - - return res; -} - -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); -} - -GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize) -{ - return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, GL2PS_TEXT_BL, 0.0F); -} - -GL2PSDLL_API GLint gl2psSpecial(GLint format, const char *str) -{ - return gl2psAddText(GL2PS_SPECIAL, str, "", 0, format, 0.0F); -} - -GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height, - GLint xorig, GLint yorig, - GLenum format, GLenum type, - const void *pixels) -{ - int size, i; - const GLfloat *piv; - GLfloat pos[4], zoom_x, zoom_y; - GL2PSprimitive *prim; - GLboolean valid; - - if(!gl2ps || !pixels) return GL2PS_UNINITIALIZED; - - if((width <= 0) || (height <= 0)) return GL2PS_ERROR; - - if(gl2ps->options & GL2PS_NO_PIXMAP) return GL2PS_SUCCESS; - - if((format != GL_RGB && format != GL_RGBA) || type != GL_FLOAT){ - gl2psMsg(GL2PS_ERROR, "gl2psDrawPixels only implemented for " - "GL_RGB/GL_RGBA, GL_FLOAT pixels"); - return GL2PS_ERROR; - } - - glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid); - 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; - prim->boundary = 0; - prim->numverts = 1; - prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex)); - prim->verts[0].xyz[0] = pos[0] + xorig; - prim->verts[0].xyz[1] = pos[1] + yorig; - prim->verts[0].xyz[2] = pos[2]; - prim->culled = 0; - prim->offset = 0; - prim->pattern = 0; - prim->factor = 0; - prim->width = 1; - glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba); - 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; - - switch(format){ - case GL_RGBA: - if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){ - /* special case: blending turned off */ - prim->data.image->format = GL_RGB; - size = height * width * 3; - prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat)); - piv = (const GLfloat*)pixels; - for(i = 0; i < size; ++i, ++piv){ - prim->data.image->pixels[i] = *piv; - if(!((i + 1) % 3)) - ++piv; - } - } - else{ - size = height * width * 4; - prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat)); - memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat)); - } - break; - case GL_RGB: - default: - size = height * width * 3; - prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat)); - memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat)); - break; - } - - gl2psListAdd(gl2ps->auxprimitives, &prim); - glPassThrough(GL2PS_DRAW_PIXELS_TOKEN); - - return GL2PS_SUCCESS; -} - -GL2PSDLL_API GLint gl2psDrawImageMap(GLsizei width, GLsizei height, - const GLfloat position[3], - 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); - glVertex3f(position[0], position[1],position[2]); - glEnd(); - glPassThrough((GLfloat)width); - glPassThrough((GLfloat)height); - for(i = 0; i < size; i += sizeoffloat){ - const float *value = (const float*)imagemap; - glPassThrough(*value); - imagemap += sizeoffloat; - } - return GL2PS_SUCCESS; -} - -GL2PSDLL_API GLint gl2psEnable(GLint mode) -{ - GLint tmp; - - if(!gl2ps) return GL2PS_UNINITIALIZED; - - switch(mode){ - case GL2PS_POLYGON_OFFSET_FILL : - glPassThrough(GL2PS_BEGIN_OFFSET_TOKEN); - glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &gl2ps->offset[0]); - glGetFloatv(GL_POLYGON_OFFSET_UNITS, &gl2ps->offset[1]); - break; - case GL2PS_POLYGON_BOUNDARY : - glPassThrough(GL2PS_BEGIN_BOUNDARY_TOKEN); - break; - case GL2PS_LINE_STIPPLE : - glPassThrough(GL2PS_BEGIN_STIPPLE_TOKEN); - glGetIntegerv(GL_LINE_STIPPLE_PATTERN, &tmp); - glPassThrough((GLfloat)tmp); - glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &tmp); - glPassThrough((GLfloat)tmp); - break; - case GL2PS_BLEND : - glPassThrough(GL2PS_BEGIN_BLEND_TOKEN); - break; - default : - gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psEnable: %d", mode); - return GL2PS_WARNING; - } - - return GL2PS_SUCCESS; -} - -GL2PSDLL_API GLint gl2psDisable(GLint mode) -{ - if(!gl2ps) return GL2PS_UNINITIALIZED; - - switch(mode){ - case GL2PS_POLYGON_OFFSET_FILL : - glPassThrough(GL2PS_END_OFFSET_TOKEN); - break; - case GL2PS_POLYGON_BOUNDARY : - glPassThrough(GL2PS_END_BOUNDARY_TOKEN); - break; - case GL2PS_LINE_STIPPLE : - glPassThrough(GL2PS_END_STIPPLE_TOKEN); - break; - case GL2PS_BLEND : - glPassThrough(GL2PS_END_BLEND_TOKEN); - break; - default : - gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psDisable: %d", mode); - return GL2PS_WARNING; - } - - return GL2PS_SUCCESS; -} - -GL2PSDLL_API GLint gl2psPointSize(GLfloat value) -{ - if(!gl2ps) return GL2PS_UNINITIALIZED; - - glPassThrough(GL2PS_POINT_SIZE_TOKEN); - glPassThrough(value); - - return GL2PS_SUCCESS; -} - -GL2PSDLL_API GLint gl2psLineWidth(GLfloat value) -{ - if(!gl2ps) return GL2PS_UNINITIALIZED; - - glPassThrough(GL2PS_LINE_WIDTH_TOKEN); - glPassThrough(value); - - return GL2PS_SUCCESS; -} - -GL2PSDLL_API GLint gl2psBlendFunc(GLenum sfactor, GLenum dfactor) -{ - if(!gl2ps) return GL2PS_UNINITIALIZED; - - if(GL_FALSE == gl2psSupportedBlendMode(sfactor, dfactor)) - return GL2PS_WARNING; - - glPassThrough(GL2PS_SRC_BLEND_TOKEN); - glPassThrough((GLfloat)sfactor); - glPassThrough(GL2PS_DST_BLEND_TOKEN); - glPassThrough((GLfloat)dfactor); - - return GL2PS_SUCCESS; -} - -GL2PSDLL_API GLint gl2psSetOptions(GLint options) -{ - if(!gl2ps) return GL2PS_UNINITIALIZED; - - gl2ps->options = options; - - return GL2PS_SUCCESS; -} - -GL2PSDLL_API GLint gl2psGetOptions(GLint *options) -{ - if(!gl2ps) { - *options = 0; - return GL2PS_UNINITIALIZED; - } - - *options = gl2ps->options; - - return GL2PS_SUCCESS; -} - -GL2PSDLL_API const char *gl2psGetFileExtension(GLint format) -{ - if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0]))) - return gl2psbackends[format]->file_extension; - else - return "Unknown format"; -} - -GL2PSDLL_API const char *gl2psGetFormatDescription(GLint format) -{ - if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0]))) - return gl2psbackends[format]->description; - else - return "Unknown format"; -} diff -r a132d206a36a -r b9b6a310ad97 src/gl2ps.h --- a/src/gl2ps.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,200 +0,0 @@ -/* - * GL2PS, an OpenGL to PostScript Printing Library - * Copyright (C) 1999-2011 C. Geuzaine - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of either: - * - * a) the GNU Library General Public License as published by the Free - * Software Foundation, either version 2 of the License, or (at your - * option) any later version; or - * - * b) the GL2PS License as published by Christophe Geuzaine, either - * version 2 of the License, or (at your option) any later version. - * - * This program 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 either - * the GNU Library General Public License or the GL2PS License for - * more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library in the file named "COPYING.LGPL"; - * if not, write to the Free Software Foundation, Inc., 675 Mass Ave, - * Cambridge, MA 02139, USA. - * - * You should have received a copy of the GL2PS License with this - * library in the file named "COPYING.GL2PS"; if not, I will be glad - * to provide one. - * - * For the latest info about gl2ps and a full list of contributors, - * see http://www.geuz.org/gl2ps/. - * - * Please report all bugs and problems to . - */ - -#ifndef __GL2PS_H__ -#define __GL2PS_H__ - -#include -#include - -/* Define GL2PSDLL at compile time to build a Windows DLL */ - -#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) -# if defined(_MSC_VER) -# pragma warning(disable:4115) -# pragma warning(disable:4996) -# endif -# define WIN32_LEAN_AND_MEAN -# include -# if defined(GL2PSDLL) -# if defined(GL2PSDLL_EXPORTS) -# define GL2PSDLL_API __declspec(dllexport) -# else -# define GL2PSDLL_API __declspec(dllimport) -# endif -# else -# define GL2PSDLL_API -# endif -#else -# define GL2PSDLL_API -#endif - -#if defined(__APPLE__) || defined(HAVE_OPENGL_GL_H) -# include -#else -# include -#endif - -/* Support for compressed PostScript/PDF/SVG and for embedded PNG - images in SVG */ - -#if defined(HAVE_ZLIB) || defined(HAVE_LIBZ) -# define GL2PS_HAVE_ZLIB -# if defined(HAVE_LIBPNG) || defined(HAVE_PNG) -# define GL2PS_HAVE_LIBPNG -# endif -#endif - -/* Version number */ - -#define GL2PS_MAJOR_VERSION 1 -#define GL2PS_MINOR_VERSION 3 -#define GL2PS_PATCH_VERSION 6 -#define GL2PS_EXTRA_VERSION "" - -#define GL2PS_VERSION (GL2PS_MAJOR_VERSION + \ - 0.01 * GL2PS_MINOR_VERSION + \ - 0.0001 * GL2PS_PATCH_VERSION) - -#define GL2PS_COPYRIGHT "(C) 1999-2011 C. Geuzaine" - -/* Output file formats (the values and the ordering are important!) */ - -#define GL2PS_PS 0 -#define GL2PS_EPS 1 -#define GL2PS_TEX 2 -#define GL2PS_PDF 3 -#define GL2PS_SVG 4 -#define GL2PS_PGF 5 - -/* Sorting algorithms */ - -#define GL2PS_NO_SORT 1 -#define GL2PS_SIMPLE_SORT 2 -#define GL2PS_BSP_SORT 3 - -/* Message levels and error codes */ - -#define GL2PS_SUCCESS 0 -#define GL2PS_INFO 1 -#define GL2PS_WARNING 2 -#define GL2PS_ERROR 3 -#define GL2PS_NO_FEEDBACK 4 -#define GL2PS_OVERFLOW 5 -#define GL2PS_UNINITIALIZED 6 - -/* Options for gl2psBeginPage */ - -#define GL2PS_NONE 0 -#define GL2PS_DRAW_BACKGROUND (1<<0) -#define GL2PS_SIMPLE_LINE_OFFSET (1<<1) -#define GL2PS_SILENT (1<<2) -#define GL2PS_BEST_ROOT (1<<3) -#define GL2PS_OCCLUSION_CULL (1<<4) -#define GL2PS_NO_TEXT (1<<5) -#define GL2PS_LANDSCAPE (1<<6) -#define GL2PS_NO_PS3_SHADING (1<<7) -#define GL2PS_NO_PIXMAP (1<<8) -#define GL2PS_USE_CURRENT_VIEWPORT (1<<9) -#define GL2PS_COMPRESS (1<<10) -#define GL2PS_NO_BLENDING (1<<11) -#define GL2PS_TIGHT_BOUNDING_BOX (1<<12) - -/* Arguments for gl2psEnable/gl2psDisable */ - -#define GL2PS_POLYGON_OFFSET_FILL 1 -#define GL2PS_POLYGON_BOUNDARY 2 -#define GL2PS_LINE_STIPPLE 3 -#define GL2PS_BLEND 4 - -/* Text alignment (o=raster position; default mode is BL): - +---+ +---+ +---+ +---+ +---+ +---+ +-o-+ o---+ +---o - | o | o | | o | | | | | | | | | | | | - +---+ +---+ +---+ +-o-+ o---+ +---o +---+ +---+ +---+ - C CL CR B BL BR T TL TR */ - -#define GL2PS_TEXT_C 1 -#define GL2PS_TEXT_CL 2 -#define GL2PS_TEXT_CR 3 -#define GL2PS_TEXT_B 4 -#define GL2PS_TEXT_BL 5 -#define GL2PS_TEXT_BR 6 -#define GL2PS_TEXT_T 7 -#define GL2PS_TEXT_TL 8 -#define GL2PS_TEXT_TR 9 - -typedef GLfloat GL2PSrgba[4]; - -#if defined(__cplusplus) -extern "C" { -#endif - -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 nr, GLint ng, GLint nb, GLint buffersize, - FILE *stream, const char *filename); -GL2PSDLL_API GLint gl2psEndPage(void); -GL2PSDLL_API GLint gl2psSetOptions(GLint options); -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, - GLshort fontsize); -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, - GLint xorig, GLint yorig, - GLenum format, GLenum type, const void *pixels); -GL2PSDLL_API GLint gl2psEnable(GLint mode); -GL2PSDLL_API GLint gl2psDisable(GLint mode); -GL2PSDLL_API GLint gl2psPointSize(GLfloat value); -GL2PSDLL_API GLint gl2psLineWidth(GLfloat value); -GL2PSDLL_API GLint gl2psBlendFunc(GLenum sfactor, GLenum dfactor); - -/* undocumented */ -GL2PSDLL_API GLint gl2psDrawImageMap(GLsizei width, GLsizei height, - const GLfloat position[3], - const unsigned char *imagemap); -GL2PSDLL_API const char *gl2psGetFileExtension(GLint format); -GL2PSDLL_API const char *gl2psGetFormatDescription(GLint format); - -#if defined(__cplusplus) -} -#endif - -#endif /* __GL2PS_H__ */ diff -r a132d206a36a -r b9b6a310ad97 src/gripes.cc --- a/src/gripes.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,238 +0,0 @@ -/* - -Copyright (C) 1993-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "defun.h" -#include "error.h" -#include "gripes.h" -#include "oct-obj.h" -#include "utils.h" - -void -gripe_not_supported (const char *fcn) -{ - error ("%s: not supported on this system", fcn); -} - -void -gripe_not_implemented (const char *fcn) -{ - error ("%s: not implemented", fcn); -} - -void -gripe_string_invalid (void) -{ - error ("std::string constant used in invalid context"); -} - -void -gripe_range_invalid (void) -{ - error ("range constant used in invalid context"); -} - -void -gripe_nonconformant (void) -{ - error ("nonconformant matrices"); -} - -void -gripe_nonconformant (octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2) -{ - error ("nonconformant matrices (op1 is %dx%d, op2 is %dx%d)", - r1, c1, r2, c2); -} - -void -gripe_empty_arg (const char *name, bool is_error) -{ - if (is_error) - error ("%s: empty matrix is invalid as an argument", name); - else - warning ("%s: argument is empty matrix", name); -} - -void -gripe_square_matrix_required (const char *name) -{ - error ("%s: argument must be a square matrix", name); -} - -void -gripe_user_supplied_eval (const char *name) -{ - error ("%s: evaluation of user-supplied function failed", name); -} - -void -gripe_user_returned_invalid (const char *name) -{ - error ("%s: user-supplied function returned invalid value", name); -} - -void -gripe_invalid_conversion (const std::string& from, const std::string& to) -{ - error ("invalid conversion from %s to %s", from.c_str (), to.c_str ()); -} - -void -gripe_invalid_value_specified (const char *name) -{ - warning ("invalid value specified for `%s'", name); -} - -void -gripe_2_or_3_dim_plot (void) -{ - error ("plot: can only plot in 2 or 3 dimensions"); -} - -void -gripe_unrecognized_float_fmt (void) -{ - error ("unrecognized floating point format requested"); -} - -void -gripe_unrecognized_data_fmt (const char *warn_for) -{ - error ("%s: unrecognized data format requested", warn_for); -} - -void -gripe_data_conversion (const char *from, const char *to) -{ - error ("unable to convert from %s to %s format", from, to); -} - -void -gripe_wrong_type_arg (const char *name, const char *s, bool is_error) -{ - if (is_error) - error ("%s: wrong type argument `%s'", name, s); - else - warning ("%s: wrong type argument `%s'", name, s); -} - -void -gripe_wrong_type_arg (const char *name, const std::string& s, bool is_error) -{ - gripe_wrong_type_arg (name, s.c_str (), is_error); -} - -void -gripe_wrong_type_arg (const char *name, const octave_value& tc, - bool is_error) -{ - std::string type = tc.type_name (); - - gripe_wrong_type_arg (name, type, is_error); -} - -void -gripe_wrong_type_arg (const std::string& name, const octave_value& tc, - bool is_error) -{ - gripe_wrong_type_arg (name.c_str (), tc, is_error); -} - -void -gripe_wrong_type_arg_for_unary_op (const octave_value& op) -{ - std::string type = op.type_name (); - error ("invalid operand `%s' for unary operator", type.c_str ()); -} - -void -gripe_wrong_type_arg_for_binary_op (const octave_value& op) -{ - std::string type = op.type_name (); - error ("invalid operand `%s' for binary operator", type.c_str ()); -} - -void -gripe_implicit_conversion (const char *id, const char *from, const char *to) -{ - warning_with_id (id, "implicit conversion from %s to %s", from, to); -} - -void -gripe_implicit_conversion (const std::string& id, - const std::string& from, const std::string& to) -{ - warning_with_id (id.c_str (), - "implicit conversion from %s to %s", - from.c_str (), to.c_str ()); -} - -void -gripe_divide_by_zero (void) -{ - warning_with_id ("Octave:divide-by-zero", "division by zero"); -} - -void -gripe_logical_conversion (void) -{ - warning_with_id ("Octave:logical-conversion", - "value not equal to 1 or 0 converted to logical 1"); -} - -void -gripe_library_execution_error (void) -{ - octave_exception_state = octave_no_exception; - - if (! error_state) - error ("caught execution error in library function"); -} - -void -gripe_invalid_inquiry_subscript (void) -{ - error ("invalid dimension inquiry of a non-existent value"); -} - -void -gripe_indexed_cs_list (void) -{ - error ("a cs-list cannot be further indexed"); -} - -void -gripe_nonbraced_cs_list_assignment (void) -{ - error ("invalid assignment to cs-list outside multiple assignment"); -} - -void -gripe_warn_complex_cmp (void) -{ - warning_with_id ("Octave:matlab-incompatible", - "potential Matlab compatibility problem: comparing complex numbers"); -} diff -r a132d206a36a -r b9b6a310ad97 src/gripes.h --- a/src/gripes.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,130 +0,0 @@ -/* - -Copyright (C) 1993-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_gripes_h) -#define octave_gripes_h 1 - -#include - -#include "lo-array-gripes.h" - -class octave_value; - -extern OCTINTERP_API void -gripe_not_supported (const char *); - -extern OCTINTERP_API void -gripe_not_implemented (const char *); - -extern OCTINTERP_API void -gripe_string_invalid (void); - -extern OCTINTERP_API void -gripe_range_invalid (void); - -extern OCTINTERP_API void -gripe_nonconformant (void); - -extern OCTINTERP_API void -gripe_nonconformant (octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2); - -extern OCTINTERP_API void -gripe_empty_arg (const char *name, bool is_error); - -extern OCTINTERP_API void -gripe_square_matrix_required (const char *name); - -extern OCTINTERP_API void -gripe_user_supplied_eval (const char *name); - -extern OCTINTERP_API void -gripe_user_returned_invalid (const char *name); - -extern OCTINTERP_API void -gripe_invalid_conversion (const std::string& from, const std::string& to); - -extern OCTINTERP_API void -gripe_invalid_value_specified (const char *name); - -extern OCTINTERP_API void -gripe_2_or_3_dim_plot (void); - -extern OCTINTERP_API void -gripe_unrecognized_float_fmt (void); - -extern OCTINTERP_API void -gripe_unrecognized_data_fmt (const char *warn_for); - -extern OCTINTERP_API void -gripe_data_conversion (const char *from, const char *to); - -extern OCTINTERP_API void -gripe_wrong_type_arg (const char *name, const char *s, - bool is_error = true); - -extern OCTINTERP_API void -gripe_wrong_type_arg (const char *name, const std::string& s, - bool is_error = true); - -extern OCTINTERP_API void -gripe_wrong_type_arg (const char *name, const octave_value& tc, - bool is_error = true); - -extern OCTINTERP_API void -gripe_wrong_type_arg (const std::string& name, const octave_value& tc, - bool is_error = true); - -extern OCTINTERP_API void -gripe_wrong_type_arg_for_unary_op (const octave_value& op); - -extern OCTINTERP_API void -gripe_wrong_type_arg_for_binary_op (const octave_value& op); - -extern OCTINTERP_API void -gripe_implicit_conversion (const char *id, const char *from, const char *to); - -extern OCTINTERP_API void -gripe_implicit_conversion (const std::string& id, const std::string& from, - const std::string& to); - -extern OCTINTERP_API void -gripe_divide_by_zero (void); - -extern OCTINTERP_API void -gripe_logical_conversion (void); - -extern OCTINTERP_API void -gripe_library_execution_error (void); - -extern OCTINTERP_API void -gripe_invalid_inquiry_subscript (void); - -extern OCTINTERP_API void -gripe_indexed_cs_list (void); - -extern OCTINTERP_API void -gripe_nonbraced_cs_list_assignment (void); - -extern OCTINTERP_API void -gripe_warn_complex_cmp (void); - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/Cell.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/Cell.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,320 @@ +/* + +Copyright (C) 1999-2012 John W. Eaton +Copyright (C) 2009-2010 VZLU Prague + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "idx-vector.h" + +#include "Cell.h" +#include "error.h" +#include "gripes.h" +#include "oct-obj.h" + +Cell::Cell (const octave_value_list& ovl) + : Array (ovl.cell_value ()) +{ +} + +Cell::Cell (const string_vector& sv, bool trim) + : Array () +{ + octave_idx_type n = sv.length (); + + if (n > 0) + { + resize (dim_vector (n, 1)); + + for (octave_idx_type i = 0; i < n; i++) + { + std::string s = sv[i]; + + if (trim) + { + size_t pos = s.find_last_not_of (' '); + + s = (pos == std::string::npos) ? "" : s.substr (0, pos+1); + } + + elem(i,0) = s; + } + } +} + +Cell::Cell (const std::list& lst) + : Array () +{ + size_t n = lst.size (); + + if (n > 0) + { + resize (dim_vector (n, 1)); + + octave_idx_type i = 0; + + for (std::list::const_iterator it = lst.begin (); + it != lst.end (); it++) + { + elem(i++,0) = *it; + } + } +} + +Cell::Cell (const Array& sa) + : Array (sa.dims ()) +{ + octave_idx_type n = sa.numel (); + + octave_value *dst = fortran_vec (); + const std::string *src = sa.data (); + + for (octave_idx_type i = 0; i < n; i++) + dst[i] = src[i]; +} + +// Set size to DV, filling with []. Then fill with as many elements of +// SV as possible. + +Cell::Cell (const dim_vector& dv, const string_vector& sv, bool trim) + : Array (dv, Matrix ()) +{ + octave_idx_type n = sv.length (); + + if (n > 0) + { + octave_idx_type m = numel (); + + octave_idx_type len = n > m ? m : n; + + for (octave_idx_type i = 0; i < len; i++) + { + std::string s = sv[i]; + + if (trim) + { + size_t pos = s.find_last_not_of (' '); + + s = (pos == std::string::npos) ? "" : s.substr (0, pos+1); + } + + elem(i) = s; + } + } +} + +bool +Cell::is_cellstr (void) const +{ + bool retval = true; + + octave_idx_type n = numel (); + + for (octave_idx_type i = 0; i < n; i++) + { + if (! elem(i).is_string ()) + { + retval = false; + break; + } + } + + return retval; +} + +Array +Cell::cellstr_value (void) const +{ + Array retval (dims ()); + + octave_idx_type n = numel (); + + for (octave_idx_type i = 0; i < n; i++) + retval.xelem (i) = elem (i).string_value (); + + return retval; +} + +Cell +Cell::index (const octave_value_list& idx_arg, bool resize_ok) const +{ + Cell retval; + + octave_idx_type n = idx_arg.length (); + + switch (n) + { + case 0: + retval = *this; + break; + + case 1: + { + idx_vector i = idx_arg(0).index_vector (); + + if (! error_state) + retval = Array::index (i, resize_ok, Matrix ()); + } + break; + + case 2: + { + idx_vector i = idx_arg(0).index_vector (); + + if (! error_state) + { + idx_vector j = idx_arg(1).index_vector (); + + if (! error_state) + retval = Array::index (i, j, resize_ok, Matrix ()); + } + } + break; + + default: + { + Array iv (dim_vector (n, 1)); + + for (octave_idx_type i = 0; i < n; i++) + { + iv(i) = idx_arg(i).index_vector (); + + if (error_state) + break; + } + + if (!error_state) + retval = Array::index (iv, resize_ok, Matrix ()); + } + break; + } + + return retval; +} + +void +Cell::assign (const octave_value_list& idx_arg, const Cell& rhs, + const octave_value& fill_val) + +{ + octave_idx_type len = idx_arg.length (); + + Array ra_idx (dim_vector (len, 1)); + + for (octave_idx_type i = 0; i < len; i++) + ra_idx(i) = idx_arg(i).index_vector (); + + Array::assign (ra_idx, rhs, fill_val); +} + +void +Cell::delete_elements (const octave_value_list& idx_arg) + +{ + octave_idx_type len = idx_arg.length (); + + Array ra_idx (dim_vector (len, 1)); + + for (octave_idx_type i = 0; i < len; i++) + ra_idx.xelem (i) = idx_arg(i).index_vector (); + + Array::delete_elements (ra_idx); +} + +octave_idx_type +Cell::nnz (void) const +{ + gripe_wrong_type_arg ("nnz", "cell array"); + return -1; +} + +Cell +Cell::column (octave_idx_type i) const +{ + Cell retval; + + if (ndims () < 3) + { + if (i < 0 || i >= cols ()) + error ("invalid column selection"); + else + { + octave_idx_type nr = rows (); + + retval.resize (dim_vector (nr, 1)); + + for (octave_idx_type j = 0; j < nr; j++) + retval.xelem (j) = elem (j, i); + } + } + else + error ("Cell::column: requires 2-d cell array"); + + return retval; +} + +Cell +Cell::concat (const Cell& rb, const Array& ra_idx) +{ + return insert (rb, ra_idx); +} + +Cell& +Cell::insert (const Cell& a, octave_idx_type r, octave_idx_type c) +{ + Array::insert (a, r, c); + return *this; +} + +Cell& +Cell::insert (const Cell& a, const Array& ra_idx) +{ + Array::insert (a, ra_idx); + return *this; +} + +Cell +Cell::map (ctype_mapper fcn) const +{ + Cell retval (dims ()); + octave_value *r = retval.fortran_vec (); + + const octave_value *p = data (); + + for (octave_idx_type i = 0; i < numel (); i++) + r[i] = ((p++)->*fcn) (); + + return retval; +} + +Cell +Cell::diag (octave_idx_type k) const +{ + return Array::diag (k); +} + +Cell +Cell::diag (octave_idx_type m, octave_idx_type n) const +{ + return Array::diag (m, n); +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/Cell.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/Cell.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,150 @@ +/* + +Copyright (C) 1999-2012 John W. Eaton +Copyright (C) 2009-2010 VZLU Prague + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (Cell_h) +#define Cell_h 1 + +#include + +#include "Array.h" +#include "oct-alloc.h" +#include "str-vec.h" +#include "ov.h" + +class octave_value_list; + +class +OCTINTERP_API +Cell : public Array +{ +public: + + Cell (void) + : Array (dim_vector (0, 0)) { } + + Cell (const octave_value& val) + : Array (dim_vector (1, 1), val) { } + + Cell (const octave_value_list& ovl); + + Cell (octave_idx_type n, octave_idx_type m, + const octave_value& val = Matrix ()) + : Array (dim_vector (n, m), val) { } + + Cell (const dim_vector& dv, const octave_value& val = Matrix ()) + : Array (dv, val) { } + + Cell (const Array& c) + : Array (c) { } + + Cell (const Array& c, octave_idx_type nr, octave_idx_type nc) + : Array (c, dim_vector (nr, nc)) { } + + Cell (const string_vector& sv, bool trim = false); + + Cell (const std::list& lst); + + Cell (const Array& sa); + + Cell (const dim_vector& dv, const string_vector& sv, bool trim = false); + + Cell (const Cell& c) + : Array (c) { } + + bool is_cellstr (void) const; + + Array cellstr_value (void) const; + + using Array::index; + + Cell index (const octave_value_list& idx, bool resize_ok = false) const; + + using Array::delete_elements; + + void delete_elements (const octave_value_list& idx); + + using Array::assign; + + void assign (const octave_value_list& idx, const Cell& rhs, + const octave_value& fill_val = Matrix ()); + + Cell reshape (const dim_vector& new_dims) const + { return Array::reshape (new_dims); } + + octave_idx_type nnz (void) const; + + Cell column (octave_idx_type i) const; + + // FIXME + boolMatrix all (int /* dim */ = 0) const { return boolMatrix (); } + + // FIXME + boolMatrix any (int /* dim */ = 0) const { return boolMatrix (); } + + Cell concat (const Cell& rb, const Array& ra_idx); + + Cell& insert (const Cell& a, octave_idx_type r, octave_idx_type c); + Cell& insert (const Cell& a, const Array& ra_idx); + + // FIXME + bool any_element_is_nan (void) const { return false; } + bool is_true (void) const { return false; } + + octave_value resize_fill_value (void) const + { + static Matrix rfv; + return rfv; + } + + Cell diag (octave_idx_type k = 0) const; + + Cell diag (octave_idx_type m, octave_idx_type n) const; + + Cell xisalnum (void) const { return map (&octave_value::xisalnum); } + Cell xisalpha (void) const { return map (&octave_value::xisalpha); } + Cell xisascii (void) const { return map (&octave_value::xisascii); } + Cell xiscntrl (void) const { return map (&octave_value::xiscntrl); } + Cell xisdigit (void) const { return map (&octave_value::xisdigit); } + Cell xisgraph (void) const { return map (&octave_value::xisgraph); } + Cell xislower (void) const { return map (&octave_value::xislower); } + Cell xisprint (void) const { return map (&octave_value::xisprint); } + Cell xispunct (void) const { return map (&octave_value::xispunct); } + Cell xisspace (void) const { return map (&octave_value::xisspace); } + Cell xisupper (void) const { return map (&octave_value::xisupper); } + Cell xisxdigit (void) const { return map (&octave_value::xisxdigit); } + Cell xtoascii (void) const { return map (&octave_value::xtoascii); } + Cell xtolower (void) const { return map (&octave_value::xtolower); } + Cell xtoupper (void) const { return map (&octave_value::xtoupper); } + +private: + + typedef octave_value (octave_value::*ctype_mapper) (void) const; + + Cell map (ctype_mapper) const; +}; + +template<> +inline Cell octave_value_extract (const octave_value& v) + { return v.cell_value (); } + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/c-file-ptr-stream.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/c-file-ptr-stream.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,362 @@ +/* + +Copyright (C) 2000-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "c-file-ptr-stream.h" + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +c_file_ptr_buf::~c_file_ptr_buf (void) +{ + buf_close (); +} + +// FIXME -- I'm sure there is room for improvement here... + +c_file_ptr_buf::int_type +c_file_ptr_buf::overflow (int_type c) +{ +#if defined (CXX_ISO_COMPLIANT_LIBRARY) + if (f) + return (c != traits_type::eof ()) ? gnulib::fputc (c, f) : flush (); + else + return traits_type::not_eof (c); +#else + if (f) + return (c != EOF) ? gnulib::fputc (c, f) : flush (); + else + return EOF; +#endif +} + +c_file_ptr_buf::int_type +c_file_ptr_buf::underflow_common (bool bump) +{ + if (f) + { + int_type c = gnulib::fgetc (f); + + if (! bump +#if defined (CXX_ISO_COMPLIANT_LIBRARY) + && c != traits_type::eof ()) +#else + && c != EOF) +#endif + ungetc (c, f); + + return c; + } + else +#if defined (CXX_ISO_COMPLIANT_LIBRARY) + return traits_type::eof (); +#else + return EOF; +#endif +} + +c_file_ptr_buf::int_type +c_file_ptr_buf::pbackfail (int_type c) +{ +#if defined (CXX_ISO_COMPLIANT_LIBRARY) + return (c != traits_type::eof () && f) ? ungetc (c, f) : + traits_type::not_eof (c); +#else + return (c != EOF && f) ? ungetc (c, f) : EOF; +#endif +} + +std::streamsize +c_file_ptr_buf::xsputn (const char* s, std::streamsize n) +{ + if (f) + return gnulib::fwrite (s, 1, n, f); + else + return 0; +} + +std::streamsize +c_file_ptr_buf::xsgetn (char *s, std::streamsize n) +{ + if (f) + return gnulib::fread (s, 1, n, f); + else + return 0; +} + +static inline int +seekdir_to_whence (std::ios::seekdir dir) +{ + return ((dir == std::ios::beg) ? SEEK_SET : + (dir == std::ios::cur) ? SEEK_CUR : + (dir == std::ios::end) ? SEEK_END : + dir); +} + +std::streampos +c_file_ptr_buf::seekoff (std::streamoff /* offset */, + std::ios::seekdir /* dir */, + std::ios::openmode) +{ + // FIXME +#if 0 + if (f) + { + fseek (f, offset, seekdir_to_whence (dir)); + + return ftell (f); + } + else + return 0; +#endif + return -1; +} + +std::streampos +c_file_ptr_buf::seekpos (std::streampos /* offset */, std::ios::openmode) +{ + // FIXME +#if 0 + if (f) + { + fseek (f, offset, SEEK_SET); + + return ftell (f); + } + else + return 0; +#endif + return -1; +} + +int +c_file_ptr_buf::sync (void) +{ + flush (); + + return 0; +} + +int +c_file_ptr_buf::flush (void) +{ + return f ? gnulib::fflush (f) : EOF; +} + +int +c_file_ptr_buf::buf_close (void) +{ + int retval = -1; + + flush (); + + if (f) + { + retval = cf (f); + f = 0; + } + + return retval; +} + +int +c_file_ptr_buf::seek (long offset, int origin) +{ + return f ? gnulib::fseek (f, offset, origin) : -1; +} + +long +c_file_ptr_buf::tell (void) +{ + return f ? gnulib::ftell (f) : -1; +} + +int +c_file_ptr_buf::file_close (FILE *f) +{ + return gnulib::fclose (f); +} + +#ifdef HAVE_ZLIB + +c_zfile_ptr_buf::~c_zfile_ptr_buf (void) +{ + buf_close (); +} + +// FIXME -- I'm sure there is room for improvement here... + +c_zfile_ptr_buf::int_type +c_zfile_ptr_buf::overflow (int_type c) +{ +#if defined (CXX_ISO_COMPLIANT_LIBRARY) + if (f) + return (c != traits_type::eof ()) ? gzputc (f, c) : flush (); + else + return traits_type::not_eof (c); +#else + if (f) + return (c != EOF) ? gzputc (f, c) : flush (); + else + return EOF; +#endif +} + +c_zfile_ptr_buf::int_type +c_zfile_ptr_buf::underflow_common (bool bump) +{ + if (f) + { + int_type c = gzgetc (f); + + if (! bump +#if defined (CXX_ISO_COMPLIANT_LIBRARY) + && c != traits_type::eof ()) +#else + && c != EOF) +#endif + gzungetc (c, f); + + return c; + } + else +#if defined (CXX_ISO_COMPLIANT_LIBRARY) + return traits_type::eof (); +#else + return EOF; +#endif +} + +c_zfile_ptr_buf::int_type +c_zfile_ptr_buf::pbackfail (int_type c) +{ +#if defined (CXX_ISO_COMPLIANT_LIBRARY) + return (c != traits_type::eof () && f) ? gzungetc (c, f) : + traits_type::not_eof (c); +#else + return (c != EOF && f) ? gzungetc (c, f) : EOF; +#endif +} + +std::streamsize +c_zfile_ptr_buf::xsputn (const char* s, std::streamsize n) +{ + if (f) + return gzwrite (f, s, n); + else + return 0; +} + +std::streamsize +c_zfile_ptr_buf::xsgetn (char *s, std::streamsize n) +{ + if (f) + return gzread (f, s, n); + else + return 0; +} + +std::streampos +c_zfile_ptr_buf::seekoff (std::streamoff /* offset */, + std::ios::seekdir /* dir */, + std::ios::openmode) +{ + // FIXME +#if 0 + if (f) + { + gzseek (f, offset, seekdir_to_whence (dir)); + + return gztell (f); + } + else + return 0; +#endif + return -1; +} + +std::streampos +c_zfile_ptr_buf::seekpos (std::streampos /* offset */, std::ios::openmode) +{ + // FIXME +#if 0 + if (f) + { + gzseek (f, offset, SEEK_SET); + + return gztell (f); + } + else + return 0; +#endif + return -1; +} + +int +c_zfile_ptr_buf::sync (void) +{ + flush (); + + return 0; +} + +int +c_zfile_ptr_buf::flush (void) +{ + // FIXME -- do we need something more complex here, passing + // something other than 0 for the second argument to gzflush and + // checking the return value, etc.? + + return f ? gzflush (f, 0) : EOF; +} + +int +c_zfile_ptr_buf::buf_close (void) +{ + int retval = -1; + + flush (); + + if (f) + { + retval = cf (f); + f = 0; + } + + return retval; +} + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/c-file-ptr-stream.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/c-file-ptr-stream.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,227 @@ +/* + +Copyright (C) 2000-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_c_file_ptr_stream_h) +#define octave_c_file_ptr_stream_h 1 + +#include + +#include + +class +c_file_ptr_buf : public std::streambuf +{ +public: + +#if !defined (CXX_ISO_COMPLIANT_LIBRARY) + typedef int int_type; +#else + typedef std::streambuf::int_type int_type; +#endif + + typedef int (*close_fcn) (FILE *); + + FILE* stdiofile (void) { return f; } + + c_file_ptr_buf (FILE *f_arg, close_fcn cf_arg = file_close) + : std::streambuf (), f (f_arg), cf (cf_arg) + { } + + ~c_file_ptr_buf (void); + + int_type overflow (int_type); + + int_type underflow (void) { return underflow_common (false); } + + int_type uflow (void) { return underflow_common (true); } + + int_type pbackfail (int_type); + + std::streamsize xsputn (const char*, std::streamsize); + + std::streamsize xsgetn (char *, std::streamsize); + + std::streampos seekoff (std::streamoff, std::ios::seekdir, + std::ios::openmode = std::ios::in | std::ios::out); + + std::streampos seekpos (std::streampos, + std::ios::openmode = std::ios::in | std::ios::out); + + int sync (void); + + int flush (void); + + int buf_close (void); + + int file_number () const { return f ? fileno (f) : -1; } + + int seek (long offset, int origin); + + long tell (void); + + void clear (void) { if (f) clearerr (f); } + + static int file_close (FILE *f); + +protected: + + FILE *f; + + close_fcn cf; + +private: + + int_type underflow_common (bool); + + // No copying! + + c_file_ptr_buf (const c_file_ptr_buf&); + + c_file_ptr_buf& operator = (const c_file_ptr_buf&); +}; + +// FIXME -- the following three classes could probably share +// some code... + +template +class +c_file_ptr_stream : public STREAM_T +{ +public: + + c_file_ptr_stream (FILE_T f, typename BUF_T::close_fcn cf = BUF_T::file_close) + : STREAM_T (0), buf (new BUF_T (f, cf)) { STREAM_T::init (buf); } + + ~c_file_ptr_stream (void) { delete buf; buf = 0; } + + BUF_T *rdbuf (void) { return buf; } + + void stream_close (void) { if (buf) buf->buf_close (); } + + int seek (long offset, int origin) + { return buf ? buf->seek (offset, origin) : -1; } + + long tell (void) { return buf ? buf->tell () : -1; } + + void clear (void) { if (buf) buf->clear (); STREAM_T::clear (); } + +private: + + BUF_T *buf; + + // No copying! + + c_file_ptr_stream (const c_file_ptr_stream&); + + c_file_ptr_stream& operator = (const c_file_ptr_stream&); +}; + +typedef c_file_ptr_stream i_c_file_ptr_stream; +typedef c_file_ptr_stream o_c_file_ptr_stream; +typedef c_file_ptr_stream io_c_file_ptr_stream; + +#ifdef HAVE_ZLIB + +#ifdef HAVE_ZLIB_H +#include +#endif + +class +c_zfile_ptr_buf : public std::streambuf +{ +public: + +#if !defined (CXX_ISO_COMPLIANT_LIBRARY) + typedef int int_type; +#else + typedef std::streambuf::int_type int_type; +#endif + + typedef int (*close_fcn) (gzFile); + + gzFile stdiofile (void) { return f; } + + c_zfile_ptr_buf (gzFile f_arg, close_fcn cf_arg = file_close) + : std::streambuf (), f (f_arg), cf (cf_arg) + { } + + ~c_zfile_ptr_buf (void); + + int_type overflow (int_type); + + int_type underflow (void) { return underflow_common (false); } + + int_type uflow (void) { return underflow_common (true); } + + int_type pbackfail (int_type); + + std::streamsize xsputn (const char*, std::streamsize); + + std::streamsize xsgetn (char *, std::streamsize); + + std::streampos seekoff (std::streamoff, std::ios::seekdir, + std::ios::openmode = std::ios::in | std::ios::out); + + std::streampos seekpos (std::streampos, + std::ios::openmode = std::ios::in | std::ios::out); + + int sync (void); + + int flush (void); + + int buf_close (void); + + int file_number () const { return -1; } + + int seek (long offset, int origin) + { return f ? gzseek (f, offset, origin) : -1; } + + long tell (void) { return f ? gztell (f) : -1; } + + void clear (void) { if (f) gzclearerr (f); } + + static int file_close (gzFile f) { return ::gzclose (f); } + +protected: + + gzFile f; + + close_fcn cf; + +private: + + int_type underflow_common (bool); + + // No copying! + + c_zfile_ptr_buf (const c_zfile_ptr_buf&); + + c_zfile_ptr_buf& operator = (const c_zfile_ptr_buf&); +}; + +typedef c_file_ptr_stream i_c_zfile_ptr_stream; +typedef c_file_ptr_stream o_c_zfile_ptr_stream; +typedef c_file_ptr_stream io_c_zfile_ptr_stream; + +#endif + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/comment-list.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/comment-list.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,106 @@ +/* + +Copyright (C) 2000-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "lo-utils.h" +#include "singleton-cleanup.h" + +#include "comment-list.h" +#include "error.h" + +octave_comment_buffer *octave_comment_buffer::instance = 0; + +octave_comment_list * +octave_comment_list::dup (void) const +{ + octave_comment_list *new_cl = new octave_comment_list (); + + for (const_iterator p = begin (); p != end (); p++) + { + const octave_comment_elt elt = *p; + + new_cl->append (elt); + } + + return new_cl; +} + +bool +octave_comment_buffer::instance_ok (void) +{ + bool retval = true; + + if (! instance) + { + instance = new octave_comment_buffer (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } + + if (! instance) + { + ::error ("unable to create comment buffer object"); + + retval = false; + } + + return retval; +} + +void +octave_comment_buffer::append (const std::string& s, + octave_comment_elt::comment_type t) +{ + if (instance_ok ()) + instance->do_append (s, t); +} + +octave_comment_list * +octave_comment_buffer::get_comment (void) +{ + return (instance_ok ()) ? instance->do_get_comment () : 0; +} + +void +octave_comment_buffer::do_append (const std::string& s, + octave_comment_elt::comment_type t) +{ + comment_list->append (s, t); +} + +octave_comment_list * +octave_comment_buffer::do_get_comment (void) +{ + octave_comment_list *retval = 0; + + if (comment_list && comment_list->length () > 0) + { + retval = comment_list; + comment_list = new octave_comment_list (); + } + + return retval; +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/comment-list.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/comment-list.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,131 @@ +/* + +Copyright (C) 2000-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_comment_list_h) +#define octave_comment_list_h 1 + +#include + +#include + +extern std::string get_comment_text (void); + +extern char *get_comment_text_c_str (void); + +extern void save_comment_text (const std::string& text); + +class +octave_comment_elt +{ +public: + + enum comment_type + { + unknown, + block, + end_of_line, + doc_string, + copyright + }; + + octave_comment_elt (const std::string& s = std::string (), + comment_type t = unknown) + : txt (s), typ (t) { } + + octave_comment_elt (const octave_comment_elt& oc) + : txt (oc.txt), typ (oc.typ) { } + + octave_comment_elt& operator = (const octave_comment_elt& oc) + { + if (this != &oc) + { + txt = oc.txt; + typ = oc.typ; + } + + return *this; + } + + std::string text (void) const { return txt; } + + comment_type type (void) const { return typ; } + + ~octave_comment_elt (void) { } + +private: + + // The text of the comment. + std::string txt; + + // The type of comment. + comment_type typ; +}; + +class +octave_comment_list : public octave_base_list +{ +public: + + octave_comment_list (void) { } + + void append (const octave_comment_elt& elt) + { octave_base_list::append (elt); } + + void append (const std::string& s, + octave_comment_elt::comment_type t = octave_comment_elt::unknown) + { append (octave_comment_elt (s, t)); } + + octave_comment_list *dup (void) const; +}; + +class +octave_comment_buffer +{ +public: + + octave_comment_buffer (void) + : comment_list (new octave_comment_list ()) { } + + ~octave_comment_buffer (void) { delete comment_list; } + + static bool instance_ok (void); + + static void append + (const std::string& s, + octave_comment_elt::comment_type t = octave_comment_elt::unknown); + + static octave_comment_list *get_comment (void); + +private: + + void do_append (const std::string& s, octave_comment_elt::comment_type t); + + octave_comment_list *do_get_comment (void); + + octave_comment_list *comment_list; + + static octave_comment_buffer *instance; + + static void cleanup_instance (void) { delete instance; instance = 0; } +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/cutils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/cutils.c Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,60 @@ +/* + +Copyright (C) 1999-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +#include "cutils.h" + +void +octave_sleep (unsigned int seconds) +{ + sleep (seconds); +} + +void +octave_usleep (unsigned int useconds) +{ + struct timespec delay; + struct timespec remaining; + + unsigned int sec = useconds / 1000000; + unsigned int usec = useconds % 1000000; + + delay.tv_sec = sec; + delay.tv_nsec = usec * 1000; + + nanosleep (&delay, &remaining); +} + +int +octave_raw_vsnprintf (char *buf, size_t n, const char *fmt, va_list args) +{ + return vsnprintf (buf, n, fmt, args); +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/cutils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/cutils.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,43 @@ +/* + +Copyright (C) 2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_cutils_h) +#define octave_cutils_h 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +OCTINTERP_API void octave_sleep (unsigned int seconds); + +OCTINTERP_API void octave_usleep (unsigned int useconds); + +OCTINTERP_API int +octave_raw_vsnprintf (char *buf, size_t n, const char *fmt, va_list args); + +#ifdef __cplusplus +} +#endif + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/defun-dld.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/defun-dld.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,71 @@ +/* + +Copyright (C) 1994-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_defun_dld_h) +#define octave_defun_dld_h 1 + +#if defined (octave_defun_h) +#error defun.h and defun-dld.h both included in same file! +#endif + +#include "defun-int.h" + +// Define a builtin function that may be loaded dynamically at run +// time. +// +// If Octave is not configured for dynamic linking of builtin +// functions, this is the same as DEFUN, except that it will generate +// an extra externally visible function. +// +// The first DECLARE_FUN is for the benefit of the installer function +// and the second is for the definition of the function. + +#if defined (MAKE_BUILTINS) + +#define DEFUN_DLD(name, args_name, nargout_name, doc) \ + DEFUN_DLD_INTERNAL (name, args_name, nargout_name, doc) + +// This one can be used when `name' cannot be used directly (if it is +// already defined as a macro). In that case, name is already a +// quoted string, and the internal name of the function must be passed +// too (the convention is to use a prefix of "F", so "foo" becomes +// "Ffoo") as well as the name of the generated installer function +// (the convention is to use a prefix of "G", so "foo" becomes "Gfoo"). + +#define DEFUNX_DLD(name, fname, gname, args_name, nargout_name, doc) \ + DEFUNX_DLD_INTERNAL (name, fname, args_name, nargout_name, doc) + +#else + +#define DEFUN_DLD(name, args_name, nargout_name, doc) \ + DECLARE_FUN (name, args_name, nargout_name); \ + DEFINE_FUN_INSTALLER_FUN (name, doc) \ + DECLARE_FUN (name, args_name, nargout_name) + +#define DEFUNX_DLD(name, fname, gname, args_name, nargout_name, doc) \ + DECLARE_FUNX (fname, args_name, nargout_name); \ + DEFINE_FUNX_INSTALLER_FUN (name, fname, gname, doc) \ + DECLARE_FUNX (fname, args_name, nargout_name) + +#endif + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/defun-int.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/defun-int.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,187 @@ +/* + +Copyright (C) 1994-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_defun_int_h) +#define octave_defun_int_h 1 + +#include + +#include "ov-builtin.h" +#include "ov-dld-fcn.h" +#include "symtab.h" +#include "version.h" + +class octave_value; + +extern OCTINTERP_API void print_usage (void); +extern OCTINTERP_API void print_usage (const std::string&); + +extern OCTINTERP_API void check_version (const std::string& version, const std::string& fcn); + +extern OCTINTERP_API void +install_builtin_function (octave_builtin::fcn f, const std::string& name, + const std::string& file, const std::string& doc, + bool can_hide_function = true); + +extern OCTINTERP_API void +install_dld_function (octave_dld_function::fcn f, const std::string& name, + const octave_shlib& shl, const std::string& doc, + bool relative = false); + +extern OCTINTERP_API void +install_mex_function (void *fptr, bool fmex, const std::string& name, + const octave_shlib& shl, bool relative = false); + +extern OCTINTERP_API void +alias_builtin (const std::string& alias, const std::string& name); + +// Gets the shlib of the currently executing DLD function, if any. +extern OCTINTERP_API octave_shlib +get_current_shlib (void); + +// This is a convenience class that calls the above function automatically at +// construction time. When deriving new classes, you can either use it as a field +// or as a parent (with multiple inheritance). + +class octave_auto_shlib : public octave_shlib +{ +public: + octave_auto_shlib (void) + : octave_shlib (get_current_shlib ()) { } + octave_auto_shlib (const octave_shlib& shl) + : octave_shlib (shl) { } +}; + +extern OCTINTERP_API bool +defun_isargout (int, int); + +extern OCTINTERP_API void +defun_isargout (int, int, bool *); + +#define DECLARE_FUNX(name, args_name, nargout_name) \ + OCTAVE_EXPORT octave_value_list \ + name (const octave_value_list& args_name, int nargout_name) + +#define DECLARE_FUN(name, args_name, nargout_name) \ + DECLARE_FUNX (F ## name, args_name, nargout_name) + +// Define the code that will be used to insert the new function into +// the symbol table. We look for this name instead of the actual +// function so that we can easily install the doc std::string too. + +typedef bool (*octave_dld_fcn_installer) (const octave_shlib&, bool relative); + +typedef octave_function * (*octave_dld_fcn_getter) (const octave_shlib&, bool relative); + +#define DEFINE_FUN_INSTALLER_FUN(name, doc) \ + DEFINE_FUNX_INSTALLER_FUN(#name, F ## name, G ## name, doc) + +#define DEFINE_FUNX_INSTALLER_FUN(name, fname, gname, doc) \ + extern "C" \ + OCTAVE_EXPORT \ + octave_function * \ + gname (const octave_shlib& shl, bool relative) \ + { \ + octave_function *retval = 0; \ + \ + check_version (OCTAVE_API_VERSION, name); \ + \ + if (! error_state) \ + { \ + octave_dld_function *fcn = octave_dld_function::create (fname, shl, name, doc); \ + \ + if (relative) \ + fcn->mark_relative (); \ + \ + retval = fcn; \ + } \ + \ + return retval; \ + } + +// MAKE_BUILTINS is defined to extract function names and related +// information and create the *.df files that are eventually used to +// create the builtins.cc file. + +#if defined (MAKE_BUILTINS) + +// Generate code to install name in the symbol table. The script +// mkdefs will create a .def file for every .cc file that uses DEFUN, +// or DEFCMD. + +#define DEFUN_INTERNAL(name, args_name, nargout_name, doc) \ + BEGIN_INSTALL_BUILTIN \ + XDEFUN_INTERNAL (name, args_name, nargout_name, doc) \ + END_INSTALL_BUILTIN + +#define DEFCONSTFUN_INTERNAL(name, args_name, nargout_name, doc) \ + BEGIN_INSTALL_BUILTIN \ + XDEFCONSTFUN_INTERNAL (name, args_name, nargout_name, doc) \ + END_INSTALL_BUILTIN + +#define DEFUNX_INTERNAL(name, fname, args_name, nargout_name, doc) \ + BEGIN_INSTALL_BUILTIN \ + XDEFUNX_INTERNAL (name, fname, args_name, nargout_name, doc) \ + END_INSTALL_BUILTIN + +// Generate code to install name in the symbol table. The script +// mkdefs will create a .def file for every .cc file that uses +// DEFUN_DLD. + +#define DEFUN_DLD_INTERNAL(name, args_name, nargout_name, doc) \ + BEGIN_INSTALL_BUILTIN \ + XDEFUN_DLD_INTERNAL (name, args_name, nargout_name, doc) \ + END_INSTALL_BUILTIN + +#define DEFUNX_DLD_INTERNAL(name, fname, args_name, nargout_name, doc) \ + BEGIN_INSTALL_BUILTIN \ + XDEFUNX_DLD_INTERNAL (name, fname, args_name, nargout_name, doc) \ + END_INSTALL_BUILTIN + +// Generate code for making another name for an existing function. + +#define DEFALIAS_INTERNAL(alias, name) \ + BEGIN_INSTALL_BUILTIN \ + XDEFALIAS_INTERNAL(alias, name) \ + END_INSTALL_BUILTIN + +#else /* ! MAKE_BUILTINS */ + +// Generate the first line of the function definition. This ensures +// that the internal functions all have the same signature. + +#define DEFUN_INTERNAL(name, args_name, nargout_name, doc) \ + DECLARE_FUN (name, args_name, nargout_name) + +#define DEFCONSTFUN_INTERNAL(name, args_name, nargout_name, doc) \ + DECLARE_FUN (name, args_name, nargout_name) + +#define DEFUNX_INTERNAL(name, fname, args_name, nargout_name, doc) \ + DECLARE_FUNX (fname, args_name, nargout_name) + +// No definition is required for an alias. + +#define DEFALIAS_INTERNAL(alias, name) + +#endif /* ! MAKE_BUILTINS */ + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/display.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/display.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,182 @@ +/* + +Copyright (C) 2009-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#if defined (OCTAVE_USE_WINDOWS_API) +#include +#elif defined (HAVE_FRAMEWORK_CARBON) +#include +#elif defined (HAVE_X_WINDOWS) +#include +#endif + +#include "singleton-cleanup.h" + +#include "display.h" +#include "error.h" + +display_info *display_info::instance = 0; + +#if defined (HAVE_FRAMEWORK_CARBON) && ! defined (HAVE_CARBON_CGDISPLAYBITSPERPIXEL) +// FIXME - This will only work for MacOS > 10.5. For earlier versions +// this code is not needed (use CGDisplayBitsPerPixel instead). +size_t DisplayBitsPerPixel (CGDirectDisplayID display) +{ + CGDisplayModeRef mode = CGDisplayCopyDisplayMode (display); + CFStringRef pixelEncoding = CGDisplayModeCopyPixelEncoding (mode); + + if (CFStringCompare (pixelEncoding, CFSTR (IO32BitDirectPixels), 0) == 0) + return 32; + else if (CFStringCompare (pixelEncoding, CFSTR (IO16BitDirectPixels), 0) == 0) + return 16; + else + return 8; +} +#endif + +void +display_info::init (bool query) +{ + if (query) + { +#if defined (OCTAVE_USE_WINDOWS_API) + + HDC hdc = GetDC (0); + + if (hdc) + { + dp = GetDeviceCaps (hdc, BITSPIXEL); + + ht = GetDeviceCaps (hdc, VERTRES); + wd = GetDeviceCaps (hdc, HORZRES); + + double ht_mm = GetDeviceCaps (hdc, VERTSIZE); + double wd_mm = GetDeviceCaps (hdc, HORZSIZE); + + rx = wd * 25.4 / wd_mm; + ry = ht * 25.4 / ht_mm; + } + else + warning ("no graphical display found"); + +#elif defined (HAVE_FRAMEWORK_CARBON) + + CGDirectDisplayID display = CGMainDisplayID (); + + if (display) + { +# if defined (HAVE_CARBON_CGDISPLAYBITSPERPIXEL) + // For MacOS < 10.7 use the line below + dp = CGDisplayBitsPerPixel (display); +# else + // For MacOS > 10.5 use the line below + dp = DisplayBitsPerPixel (display); +# endif + + ht = CGDisplayPixelsHigh (display); + wd = CGDisplayPixelsWide (display); + + CGSize sz_mm = CGDisplayScreenSize (display); + // For MacOS >= 10.6, CGSize is a struct keeping 2 CGFloat values, + // but the CGFloat typedef is not present on older systems, + // so use double instead. + double ht_mm = sz_mm.height; + double wd_mm = sz_mm.width; + + rx = wd * 25.4 / wd_mm; + ry = ht * 25.4 / ht_mm; + } + else + warning ("no graphical display found"); + +#elif defined (HAVE_X_WINDOWS) + + const char *display_name = getenv ("DISPLAY"); + + if (display_name && *display_name) + { + Display *display = XOpenDisplay (display_name); + + if (display) + { + Screen *screen = DefaultScreenOfDisplay (display); + + if (screen) + { + dp = DefaultDepthOfScreen (screen); + + ht = HeightOfScreen (screen); + wd = WidthOfScreen (screen); + + int screen_number = XScreenNumberOfScreen (screen); + + double ht_mm = DisplayHeightMM (display, screen_number); + double wd_mm = DisplayWidthMM (display, screen_number); + + rx = wd * 25.4 / wd_mm; + ry = ht * 25.4 / ht_mm; + } + else + warning ("X11 display has no default screen"); + + XCloseDisplay (display); + } + else + warning ("unable to open X11 DISPLAY"); + } + else + warning ("X11 DISPLAY environment variable not set"); +#else + + warning ("no graphical display found"); + +#endif + } +} + +bool +display_info::instance_ok (bool query) +{ + bool retval = true; + + if (! instance) + { + instance = new display_info (query); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } + + if (! instance) + { + ::error ("unable to create display_info object!"); + + retval = false; + } + + return retval; +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/display.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/display.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,99 @@ +/* + +Copyright (C) 2009-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_display_h) +#define octave_display_h 1 + +class Matrix; + +class display_info +{ +protected: + + display_info (bool query = true) + : ht (1), wd (1), dp (0), rx (72), ry (72) + { + init (query); + } + +public: + + static int height (void) + { + return instance_ok () ? instance->do_height () : 0; + } + + static int width (void) + { + return instance_ok () ? instance->do_width () : 0; + } + + static int depth (void) + { + return instance_ok () ? instance->do_depth () : 0; + } + + static double x_dpi (void) + { + return instance_ok () ? instance->do_x_dpi () : 0; + } + + static double y_dpi (void) + { + return instance_ok () ? instance->do_y_dpi () : 0; + } + + // To disable querying the window system for defaults, this function + // must be called before any other display_info function. + static void no_window_system (void) + { + instance_ok (false); + } + +private: + + static display_info *instance; + + static void cleanup_instance (void) { delete instance; instance = 0; } + + // Height, width, and depth of the display. + int ht; + int wd; + int dp; + + // X- and Y- Resolution of the display in dots (pixels) per inch. + double rx; + double ry; + + int do_height (void) const { return ht; } + int do_width (void) const { return wd; } + int do_depth (void) const { return dp; } + + double do_x_dpi (void) const { return rx; } + double do_y_dpi (void) const { return ry; } + + void init (bool query = true); + + static bool instance_ok (bool query = true); +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/dynamic-ld.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/dynamic-ld.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,582 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "file-stat.h" +#include "oct-env.h" +#include "oct-time.h" +#include "singleton-cleanup.h" + +#include + +#include "defun.h" +#include "dynamic-ld.h" +#include "ov-fcn.h" +#include "ov-dld-fcn.h" +#include "ov-mex-fcn.h" +#include "parse.h" +#include "unwind-prot.h" +#include "utils.h" +#include "variables.h" + +#define STRINGIFY(s) STRINGIFY1(s) +#define STRINGIFY1(s) #s + +class +octave_shlib_list +{ +public: + + typedef std::list::iterator iterator; + typedef std::list::const_iterator const_iterator; + + static void append (const octave_shlib& shl); + + static void remove (octave_shlib& shl, octave_shlib::close_hook cl_hook = 0); + + static octave_shlib find_file (const std::string& file_name); + + static void display (void); + +private: + + octave_shlib_list (void) : lib_list () { } + + ~octave_shlib_list (void) { } + + void do_append (const octave_shlib& shl); + + void do_remove (octave_shlib& shl, octave_shlib::close_hook cl_hook = 0); + + octave_shlib do_find_file (const std::string& file_name) const; + + void do_display (void) const; + + static octave_shlib_list *instance; + + static void cleanup_instance (void) { delete instance; instance = 0; } + + static bool instance_ok (void); + + // List of libraries we have loaded. + std::list lib_list; + + // No copying! + + octave_shlib_list (const octave_shlib_list&); + + octave_shlib_list& operator = (const octave_shlib_list&); +}; + +octave_shlib_list *octave_shlib_list::instance = 0; + +void +octave_shlib_list::do_append (const octave_shlib& shl) +{ + lib_list.push_back (shl); +} + +void +octave_shlib_list::do_remove (octave_shlib& shl, + octave_shlib::close_hook cl_hook) +{ + for (iterator p = lib_list.begin (); p != lib_list.end (); p++) + { + if (*p == shl) + { + // Erase first to avoid potentially invalidating the pointer by the + // following hooks. + lib_list.erase (p); + + shl.close (cl_hook); + + break; + } + } +} + +octave_shlib +octave_shlib_list::do_find_file (const std::string& file_name) const +{ + octave_shlib retval; + + for (const_iterator p = lib_list.begin (); p != lib_list.end (); p++) + { + if (p->file_name () == file_name) + { + retval = *p; + break; + } + } + + return retval; +} + +void +octave_shlib_list::do_display (void) const +{ + std::cerr << "current shared libraries:" << std::endl; + for (const_iterator p = lib_list.begin (); p != lib_list.end (); p++) + std::cerr << " " << p->file_name () << std::endl; +} + +bool +octave_shlib_list::instance_ok (void) +{ + bool retval = true; + + if (! instance) + { + instance = new octave_shlib_list (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } + + if (! instance) + { + ::error ("unable to create shared library list object!"); + + retval = false; + } + + return retval; +} + +void +octave_shlib_list::append (const octave_shlib& shl) +{ + if (instance_ok ()) + instance->do_append (shl); +} + +void +octave_shlib_list::remove (octave_shlib& shl, + octave_shlib::close_hook cl_hook) +{ + if (instance_ok ()) + instance->do_remove (shl, cl_hook); +} + +octave_shlib +octave_shlib_list::find_file (const std::string& file_name) +{ + return (instance_ok ()) + ? instance->do_find_file (file_name) : octave_shlib (); +} + +void +octave_shlib_list::display (void) +{ + if (instance_ok ()) + instance->do_display (); +} + +class +octave_mex_file_list +{ +public: + + typedef std::list::iterator iterator; + typedef std::list::const_iterator const_iterator; + + static void append (const octave_shlib& shl); + + static void remove (octave_shlib& shl, octave_shlib::close_hook cl_hook = 0); + +private: + + octave_mex_file_list (void) : file_list () { } + + ~octave_mex_file_list (void) { } + + void do_append (const octave_shlib& shl); + + void do_remove (octave_shlib& shl, octave_shlib::close_hook cl_hook = 0); + + static octave_mex_file_list *instance; + + static void cleanup_instance (void) { delete instance; instance = 0; } + + static bool instance_ok (void); + + // List of libraries we have loaded. + std::list file_list; + + // No copying! + + octave_mex_file_list (const octave_mex_file_list&); + + octave_mex_file_list& operator = (const octave_mex_file_list&); +}; + +octave_mex_file_list *octave_mex_file_list::instance = 0; + +void +octave_mex_file_list::do_append (const octave_shlib& shl) +{ + file_list.push_back (shl); +} + +void +octave_mex_file_list::do_remove (octave_shlib& shl, + octave_shlib::close_hook cl_hook) +{ + for (iterator p = file_list.begin (); p != file_list.end (); p++) + { + if (*p == shl) + { + // Erase first to avoid potentially invalidating the pointer by the + // following hooks. + file_list.erase (p); + + shl.close (cl_hook); + + break; + } + } +} + +bool +octave_mex_file_list::instance_ok (void) +{ + bool retval = true; + + if (! instance) + { + instance = new octave_mex_file_list (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } + + if (! instance) + { + ::error ("unable to create shared library list object!"); + + retval = false; + } + + return retval; +} + +void +octave_mex_file_list::append (const octave_shlib& shl) +{ + if (instance_ok ()) + instance->do_append (shl); +} + +void +octave_mex_file_list::remove (octave_shlib& shl, + octave_shlib::close_hook cl_hook) +{ + if (instance_ok ()) + instance->do_remove (shl, cl_hook); +} + +octave_dynamic_loader *octave_dynamic_loader::instance = 0; + +bool octave_dynamic_loader::doing_load = false; + +bool +octave_dynamic_loader::instance_ok (void) +{ + bool retval = true; + + if (! instance) + { + instance = new octave_dynamic_loader (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } + + if (! instance) + { + ::error ("unable to create dynamic loader object!"); + + retval = false; + } + + return retval; +} + +static void +do_clear_function (const std::string& fcn_name) +{ + warning_with_id ("Octave:reload-forces-clear", " %s", fcn_name.c_str ()); + + symbol_table::clear_dld_function (fcn_name); +} + +static void +clear (octave_shlib& oct_file) +{ + if (oct_file.number_of_functions_loaded () > 1) + { + warning_with_id ("Octave:reload-forces-clear", + "reloading %s clears the following functions:", + oct_file.file_name ().c_str ()); + + octave_shlib_list::remove (oct_file, do_clear_function); + } + else + octave_shlib_list::remove (oct_file, symbol_table::clear_dld_function); +} + +octave_function * +octave_dynamic_loader::do_load_oct (const std::string& fcn_name, + const std::string& file_name, + bool relative) +{ + octave_function *retval = 0; + + unwind_protect frame; + + frame.protect_var (octave_dynamic_loader::doing_load); + + doing_load = true; + + octave_shlib oct_file = octave_shlib_list::find_file (file_name); + + if (oct_file && oct_file.is_out_of_date ()) + clear (oct_file); + + if (! oct_file) + { + oct_file.open (file_name); + + if (! error_state && oct_file) + octave_shlib_list::append (oct_file); + } + + if (! error_state) + { + if (oct_file) + { + void *function = oct_file.search (fcn_name, name_mangler); + + if (! function) + { + // FIXME -- can we determine this C mangling scheme + // automatically at run time or configure time? + + function = oct_file.search (fcn_name, name_uscore_mangler); + } + + if (function) + { + octave_dld_fcn_getter f + = FCN_PTR_CAST (octave_dld_fcn_getter, function); + + retval = f (oct_file, relative); + + if (! retval) + ::error ("failed to install .oct file function `%s'", + fcn_name.c_str ()); + } + } + else + ::error ("%s is not a valid shared library", + file_name.c_str ()); + } + + return retval; +} + +octave_function * +octave_dynamic_loader::do_load_mex (const std::string& fcn_name, + const std::string& file_name, + bool /*relative*/) +{ + octave_function *retval = 0; + + unwind_protect frame; + + frame.protect_var (octave_dynamic_loader::doing_load); + + doing_load = true; + + octave_shlib mex_file = octave_shlib_list::find_file (file_name); + + if (mex_file && mex_file.is_out_of_date ()) + clear (mex_file); + + if (! mex_file) + { + mex_file.open (file_name); + + if (! error_state && mex_file) + octave_shlib_list::append (mex_file); + } + + if (! error_state) + { + if (mex_file) + { + void *function = 0; + + bool have_fmex = false; + + octave_mex_file_list::append (mex_file); + + function = mex_file.search (fcn_name, mex_mangler); + + if (! function) + { + // FIXME -- can we determine this C mangling scheme + // automatically at run time or configure time? + + function = mex_file.search (fcn_name, mex_uscore_mangler); + + if (! function) + { + function = mex_file.search (fcn_name, mex_f77_mangler); + + if (function) + have_fmex = true; + } + } + + if (function) + retval = new octave_mex_function (function, have_fmex, + mex_file, fcn_name); + else + ::error ("failed to install .mex file function `%s'", + fcn_name.c_str ()); + } + else + ::error ("%s is not a valid shared library", + file_name.c_str ()); + } + + return retval; +} + +bool +octave_dynamic_loader::do_remove_oct (const std::string& fcn_name, + octave_shlib& shl) +{ + bool retval = false; + + // We don't need to do anything if this is called because we are in + // the process of reloading a .oct file that has changed. + + if (! doing_load) + { + retval = shl.remove (fcn_name); + + if (shl.number_of_functions_loaded () == 0) + octave_shlib_list::remove (shl); + } + + return retval; +} + +bool +octave_dynamic_loader::do_remove_mex (const std::string& fcn_name, + octave_shlib& shl) +{ + bool retval = false; + + // We don't need to do anything if this is called because we are in + // the process of reloading a .oct file that has changed. + + if (! doing_load) + { + retval = shl.remove (fcn_name); + + if (shl.number_of_functions_loaded () == 0) + octave_mex_file_list::remove (shl); + } + + return retval; +} + +octave_function * +octave_dynamic_loader::load_oct (const std::string& fcn_name, + const std::string& file_name, + bool relative) +{ + return (instance_ok ()) + ? instance->do_load_oct (fcn_name, file_name, relative) : 0; +} + +octave_function * +octave_dynamic_loader::load_mex (const std::string& fcn_name, + const std::string& file_name, + bool relative) +{ + return (instance_ok ()) + ? instance->do_load_mex (fcn_name, file_name, relative) : 0; +} + +bool +octave_dynamic_loader::remove_oct (const std::string& fcn_name, + octave_shlib& shl) +{ + return (instance_ok ()) ? instance->do_remove_oct (fcn_name, shl) : false; +} + +bool +octave_dynamic_loader::remove_mex (const std::string& fcn_name, + octave_shlib& shl) +{ + return (instance_ok ()) ? instance->do_remove_mex (fcn_name, shl) : false; +} + +std::string +octave_dynamic_loader::name_mangler (const std::string& name) +{ + return "G" + name; +} + +std::string +octave_dynamic_loader::name_uscore_mangler (const std::string& name) +{ + return "_G" + name; +} + +std::string +octave_dynamic_loader::mex_mangler (const std::string&) +{ + return "mexFunction"; +} + +std::string +octave_dynamic_loader::mex_uscore_mangler (const std::string&) +{ + return "_mexFunction"; +} + +std::string +octave_dynamic_loader::mex_f77_mangler (const std::string&) +{ + return STRINGIFY (F77_FUNC (mexfunction, MEXFUNCTION)); +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/dynamic-ld.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/dynamic-ld.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,100 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_dynamic_ld_h) +#define octave_dynamic_ld_h 1 + +#include + +#include "oct-shlib.h" + +class octave_function; + +class +octave_dynamic_loader +{ +protected: + + octave_dynamic_loader (void) { } + +public: + + virtual ~octave_dynamic_loader (void) { } + + static octave_function * + load_oct (const std::string& fcn_name, + const std::string& file_name = std::string (), + bool relative = false); + + static octave_function * + load_mex (const std::string& fcn_name, + const std::string& file_name = std::string (), + bool relative = false); + + static bool remove_oct (const std::string& fcn_name, octave_shlib& shl); + + static bool remove_mex (const std::string& fcn_name, octave_shlib& shl); + +private: + + // No copying! + + octave_dynamic_loader (const octave_dynamic_loader&); + + octave_dynamic_loader& operator = (const octave_dynamic_loader&); + + static octave_dynamic_loader *instance; + + static void cleanup_instance (void) { delete instance; instance = 0; } + + static bool instance_ok (void); + + octave_function * + do_load_oct (const std::string& fcn_name, + const std::string& file_name = std::string (), + bool relative = false); + + octave_function * + do_load_mex (const std::string& fcn_name, + const std::string& file_name = std::string (), + bool relative = false); + + bool do_remove_oct (const std::string& fcn_name, octave_shlib& shl); + + bool do_remove_mex (const std::string& fcn_name, octave_shlib& shl); + + static bool doing_load; + +protected: + + static std::string name_mangler (const std::string& name); + + static std::string name_uscore_mangler (const std::string& name); + + static std::string mex_mangler (const std::string& name); + + static std::string mex_uscore_mangler (const std::string& name); + + static std::string mex_f77_mangler (const std::string& name); +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/gl-render.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/gl-render.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,3039 @@ +/* + +Copyright (C) 2008-2012 Michael Goffioul + +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 +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined (HAVE_OPENGL) + +#include + +#include +#include "oct-locbuf.h" +#include "oct-refcount.h" +#include "gl-render.h" +#include "txt-eng.h" +#include "txt-eng-ft.h" + +#define LIGHT_MODE GL_FRONT_AND_BACK + +// Win32 API requires the CALLBACK attributes for +// GLU callback functions. Define it to empty on +// other platforms. +#ifndef CALLBACK +#define CALLBACK +#endif + +static octave_idx_type +xmin (octave_idx_type x, octave_idx_type y) +{ + return x < y ? x : y; +} + +class +opengl_texture +{ +protected: + class texture_rep + { + public: + texture_rep (void) + : id (), w (), h (), tw (), th (), tx (), ty (), + valid (false), count (1) + { } + + texture_rep (GLuint id_arg, int w_arg, int h_arg, int tw_arg, int th_arg) + : id (id_arg), w (w_arg), h (h_arg), tw (tw_arg), th (th_arg), + tx (double(w)/tw), ty (double(h)/th), valid (true), + count (1) { } + + ~texture_rep (void) + { + if (valid) + glDeleteTextures (1, &id); + } + + void bind (int mode) const + { if (valid) glBindTexture (mode, id); } + + void tex_coord (double q, double r) const + { if (valid) glTexCoord2d (q*tx, r*ty); } + + GLuint id; + int w, h; + int tw, th; + double tx, ty; + bool valid; + octave_refcount count; + }; + + texture_rep *rep; + +private: + opengl_texture (texture_rep *_rep) : rep (_rep) { } + +public: + opengl_texture (void) : rep (new texture_rep ()) { } + + opengl_texture (const opengl_texture& tx) + : rep (tx.rep) + { + rep->count++; + } + + ~opengl_texture (void) + { + if (--rep->count == 0) + delete rep; + } + + opengl_texture& operator = (const opengl_texture& tx) + { + if (--rep->count == 0) + delete rep; + + rep = tx.rep; + rep->count++; + + return *this; + } + + static opengl_texture create (const octave_value& data); + + void bind (int mode = GL_TEXTURE_2D) const + { rep->bind (mode); } + + void tex_coord (double q, double r) const + { rep->tex_coord (q, r); } + + bool is_valid (void) const + { return rep->valid; } +}; + +static int +next_power_of_2 (int n) +{ + int m = 1; + + while (m < n && m < INT_MAX) + m <<= 1; + + return m; +} + +opengl_texture +opengl_texture::create (const octave_value& data) +{ + opengl_texture retval; + + dim_vector dv (data.dims ()); + + // Expect RGB data + if (dv.length () == 3 && dv(2) == 3) + { + // FIXME -- dim_vectors hold octave_idx_type values. Should we + // check for dimensions larger than intmax? + int h = dv(0), w = dv(1), tw, th; + GLuint id; + bool ok = true; + + tw = next_power_of_2 (w); + th = next_power_of_2 (w); + + glGenTextures (1, &id); + glBindTexture (GL_TEXTURE_2D, id); + + if (data.is_double_type ()) + { + const NDArray xdata = data.array_value (); + + OCTAVE_LOCAL_BUFFER (float, a, (3*tw*th)); + + for (int i = 0; i < h; i++) + { + for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3) + { + a[idx] = xdata(i,j,0); + a[idx+1] = xdata(i,j,1); + a[idx+2] = xdata(i,j,2); + } + } + + glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0, + GL_RGB, GL_FLOAT, a); + } + else if (data.is_uint8_type ()) + { + const uint8NDArray xdata = data.uint8_array_value (); + + OCTAVE_LOCAL_BUFFER (octave_uint8, a, (3*tw*th)); + + for (int i = 0; i < h; i++) + { + for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3) + { + a[idx] = xdata(i,j,0); + a[idx+1] = xdata(i,j,1); + a[idx+2] = xdata(i,j,2); + } + } + + glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0, + GL_RGB, GL_UNSIGNED_BYTE, a); + } + else + { + ok = false; + warning ("opengl_texture::create: invalid texture data type (expected double or uint8)"); + } + + if (ok) + { + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + if (glGetError () != GL_NO_ERROR) + warning ("opengl_texture::create: OpenGL error while generating texture data"); + else + retval = opengl_texture (new texture_rep (id, w, h, tw, th)); + } + } + else + warning ("opengl_texture::create: invalid texture data size"); + + return retval; +} + +class +opengl_tesselator +{ +public: +#if defined (HAVE_FRAMEWORK_OPENGL) && defined (HAVE_GLUTESSCALLBACK_THREEDOTS) + typedef GLvoid (CALLBACK *fcn) (...); +#else + typedef void (CALLBACK *fcn) (void); +#endif + +public: + + opengl_tesselator (void) : glu_tess (0), fill () { init (); } + + virtual ~opengl_tesselator (void) + { if (glu_tess) gluDeleteTess (glu_tess); } + + void begin_polygon (bool filled = true) + { + gluTessProperty (glu_tess, GLU_TESS_BOUNDARY_ONLY, + (filled ? GL_FALSE : GL_TRUE)); + fill = filled; + gluTessBeginPolygon (glu_tess, this); + } + + void end_polygon (void) const + { gluTessEndPolygon (glu_tess); } + + void begin_contour (void) const + { gluTessBeginContour (glu_tess); } + + void end_contour (void) const + { gluTessEndContour (glu_tess); } + + void add_vertex (double *loc, void *data) const + { gluTessVertex (glu_tess, loc, data); } + +protected: + virtual void begin (GLenum /*type*/) { } + + virtual void end (void) { } + + virtual void vertex (void */*data*/) { } + + virtual void combine (GLdouble /*c*/[3], void */*data*/[4], + GLfloat /*w*/[4], void **/*out_data*/) { } + + virtual void edge_flag (GLboolean /*flag*/) { } + + virtual void error (GLenum err) + { ::error ("OpenGL tesselation error (%d)", err); } + + virtual void init (void) + { + glu_tess = gluNewTess (); + + gluTessCallback (glu_tess, GLU_TESS_BEGIN_DATA, + reinterpret_cast (tess_begin)); + gluTessCallback (glu_tess, GLU_TESS_END_DATA, + reinterpret_cast (tess_end)); + gluTessCallback (glu_tess, GLU_TESS_VERTEX_DATA, + reinterpret_cast (tess_vertex)); + gluTessCallback (glu_tess, GLU_TESS_COMBINE_DATA, + reinterpret_cast (tess_combine)); + gluTessCallback (glu_tess, GLU_TESS_EDGE_FLAG_DATA, + reinterpret_cast (tess_edge_flag)); + gluTessCallback (glu_tess, GLU_TESS_ERROR_DATA, + reinterpret_cast (tess_error)); + } + + bool is_filled (void) const { return fill; } + +private: + static void CALLBACK tess_begin (GLenum type, void *t) + { reinterpret_cast (t)->begin (type); } + + static void CALLBACK tess_end (void *t) + { reinterpret_cast (t)->end (); } + + static void CALLBACK tess_vertex (void *v, void *t) + { reinterpret_cast (t)->vertex (v); } + + static void CALLBACK tess_combine (GLdouble c[3], void *v[4], GLfloat w[4], + void **out, void *t) + { reinterpret_cast (t)->combine (c, v, w, out); } + + static void CALLBACK tess_edge_flag (GLboolean flag, void *t) + { reinterpret_cast (t)->edge_flag (flag); } + + static void CALLBACK tess_error (GLenum err, void *t) + { reinterpret_cast (t)->error (err); } + +private: + + // No copying! + + opengl_tesselator (const opengl_tesselator&); + + opengl_tesselator operator = (const opengl_tesselator&); + + GLUtesselator *glu_tess; + bool fill; +}; + +class +vertex_data +{ +public: + class vertex_data_rep + { + public: + Matrix coords; + Matrix color; + Matrix normal; + double alpha; + float ambient; + float diffuse; + float specular; + float specular_exp; + + // reference counter + octave_refcount count; + + vertex_data_rep (void) + : coords (), color (), normal (), alpha (), + ambient (), diffuse (), specular (), specular_exp (),count (1) { } + + vertex_data_rep (const Matrix& c, const Matrix& col, const Matrix& n, + double a, float as, float ds, float ss, float se) + : coords (c), color (col), normal (n), alpha (a), + ambient (as), diffuse (ds), specular (ss), specular_exp (se), + count (1) { } + }; + +private: + vertex_data_rep *rep; + + vertex_data_rep *nil_rep (void) const + { + static vertex_data_rep *nr = new vertex_data_rep (); + + return nr; + } + +public: + vertex_data (void) : rep (nil_rep ()) + { rep->count++; } + + vertex_data (const vertex_data& v) : rep (v.rep) + { rep->count++; } + + vertex_data (const Matrix& c, const Matrix& col, const Matrix& n, + double a, float as, float ds, float ss, float se) + : rep (new vertex_data_rep (c, col, n, a, as, ds, ss, se)) + { } + + vertex_data (vertex_data_rep *new_rep) + : rep (new_rep) { } + + ~vertex_data (void) + { + if (--rep->count == 0) + delete rep; + } + + vertex_data& operator = (const vertex_data& v) + { + if (--rep->count == 0) + delete rep; + + rep = v.rep; + rep->count++; + + return *this; + } + + vertex_data_rep *get_rep (void) const { return rep; } +}; + +class +opengl_renderer::patch_tesselator : public opengl_tesselator +{ +public: + patch_tesselator (opengl_renderer *r, int cmode, int lmode, int idx = 0) + : opengl_tesselator (), renderer (r), + color_mode (cmode), light_mode (lmode), index (idx), + first (true), tmp_vdata () + { } + +protected: + void begin (GLenum type) + { + //printf ("patch_tesselator::begin (%d)\n", type); + first = true; + + if (color_mode == 2 || light_mode == 2) + glShadeModel (GL_SMOOTH); + else + glShadeModel (GL_FLAT); + + if (is_filled ()) + renderer->set_polygon_offset (true, 1+index); + + glBegin (type); + } + + void end (void) + { + //printf ("patch_tesselator::end\n"); + glEnd (); + renderer->set_polygon_offset (false); + } + + void vertex (void *data) + { + vertex_data::vertex_data_rep *v + = reinterpret_cast (data); + //printf ("patch_tesselator::vertex (%g, %g, %g)\n", v->coords(0), v->coords(1), v->coords(2)); + + // FIXME: why did I need to keep the first vertex of the face + // in JHandles? I think it's related to the fact that the + // tessellation process might re-order the vertices, such that + // the first one you get here might not be the first one of the face; + // but I can't figure out the actual reason. + if (color_mode > 0 && (first || color_mode == 2)) + { + Matrix col = v->color; + + if (col.numel () == 3) + { + glColor3dv (col.data ()); + if (light_mode > 0) + { + float buf[4] = { 0, 0, 0, 1 }; + + for (int k = 0; k < 3; k++) + buf[k] = (v->ambient * col(k)); + glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf); + + for (int k = 0; k < 3; k++) + buf[k] = (v->diffuse * col(k)); + glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf); + } + } + } + + if (light_mode > 0 && (first || light_mode == 2)) + glNormal3dv (v->normal.data ()); + + glVertex3dv (v->coords.data ()); + + first = false; + } + + void combine (GLdouble xyz[3], void *data[4], GLfloat w[4], + void **out_data) + { + //printf ("patch_tesselator::combine\n"); + + vertex_data::vertex_data_rep *v[4]; + int vmax = 4; + + for (int i = 0; i < 4; i++) + { + v[i] = reinterpret_cast (data[i]); + + if (vmax == 4 && ! v[i]) + vmax = i; + } + + Matrix vv (1, 3, 0.0); + Matrix cc; + Matrix nn (1, 3, 0.0); + double aa = 0.0; + + vv(0) = xyz[0]; + vv(1) = xyz[1]; + vv(2) = xyz[2]; + + if (v[0]->color.numel ()) + { + cc.resize (1, 3, 0.0); + for (int ic = 0; ic < 3; ic++) + for (int iv = 0; iv < vmax; iv++) + cc(ic) += (w[iv] * v[iv]->color (ic)); + } + + if (v[0]->normal.numel () > 0) + { + for (int in = 0; in < 3; in++) + for (int iv = 0; iv < vmax; iv++) + nn(in) += (w[iv] * v[iv]->normal (in)); + } + + for (int iv = 0; iv < vmax; iv++) + aa += (w[iv] * v[iv]->alpha); + + vertex_data new_v (vv, cc, nn, aa, v[0]->ambient, v[0]->diffuse, + v[0]->specular, v[0]->specular_exp); + tmp_vdata.push_back (new_v); + + *out_data = new_v.get_rep (); + } + +private: + + // No copying! + + patch_tesselator (const patch_tesselator&); + + patch_tesselator& operator = (const patch_tesselator&); + + opengl_renderer *renderer; + int color_mode; // 0: uni, 1: flat, 2: interp + int light_mode; // 0: none, 1: flat, 2: gouraud + int index; + bool first; + std::list tmp_vdata; +}; + +void +opengl_renderer::draw (const graphics_object& go, bool toplevel) +{ + if (! go.valid_object ()) + return; + + const base_properties& props = go.get_properties (); + + if (! toolkit) + toolkit = props.get_toolkit (); + + if (go.isa ("figure")) + draw_figure (dynamic_cast (props)); + else if (go.isa ("axes")) + draw_axes (dynamic_cast (props)); + else if (go.isa ("line")) + draw_line (dynamic_cast (props)); + else if (go.isa ("surface")) + draw_surface (dynamic_cast (props)); + else if (go.isa ("patch")) + draw_patch (dynamic_cast (props)); + else if (go.isa ("hggroup")) + draw_hggroup (dynamic_cast (props)); + else if (go.isa ("text")) + draw_text (dynamic_cast (props)); + else if (go.isa ("image")) + draw_image (dynamic_cast (props)); + else if (go.isa ("uimenu") || go.isa ("uicontrol") + || go.isa ("uicontextmenu") || go.isa ("uitoolbar") + || go.isa ("uipushtool") || go.isa ("uitoggletool")) + /* SKIP */; + else if (go.isa ("uipanel")) + { + if (toplevel) + draw_uipanel (dynamic_cast (props), go); + } + else + { + warning ("opengl_renderer: cannot render object of type `%s'", + props.graphics_object_name ().c_str ()); + } +} + +void +opengl_renderer::draw_figure (const figure::properties& props) +{ + // Initialize OpenGL context + + init_gl_context (props.is___enhanced__ (), props.get_color_rgb ()); + + // Draw children + + draw (props.get_all_children (), false); +} + +void +opengl_renderer::draw_uipanel (const uipanel::properties& props, + const graphics_object& go) +{ + graphics_object fig = go.get_ancestor ("figure"); + const figure::properties& figProps = + dynamic_cast (fig.get_properties ()); + + // Initialize OpenGL context + + init_gl_context (figProps.is___enhanced__ (), + props.get_backgroundcolor_rgb ()); + + // Draw children + + draw (props.get_all_children (), false); +} + +void +opengl_renderer::init_gl_context (bool enhanced, const Matrix& c) +{ + // Initialize OpenGL context + + glEnable (GL_DEPTH_TEST); + glDepthFunc (GL_LEQUAL); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glAlphaFunc (GL_GREATER, 0.0f); + glEnable (GL_NORMALIZE); + + if (enhanced) + { + glEnable (GL_BLEND); + glEnable (GL_LINE_SMOOTH); + } + else + { + glDisable (GL_BLEND); + glDisable (GL_LINE_SMOOTH); + } + + // Clear background + + if (c.length () >= 3) + { + glClearColor (c(0), c(1), c(2), 1); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } +} + +void +opengl_renderer::render_grid (const std::string& gridstyle, + const Matrix& ticks, double lim1, double lim2, + double p1, double p1N, double p2, double p2N, + int xyz, bool is_3D) +{ + set_linestyle (gridstyle, true); + glBegin (GL_LINES); + for (int i = 0; i < ticks.numel (); i++) + { + double val = ticks(i); + if (lim1 <= val && val <= lim2) + { + if (xyz == 0) // X + { + glVertex3d (val, p1N, p2); + glVertex3d (val, p1, p2); + if (is_3D) + { + glVertex3d (val, p1, p2N); + glVertex3d (val, p1, p2); + } + } + else if (xyz == 1) // Y + { + glVertex3d (p1N, val, p2); + glVertex3d (p1, val, p2); + if (is_3D) + { + glVertex3d (p1, val, p2N); + glVertex3d (p1, val, p2); + } + } + else if (xyz == 2) // Z + { + glVertex3d (p1N, p2, val); + glVertex3d (p1, p2, val); + glVertex3d (p1, p2N, val); + glVertex3d (p1, p2, val); + } + } + } + glEnd (); + set_linestyle ("-", true); +} + +void +opengl_renderer::render_tickmarks (const Matrix& ticks, + double lim1, double lim2, + double p1, double p1N, + double p2, double p2N, + double dx, double dy, double dz, + int xyz, bool mirror) +{ + glBegin (GL_LINES); + + for (int i = 0; i < ticks.numel (); i++) + { + double val = ticks(i); + + if (lim1 <= val && val <= lim2) + { + if (xyz == 0) // X + { + glVertex3d (val, p1, p2); + glVertex3d (val, p1+dy, p2+dz); + if (mirror) + { + glVertex3d (val, p1N, p2N); + glVertex3d (val, p1N-dy, p2N-dz); + } + } + else if (xyz == 1) // Y + { + glVertex3d (p1, val, p2); + glVertex3d (p1+dx, val, p2+dz); + if (mirror) + { + glVertex3d (p1N, val, p2N); + glVertex3d (p1N-dx, val, p2N-dz); + } + } + else if (xyz == 2) // Z + { + glVertex3d (p1, p2, val); + glVertex3d (p1+dx, p2+dy, val); + if (mirror) + { + glVertex3d (p1N, p2N, val); + glVertex3d (p1N-dx, p2N-dy, val); + } + } + } + } + + glEnd (); +} + +void +opengl_renderer::render_ticktexts (const Matrix& ticks, + const string_vector& ticklabels, + double lim1, double lim2, + double p1, double p2, + int xyz, int ha, int va, + int& wmax, int& hmax) +{ + int n = std::min (ticklabels.numel (), ticks.numel ()); + + for (int i = 0; i < n; i++) + { + double val = ticks(i); + + if (lim1 <= val && val <= lim2) + { + Matrix b; + // FIXME: as tick text is transparent, shouldn't be + // drawn after axes object, for correct rendering? + if (xyz == 0) // X + { + b = render_text (ticklabels(i), val, p1, p2, ha, va); + } + else if (xyz == 1) // Y + { + b = render_text (ticklabels(i), p1, val, p2, ha, va); + } + else if (xyz == 2) // Z + { + b = render_text (ticklabels(i), p1, p2, val, ha, va); + } + + wmax = std::max (wmax, static_cast (b(2))); + hmax = std::max (hmax, static_cast (b(3))); + } + } +} + +void +opengl_renderer::setup_opengl_transformation (const axes::properties& props) +{ + // setup OpenGL transformation + + Matrix x_zlim = props.get_transform_zlim (); + + xZ1 = x_zlim(0)-(x_zlim(1)-x_zlim(0))/2; + xZ2 = x_zlim(1)+(x_zlim(1)-x_zlim(0))/2; + + Matrix x_mat1 = props.get_opengl_matrix_1 (); + Matrix x_mat2 = props.get_opengl_matrix_2 (); + +#if defined (HAVE_FRAMEWORK_OPENGL) + GLint vw[4]; +#else + int vw[4]; +#endif + + glGetIntegerv (GL_VIEWPORT, vw); + + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + glScaled (1, 1, -1); + glMultMatrixd (x_mat1.data ()); + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2); + glMultMatrixd (x_mat2.data ()); + glMatrixMode (GL_MODELVIEW); + + glClear (GL_DEPTH_BUFFER_BIT); + + glDisable (GL_LINE_SMOOTH); + + // store axes transformation data + + xform = props.get_transform (); +} + +void +opengl_renderer::draw_axes_planes (const axes::properties& props) +{ + double xPlane = props.get_xPlane (); + double yPlane = props.get_yPlane (); + double zPlane = props.get_zPlane (); + double xPlaneN = props.get_xPlaneN (); + double yPlaneN = props.get_yPlaneN (); + double zPlaneN = props.get_zPlaneN (); + + // Axes planes + Matrix axe_color = props.get_color_rgb (); + if (axe_color.numel () > 0 && props.is_visible ()) + { + set_color (axe_color); + set_polygon_offset (true, 2.5); + + glBegin (GL_QUADS); + + // X plane + glVertex3d (xPlane, yPlaneN, zPlaneN); + glVertex3d (xPlane, yPlane, zPlaneN); + glVertex3d (xPlane, yPlane, zPlane); + glVertex3d (xPlane, yPlaneN, zPlane); + + // Y plane + glVertex3d (xPlaneN, yPlane, zPlaneN); + glVertex3d (xPlane, yPlane, zPlaneN); + glVertex3d (xPlane, yPlane, zPlane); + glVertex3d (xPlaneN, yPlane, zPlane); + + // Z plane + glVertex3d (xPlaneN, yPlaneN, zPlane); + glVertex3d (xPlane, yPlaneN, zPlane); + glVertex3d (xPlane, yPlane, zPlane); + glVertex3d (xPlaneN, yPlane, zPlane); + + glEnd (); + + set_polygon_offset (false); + } +} + +void +opengl_renderer::draw_axes_boxes (const axes::properties& props) +{ + bool xySym = props.get_xySym (); + double xPlane = props.get_xPlane (); + double yPlane = props.get_yPlane (); + double zPlane = props.get_zPlane (); + double xPlaneN = props.get_xPlaneN (); + double yPlaneN = props.get_yPlaneN (); + double zPlaneN = props.get_zPlaneN (); + double xpTick = props.get_xpTick (); + double ypTick = props.get_ypTick (); + double zpTick = props.get_zpTick (); + double xpTickN = props.get_xpTickN (); + double ypTickN = props.get_ypTickN (); + double zpTickN = props.get_zpTickN (); + + bool plotyy = (props.has_property ("__plotyy_axes__")); + + // Axes box + + set_linestyle ("-", true); + set_linewidth (props.get_linewidth ()); + + if (props.is_visible ()) + { + glBegin (GL_LINES); + + // X box + set_color (props.get_xcolor_rgb ()); + glVertex3d (xPlaneN, ypTick, zpTick); + glVertex3d (xPlane, ypTick, zpTick); + + if (props.is_box ()) + { + glVertex3d (xPlaneN, ypTickN, zpTick); + glVertex3d (xPlane, ypTickN, zpTick); + glVertex3d (xPlaneN, ypTickN, zpTickN); + glVertex3d (xPlane, ypTickN, zpTickN); + glVertex3d (xPlaneN, ypTick, zpTickN); + glVertex3d (xPlane, ypTick, zpTickN); + } + + // Y box + set_color (props.get_ycolor_rgb ()); + glVertex3d (xpTick, yPlaneN, zpTick); + glVertex3d (xpTick, yPlane, zpTick); + + if (props.is_box () && ! plotyy) + { + glVertex3d (xpTickN, yPlaneN, zpTick); + glVertex3d (xpTickN, yPlane, zpTick); + glVertex3d (xpTickN, yPlaneN, zpTickN); + glVertex3d (xpTickN, yPlane, zpTickN); + glVertex3d (xpTick, yPlaneN, zpTickN); + glVertex3d (xpTick, yPlane, zpTickN); + } + + // Z box + set_color (props.get_zcolor_rgb ()); + + if (xySym) + { + glVertex3d (xPlaneN, yPlane, zPlaneN); + glVertex3d (xPlaneN, yPlane, zPlane); + } + else + { + glVertex3d (xPlane, yPlaneN, zPlaneN); + glVertex3d (xPlane, yPlaneN, zPlane); + } + + if (props.is_box ()) + { + glVertex3d (xPlane, yPlane, zPlaneN); + glVertex3d (xPlane, yPlane, zPlane); + + if (xySym) + { + glVertex3d (xPlane, yPlaneN, zPlaneN); + glVertex3d (xPlane, yPlaneN, zPlane); + } + else + { + glVertex3d (xPlaneN, yPlane, zPlaneN); + glVertex3d (xPlaneN, yPlane, zPlane); + } + + glVertex3d (xPlaneN, yPlaneN, zPlaneN); + glVertex3d (xPlaneN, yPlaneN, zPlane); + } + + glEnd (); + } +} + +void +opengl_renderer::draw_axes_x_grid (const axes::properties& props) +{ + int xstate = props.get_xstate (); + int zstate = props.get_zstate (); + bool x2Dtop = props.get_x2Dtop (); + bool layer2Dtop = props.get_layer2Dtop (); + bool xyzSym = props.get_xyzSym (); + bool nearhoriz = props.get_nearhoriz (); + double xticklen = props.get_xticklen (); + double xtickoffset = props.get_xtickoffset (); + double fy = props.get_fy (); + double fz = props.get_fz (); + double x_min = props.get_x_min (); + double x_max = props.get_x_max (); + double yPlane = props.get_yPlane (); + double yPlaneN = props.get_yPlaneN (); + double ypTick = props.get_ypTick (); + double ypTickN = props.get_ypTickN (); + double zPlane = props.get_zPlane (); + double zPlaneN = props.get_zPlaneN (); + double zpTick = props.get_zpTick (); + double zpTickN = props.get_zpTickN (); + + // X grid + + if (props.is_visible () && xstate != AXE_DEPTH_DIR) + { + std::string gridstyle = props.get_gridlinestyle (); + std::string minorgridstyle = props.get_minorgridlinestyle (); + bool do_xgrid = (props.is_xgrid () && (gridstyle != "none")); + bool do_xminorgrid = (props.is_xminorgrid () && (minorgridstyle != "none")); + bool do_xminortick = props.is_xminortick (); + Matrix xticks = xform.xscale (props.get_xtick ().matrix_value ()); + Matrix xmticks = xform.xscale (props.get_xmtick ().matrix_value ()); + string_vector xticklabels = props.get_xticklabel ().all_strings (); + int wmax = 0, hmax = 0; + bool tick_along_z = nearhoriz || xisinf (fy); + bool mirror = props.is_box () && xstate != AXE_ANY_DIR; + + set_color (props.get_xcolor_rgb ()); + + // grid lines + if (do_xgrid) + render_grid (gridstyle, xticks, x_min, x_max, + yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane, + zPlaneN, 0, (zstate != AXE_DEPTH_DIR)); + + // tick marks + if (tick_along_z) + { + render_tickmarks (xticks, x_min, x_max, ypTick, ypTick, + zpTick, zpTickN, 0., 0., + signum (zpTick-zpTickN)*fz*xticklen, + 0, mirror); + } + else + { + render_tickmarks (xticks, x_min, x_max, ypTick, ypTickN, + zpTick, zpTick, 0., + signum (ypTick-ypTickN)*fy*xticklen, + 0., 0, mirror); + } + + // tick texts + if (xticklabels.numel () > 0) + { + int halign = (xstate == AXE_HORZ_DIR ? 1 : (xyzSym ? 0 : 2)); + int valign = (xstate == AXE_VERT_DIR ? 1 : (x2Dtop ? 0 : 2)); + + if (tick_along_z) + render_ticktexts (xticks, xticklabels, x_min, x_max, ypTick, + zpTick+signum (zpTick-zpTickN)*fz*xtickoffset, + 0, halign, valign, wmax, hmax); + else + render_ticktexts (xticks, xticklabels, x_min, x_max, + ypTick+signum (ypTick-ypTickN)*fy*xtickoffset, + zpTick, 0, halign, valign, wmax, hmax); + } + + // minor grid lines + if (do_xminorgrid) + render_grid (minorgridstyle, xmticks, x_min, x_max, + yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane, + zPlaneN, 0, (zstate != AXE_DEPTH_DIR)); + + // minor tick marks + if (do_xminortick) + { + if (tick_along_z) + render_tickmarks (xmticks, x_min, x_max, ypTick, ypTick, + zpTick, zpTickN, 0., 0., + signum (zpTick-zpTickN)*fz*xticklen/2, + 0, mirror); + else + render_tickmarks (xmticks, x_min, x_max, ypTick, ypTickN, + zpTick, zpTick, 0., + signum (ypTick-ypTickN)*fy*xticklen/2, + 0., 0, mirror); + } + + gh_manager::get_object (props.get_xlabel ()).set ("visible", "on"); + } + else + gh_manager::get_object (props.get_xlabel ()).set ("visible", "off"); +} + +void +opengl_renderer::draw_axes_y_grid (const axes::properties& props) +{ + int ystate = props.get_ystate (); + int zstate = props.get_zstate (); + bool y2Dright = props.get_y2Dright (); + bool layer2Dtop = props.get_layer2Dtop (); + bool xyzSym = props.get_xyzSym (); + bool nearhoriz = props.get_nearhoriz (); + double yticklen = props.get_yticklen (); + double ytickoffset = props.get_ytickoffset (); + double fx = props.get_fx (); + double fz = props.get_fz (); + double xPlane = props.get_xPlane (); + double xPlaneN = props.get_xPlaneN (); + double xpTick = props.get_xpTick (); + double xpTickN = props.get_xpTickN (); + double y_min = props.get_y_min (); + double y_max = props.get_y_max (); + double zPlane = props.get_zPlane (); + double zPlaneN = props.get_zPlaneN (); + double zpTick = props.get_zpTick (); + double zpTickN = props.get_zpTickN (); + + // Y grid + + if (ystate != AXE_DEPTH_DIR && props.is_visible ()) + { + std::string gridstyle = props.get_gridlinestyle (); + std::string minorgridstyle = props.get_minorgridlinestyle (); + bool do_ygrid = (props.is_ygrid () && (gridstyle != "none")); + bool do_yminorgrid = (props.is_yminorgrid () && (minorgridstyle != "none")); + bool do_yminortick = props.is_yminortick (); + Matrix yticks = xform.yscale (props.get_ytick ().matrix_value ()); + Matrix ymticks = xform.yscale (props.get_ymtick ().matrix_value ()); + string_vector yticklabels = props.get_yticklabel ().all_strings (); + int wmax = 0, hmax = 0; + bool tick_along_z = nearhoriz || xisinf (fx); + bool mirror = props.is_box () && ystate != AXE_ANY_DIR + && (! props.has_property ("__plotyy_axes__")); + + set_color (props.get_ycolor_rgb ()); + + // grid lines + if (do_ygrid) + render_grid (gridstyle, yticks, y_min, y_max, + xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane, + zPlaneN, 1, (zstate != AXE_DEPTH_DIR)); + + // tick marks + if (tick_along_z) + render_tickmarks (yticks, y_min, y_max, xpTick, xpTick, + zpTick, zpTickN, 0., 0., + signum (zpTick-zpTickN)*fz*yticklen, + 1, mirror); + else + render_tickmarks (yticks, y_min, y_max, xpTick, xpTickN, + zpTick, zpTick, + signum (xPlaneN-xPlane)*fx*yticklen, + 0., 0., 1, mirror); + + // tick texts + if (yticklabels.numel () > 0) + { + int halign = (ystate == AXE_HORZ_DIR + ? 1 : (!xyzSym || y2Dright ? 0 : 2)); + int valign = (ystate == AXE_VERT_DIR ? 1 : 2); + + if (tick_along_z) + render_ticktexts (yticks, yticklabels, y_min, y_max, xpTick, + zpTick+signum (zpTick-zpTickN)*fz*ytickoffset, + 1, halign, valign, wmax, hmax); + else + render_ticktexts (yticks, yticklabels, y_min, y_max, + xpTick+signum (xpTick-xpTickN)*fx*ytickoffset, + zpTick, 1, halign, valign, wmax, hmax); + } + + // minor grid lines + if (do_yminorgrid) + render_grid (minorgridstyle, ymticks, y_min, y_max, + xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane, + zPlaneN, 1, (zstate != AXE_DEPTH_DIR)); + + // minor tick marks + if (do_yminortick) + { + if (tick_along_z) + render_tickmarks (ymticks, y_min, y_max, xpTick, xpTick, + zpTick, zpTickN, 0., 0., + signum (zpTick-zpTickN)*fz*yticklen/2, + 1, mirror); + else + render_tickmarks (ymticks, y_min, y_max, xpTick, xpTickN, + zpTick, zpTick, + signum (xpTick-xpTickN)*fx*yticklen/2, + 0., 0., 1, mirror); + } + + gh_manager::get_object (props.get_ylabel ()).set ("visible", "on"); + } + else + gh_manager::get_object (props.get_ylabel ()).set ("visible", "off"); +} + +void +opengl_renderer::draw_axes_z_grid (const axes::properties& props) +{ + int zstate = props.get_zstate (); + bool xySym = props.get_xySym (); + bool zSign = props.get_zSign (); + double zticklen = props.get_zticklen (); + double ztickoffset = props.get_ztickoffset (); + double fx = props.get_fx (); + double fy = props.get_fy (); + double xPlane = props.get_xPlane (); + double xPlaneN = props.get_xPlaneN (); + double yPlane = props.get_yPlane (); + double yPlaneN = props.get_yPlaneN (); + double z_min = props.get_z_min (); + double z_max = props.get_z_max (); + + // Z Grid + + if (zstate != AXE_DEPTH_DIR && props.is_visible ()) + { + std::string gridstyle = props.get_gridlinestyle (); + std::string minorgridstyle = props.get_minorgridlinestyle (); + bool do_zgrid = (props.is_zgrid () && (gridstyle != "none")); + bool do_zminorgrid = (props.is_zminorgrid () && (minorgridstyle != "none")); + bool do_zminortick = props.is_zminortick (); + Matrix zticks = xform.zscale (props.get_ztick ().matrix_value ()); + Matrix zmticks = xform.zscale (props.get_zmtick ().matrix_value ()); + string_vector zticklabels = props.get_zticklabel ().all_strings (); + int wmax = 0, hmax = 0; + bool mirror = props.is_box () && zstate != AXE_ANY_DIR; + + set_color (props.get_zcolor_rgb ()); + + // grid lines + if (do_zgrid) + render_grid (gridstyle, zticks, z_min, z_max, + xPlane, xPlaneN, yPlane, yPlaneN, 2, true); + + // tick marks + if (xySym) + { + if (xisinf (fy)) + render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane, + yPlane, yPlane, + signum (xPlaneN-xPlane)*fx*zticklen, + 0., 0., 2, mirror); + else + render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlaneN, + yPlane, yPlane, 0., + signum (yPlane-yPlaneN)*fy*zticklen, + 0., 2, false); + } + else + { + if (xisinf (fx)) + render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane, + yPlaneN, yPlane, 0., + signum (yPlaneN-yPlane)*fy*zticklen, + 0., 2, mirror); + else + render_tickmarks (zticks, z_min, z_max, xPlane, xPlane, + yPlaneN, yPlane, + signum (xPlane-xPlaneN)*fx*zticklen, + 0., 0., 2, false); + } + + // FIXME: tick texts + if (zticklabels.numel () > 0) + { + int halign = 2; + int valign = (zstate == AXE_VERT_DIR ? 1 : (zSign ? 3 : 2)); + + if (xySym) + { + if (xisinf (fy)) + render_ticktexts (zticks, zticklabels, z_min, z_max, + xPlaneN+signum (xPlaneN-xPlane)*fx*ztickoffset, + yPlane, 2, halign, valign, wmax, hmax); + else + render_ticktexts (zticks, zticklabels, z_min, z_max, xPlaneN, + yPlane+signum (yPlane-yPlaneN)*fy*ztickoffset, + 2, halign, valign, wmax, hmax); + } + else + { + if (xisinf (fx)) + render_ticktexts (zticks, zticklabels, z_min, z_max, xPlane, + yPlaneN+signum (yPlaneN-yPlane)*fy*ztickoffset, + 2, halign, valign, wmax, hmax); + else + render_ticktexts (zticks, zticklabels, z_min, z_max, + xPlane+signum (xPlane-xPlaneN)*fx*ztickoffset, + yPlaneN, 2, halign, valign, wmax, hmax); + } + } + + // minor grid lines + if (do_zminorgrid) + render_grid (minorgridstyle, zmticks, z_min, z_max, + xPlane, xPlaneN, yPlane, yPlaneN, 2, true); + + // minor tick marks + if (do_zminortick) + { + if (xySym) + { + if (xisinf (fy)) + render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlane, + yPlane, yPlane, + signum (xPlaneN-xPlane)*fx*zticklen/2, + 0., 0., 2, mirror); + else + render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlaneN, + yPlane, yPlane, 0., + signum (yPlane-yPlaneN)*fy*zticklen/2, + 0., 2, false); + } + else + { + if (xisinf (fx)) + render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane, + yPlaneN, yPlane, 0., + signum (yPlaneN-yPlane)*fy*zticklen/2, + 0., 2, mirror); + else + render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane, + yPlaneN, yPlaneN, + signum (xPlane-xPlaneN)*fx*zticklen/2, + 0., 0., 2, false); + } + } + + gh_manager::get_object (props.get_zlabel ()).set ("visible", "on"); + } + else + gh_manager::get_object (props.get_zlabel ()).set ("visible", "off"); +} + +void +opengl_renderer::draw_axes_children (const axes::properties& props) +{ + // Children + + GLboolean antialias; + glGetBooleanv (GL_LINE_SMOOTH, &antialias); + + if (antialias == GL_TRUE) + glEnable (GL_LINE_SMOOTH); + + Matrix children = props.get_all_children (); + std::list obj_list; + std::list::iterator it; + + // 1st pass: draw light objects + + // Start with the last element of the array of child objects to + // display them in the oder they were added to the array. + + for (octave_idx_type i = children.numel () - 1; i >= 0; i--) + { + graphics_object go = gh_manager::get_object (children (i)); + + if (go.get_properties ().is_visible ()) + { + if (go.isa ("light")) + draw (go); + else + obj_list.push_back (go); + } + } + + // 2nd pass: draw other objects (with units set to "data") + + it = obj_list.begin (); + while (it != obj_list.end ()) + { + graphics_object go = (*it); + + // FIXME: check whether object has "units" property and it is set + // to "data" + if (! go.isa ("text") || go.get ("units").string_value () == "data") + { + set_clipping (go.get_properties ().is_clipping ()); + draw (go); + + it = obj_list.erase (it); + } + else + it++; + } + + // 3rd pass: draw remaining objects + + glDisable (GL_DEPTH_TEST); + + for (it = obj_list.begin (); it != obj_list.end (); it++) + { + graphics_object go = (*it); + + set_clipping (go.get_properties ().is_clipping ()); + draw (go); + } + + glEnable (GL_DEPTH_TEST); + + set_clipping (false); + + // FIXME: finalize rendering (transparency processing) + // FIXME: draw zoom box, if needed +} + +void +opengl_renderer::draw_axes (const axes::properties& props) +{ + double x_min = props.get_x_min (); + double x_max = props.get_x_max (); + double y_min = props.get_y_min (); + double y_max = props.get_y_max (); + double z_min = props.get_z_min (); + double z_max = props.get_z_max (); + + setup_opengl_transformation (props); + + // draw axes object + + draw_axes_planes (props); + draw_axes_boxes (props); + + set_font (props); + + draw_axes_x_grid (props); + draw_axes_y_grid (props); + draw_axes_z_grid (props); + + set_linestyle ("-"); + + set_clipbox (x_min, x_max, y_min, y_max, z_min, z_max); + + draw_axes_children (props); +} + +void +opengl_renderer::draw_line (const line::properties& props) +{ + Matrix x = xform.xscale (props.get_xdata ().matrix_value ()); + Matrix y = xform.yscale (props.get_ydata ().matrix_value ()); + Matrix z = xform.zscale (props.get_zdata ().matrix_value ()); + + bool has_z = (z.numel () > 0); + int n = static_cast (::xmin (::xmin (x.numel (), y.numel ()), (has_z ? z.numel () : INT_MAX))); + octave_uint8 clip_mask = (props.is_clipping () ? 0x7F : 0x40), clip_ok (0x40); + + std::vector clip (n); + + if (has_z) + for (int i = 0; i < n; i++) + clip[i] = (clip_code (x(i), y(i), z(i)) & clip_mask); + else + { + double z_mid = (zmin+zmax)/2; + + for (int i = 0; i < n; i++) + clip[i] = (clip_code (x(i), y(i), z_mid) & clip_mask); + } + + if (! props.linestyle_is ("none")) + { + set_color (props.get_color_rgb ()); + set_linestyle (props.get_linestyle (), false); + set_linewidth (props.get_linewidth ()); + + if (has_z) + { + bool flag = false; + + for (int i = 1; i < n; i++) + { + if ((clip[i-1] & clip[i]) == clip_ok) + { + if (! flag) + { + flag = true; + glBegin (GL_LINE_STRIP); + glVertex3d (x(i-1), y(i-1), z(i-1)); + } + glVertex3d (x(i), y(i), z(i)); + } + else if (flag) + { + flag = false; + glEnd (); + } + } + + if (flag) + glEnd (); + } + else + { + bool flag = false; + + for (int i = 1; i < n; i++) + { + if ((clip[i-1] & clip[i]) == clip_ok) + { + if (! flag) + { + flag = true; + glBegin (GL_LINE_STRIP); + glVertex2d (x(i-1), y(i-1)); + } + glVertex2d (x(i), y(i)); + } + else if (flag) + { + flag = false; + glEnd (); + } + } + + if (flag) + glEnd (); + } + + set_linewidth (0.5); + set_linestyle ("-"); + } + + set_clipping (false); + + if (! props.marker_is ("none") && + ! (props.markeredgecolor_is ("none") + && props.markerfacecolor_is ("none"))) + { + Matrix lc, fc; + + if (props.markeredgecolor_is ("auto")) + lc = props.get_color_rgb (); + else if (! props.markeredgecolor_is ("none")) + lc = props.get_markeredgecolor_rgb (); + + if (props.markerfacecolor_is ("auto")) + fc = props.get_color_rgb (); + else if (! props.markerfacecolor_is ("none")) + fc = props.get_markerfacecolor_rgb (); + + init_marker (props.get_marker (), props.get_markersize (), + props.get_linewidth ()); + + for (int i = 0; i < n; i++) + { + if (clip[i] == clip_ok) + draw_marker (x(i), y(i), + has_z ? z(i) : static_cast (i) / n, + lc, fc); + } + + end_marker (); + } + + set_clipping (props.is_clipping ()); +} + +void +opengl_renderer::draw_surface (const surface::properties& props) +{ + const Matrix x = xform.xscale (props.get_xdata ().matrix_value ()); + const Matrix y = xform.yscale (props.get_ydata ().matrix_value ()); + const Matrix z = xform.zscale (props.get_zdata ().matrix_value ()); + + int zr = z.rows (), zc = z.columns (); + + NDArray c; + const NDArray n = props.get_vertexnormals ().array_value (); + + // FIXME: handle transparency + Matrix a; + + if (props.facelighting_is ("phong") || props.edgelighting_is ("phong")) + warning ("opengl_renderer::draw: phong light model not supported"); + + int fc_mode = (props.facecolor_is_rgb () ? 0 : + (props.facecolor_is ("flat") ? 1 : + (props.facecolor_is ("interp") ? 2 : + (props.facecolor_is ("texturemap") ? 3 : -1)))); + int fl_mode = (props.facelighting_is ("none") ? 0 : + (props.facelighting_is ("flat") ? 1 : 2)); + int fa_mode = (props.facealpha_is_double () ? 0 : + (props.facealpha_is ("flat") ? 1 : 2)); + int ec_mode = (props.edgecolor_is_rgb () ? 0 : + (props.edgecolor_is ("flat") ? 1 : + (props.edgecolor_is ("interp") ? 2 : -1))); + int el_mode = (props.edgelighting_is ("none") ? 0 : + (props.edgelighting_is ("flat") ? 1 : 2)); + int ea_mode = (props.edgealpha_is_double () ? 0 : + (props.edgealpha_is ("flat") ? 1 : 2)); + + Matrix fcolor = (fc_mode == 3 ? Matrix (1, 3, 1.0) : props.get_facecolor_rgb ()); + Matrix ecolor = props.get_edgecolor_rgb (); + + float as = props.get_ambientstrength (); + float ds = props.get_diffusestrength (); + float ss = props.get_specularstrength (); + float se = props.get_specularexponent (); + float cb[4] = { 0.0, 0.0, 0.0, 1.0 }; + double d = 1.0; + + opengl_texture tex; + + int i1, i2, j1, j2; + bool x_mat = (x.rows () == z.rows ()); + bool y_mat = (y.columns () == z.columns ()); + + i1 = i2 = j1 = j2 = 0; + + boolMatrix clip (z.dims (), false); + + for (int i = 0; i < zr; i++) + { + if (x_mat) + i1 = i; + + for (int j = 0; j < zc; j++) + { + if (y_mat) + j1 = j; + + clip(i,j) = is_nan_or_inf (x(i1,j), y(i,j1), z(i,j)); + } + } + + if ((fc_mode > 0 && fc_mode < 3) || ec_mode > 0) + c = props.get_color_data ().array_value (); + + if (fa_mode > 0 || ea_mode > 0) + { + // FIXME: implement alphadata conversion + //a = props.get_alpha_data (); + } + + if (fl_mode > 0 || el_mode > 0) + { + float buf[4] = { ss, ss, ss, 1 }; + + glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf); + glMaterialf (LIGHT_MODE, GL_SHININESS, se); + } + + // FIXME: good candidate for caching, transfering pixel + // data to OpenGL is time consuming. + if (fc_mode == 3) + tex = opengl_texture::create (props.get_color_data ()); + + if (! props.facecolor_is ("none")) + { + if (props.get_facealpha_double () == 1) + { + if (fc_mode == 0 || fc_mode == 3) + { + glColor3dv (fcolor.data ()); + if (fl_mode > 0) + { + for (int i = 0; i < 3; i++) + cb[i] = as * fcolor(i); + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int i = 0; i < 3; i++) + cb[i] = ds * fcolor(i); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + + if (fl_mode > 0) + glEnable (GL_LIGHTING); + glShadeModel ((fc_mode == 2 || fl_mode == 2) ? GL_SMOOTH : GL_FLAT); + set_polygon_offset (true, 1); + if (fc_mode == 3) + glEnable (GL_TEXTURE_2D); + + for (int i = 1; i < zc; i++) + { + if (y_mat) + { + i1 = i-1; + i2 = i; + } + + for (int j = 1; j < zr; j++) + { + if (clip(j-1, i-1) || clip (j, i-1) + || clip (j-1, i) || clip (j, i)) + continue; + + if (x_mat) + { + j1 = j-1; + j2 = j; + } + + glBegin (GL_QUADS); + + // Vertex 1 + if (fc_mode == 3) + tex.tex_coord (double (i-1) / (zc-1), double (j-1) / (zr-1)); + else if (fc_mode > 0) + { + // FIXME: is there a smarter way to do this? + for (int k = 0; k < 3; k++) + cb[k] = c(j-1, i-1, k); + glColor3fv (cb); + + if (fl_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] *= as; + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] = ds * c(j-1, i-1, k); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + if (fl_mode > 0) + { + d = sqrt (n(j-1,i-1,0) * n(j-1,i-1,0) + + n(j-1,i-1,1) * n(j-1,i-1,1) + + n(j-1,i-1,2) * n(j-1,i-1,2)); + glNormal3d (n(j-1,i-1,0)/d, n(j-1,i-1,1)/d, n(j-1,i-1,2)/d); + } + glVertex3d (x(j1,i-1), y(j-1,i1), z(j-1,i-1)); + + // Vertex 2 + if (fc_mode == 3) + tex.tex_coord (double (i) / (zc-1), double (j-1) / (zr-1)); + else if (fc_mode == 2) + { + for (int k = 0; k < 3; k++) + cb[k] = c(j-1, i, k); + glColor3fv (cb); + + if (fl_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] *= as; + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] = ds * c(j-1, i, k); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + + if (fl_mode == 2) + { + d = sqrt (n(j-1,i,0) * n(j-1,i,0) + + n(j-1,i,1) * n(j-1,i,1) + + n(j-1,i,2) * n(j-1,i,2)); + glNormal3d (n(j-1,i,0)/d, n(j-1,i,1)/d, n(j-1,i,2)/d); + } + + glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i)); + + // Vertex 3 + if (fc_mode == 3) + tex.tex_coord (double (i) / (zc-1), double (j) / (zr-1)); + else if (fc_mode == 2) + { + for (int k = 0; k < 3; k++) + cb[k] = c(j, i, k); + glColor3fv (cb); + + if (fl_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] *= as; + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] = ds * c(j, i, k); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + if (fl_mode == 2) + { + d = sqrt (n(j,i,0) * n(j,i,0) + + n(j,i,1) * n(j,i,1) + + n(j,i,2) * n(j,i,2)); + glNormal3d (n(j,i,0)/d, n(j,i,1)/d, n(j,i,2)/d); + } + glVertex3d (x(j2,i), y(j,i2), z(j,i)); + + // Vertex 4 + if (fc_mode == 3) + tex.tex_coord (double (i-1) / (zc-1), double (j) / (zr-1)); + else if (fc_mode == 2) + { + for (int k = 0; k < 3; k++) + cb[k] = c(j, i-1, k); + glColor3fv (cb); + + if (fl_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] *= as; + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] = ds * c(j, i-1, k); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + if (fl_mode == 2) + { + d = sqrt (n(j,i-1,0) * n(j,i-1,0) + + n(j,i-1,1) * n(j,i-1,1) + + n(j,i-1,2) * n(j,i-1,2)); + glNormal3d (n(j,i-1,0)/d, n(j,i-1,1)/d, n(j,i-1,2)/d); + } + glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1)); + + glEnd (); + } + } + + set_polygon_offset (false); + if (fc_mode == 3) + glDisable (GL_TEXTURE_2D); + + if (fl_mode > 0) + glDisable (GL_LIGHTING); + } + else + { + // FIXME: implement transparency + } + } + + if (! props.edgecolor_is ("none")) + { + if (props.get_edgealpha_double () == 1) + { + if (ec_mode == 0) + { + glColor3dv (ecolor.data ()); + if (fl_mode > 0) + { + for (int i = 0; i < 3; i++) + cb[i] = as * ecolor(i); + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int i = 0; i < 3; i++) + cb[i] = ds * ecolor(i); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + + if (el_mode > 0) + glEnable (GL_LIGHTING); + glShadeModel ((ec_mode == 2 || el_mode == 2) ? GL_SMOOTH : GL_FLAT); + + set_linestyle (props.get_linestyle (), false); + set_linewidth (props.get_linewidth ()); + + // Mesh along Y-axis + + if (props.meshstyle_is ("both") || props.meshstyle_is ("column")) + { + for (int i = 0; i < zc; i++) + { + if (y_mat) + { + i1 = i-1; + i2 = i; + } + + for (int j = 1; j < zr; j++) + { + if (clip(j-1,i) || clip(j,i)) + continue; + + if (x_mat) + { + j1 = j-1; + j2 = j; + } + + glBegin (GL_LINES); + + // Vertex 1 + if (ec_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] = c(j-1, i, k); + glColor3fv (cb); + + if (fl_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] *= as; + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] = ds * c(j-1, i, k); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + if (el_mode > 0) + { + d = sqrt (n(j-1,i,0) * n(j-1,i,0) + + n(j-1,i,1) * n(j-1,i,1) + + n(j-1,i,2) * n(j-1,i,2)); + glNormal3d (n(j-1,i,0)/d, n(j-1,i,1)/d, n(j-1,i,2)/d); + } + glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i)); + + // Vertex 2 + if (ec_mode == 2) + { + for (int k = 0; k < 3; k++) + cb[k] = c(j, i, k); + glColor3fv (cb); + + if (fl_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] *= as; + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] = ds * c(j, i, k); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + if (el_mode == 2) + { + d = sqrt (n(j,i,0) * n(j,i,0) + + n(j,i,1) * n(j,i,1) + + n(j,i,2) * n(j,i,2)); + glNormal3d (n(j,i,0)/d, n(j,i,1)/d, n(j,i,2)/d); + } + glVertex3d (x(j2,i), y(j,i2), z(j,i)); + + glEnd (); + } + } + } + + // Mesh along X-axis + + if (props.meshstyle_is ("both") || props.meshstyle_is ("row")) + { + for (int j = 0; j < zr; j++) + { + if (x_mat) + { + j1 = j-1; + j2 = j; + } + + for (int i = 1; i < zc; i++) + { + if (clip(j,i-1) || clip(j,i)) + continue; + + if (y_mat) + { + i1 = i-1; + i2 = i; + } + + glBegin (GL_LINES); + + // Vertex 1 + if (ec_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] = c(j, i-1, k); + glColor3fv (cb); + + if (fl_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] *= as; + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] = ds * c(j, i-1, k); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + if (el_mode > 0) + { + d = sqrt (n(j,i-1,0) * n(j,i-1,0) + + n(j,i-1,1) * n(j,i-1,1) + + n(j,i-1,2) * n(j,i-1,2)); + glNormal3d (n(j,i-1,0)/d, n(j,i-1,1)/d, n(j,i-1,2)/d); + } + glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1)); + + // Vertex 2 + if (ec_mode == 2) + { + for (int k = 0; k < 3; k++) + cb[k] = c(j, i, k); + glColor3fv (cb); + + if (fl_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] *= as; + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] = ds * c(j, i, k); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + if (el_mode == 2) + { + d = sqrt (n(j,i,0) * n(j,i,0) + + n(j,i,1) * n(j,i,1) + + n(j,i,2) * n(j,i,2)); + glNormal3d (n(j,i,0)/d, n(j,i,1)/d, n(j,i,2)/d); + } + glVertex3d (x(j2,i), y(j,i2), z(j,i)); + + glEnd (); + } + } + } + + set_linestyle ("-"); + set_linewidth (0.5); + + if (el_mode > 0) + glDisable (GL_LIGHTING); + } + else + { + // FIXME: implement transparency + } + } + + if (! props.marker_is ("none") && + ! (props.markeredgecolor_is ("none") + && props.markerfacecolor_is ("none"))) + { + // FIXME: check how transparency should be handled in markers + // FIXME: check what to do with marker facecolor set to auto + // and facecolor set to none. + + bool do_edge = ! props.markeredgecolor_is ("none"); + bool do_face = ! props.markerfacecolor_is ("none"); + + Matrix mecolor = props.get_markeredgecolor_rgb (); + Matrix mfcolor = props.get_markerfacecolor_rgb (); + Matrix cc (1, 3, 0.0); + + if (mecolor.numel () == 0 && props.markeredgecolor_is ("auto")) + { + mecolor = props.get_edgecolor_rgb (); + do_edge = ! props.edgecolor_is ("none"); + } + + if (mfcolor.numel () == 0 && props.markerfacecolor_is ("auto")) + { + mfcolor = props.get_facecolor_rgb (); + do_face = ! props.facecolor_is ("none"); + } + + if ((mecolor.numel () == 0 || mfcolor.numel () == 0) + && c.numel () == 0) + c = props.get_color_data ().array_value (); + + init_marker (props.get_marker (), props.get_markersize (), + props.get_linewidth ()); + + for (int i = 0; i < zc; i++) + { + if (y_mat) + i1 = i; + + for (int j = 0; j < zr; j++) + { + if (clip(j,i)) + continue; + + if (x_mat) + j1 = j; + + if ((do_edge && mecolor.numel () == 0) + || (do_face && mfcolor.numel () == 0)) + { + for (int k = 0; k < 3; k++) + cc(k) = c(j,i,k); + } + + Matrix lc = (do_edge ? (mecolor.numel () == 0 ? cc : mecolor) : Matrix ()); + Matrix fc = (do_face ? (mfcolor.numel () == 0 ? cc : mfcolor) : Matrix ()); + + draw_marker (x(j1,i), y(j,i1), z(j,i), lc, fc); + } + } + + end_marker (); + } +} + +// FIXME: global optimization (rendering, data structures...), there +// is probably a smarter/faster/less-memory-consuming way to do this. +void +opengl_renderer::draw_patch (const patch::properties &props) +{ + const Matrix f = props.get_faces ().matrix_value (); + const Matrix v = xform.scale (props.get_vertices ().matrix_value ()); + Matrix c; + const Matrix n = props.get_vertexnormals ().matrix_value (); + Matrix a; + + int nv = v.rows (); + // int vmax = v.columns (); + int nf = f.rows (); + int fcmax = f.columns (); + + bool has_z = (v.columns () > 2); + bool has_facecolor = false; + bool has_facealpha = false; + + int fc_mode = ((props.facecolor_is ("none") + || props.facecolor_is_rgb ()) ? 0 : + (props.facecolor_is ("flat") ? 1 : 2)); + int fl_mode = (props.facelighting_is ("none") ? 0 : + (props.facelighting_is ("flat") ? 1 : 2)); + int fa_mode = (props.facealpha_is_double () ? 0 : + (props.facealpha_is ("flat") ? 1 : 2)); + int ec_mode = ((props.edgecolor_is ("none") + || props.edgecolor_is_rgb ()) ? 0 : + (props.edgecolor_is ("flat") ? 1 : 2)); + int el_mode = (props.edgelighting_is ("none") ? 0 : + (props.edgelighting_is ("flat") ? 1 : 2)); + int ea_mode = (props.edgealpha_is_double () ? 0 : + (props.edgealpha_is ("flat") ? 1 : 2)); + + Matrix fcolor = props.get_facecolor_rgb (); + Matrix ecolor = props.get_edgecolor_rgb (); + + float as = props.get_ambientstrength (); + float ds = props.get_diffusestrength (); + float ss = props.get_specularstrength (); + float se = props.get_specularexponent (); + + boolMatrix clip (1, nv, false); + + if (has_z) + for (int i = 0; i < nv; i++) + clip(i) = is_nan_or_inf (v(i,0), v(i,1), v(i,2)); + else + for (int i = 0; i < nv; i++) + clip(i) = is_nan_or_inf (v(i,0), v(i,1), 0); + + boolMatrix clip_f (1, nf, false); + Array count_f (dim_vector (nf, 1), 0); + + for (int i = 0; i < nf; i++) + { + bool fclip = false; + int count = 0; + + for (int j = 0; j < fcmax && ! xisnan (f(i,j)); j++, count++) + fclip = (fclip || clip(int (f(i,j) - 1))); + + clip_f(i) = fclip; + count_f(i) = count; + } + + if (fc_mode > 0 || ec_mode > 0) + { + c = props.get_color_data ().matrix_value (); + + if (c.rows () == 1) + { + // Single color specifications, we can simplify a little bit + + if (fc_mode > 0) + { + fcolor = c; + fc_mode = 0; + } + + if (ec_mode > 0) + { + ecolor = c; + ec_mode = 0; + } + + c = Matrix (); + } + else + has_facecolor = ((c.numel () > 0) && (c.rows () == f.rows ())); + } + + if (fa_mode > 0 || ea_mode > 0) + { + // FIXME: retrieve alpha data from patch object + //a = props.get_alpha_data (); + has_facealpha = ((a.numel () > 0) && (a.rows () == f.rows ())); + } + + octave_idx_type fr = f.rows (); + std::vector vdata (f.numel ()); + + for (int i = 0; i < nf; i++) + for (int j = 0; j < count_f(i); j++) + { + int idx = int (f(i,j) - 1); + + Matrix vv (1, 3, 0.0); + Matrix cc; + Matrix nn(1, 3, 0.0); + double aa = 1.0; + + vv(0) = v(idx,0); vv(1) = v(idx,1); + if (has_z) + vv(2) = v(idx,2); + // FIXME: uncomment when patch object has normal computation + //nn(0) = n(idx,0); nn(1) = n(idx,1); nn(2) = n(idx,2); + if (c.numel () > 0) + { + cc.resize (1, 3); + if (has_facecolor) + cc(0) = c(i,0), cc(1) = c(i,1), cc(2) = c(i,2); + else + cc(0) = c(idx,0), cc(1) = c(idx,1), cc(2) = c(idx,2); + } + if (a.numel () > 0) + { + if (has_facealpha) + aa = a(i); + else + aa = a(idx); + } + + vdata[i+j*fr] = + vertex_data (vv, cc, nn, aa, as, ds, ss, se); + } + + if (fl_mode > 0 || el_mode > 0) + { + float buf[4] = { ss, ss, ss, 1 }; + + glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf); + glMaterialf (LIGHT_MODE, GL_SHININESS, se); + } + + if (! props.facecolor_is ("none")) + { + // FIXME: adapt to double-radio property + if (props.get_facealpha_double () == 1) + { + if (fc_mode == 0) + { + glColor3dv (fcolor.data ()); + if (fl_mode > 0) + { + float cb[4] = { 0, 0, 0, 1 }; + + for (int i = 0; i < 3; i++) + cb[i] = (as * fcolor(i)); + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int i = 0; i < 3; i++) + cb[i] = ds * fcolor(i); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + + if (fl_mode > 0) + glEnable (GL_LIGHTING); + + // FIXME: use __index__ property from patch object + patch_tesselator tess (this, fc_mode, fl_mode, 0); + + for (int i = 0; i < nf; i++) + { + if (clip_f(i)) + continue; + + tess.begin_polygon (true); + tess.begin_contour (); + + for (int j = 0; j < count_f(i); j++) + { + vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep (); + + tess.add_vertex (vv->coords.fortran_vec (), vv); + } + + tess.end_contour (); + tess.end_polygon (); + } + + if (fl_mode > 0) + glDisable (GL_LIGHTING); + } + else + { + // FIXME: implement transparency + } + } + + if (! props.edgecolor_is ("none")) + { + // FIXME: adapt to double-radio property + if (props.get_edgealpha_double () == 1) + { + if (ec_mode == 0) + { + glColor3dv (ecolor.data ()); + if (el_mode > 0) + { + float cb[4] = { 0, 0, 0, 1 }; + + for (int i = 0; i < 3; i++) + cb[i] = (as * ecolor(i)); + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int i = 0; i < 3; i++) + cb[i] = ds * ecolor(i); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + + if (el_mode > 0) + glEnable (GL_LIGHTING); + + set_linestyle (props.get_linestyle (), false); + set_linewidth (props.get_linewidth ()); + + + // FIXME: use __index__ property from patch object; should we + // offset patch contour as well? + patch_tesselator tess (this, ec_mode, el_mode); + + for (int i = 0; i < nf; i++) + { + if (clip_f(i)) + { + // This is an unclosed contour. Draw it as a line + bool flag = false; + + for (int j = 0; j < count_f(i); j++) + { + if (! clip(int (f(i,j) - 1))) + { + vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep (); + const Matrix m = vv->coords; + if (! flag) + { + flag = true; + glBegin (GL_LINE_STRIP); + } + glVertex3d (m(0), m(1), m(2)); + } + else if (flag) + { + flag = false; + glEnd (); + } + } + + if (flag) + glEnd (); + } + else + { + tess.begin_polygon (false); + tess.begin_contour (); + + for (int j = 0; j < count_f(i); j++) + { + vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep (); + tess.add_vertex (vv->coords.fortran_vec (), vv); + } + + tess.end_contour (); + tess.end_polygon (); + } + } + + set_linestyle ("-"); + set_linewidth (0.5); + + if (el_mode > 0) + glDisable (GL_LIGHTING); + } + else + { + // FIXME: implement transparency + } + } + + if (! props.marker_is ("none") && + ! (props.markeredgecolor_is ("none") && props.markerfacecolor_is ("none"))) + { + bool do_edge = ! props.markeredgecolor_is ("none"); + bool do_face = ! props.markerfacecolor_is ("none"); + + Matrix mecolor = props.get_markeredgecolor_rgb (); + Matrix mfcolor = props.get_markerfacecolor_rgb (); + + bool has_markerfacecolor = false; + + if ((mecolor.numel () == 0 && ! props.markeredgecolor_is ("none")) + || (mfcolor.numel () == 0 && ! props.markerfacecolor_is ("none"))) + { + Matrix mc = props.get_color_data ().matrix_value (); + + if (mc.rows () == 1) + { + // Single color specifications, we can simplify a little bit + + if (mfcolor.numel () == 0 + && ! props.markerfacecolor_is ("none")) + mfcolor = mc; + + if (mecolor.numel () == 0 + && ! props.markeredgecolor_is ("none")) + mecolor = mc; + } + else + { + if (c.numel () == 0) + c = props.get_color_data ().matrix_value (); + has_markerfacecolor = ((c.numel () > 0) + && (c.rows () == f.rows ())); + } + } + + + init_marker (props.get_marker (), props.get_markersize (), + props.get_linewidth ()); + + for (int i = 0; i < nf; i++) + for (int j = 0; j < count_f(i); j++) + { + int idx = int (f(i,j) - 1); + + if (clip(idx)) + continue; + + Matrix cc; + if (c.numel () > 0) + { + cc.resize (1, 3); + if (has_markerfacecolor) + cc(0) = c(i,0), cc(1) = c(i,1), cc(2) = c(i,2); + else + cc(0) = c(idx,0), cc(1) = c(idx,1), cc(2) = c(idx,2); + } + + Matrix lc = (do_edge ? (mecolor.numel () == 0 ? cc : mecolor) + : Matrix ()); + Matrix fc = (do_face ? (mfcolor.numel () == 0 ? cc : mfcolor) + : Matrix ()); + + draw_marker (v(idx,0), v(idx,1), (has_z ? v(idx,2) : 0), lc, fc); + } + + end_marker (); + } +} + +void +opengl_renderer::draw_hggroup (const hggroup::properties &props) +{ + draw (props.get_children ()); +} + +void +opengl_renderer::draw_text (const text::properties& props) +{ + if (props.get_string ().is_empty ()) + return; + + Matrix pos = xform.scale (props.get_data_position ()); + const Matrix bbox = props.get_extent_matrix (); + + // FIXME: handle margin and surrounding box + bool blend = glIsEnabled (GL_BLEND); + + glEnable (GL_BLEND); + glEnable (GL_ALPHA_TEST); + glRasterPos3d (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0); + glBitmap (0, 0, 0, 0, bbox(0), bbox(1), 0); + glDrawPixels (bbox(2), bbox(3), + GL_RGBA, GL_UNSIGNED_BYTE, props.get_pixels ().data ()); + glDisable (GL_ALPHA_TEST); + if (! blend) + glDisable (GL_BLEND); + +} + +void +opengl_renderer::draw_image (const image::properties& props) +{ + octave_value cdata = props.get_color_data (); + dim_vector dv (cdata.dims ()); + int h = dv(0), w = dv(1); + + Matrix x = props.get_xdata ().matrix_value (); + Matrix y = props.get_ydata ().matrix_value (); + + // Someone wants us to draw an empty image? No way. + if (x.is_empty () || y.is_empty ()) + return; + + if (w > 1 && x(1) == x(0)) + x(1) = x(1) + (w-1); + + if (h > 1 && y(1) == y(0)) + y(1) = y(1) + (h-1); + + const ColumnVector p0 = xform.transform (x(0), y(0), 0); + const ColumnVector p1 = xform.transform (x(1), y(1), 0); + + // image pixel size in screen pixel units + float pix_dx, pix_dy; + // image pixel size in normalized units + float nor_dx, nor_dy; + + if (w > 1) + { + pix_dx = (p1(0) - p0(0))/(w-1); + nor_dx = (x(1) - x(0))/(w-1); + } + else + { + const ColumnVector p1w = xform.transform (x(1) + 1, y(1), 0); + pix_dx = p1w(0) - p0(0); + nor_dx = 1; + } + + if (h > 1) + { + pix_dy = (p1(1) - p0(1))/(h-1); + nor_dy = (y(1) - y(0))/(h-1); + } + else + { + const ColumnVector p1h = xform.transform (x(1), y(1) + 1, 0); + pix_dy = p1h(1) - p0(1); + nor_dy = 1; + } + + + // OpenGL won't draw the image if it's origin is outside the + // viewport/clipping plane so we must do the clipping + // ourselfes - only draw part of the image + + int j0 = 0, j1 = w; + int i0 = 0, i1 = h; + + float im_xmin = x(0) - nor_dx/2; + float im_xmax = x(1) + nor_dx/2; + float im_ymin = y(0) - nor_dy/2; + float im_ymax = y(1) + nor_dy/2; + if (props.is_clipping ()) // clip to axes + { + if (im_xmin < xmin) + j0 += (xmin - im_xmin)/nor_dx + 1; + if (im_xmax > xmax) + j1 -= (im_xmax - xmax)/nor_dx ; + + if (im_ymin < ymin) + i0 += (ymin - im_ymin)/nor_dy + 1; + if (im_ymax > ymax) + i1 -= (im_ymax - ymax)/nor_dy; + } + else // clip to viewport + { + GLfloat vp[4]; + glGetFloatv (GL_VIEWPORT, vp); + // FIXME -- actually add the code to do it! + + } + + if (i0 >= i1 || j0 >= j1) + return; + + glPixelZoom (pix_dx, -pix_dy); + glRasterPos3d (im_xmin + nor_dx*j0, im_ymin + nor_dy*i0, 0); + + // by default this is 4 + glPixelStorei (GL_UNPACK_ALIGNMENT,1); + + // Expect RGB data + if (dv.length () == 3 && dv(2) == 3) + { + if (cdata.is_double_type ()) + { + const NDArray xcdata = cdata.array_value (); + + OCTAVE_LOCAL_BUFFER (GLfloat, a, 3*(j1-j0)*(i1-i0)); + + for (int i = i0; i < i1; i++) + { + for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3) + { + a[idx] = xcdata(i,j,0); + a[idx+1] = xcdata(i,j,1); + a[idx+2] = xcdata(i,j,2); + } + } + + draw_pixels (j1-j0, i1-i0, GL_RGB, GL_FLOAT, a); + + } + else if (cdata.is_uint16_type ()) + { + const uint16NDArray xcdata = cdata.uint16_array_value (); + + OCTAVE_LOCAL_BUFFER (GLushort, a, 3*(j1-j0)*(i1-i0)); + + for (int i = i0; i < i1; i++) + { + for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3) + { + a[idx] = xcdata(i,j,0); + a[idx+1] = xcdata(i,j,1); + a[idx+2] = xcdata(i,j,2); + } + } + + draw_pixels (j1-j0, i1-i0, GL_RGB, GL_UNSIGNED_SHORT, a); + + } + else if (cdata.is_uint8_type ()) + { + const uint8NDArray xcdata = cdata.uint8_array_value (); + + OCTAVE_LOCAL_BUFFER (GLubyte, a, 3*(j1-j0)*(i1-i0)); + + for (int i = i0; i < i1; i++) + { + for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3) + { + a[idx] = xcdata(i,j,0); + a[idx+1] = xcdata(i,j,1); + a[idx+2] = xcdata(i,j,2); + } + } + + draw_pixels (j1-j0, i1-i0, GL_RGB, GL_UNSIGNED_BYTE, a); + } + else + warning ("opengl_texture::draw: invalid image data type (expected double, uint16, or uint8)"); + } + else + warning ("opengl_texture::draw: invalid image size (expected n*m*3 or n*m)"); + + glPixelZoom (1, 1); +} + +void +opengl_renderer::set_viewport (int w, int h) +{ + glViewport (0, 0, w, h); +} + +void +opengl_renderer::draw_pixels (GLsizei width, GLsizei height, GLenum format, + GLenum type, const GLvoid *data) +{ + glDrawPixels (width, height, format, type, data); +} + +void +opengl_renderer::set_color (const Matrix& c) +{ + glColor3dv (c.data ()); +#if HAVE_FREETYPE + text_renderer.set_color (c); +#endif +} + +void +opengl_renderer::set_font (const base_properties& props) +{ +#if HAVE_FREETYPE + text_renderer.set_font (props.get ("fontname").string_value (), + props.get ("fontweight").string_value (), + props.get ("fontangle").string_value (), + props.get ("fontsize").double_value ()); +#endif +} + +void +opengl_renderer::set_polygon_offset (bool on, double offset) +{ + if (on) + { + glPolygonOffset (offset, offset); + glEnable (GL_POLYGON_OFFSET_FILL); + glEnable (GL_POLYGON_OFFSET_LINE); + } + else + { + glDisable (GL_POLYGON_OFFSET_FILL); + glDisable (GL_POLYGON_OFFSET_LINE); + } +} + +void +opengl_renderer::set_linewidth (float w) +{ + glLineWidth (w); +} + +void +opengl_renderer::set_linestyle (const std::string& s, bool use_stipple) +{ + bool solid = false; + + if (s == "-") + { + glLineStipple (1, static_cast (0xFFFF)); + solid = true; + } + else if (s == ":") + glLineStipple (1, static_cast (0x8888)); + else if (s == "--") + glLineStipple (1, static_cast (0x0FFF)); + else if (s == "-.") + glLineStipple (1, static_cast (0x020F)); + else + glLineStipple (1, static_cast (0x0000)); + + if (solid && ! use_stipple) + glDisable (GL_LINE_STIPPLE); + else + glEnable (GL_LINE_STIPPLE); +} + +void +opengl_renderer::set_clipbox (double x1, double x2, double y1, double y2, + double z1, double z2) +{ + double dx = (x2-x1); + double dy = (y2-y1); + double dz = (z2-z1); + + x1 -= 0.001*dx; x2 += 0.001*dx; + y1 -= 0.001*dy; y2 += 0.001*dy; + z1 -= 0.001*dz; z2 += 0.001*dz; + + ColumnVector p (4, 0.0); + + p(0) = -1; p(3) = x2; + glClipPlane (GL_CLIP_PLANE0, p.data ()); + p(0) = 1; p(3) = -x1; + glClipPlane (GL_CLIP_PLANE1, p.data ()); + p(0) = 0; p(1) = -1; p(3) = y2; + glClipPlane (GL_CLIP_PLANE2, p.data ()); + p(1) = 1; p(3) = -y1; + glClipPlane (GL_CLIP_PLANE3, p.data ()); + p(1) = 0; p(2) = -1; p(3) = z2; + glClipPlane (GL_CLIP_PLANE4, p.data ()); + p(2) = 1; p(3) = -z1; + glClipPlane (GL_CLIP_PLANE5, p.data ()); + + xmin = x1; xmax = x2; + ymin = y1; ymax = y2; + zmin = z1; zmax = z2; +} + +void +opengl_renderer::set_clipping (bool enable) +{ + bool has_clipping = (glIsEnabled (GL_CLIP_PLANE0) == GL_TRUE); + + if (enable != has_clipping) + { + if (enable) + for (int i = 0; i < 6; i++) + glEnable (GL_CLIP_PLANE0+i); + else + for (int i = 0; i < 6; i++) + glDisable (GL_CLIP_PLANE0+i); + } +} + +void +opengl_renderer::init_marker (const std::string& m, double size, float width) +{ +#if defined (HAVE_FRAMEWORK_OPENGL) + GLint vw[4]; +#else + int vw[4]; +#endif + + glGetIntegerv (GL_VIEWPORT, vw); + + glMatrixMode (GL_PROJECTION); + glPushMatrix (); + glLoadIdentity (); + glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2); + glMatrixMode (GL_MODELVIEW); + glPushMatrix (); + + set_clipping (false); + set_linewidth (width); + + marker_id = make_marker_list (m, size, false); + filled_marker_id = make_marker_list (m, size, true); +} + +void +opengl_renderer::end_marker (void) +{ + glDeleteLists (marker_id, 1); + glDeleteLists (filled_marker_id, 1); + + glMatrixMode (GL_MODELVIEW); + glPopMatrix (); + glMatrixMode (GL_PROJECTION); + glPopMatrix (); + set_linewidth (0.5f); +} + +void +opengl_renderer::draw_marker (double x, double y, double z, + const Matrix& lc, const Matrix& fc) +{ + ColumnVector tmp = xform.transform (x, y, z, false); + + glLoadIdentity (); + glTranslated (tmp(0), tmp(1), -tmp(2)); + + if (filled_marker_id > 0 && fc.numel () > 0) + { + glColor3dv (fc.data ()); + set_polygon_offset (true, -1.0); + glCallList (filled_marker_id); + if (lc.numel () > 0) + { + glColor3dv (lc.data ()); + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + glEdgeFlag (GL_TRUE); + set_polygon_offset (true, -2.0); + glCallList (filled_marker_id); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + } + set_polygon_offset (false); + } + else if (marker_id > 0 && lc.numel () > 0) + { + glColor3dv (lc.data ()); + glCallList (marker_id); + } +} + +unsigned int +opengl_renderer::make_marker_list (const std::string& marker, double size, + bool filled) const +{ + char c = marker[0]; + + if (filled && (c == '+' || c == 'x' || c == '*' || c == '.')) + return 0; + + unsigned int ID = glGenLists (1); + double sz = size * toolkit.get_screen_resolution () / 72.0; + + // constants for the * marker + const double sqrt2d4 = 0.35355339059327; + double tt = sz*sqrt2d4; + + glNewList (ID, GL_COMPILE); + + switch (marker[0]) + { + case '+': + glBegin (GL_LINES); + glVertex2f (-sz/2, 0); + glVertex2f (sz/2, 0); + glVertex2f (0, -sz/2); + glVertex2f (0, sz/2); + glEnd (); + break; + case 'x': + glBegin (GL_LINES); + glVertex2f (-sz/2, -sz/2); + glVertex2f (sz/2, sz/2); + glVertex2f (-sz/2, sz/2); + glVertex2f (sz/2, -sz/2); + glEnd (); + break; + case '*': + glBegin (GL_LINES); + glVertex2f (-sz/2, 0); + glVertex2f (sz/2, 0); + glVertex2f (0, -sz/2); + glVertex2f (0, sz/2); + glVertex2f (-tt, -tt); + glVertex2f (+tt, +tt); + glVertex2f (-tt, +tt); + glVertex2f (+tt, -tt); + glEnd (); + break; + case '.': + { + double ang_step = M_PI / 5; + + glBegin (GL_POLYGON); + for (double ang = 0; ang < (2*M_PI); ang += ang_step) + glVertex2d (sz*cos (ang)/3, sz*sin (ang)/3); + glEnd (); + } + break; + case 's': + glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); + glVertex2d (-sz/2, -sz/2); + glVertex2d (-sz/2, sz/2); + glVertex2d (sz/2, sz/2); + glVertex2d (sz/2, -sz/2); + glEnd (); + break; + case 'o': + { + double ang_step = M_PI / 5; + + glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); + for (double ang = 0; ang < (2*M_PI); ang += ang_step) + glVertex2d (sz*cos (ang)/2, sz*sin (ang)/2); + glEnd (); + } + break; + case 'd': + glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); + glVertex2d (0, -sz/2); + glVertex2d (sz/2, 0); + glVertex2d (0, sz/2); + glVertex2d (-sz/2, 0); + glEnd (); + break; + case 'v': + glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); + glVertex2f (0, sz/2); + glVertex2f (sz/2, -sz/2); + glVertex2f (-sz/2, -sz/2); + glEnd (); + break; + case '^': + glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); + glVertex2f (0, -sz/2); + glVertex2f (-sz/2, sz/2); + glVertex2f (sz/2, sz/2); + glEnd (); + break; + case '>': + glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); + glVertex2f (sz/2, 0); + glVertex2f (-sz/2, sz/2); + glVertex2f (-sz/2, -sz/2); + glEnd (); + break; + case '<': + glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); + glVertex2f (-sz/2, 0); + glVertex2f (sz/2, -sz/2); + glVertex2f (sz/2, sz/2); + glEnd (); + break; + case 'p': + { + double ang; + double r; + double dr = 1.0 - sin (M_PI/10)/sin (3*M_PI/10)*1.02; + + glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); + for (int i = 0; i < 2*5; i++) + { + ang = (-0.5 + double(i+1)/5) * M_PI; + r = 1.0 - (dr * fmod (double(i+1), 2.0)); + glVertex2d (sz*r*cos (ang)/2, sz*r*sin (ang)/2); + } + glEnd (); + } + break; + case 'h': + { + double ang; + double r; + double dr = 1.0 - 0.5/sin (M_PI/3)*1.02; + + glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); + for (int i = 0; i < 2*6; i++) + { + ang = (0.5 + double(i+1)/6.0) * M_PI; + r = 1.0 - (dr * fmod (double(i+1), 2.0)); + glVertex2d (sz*r*cos (ang)/2, sz*r*sin (ang)/2); + } + glEnd (); + } + break; + default: + warning ("opengl_renderer: unsupported marker `%s'", + marker.c_str ()); + break; + } + + glEndList (); + + return ID; +} + +void +opengl_renderer::text_to_pixels (const std::string& txt, + uint8NDArray& pixels, + Matrix& bbox, + int halign, int valign, double rotation) +{ +#if HAVE_FREETYPE + text_renderer.text_to_pixels (txt, pixels, bbox, + halign, valign, rotation); +#endif +} + +Matrix +opengl_renderer::render_text (const std::string& txt, + double x, double y, double z, + int halign, int valign, double rotation) +{ +#if HAVE_FREETYPE + if (txt.empty ()) + return Matrix (1, 4, 0.0); + + uint8NDArray pixels; + Matrix bbox; + text_to_pixels (txt, pixels, bbox, halign, valign, rotation); + + bool blend = glIsEnabled (GL_BLEND); + + glEnable (GL_BLEND); + glEnable (GL_ALPHA_TEST); + glRasterPos3d (x, y, z); + glBitmap(0, 0, 0, 0, bbox(0), bbox(1), 0); + glDrawPixels (bbox(2), bbox(3), + GL_RGBA, GL_UNSIGNED_BYTE, pixels.data ()); + glDisable (GL_ALPHA_TEST); + if (! blend) + glDisable (GL_BLEND); + + return bbox; +#else + ::warning ("render_text: cannot render text, Freetype library not available"); + return Matrix (1, 4, 0.0); +#endif +} + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/gl-render.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/gl-render.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,211 @@ +/* + +Copyright (C) 2008-2012 Michael Goffioul + +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 (gl_render_h) +#define gl_render_h 1 + +#ifdef HAVE_WINDOWS_H +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#ifdef HAVE_GL_GL_H +#include +#elif defined HAVE_OPENGL_GL_H || defined HAVE_FRAMEWORK_OPENGL +#include +#endif + +#ifdef HAVE_GL_GLU_H +#include +#elif defined HAVE_OPENGL_GLU_H || defined HAVE_FRAMEWORK_OPENGL +#include +#endif + +#include "graphics.h" +#include "txt-eng-ft.h" + +class +OCTINTERP_API +opengl_renderer +{ +public: + opengl_renderer (void) + : toolkit (), xform (), xmin (), xmax (), ymin (), ymax (), + zmin (), zmax (), xZ1 (), xZ2 (), marker_id (), filled_marker_id (), + camera_pos (), camera_dir () +#if HAVE_FREETYPE + , text_renderer () +#endif + { } + + virtual ~opengl_renderer (void) { } + + virtual void draw (const graphics_object& go, bool toplevel = true); + + virtual void draw (const Matrix& hlist, bool toplevel = false) + { + int len = hlist.length (); + + for (int i = len-1; i >= 0; i--) + { + graphics_object obj = gh_manager::get_object (hlist(i)); + + if (obj) + draw (obj, toplevel); + } + } + + virtual void set_viewport (int w, int h); + virtual graphics_xform get_transform (void) const { return xform; } + +protected: + virtual void draw_figure (const figure::properties& props); + virtual void draw_axes (const axes::properties& props); + virtual void draw_line (const line::properties& props); + virtual void draw_surface (const surface::properties& props); + virtual void draw_patch (const patch::properties& props); + virtual void draw_hggroup (const hggroup::properties& props); + virtual void draw_text (const text::properties& props); + virtual void draw_image (const image::properties& props); + virtual void draw_uipanel (const uipanel::properties& props, + const graphics_object& go); + + virtual void init_gl_context (bool enhanced, const Matrix& backgroundColor); + virtual void setup_opengl_transformation (const axes::properties& props); + + virtual void set_color (const Matrix& c); + virtual void set_polygon_offset (bool on, double offset = 0.0); + virtual void set_linewidth (float w); + virtual void set_linestyle (const std::string& s, bool stipple = false); + virtual void set_clipbox (double x1, double x2, double y1, double y2, + double z1, double z2); + virtual void set_clipping (bool on); + virtual void set_font (const base_properties& props); + + virtual void init_marker (const std::string& m, double size, float width); + virtual void end_marker (void); + virtual void draw_marker (double x, double y, double z, + const Matrix& lc, const Matrix& fc); + + virtual void text_to_pixels (const std::string& txt, + uint8NDArray& pixels, + Matrix& bbox, + int halign = 0, int valign = 0, + double rotation = 0.0); + + virtual Matrix render_text (const std::string& txt, + double x, double y, double z, + int halign, int valign, double rotation = 0.0); + + virtual void draw_pixels (GLsizei w, GLsizei h, GLenum format, + GLenum type, const GLvoid *data); + + virtual void render_grid (const std::string& gridstyle, const Matrix& ticks, + double lim1, double lim2, + double p1, double p1N, double p2, double p2N, + int xyz, bool is_3D); + + virtual void render_tickmarks (const Matrix& ticks, double lim1, double lim2, + double p1, double p1N, double p2, double p2N, + double dx, double dy, double dz, + int xyz, bool doubleside); + + virtual void render_ticktexts (const Matrix& ticks, + const string_vector& ticklabels, + double lim1, double lim2, + double p1, double p2, + int xyz, int ha, int va, + int& wmax, int& hmax); + +private: + opengl_renderer (const opengl_renderer&) + : toolkit (), xform (), xmin (), xmax (), ymin (), ymax (), + zmin (), zmax (), xZ1 (), xZ2 (), marker_id (), filled_marker_id (), + camera_pos (), camera_dir () +#if HAVE_FREETYPE + , text_renderer () +#endif + { } + + opengl_renderer& operator = (const opengl_renderer&) + { return *this; } + + bool is_nan_or_inf (double x, double y, double z) const + { + return (xisnan (x) || xisnan (y) || xisnan (z) + || xisinf (x) || xisinf (y) || xisinf (z)); + } + + octave_uint8 clip_code (double x, double y, double z) const + { + return ((x < xmin ? 1 : 0) + | (x > xmax ? 1 : 0) << 1 + | (y < ymin ? 1 : 0) << 2 + | (y > ymax ? 1 : 0) << 3 + | (z < zmin ? 1 : 0) << 4 + | (z > zmax ? 1 : 0) << 5 + | (is_nan_or_inf (x, y, z) ? 0 : 1) << 6); + } + + unsigned int make_marker_list (const std::string& m, double size, + bool filled) const; + + void draw_axes_planes (const axes::properties& props); + void draw_axes_boxes (const axes::properties& props); + + void draw_axes_x_grid (const axes::properties& props); + void draw_axes_y_grid (const axes::properties& props); + void draw_axes_z_grid (const axes::properties& props); + + void draw_axes_children (const axes::properties& props); + +private: + // The graphics toolkit associated with the figure being rendered. + graphics_toolkit toolkit; + + // axes transformation data + graphics_xform xform; + + // axis limits in model scaled coordinate + double xmin, xmax; + double ymin, ymax; + double zmin, zmax; + + // Z projection limits in windows coordinate + double xZ1, xZ2; + + // call lists identifiers for markers + unsigned int marker_id, filled_marker_id; + + // camera information for primitive sorting + ColumnVector camera_pos, camera_dir; + +#if HAVE_FREETYPE + // freetype render, used for text rendering + ft_render text_renderer; +#endif + +private: + class patch_tesselator; +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/gl2ps-renderer.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/gl2ps-renderer.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,232 @@ +/* + +Copyright (C) 2009-2012 Shai Ayal + +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 +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined (HAVE_OPENGL) + +#include + +#include "lo-mappers.h" +#include "oct-locbuf.h" + +#include "gl2ps-renderer.h" +#include "gl2ps.h" + +void +glps_renderer::draw (const graphics_object& go) +{ + static bool in_draw = false; + + if (!in_draw) + { + in_draw = true; + + GLint buffsize = 0, state = GL2PS_OVERFLOW; + GLint viewport[4]; + + glGetIntegerv (GL_VIEWPORT, viewport); + + GLint gl2ps_term; + if (term.find ("eps") != std::string::npos) gl2ps_term = GL2PS_EPS; + else if (term.find ("pdf") != std::string::npos) gl2ps_term = GL2PS_PDF; + else if (term.find ("svg") != std::string::npos) gl2ps_term = GL2PS_SVG; + else if (term.find ("ps") != std::string::npos) gl2ps_term = GL2PS_PS; + else if (term.find ("pgf") != std::string::npos) gl2ps_term = GL2PS_PGF; + else if (term.find ("tex") != std::string::npos) gl2ps_term = GL2PS_TEX; + else + { + error ("gl2ps-renderer:: Unknown terminal"); + return; + } + + GLint gl2ps_text = 0; + if (term.find ("notxt") != std::string::npos) gl2ps_text = GL2PS_NO_TEXT; + + // Default sort order optimizes for 3D plots + GLint gl2ps_sort = GL2PS_BSP_SORT; + if (term.find ("is2D") != std::string::npos) gl2ps_sort = GL2PS_NO_SORT; + + while (state == GL2PS_OVERFLOW) + { + buffsize += 1024*1024; + gl2psBeginPage ("glps_renderer figure", "Octave", viewport, + gl2ps_term, gl2ps_sort, + (GL2PS_SILENT | GL2PS_SIMPLE_LINE_OFFSET + | GL2PS_NO_BLENDING | GL2PS_OCCLUSION_CULL + | GL2PS_BEST_ROOT | gl2ps_text + | GL2PS_NO_PS3_SHADING), + GL_RGBA, 0, NULL, 0, 0, 0, + buffsize, fp, "" ); + + opengl_renderer::draw (go); + state = gl2psEndPage (); + } + + in_draw = 0; + } + else + opengl_renderer::draw (go); +} + +int +glps_renderer::alignment_to_mode (int ha, int va) const +{ + int gl2psa=GL2PS_TEXT_BL; + if (ha == 0) + { + if (va == 0 || va == 3) + gl2psa=GL2PS_TEXT_BL; + else if (va == 2) + gl2psa=GL2PS_TEXT_TL; + else if (va == 1) + gl2psa=GL2PS_TEXT_CL; + } + else if (ha == 2) + { + if (va == 0 || va == 3) + gl2psa=GL2PS_TEXT_BR; + else if (va == 2) + gl2psa=GL2PS_TEXT_TR; + else if (va == 1) + gl2psa=GL2PS_TEXT_CR; + } + else if (ha == 1) + { + if (va == 0 || va == 3) + gl2psa=GL2PS_TEXT_B; + else if (va == 2) + gl2psa=GL2PS_TEXT_T; + else if (va == 1) + gl2psa=GL2PS_TEXT_C; + } + return gl2psa; +} + +Matrix +glps_renderer::render_text (const std::string& txt, + double x, double y, double z, + int ha, int va, double rotation) +{ + if (txt.empty ()) + return Matrix (1, 4, 0.0); + + glRasterPos3d (x, y, z); + gl2psTextOpt (txt.c_str (), fontname.c_str (), fontsize, + alignment_to_mode (ha, va), rotation); + + // FIXME? -- we have no way of getting a bounding box from gl2ps, so + // we use freetype + Matrix bbox; + uint8NDArray pixels; + text_to_pixels (txt, pixels, bbox, 0, 0, rotation); + return bbox; +} + +void +glps_renderer::set_font (const base_properties& props) +{ + opengl_renderer::set_font (props); + + fontsize = props.get ("fontsize").double_value (); + + caseless_str fn = props.get ("fontname").string_value (); + fontname = ""; + if (fn == "times" || fn == "times-roman") + fontname = "Times-Roman"; + else if (fn == "courier") + fontname = "Courier"; + else if (fn == "symbol") + fontname = "Symbol"; + else if (fn == "zapfdingbats") + fontname = "ZapfDingbats"; + else + fontname = "Helvetica"; + + // FIXME -- add support for bold and italic +} + +template +static void +draw_pixels (GLsizei w, GLsizei h, GLenum format, const T *data) +{ + OCTAVE_LOCAL_BUFFER (GLfloat, a, 3*w*h); + + for (int i = 0; i < 3*w*h; i++) + a[i] = data[i]; + + gl2psDrawPixels (w, h, 0, 0, format, GL_FLOAT, a); +} + +void +glps_renderer::draw_pixels (GLsizei w, GLsizei h, GLenum format, + GLenum type, const GLvoid *data) +{ + if (type == GL_UNSIGNED_SHORT) + ::draw_pixels (w, h, format, static_cast (data)); + else if (type == GL_UNSIGNED_BYTE) + ::draw_pixels (w, h, format, static_cast (data)); + else + gl2psDrawPixels (w, h, 0, 0, format, type, data); +} + +void +glps_renderer::draw_text (const text::properties& props) +{ + if (props.get_string ().is_empty ()) + return; + + set_font (props); + set_color (props.get_color_rgb ()); + + const Matrix pos = get_transform ().scale (props.get_data_position ()); + int halign = 0, valign = 0; + + if (props.horizontalalignment_is ("center")) + halign = 1; + else if (props.horizontalalignment_is ("right")) + halign = 2; + + if (props.verticalalignment_is ("top")) + valign = 2; + else if (props.verticalalignment_is ("baseline")) + valign = 3; + else if (props.verticalalignment_is ("middle")) + valign = 1; + + // FIXME: handle margin and surrounding box + + glRasterPos3d (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0); + + 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 a132d206a36a -r b9b6a310ad97 src/interp-core/gl2ps-renderer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/gl2ps-renderer.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,87 @@ +/* + +Copyright (C) 2009-2012 Shai Ayal + +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 (gl2ps_renderer_h) +#define gl2ps_renderer_h 1 + +#include "gl-render.h" +#include "gl2ps.h" + +class +OCTINTERP_API +glps_renderer : public opengl_renderer +{ +public: + glps_renderer (FILE *_fp, const std::string& _term) + : opengl_renderer () , fp (_fp), term (_term), + fontsize (), fontname () { } + + ~glps_renderer (void) { } + + void draw (const graphics_object& go); + +protected: + + Matrix render_text (const std::string& txt, + double x, double y, double z, + int halign, int valign, double rotation = 0.0); + + + void set_font (const base_properties& props); + + void draw_text (const text::properties& props); + void draw_pixels (GLsizei w, GLsizei h, GLenum format, + GLenum type, const GLvoid *data); + + void set_linestyle (const std::string& s, bool use_stipple = false) + { + opengl_renderer::set_linestyle (s, use_stipple); + + if (s == "-" && ! use_stipple) + gl2psDisable (GL2PS_LINE_STIPPLE); + else + gl2psEnable (GL2PS_LINE_STIPPLE); + } + + void set_polygon_offset (bool on, double offset = 0.0) + { + opengl_renderer::set_polygon_offset (on, offset); + if (on) + gl2psEnable (GL2PS_POLYGON_OFFSET_FILL); + else + gl2psDisable (GL2PS_POLYGON_OFFSET_FILL); + } + + void set_linewidth (float w) + { + gl2psLineWidth (w); + } + +private: + int alignment_to_mode (int ha, int va) const; + FILE *fp; + caseless_str term; + double fontsize; + std::string fontname; +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/gl2ps.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/gl2ps.c Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,6078 @@ +/* + * GL2PS, an OpenGL to PostScript Printing Library + * Copyright (C) 1999-2011 C. Geuzaine + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of either: + * + * a) the GNU Library General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your + * option) any later version; or + * + * b) the GL2PS License as published by Christophe Geuzaine, either + * version 2 of the License, or (at your option) any later version. + * + * This program 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 either + * the GNU Library General Public License or the GL2PS License for + * more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library in the file named "COPYING.LGPL"; + * if not, write to the Free Software Foundation, Inc., 675 Mass Ave, + * Cambridge, MA 02139, USA. + * + * You should have received a copy of the GL2PS License with this + * library in the file named "COPYING.GL2PS"; if not, I will be glad + * to provide one. + * + * For the latest info about gl2ps and a full list of contributors, + * see http://www.geuz.org/gl2ps/. + * + * Please report all bugs and problems to . + */ + +#include "gl2ps.h" + +#include +#include +#include +#include +#include +#include + +#if defined(GL2PS_HAVE_ZLIB) +#include +#endif + +#if defined(GL2PS_HAVE_LIBPNG) +#include +#endif + +/********************************************************************* + * + * Private definitions, data structures and prototypes + * + *********************************************************************/ + +/* Magic numbers (assuming that the order of magnitude of window + coordinates is 10^3) */ + +#define GL2PS_EPSILON 5.0e-3F +#define GL2PS_ZSCALE 1000.0F +#define GL2PS_ZOFFSET 5.0e-2F +#define GL2PS_ZOFFSET_LARGE 20.0F +#define GL2PS_ZERO(arg) (fabs(arg) < 1.e-20) + +/* Primitive types */ + +#define GL2PS_NO_TYPE -1 +#define GL2PS_TEXT 1 +#define GL2PS_POINT 2 +#define GL2PS_LINE 3 +#define GL2PS_QUADRANGLE 4 +#define GL2PS_TRIANGLE 5 +#define GL2PS_PIXMAP 6 +#define GL2PS_IMAGEMAP 7 +#define GL2PS_IMAGEMAP_WRITTEN 8 +#define GL2PS_IMAGEMAP_VISIBLE 9 +#define GL2PS_SPECIAL 10 + +/* BSP tree primitive comparison */ + +#define GL2PS_COINCIDENT 1 +#define GL2PS_IN_FRONT_OF 2 +#define GL2PS_IN_BACK_OF 3 +#define GL2PS_SPANNING 4 + +/* 2D BSP tree primitive comparison */ + +#define GL2PS_POINT_COINCIDENT 0 +#define GL2PS_POINT_INFRONT 1 +#define GL2PS_POINT_BACK 2 + +/* Internal feedback buffer pass-through tokens */ + +#define GL2PS_BEGIN_OFFSET_TOKEN 1 +#define GL2PS_END_OFFSET_TOKEN 2 +#define GL2PS_BEGIN_BOUNDARY_TOKEN 3 +#define GL2PS_END_BOUNDARY_TOKEN 4 +#define GL2PS_BEGIN_STIPPLE_TOKEN 5 +#define GL2PS_END_STIPPLE_TOKEN 6 +#define GL2PS_POINT_SIZE_TOKEN 7 +#define GL2PS_LINE_WIDTH_TOKEN 8 +#define GL2PS_BEGIN_BLEND_TOKEN 9 +#define GL2PS_END_BLEND_TOKEN 10 +#define GL2PS_SRC_BLEND_TOKEN 11 +#define GL2PS_DST_BLEND_TOKEN 12 +#define GL2PS_IMAGEMAP_TOKEN 13 +#define GL2PS_DRAW_PIXELS_TOKEN 14 +#define GL2PS_TEXT_TOKEN 15 + +typedef enum { + T_UNDEFINED = -1, + T_CONST_COLOR = 1, + T_VAR_COLOR = 1<<1, + T_ALPHA_1 = 1<<2, + T_ALPHA_LESS_1 = 1<<3, + T_VAR_ALPHA = 1<<4 +} GL2PS_TRIANGLE_PROPERTY; + +typedef GLfloat GL2PSxyz[3]; +typedef GLfloat GL2PSplane[4]; + +typedef struct _GL2PSbsptree2d GL2PSbsptree2d; + +struct _GL2PSbsptree2d { + GL2PSplane plane; + GL2PSbsptree2d *front, *back; +}; + +typedef struct { + GLint nmax, size, incr, n; + char *array; +} GL2PSlist; + +typedef struct _GL2PSbsptree GL2PSbsptree; + +struct _GL2PSbsptree { + GL2PSplane plane; + GL2PSlist *primitives; + GL2PSbsptree *front, *back; +}; + +typedef struct { + GL2PSxyz xyz; + GL2PSrgba rgba; +} GL2PSvertex; + +typedef struct { + GL2PSvertex vertex[3]; + int prop; +} GL2PStriangle; + +typedef struct { + GLshort fontsize; + char *str, *fontname; + /* Note: for a 'special' string, 'alignment' holds the format + (PostScript, PDF, etc.) of the special string */ + GLint alignment; + GLfloat angle; +} GL2PSstring; + +typedef struct { + GLsizei width, height; + /* Note: for an imagemap, 'type' indicates if it has already been + 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; + +typedef struct _GL2PSimagemap GL2PSimagemap; + +struct _GL2PSimagemap { + GL2PSimage *image; + GL2PSimagemap *next; +}; + +typedef struct { + GLshort type, numverts; + GLushort pattern; + char boundary, offset, culled; + GLint factor; + GLfloat width; + GL2PSvertex *verts; + union { + GL2PSstring *text; + GL2PSimage *image; + } data; +} GL2PSprimitive; + +typedef struct { +#if defined(GL2PS_HAVE_ZLIB) + Bytef *dest, *src, *start; + uLongf destLen, srcLen; +#else + int dummy; +#endif +} GL2PScompress; + +typedef struct{ + GL2PSlist* ptrlist; + int gsno, fontno, imno, shno, maskshno, trgroupno; + int gsobjno, fontobjno, imobjno, shobjno, maskshobjno, trgroupobjno; +} GL2PSpdfgroup; + +typedef struct { + /* General */ + GLint format, sort, options, colorsize, colormode, buffersize; + char *title, *producer, *filename; + GLboolean boundary, blending; + GLfloat *feedback, offset[2], lastlinewidth; + GLint viewport[4], blendfunc[2], lastfactor; + GL2PSrgba *colormap, lastrgba, threshold, bgcolor; + GLushort lastpattern; + GL2PSvertex lastvertex; + GL2PSlist *primitives, *auxprimitives; + FILE *stream; + GL2PScompress *compress; + GLboolean header; + + /* BSP-specific */ + GLint maxbestroot; + + /* Occlusion culling-specific */ + GLboolean zerosurfacearea; + GL2PSbsptree2d *imagetree; + GL2PSprimitive *primitivetoadd; + + /* PDF-specific */ + int streamlength; + GL2PSlist *pdfprimlist, *pdfgrouplist; + int *xreflist; + int objects_stack; /* available objects */ + int extgs_stack; /* graphics state object number */ + int font_stack; /* font object number */ + int im_stack; /* image object number */ + int trgroupobjects_stack; /* xobject numbers */ + int shader_stack; /* shader object numbers */ + int mshader_stack; /* mask shader object numbers */ + + /* for image map list */ + GL2PSimagemap *imagemap_head; + GL2PSimagemap *imagemap_tail; +} GL2PScontext; + +typedef struct { + void (*printHeader)(void); + void (*printFooter)(void); + void (*beginViewport)(GLint viewport[4]); + GLint (*endViewport)(void); + void (*printPrimitive)(void *data); + void (*printFinalPrimitive)(void); + const char *file_extension; + const char *description; +} GL2PSbackend; + +/* The gl2ps context. gl2ps is not thread safe (we should create a + local GL2PScontext during gl2psBeginPage) */ + +static GL2PScontext *gl2ps = NULL; + +/* Need to forward-declare this one */ + +static GLint gl2psPrintPrimitives(void); + +/********************************************************************* + * + * Utility routines + * + *********************************************************************/ + +static void gl2psMsg(GLint level, const char *fmt, ...) +{ + va_list args; + + if(!(gl2ps->options & GL2PS_SILENT)){ + switch(level){ + case GL2PS_INFO : fprintf(stderr, "GL2PS info: "); break; + case GL2PS_WARNING : fprintf(stderr, "GL2PS warning: "); break; + case GL2PS_ERROR : fprintf(stderr, "GL2PS error: "); break; + } + va_start(args, fmt); + vfprintf(stderr, fmt, args); + va_end(args); + fprintf(stderr, "\n"); + } + /* if(level == GL2PS_ERROR) exit(1); */ +} + +static void *gl2psMalloc(size_t size) +{ + void *ptr; + + if(!size) return NULL; + ptr = malloc(size); + if(!ptr){ + gl2psMsg(GL2PS_ERROR, "Couldn't allocate requested memory"); + return NULL; + } + return ptr; +} + +static void *gl2psRealloc(void *ptr, size_t size) +{ + void *orig = ptr; + if(!size) return NULL; + ptr = realloc(orig, size); + if(!ptr){ + gl2psMsg(GL2PS_ERROR, "Couldn't reallocate requested memory"); + free(orig); + return NULL; + } + return ptr; +} + +static void gl2psFree(void *ptr) +{ + if(!ptr) return; + free(ptr); +} + +static int gl2psWriteBigEndian(unsigned long data, int bytes) +{ + int i; + int size = sizeof(unsigned long); + for(i = 1; i <= bytes; ++i){ + fputc(0xff & (data >> (size - i) * 8), gl2ps->stream); + } + return bytes; +} + +/* zlib compression helper routines */ + +#if defined(GL2PS_HAVE_ZLIB) + +static void gl2psSetupCompress(void) +{ + gl2ps->compress = (GL2PScompress*)gl2psMalloc(sizeof(GL2PScompress)); + gl2ps->compress->src = NULL; + gl2ps->compress->start = NULL; + gl2ps->compress->dest = NULL; + gl2ps->compress->srcLen = 0; + gl2ps->compress->destLen = 0; +} + +static void gl2psFreeCompress(void) +{ + if(!gl2ps->compress) + return; + gl2psFree(gl2ps->compress->start); + gl2psFree(gl2ps->compress->dest); + gl2ps->compress->src = NULL; + gl2ps->compress->start = NULL; + gl2ps->compress->dest = NULL; + gl2ps->compress->srcLen = 0; + gl2ps->compress->destLen = 0; +} + +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; +} + +static void *gl2psReallocCompress(unsigned int srcsize) +{ + 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->srcLen); + gl2ps->compress->start = gl2ps->compress->src; + gl2ps->compress->dest = (Bytef*)gl2psRealloc(gl2ps->compress->dest, + gl2ps->compress->destLen); + + return gl2ps->compress->start; +} + +static int gl2psWriteBigEndianCompress(unsigned long data, int bytes) +{ + int i; + int size = sizeof(unsigned long); + for(i = 1; i <= bytes; ++i){ + *gl2ps->compress->src = (Bytef)(0xff & (data >> (size-i) * 8)); + ++gl2ps->compress->src; + } + return bytes; +} + +static int gl2psDeflate(void) +{ + /* 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); +} + +#endif + +static int gl2psPrintf(const char* fmt, ...) +{ + int ret; + va_list args; + +#if defined(GL2PS_HAVE_ZLIB) + unsigned int oldsize = 0; + static char buf[1000]; + if(gl2ps->options & GL2PS_COMPRESS){ + va_start(args, fmt); + ret = vsprintf(buf, fmt, args); + va_end(args); + oldsize = gl2ps->compress->srcLen; + gl2ps->compress->start = (Bytef*)gl2psReallocCompress(oldsize + ret); + memcpy(gl2ps->compress->start+oldsize, buf, ret); + ret = 0; + } + else{ +#endif + va_start(args, fmt); + ret = vfprintf(gl2ps->stream, fmt, args); + va_end(args); +#if defined(GL2PS_HAVE_ZLIB) + } +#endif + return ret; +} + +static void gl2psPrintGzipHeader(void) +{ +#if defined(GL2PS_HAVE_ZLIB) + char tmp[10] = {'\x1f', '\x8b', /* magic numbers: 0x1f, 0x8b */ + 8, /* compression method: Z_DEFLATED */ + 0, /* flags */ + 0, 0, 0, 0, /* time */ + 2, /* extra flags: max compression */ + '\x03'}; /* OS code: 0x03 (Unix) */ + + if(gl2ps->options & GL2PS_COMPRESS){ + gl2psSetupCompress(); + /* add the gzip file header */ + fwrite(tmp, 10, 1, gl2ps->stream); + } +#endif +} + +static void gl2psPrintGzipFooter(void) +{ +#if defined(GL2PS_HAVE_ZLIB) + int n; + uLong crc, len; + char tmp[8]; + + if(gl2ps->options & GL2PS_COMPRESS){ + if(Z_OK != gl2psDeflate()){ + gl2psMsg(GL2PS_ERROR, "Zlib deflate error"); + } + else{ + /* determine the length of the header in the zlib stream */ + n = 2; /* CMF+FLG */ + if(gl2ps->compress->dest[1] & (1<<5)){ + n += 4; /* DICTID */ + } + /* write the data, without the zlib header and footer */ + 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); + for(n = 0; n < 4; ++n){ + tmp[n] = (char)(crc & 0xff); + crc >>= 8; + } + len = gl2ps->compress->srcLen; + for(n = 4; n < 8; ++n){ + tmp[n] = (char)(len & 0xff); + len >>= 8; + } + fwrite(tmp, 8, 1, gl2ps->stream); + } + gl2psFreeCompress(); + gl2psFree(gl2ps->compress); + gl2ps->compress = NULL; + } +#endif +} + +/* The list handling routines */ + +static void gl2psListRealloc(GL2PSlist *list, GLint n) +{ + if(!list){ + gl2psMsg(GL2PS_ERROR, "Cannot reallocate NULL list"); + return; + } + if(n <= 0) return; + if(!list->array){ + list->nmax = n; + list->array = (char*)gl2psMalloc(list->nmax * list->size); + } + else{ + if(n > list->nmax){ + list->nmax = ((n - 1) / list->incr + 1) * list->incr; + list->array = (char*)gl2psRealloc(list->array, + list->nmax * list->size); + } + } +} + +static GL2PSlist *gl2psListCreate(GLint n, GLint incr, GLint size) +{ + GL2PSlist *list; + + if(n < 0) n = 0; + if(incr <= 0) incr = 1; + list = (GL2PSlist*)gl2psMalloc(sizeof(GL2PSlist)); + list->nmax = 0; + list->incr = incr; + list->size = size; + list->n = 0; + list->array = NULL; + gl2psListRealloc(list, n); + return list; +} + +static void gl2psListReset(GL2PSlist *list) +{ + if(!list) return; + list->n = 0; +} + +static void gl2psListDelete(GL2PSlist *list) +{ + if(!list) return; + gl2psFree(list->array); + gl2psFree(list); +} + +static void gl2psListAdd(GL2PSlist *list, void *data) +{ + if(!list){ + gl2psMsg(GL2PS_ERROR, "Cannot add into unallocated list"); + return; + } + list->n++; + gl2psListRealloc(list, list->n); + memcpy(&list->array[(list->n - 1) * list->size], data, list->size); +} + +static int gl2psListNbr(GL2PSlist *list) +{ + if(!list) + return 0; + return list->n; +} + +static void *gl2psListPointer(GL2PSlist *list, GLint index) +{ + if(!list){ + gl2psMsg(GL2PS_ERROR, "Cannot point into unallocated list"); + return NULL; + } + if((index < 0) || (index >= list->n)){ + gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListPointer"); + return NULL; + } + return &list->array[index * list->size]; +} + +static void gl2psListSort(GL2PSlist *list, + int (*fcmp)(const void *a, const void *b)) +{ + if(!list) + return; + qsort(list->array, list->n, list->size, fcmp); +} + +static void gl2psListAction(GL2PSlist *list, void (*action)(void *data)) +{ + GLint i; + + for(i = 0; i < gl2psListNbr(list); i++){ + (*action)(gl2psListPointer(list, i)); + } +} + +static void gl2psListActionInverse(GL2PSlist *list, void (*action)(void *data)) +{ + GLint i; + + for(i = gl2psListNbr(list); i > 0; i--){ + (*action)(gl2psListPointer(list, i-1)); + } +} + +#if defined(GL2PS_HAVE_LIBPNG) + +static void gl2psListRead(GL2PSlist *list, int index, void *data) +{ + if((index < 0) || (index >= list->n)) + gl2psMsg(GL2PS_ERROR, "Wrong list index in gl2psListRead"); + memcpy(data, &list->array[index * list->size], list->size); +} + +static void gl2psEncodeBase64Block(unsigned char in[3], unsigned char out[4], int len) +{ + static const char cb64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + out[0] = cb64[ in[0] >> 2 ]; + out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ]; + out[2] = (len > 1) ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '='; + out[3] = (len > 2) ? cb64[ in[2] & 0x3f ] : '='; +} + +static void gl2psListEncodeBase64(GL2PSlist *list) +{ + unsigned char *buffer, in[3], out[4]; + int i, n, index, len; + + n = list->n * list->size; + buffer = (unsigned char*)gl2psMalloc(n * sizeof(unsigned char)); + memcpy(buffer, list->array, n * sizeof(unsigned char)); + gl2psListReset(list); + + index = 0; + while(index < n) { + len = 0; + for(i = 0; i < 3; i++) { + if(index < n){ + in[i] = buffer[index]; + len++; + } + else{ + in[i] = 0; + } + index++; + } + if(len) { + gl2psEncodeBase64Block(in, out, len); + for(i = 0; i < 4; i++) + gl2psListAdd(list, &out[i]); + } + } + gl2psFree(buffer); +} + +#endif + +/* Helpers for rgba colors */ + +static GLboolean gl2psSameColor(GL2PSrgba rgba1, GL2PSrgba rgba2) +{ + if(!GL2PS_ZERO(rgba1[0] - rgba2[0]) || + !GL2PS_ZERO(rgba1[1] - rgba2[1]) || + !GL2PS_ZERO(rgba1[2] - rgba2[2])) + return GL_FALSE; + return GL_TRUE; +} + +static GLboolean gl2psVertsSameColor(const GL2PSprimitive *prim) +{ + int i; + + for(i = 1; i < prim->numverts; i++){ + if(!gl2psSameColor(prim->verts[0].rgba, prim->verts[i].rgba)){ + return GL_FALSE; + } + } + return GL_TRUE; +} + +static GLboolean gl2psSameColorThreshold(int n, GL2PSrgba rgba[], + GL2PSrgba threshold) +{ + 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; + for(i = 0; i < 3; ++i){ + gl2ps->lastrgba[i] = rgba[i]; + } +} + +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 */ + switch(im->format){ + case GL_RGBA: + pimag = pixels + 4 * (width * (height - 1 - y) + x); + break; + case GL_RGB: + default: + pimag = pixels + 3 * (width * (height - 1 - y) + x); + break; + } + *red = *pimag; pimag++; + *green = *pimag; pimag++; + *blue = *pimag; pimag++; + + return (im->format == GL_RGBA) ? *pimag : 1.0F; +} + +/* Helper routines for pixmaps */ + +static GL2PSimage *gl2psCopyPixmap(GL2PSimage *im) +{ + 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: + size = image->height * image->width * 4 * sizeof(GLfloat); + break; + case GL_RGB: + default: + size = image->height * image->width * 3 * sizeof(GLfloat); + break; + } + + image->pixels = (GLfloat*)gl2psMalloc(size); + memcpy(image->pixels, im->pixels, size); + + return image; +} + +static void gl2psFreePixmap(GL2PSimage *im) +{ + if(!im) + return; + gl2psFree(im->pixels); + gl2psFree(im); +} + +#if defined(GL2PS_HAVE_LIBPNG) + +#if !defined(png_jmpbuf) +# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) +#endif + +static void gl2psUserWritePNG(png_structp png_ptr, png_bytep data, png_size_t length) +{ + unsigned int i; + GL2PSlist *png = (GL2PSlist*)png_get_io_ptr(png_ptr); + for(i = 0; i < length; i++) + gl2psListAdd(png, &data[i]); +} + +static void gl2psUserFlushPNG(png_structp png_ptr) +{ + (void) png_ptr; /* not used */ +} + +static void gl2psConvertPixmapToPNG(GL2PSimage *pixmap, GL2PSlist *png) +{ + png_structp png_ptr; + png_infop info_ptr; + unsigned char *row_data; + GLfloat dr, dg, db; + int row, col; + + 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_FILTER_TYPE_BASE); + png_write_info(png_ptr, info_ptr); + + row_data = (unsigned char*)gl2psMalloc(3 * pixmap->width * sizeof(unsigned char)); + for(row = 0; row < pixmap->height; row++){ + for(col = 0; col < pixmap->width; col++){ + gl2psGetRGB(pixmap, col, row, &dr, &dg, &db); + row_data[3*col] = (unsigned char)(255. * dr); + row_data[3*col+1] = (unsigned char)(255. * dg); + row_data[3*col+2] = (unsigned char)(255. * db); + } + png_write_row(png_ptr, (png_bytep)row_data); + } + gl2psFree(row_data); + + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, &info_ptr); +} + +#endif + +/* Helper routines for text strings */ + +static GLint gl2psAddText(GLint type, const char *str, const char *fontname, + GLshort fontsize, GLint alignment, GLfloat angle) +{ + GLfloat pos[4]; + GL2PSprimitive *prim; + GLboolean valid; + + if(!gl2ps || !str || !fontname) return GL2PS_UNINITIALIZED; + + if(gl2ps->options & GL2PS_NO_TEXT) return GL2PS_SUCCESS; + + glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid); + if(GL_FALSE == valid) return GL2PS_SUCCESS; /* the primitive is culled */ + + glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); + + prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); + prim->type = type; + prim->boundary = 0; + prim->numverts = 1; + prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex)); + prim->verts[0].xyz[0] = pos[0]; + prim->verts[0].xyz[1] = pos[1]; + prim->verts[0].xyz[2] = pos[2]; + prim->culled = 0; + prim->offset = 0; + prim->pattern = 0; + prim->factor = 0; + prim->width = 1; + 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); + prim->data.text->fontname = (char*)gl2psMalloc((strlen(fontname)+1)*sizeof(char)); + strcpy(prim->data.text->fontname, fontname); + prim->data.text->fontsize = fontsize; + prim->data.text->alignment = alignment; + prim->data.text->angle = angle; + + gl2psListAdd(gl2ps->auxprimitives, &prim); + glPassThrough(GL2PS_TEXT_TOKEN); + + return GL2PS_SUCCESS; +} + +static GL2PSstring *gl2psCopyText(GL2PSstring *t) +{ + GL2PSstring *text = (GL2PSstring*)gl2psMalloc(sizeof(GL2PSstring)); + text->str = (char*)gl2psMalloc((strlen(t->str)+1)*sizeof(char)); + 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; +} + +static void gl2psFreeText(GL2PSstring *text) +{ + if(!text) + return; + gl2psFree(text->str); + gl2psFree(text->fontname); + gl2psFree(text); +} + +/* Helpers for blending modes */ + +static GLboolean gl2psSupportedBlendMode(GLenum sfactor, GLenum dfactor) +{ + /* 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) || + (sfactor == GL_ONE && dfactor == GL_ZERO) ) + return GL_TRUE; + return GL_FALSE; +} + +static void gl2psAdaptVertexForBlending(GL2PSvertex *v) +{ + /* Transforms vertex depending on the actual blending function - + currently the vertex v is considered as source vertex and his + alpha value is changed to 1.0 if source blending GL_ONE is + active. This might be extended in the future */ + + if(!v || !gl2ps) + return; + + if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){ + v->rgba[3] = 1.0F; + return; + } + + switch(gl2ps->blendfunc[0]){ + case GL_ONE: + v->rgba[3] = 1.0F; + break; + default: + break; + } +} + +static void gl2psAssignTriangleProperties(GL2PStriangle *t) +{ + /* int i; */ + + t->prop = T_VAR_COLOR; + + /* Uncommenting the following lines activates an even more fine + grained distinction between triangle types - please don't delete, + a remarkable amount of PDF handling code inside this file depends + on it if activated */ + /* + t->prop = T_CONST_COLOR; + for(i = 0; i < 3; ++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; + } + } + */ + + 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; + } + else{ + if(t->vertex[0].rgba[3] < 1) + t->prop |= T_ALPHA_LESS_1; + else + t->prop |= T_ALPHA_1; + } +} + +static void gl2psFillTriangleFromPrimitive(GL2PStriangle *t, GL2PSprimitive *p, + GLboolean assignprops) +{ + t->vertex[0] = p->verts[0]; + t->vertex[1] = p->verts[1]; + t->vertex[2] = p->verts[2]; + if(GL_TRUE == assignprops) + gl2psAssignTriangleProperties(t); +} + +static void gl2psInitTriangle(GL2PStriangle *t) +{ + int i; + GL2PSvertex vertex = { {-1.0F, -1.0F, -1.0F}, {-1.0F, -1.0F, -1.0F, -1.0F} }; + for(i = 0; i < 3; i++) + t->vertex[i] = vertex; + t->prop = T_UNDEFINED; +} + +/* Miscellaneous helper routines */ + +static GL2PSprimitive *gl2psCopyPrimitive(GL2PSprimitive *p) +{ + GL2PSprimitive *prim; + + if(!p){ + gl2psMsg(GL2PS_ERROR, "Trying to copy an empty primitive"); + return NULL; + } + + prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); + + prim->type = p->type; + prim->numverts = p->numverts; + prim->boundary = p->boundary; + prim->offset = p->offset; + prim->pattern = p->pattern; + prim->factor = p->factor; + prim->culled = p->culled; + prim->width = p->width; + prim->verts = (GL2PSvertex*)gl2psMalloc(p->numverts*sizeof(GL2PSvertex)); + memcpy(prim->verts, p->verts, p->numverts * sizeof(GL2PSvertex)); + + switch(prim->type){ + case GL2PS_PIXMAP : + prim->data.image = gl2psCopyPixmap(p->data.image); + break; + case GL2PS_TEXT : + case GL2PS_SPECIAL : + prim->data.text = gl2psCopyText(p->data.text); + break; + default: + break; + } + + return prim; +} + +static GLboolean gl2psSamePosition(GL2PSxyz p1, GL2PSxyz p2) +{ + if(!GL2PS_ZERO(p1[0] - p2[0]) || + !GL2PS_ZERO(p1[1] - p2[1]) || + !GL2PS_ZERO(p1[2] - p2[2])) + return GL_FALSE; + return GL_TRUE; +} + +/********************************************************************* + * + * 3D sorting routines + * + *********************************************************************/ + +static GLfloat gl2psComparePointPlane(GL2PSxyz point, GL2PSplane plane) +{ + return (plane[0] * point[0] + + plane[1] * point[1] + + plane[2] * point[2] + + plane[3]); +} + +static GLfloat gl2psPsca(GLfloat *a, GLfloat *b) +{ + return (a[0]*b[0] + a[1]*b[1] + a[2]*b[2]); +} + +static void gl2psPvec(GLfloat *a, GLfloat *b, GLfloat *c) +{ + c[0] = a[1]*b[2] - a[2]*b[1]; + c[1] = a[2]*b[0] - a[0]*b[2]; + c[2] = a[0]*b[1] - a[1]*b[0]; +} + +static GLfloat gl2psNorm(GLfloat *a) +{ + return (GLfloat)sqrt(a[0]*a[0] + a[1]*a[1] + a[2]*a[2]); +} + +static void gl2psGetNormal(GLfloat *a, GLfloat *b, GLfloat *c) +{ + GLfloat norm; + + gl2psPvec(a, b, c); + if(!GL2PS_ZERO(norm = gl2psNorm(c))){ + c[0] = c[0] / norm; + c[1] = c[1] / norm; + c[2] = c[2] / norm; + } + else{ + /* The plane is still wrong despite our tests in gl2psGetPlane. + Let's return a dummy value for now (this is a hack: we should + do more intelligent tests in GetPlane) */ + c[0] = c[1] = 0.0F; + c[2] = 1.0F; + } +} + +static void gl2psGetPlane(GL2PSprimitive *prim, GL2PSplane plane) +{ + GL2PSxyz v = {0.0F, 0.0F, 0.0F}, w = {0.0F, 0.0F, 0.0F}; + + 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])) || + (GL2PS_ZERO(w[0]) && GL2PS_ZERO(w[1]) && GL2PS_ZERO(w[2]))){ + plane[0] = plane[1] = 0.0F; + plane[2] = 1.0F; + plane[3] = -prim->verts[0].xyz[2]; + } + else{ + gl2psGetNormal(v, w, plane); + 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]; + if(GL2PS_ZERO(v[0]) && GL2PS_ZERO(v[1]) && GL2PS_ZERO(v[2])){ + plane[0] = plane[1] = 0.0F; + plane[2] = 1.0F; + plane[3] = -prim->verts[0].xyz[2]; + } + else{ + if(GL2PS_ZERO(v[0])) w[0] = 1.0F; + 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[2] * prim->verts[0].xyz[2]; + } + break; + case GL2PS_POINT : + case GL2PS_PIXMAP : + case GL2PS_TEXT : + case GL2PS_SPECIAL : + case GL2PS_IMAGEMAP: + plane[0] = plane[1] = 0.0F; + plane[2] = 1.0F; + plane[3] = -prim->verts[0].xyz[2]; + break; + default : + gl2psMsg(GL2PS_ERROR, "Unknown primitive type in BSP tree"); + plane[0] = plane[1] = plane[3] = 0.0F; + plane[2] = 1.0F; + break; + } +} + +static void gl2psCutEdge(GL2PSvertex *a, GL2PSvertex *b, GL2PSplane plane, + GL2PSvertex *c) +{ + GL2PSxyz v; + GLfloat sect, psca; + + v[0] = b->xyz[0] - a->xyz[0]; + v[1] = b->xyz[1] - a->xyz[1]; + v[2] = b->xyz[2] - a->xyz[2]; + + if(!GL2PS_ZERO(psca = gl2psPsca(plane, v))) + 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]; + c->rgba[3] = (1 - sect) * a->rgba[3] + sect * b->rgba[3]; +} + +static void gl2psCreateSplitPrimitive(GL2PSprimitive *parent, GL2PSplane plane, + GL2PSprimitive *child, GLshort numverts, + GLshort *index0, GLshort *index1) +{ + GLshort i; + + if(parent->type == GL2PS_IMAGEMAP){ + child->type = GL2PS_IMAGEMAP; + child->data.image = parent->data.image; + } + else{ + if(numverts > 4){ + gl2psMsg(GL2PS_WARNING, "%d vertices in polygon", numverts); + 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; + default: child->type = GL2PS_NO_TYPE; break; + } + } + + child->boundary = 0; /* FIXME: not done! */ + child->culled = parent->culled; + child->offset = parent->offset; + child->pattern = parent->pattern; + child->factor = parent->factor; + child->width = parent->width; + child->numverts = numverts; + child->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex)); + + for(i = 0; i < numverts; i++){ + if(index1[i] < 0){ + child->verts[i] = parent->verts[index0[i]]; + } + else{ + gl2psCutEdge(&parent->verts[index0[i]], &parent->verts[index1[i]], + plane, &child->verts[i]); + } + } +} + +static void gl2psAddIndex(GLshort *index0, GLshort *index1, GLshort *nb, + GLshort i, GLshort j) +{ + GLint k; + + for(k = 0; k < *nb; k++){ + if((index0[k] == i && index1[k] == j) || + (index1[k] == i && index0[k] == j)) return; + } + index0[*nb] = i; + index1[*nb] = j; + (*nb)++; +} + +static GLshort gl2psGetIndex(GLshort i, GLshort num) +{ + return (i < num - 1) ? i + 1 : 0; +} + +static GLint gl2psTestSplitPrimitive(GL2PSprimitive *prim, GL2PSplane plane) +{ + GLint type = GL2PS_COINCIDENT; + GLshort i, j; + GLfloat d[5]; + + for(i = 0; i < prim->numverts; i++){ + d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane); + } + + if(prim->numverts < 2){ + return 0; + } + else{ + for(i = 0; i < prim->numverts; i++){ + 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; + if(d[i] < -GL2PS_EPSILON) return 1; + } + else if(d[j] < -GL2PS_EPSILON){ + 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; + } + } + } + return 0; +} + +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]; + + type = GL2PS_COINCIDENT; + + for(i = 0; i < prim->numverts; i++){ + d[i] = gl2psComparePointPlane(prim->verts[i].xyz, plane); + } + + switch(prim->type){ + case GL2PS_POINT : + if(d[0] > GL2PS_EPSILON) type = GL2PS_IN_BACK_OF; + else if(d[0] < -GL2PS_EPSILON) type = GL2PS_IN_FRONT_OF; + else type = GL2PS_COINCIDENT; + break; + default : + for(i = 0; i < prim->numverts; i++){ + 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; + if(d[i] < -GL2PS_EPSILON){ + gl2psAddIndex(in0, in1, &in, i, j); + gl2psAddIndex(out0, out1, &out, i, j); + type = GL2PS_SPANNING; + } + gl2psAddIndex(out0, out1, &out, j, -1); + } + else if(d[j] < -GL2PS_EPSILON){ + 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); + gl2psAddIndex(out0, out1, &out, i, j); + type = GL2PS_SPANNING; + } + gl2psAddIndex(in0, in1, &in, j, -1); + } + else{ + gl2psAddIndex(in0, in1, &in, j, -1); + gl2psAddIndex(out0, out1, &out, j, -1); + } + } + break; + } + + if(type == GL2PS_SPANNING){ + *back = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); + *front = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); + gl2psCreateSplitPrimitive(prim, plane, *back, out, out0, out1); + gl2psCreateSplitPrimitive(prim, plane, *front, in, in0, in1); + } + + return type; +} + +static void gl2psDivideQuad(GL2PSprimitive *quad, + GL2PSprimitive **t1, GL2PSprimitive **t2) +{ + *t1 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); + *t2 = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); + (*t1)->type = (*t2)->type = GL2PS_TRIANGLE; + (*t1)->numverts = (*t2)->numverts = 3; + (*t1)->culled = (*t2)->culled = quad->culled; + (*t1)->offset = (*t2)->offset = quad->offset; + (*t1)->pattern = (*t2)->pattern = quad->pattern; + (*t1)->factor = (*t2)->factor = quad->factor; + (*t1)->width = (*t2)->width = quad->width; + (*t1)->verts = (GL2PSvertex*)gl2psMalloc(3 * sizeof(GL2PSvertex)); + (*t2)->verts = (GL2PSvertex*)gl2psMalloc(3 * sizeof(GL2PSvertex)); + (*t1)->verts[0] = quad->verts[0]; + (*t1)->verts[1] = quad->verts[1]; + (*t1)->verts[2] = quad->verts[2]; + (*t1)->boundary = ((quad->boundary & 1) ? 1 : 0) | ((quad->boundary & 2) ? 2 : 0); + (*t2)->verts[0] = quad->verts[0]; + (*t2)->verts[1] = quad->verts[2]; + (*t2)->verts[2] = quad->verts[3]; + (*t2)->boundary = ((quad->boundary & 4) ? 2 : 0) | ((quad->boundary & 8) ? 4 : 0); +} + +static int gl2psCompareDepth(const void *a, const void *b) +{ + const GL2PSprimitive *q, *w; + GLfloat dq = 0.0F, dw = 0.0F, diff; + int i; + + q = *(const GL2PSprimitive* const*)a; + w = *(const GL2PSprimitive* const*)b; + + for(i = 0; i < q->numverts; i++){ + dq += q->verts[i].xyz[2]; + } + dq /= (GLfloat)q->numverts; + + for(i = 0; i < w->numverts; i++){ + dw += w->verts[i].xyz[2]; + } + dw /= (GLfloat)w->numverts; + + diff = dq - dw; + if(diff > 0.){ + return -1; + } + else if(diff < 0.){ + return 1; + } + else{ + return 0; + } +} + +static int gl2psTrianglesFirst(const void *a, const void *b) +{ + const GL2PSprimitive *q, *w; + + q = *(const GL2PSprimitive* const*)a; + w = *(const GL2PSprimitive* const*)b; + return (q->type < w->type ? 1 : -1); +} + +static GLint gl2psFindRoot(GL2PSlist *primitives, GL2PSprimitive **root) +{ + GLint i, j, count, best = 1000000, index = 0; + GL2PSprimitive *prim1, *prim2; + GL2PSplane plane; + GLint maxp; + + if(!gl2psListNbr(primitives)){ + gl2psMsg(GL2PS_ERROR, "Cannot fint root in empty primitive list"); + return 0; + } + + *root = *(GL2PSprimitive**)gl2psListPointer(primitives, 0); + + if(gl2ps->options & GL2PS_BEST_ROOT){ + maxp = gl2psListNbr(primitives); + if(maxp > gl2ps->maxbestroot){ + maxp = gl2ps->maxbestroot; + } + for(i = 0; i < maxp; i++){ + prim1 = *(GL2PSprimitive**)gl2psListPointer(primitives, i); + gl2psGetPlane(prim1, plane); + count = 0; + for(j = 0; j < gl2psListNbr(primitives); j++){ + if(j != i){ + prim2 = *(GL2PSprimitive**)gl2psListPointer(primitives, j); + count += gl2psTestSplitPrimitive(prim2, plane); + } + if(count > best) break; + } + if(count < best){ + best = count; + index = i; + *root = prim1; + if(!count) return index; + } + } + /* if(index) gl2psMsg(GL2PS_INFO, "GL2PS_BEST_ROOT was worth it: %d", index); */ + return index; + } + else{ + return 0; + } +} + +static void gl2psFreeImagemap(GL2PSimagemap *list) +{ + GL2PSimagemap *next; + while(list != NULL){ + next = list->next; + gl2psFree(list->image->pixels); + gl2psFree(list->image); + gl2psFree(list); + list = next; + } +} + +static void gl2psFreePrimitive(void *data) +{ + GL2PSprimitive *q; + + q = *(GL2PSprimitive**)data; + gl2psFree(q->verts); + if(q->type == GL2PS_TEXT || q->type == GL2PS_SPECIAL){ + gl2psFreeText(q->data.text); + } + else if(q->type == GL2PS_PIXMAP){ + gl2psFreePixmap(q->data.image); + } + gl2psFree(q); +} + +static void gl2psAddPrimitiveInList(GL2PSprimitive *prim, GL2PSlist *list) +{ + GL2PSprimitive *t1, *t2; + + if(prim->type != GL2PS_QUADRANGLE){ + gl2psListAdd(list, &prim); + } + else{ + gl2psDivideQuad(prim, &t1, &t2); + gl2psListAdd(list, &t1); + gl2psListAdd(list, &t2); + gl2psFreePrimitive(&prim); + } + +} + +static void gl2psFreeBspTree(GL2PSbsptree **tree) +{ + if(*tree){ + if((*tree)->back) gl2psFreeBspTree(&(*tree)->back); + if((*tree)->primitives){ + gl2psListAction((*tree)->primitives, gl2psFreePrimitive); + gl2psListDelete((*tree)->primitives); + } + if((*tree)->front) gl2psFreeBspTree(&(*tree)->front); + gl2psFree(*tree); + *tree = NULL; + } +} + +static GLboolean gl2psGreater(GLfloat f1, GLfloat f2) +{ + if(f1 > f2) return GL_TRUE; + else return GL_FALSE; +} + +static GLboolean gl2psLess(GLfloat f1, GLfloat f2) +{ + if(f1 < f2) return GL_TRUE; + else return GL_FALSE; +} + +static void gl2psBuildBspTree(GL2PSbsptree *tree, GL2PSlist *primitives) +{ + GL2PSprimitive *prim, *frontprim = NULL, *backprim = NULL; + GL2PSlist *frontlist, *backlist; + GLint i, index; + + tree->front = NULL; + tree->back = NULL; + tree->primitives = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); + index = gl2psFindRoot(primitives, &prim); + gl2psGetPlane(prim, tree->plane); + gl2psAddPrimitiveInList(prim, tree->primitives); + + frontlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); + backlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); + + for(i = 0; i < gl2psListNbr(primitives); i++){ + if(i != index){ + prim = *(GL2PSprimitive**)gl2psListPointer(primitives,i); + switch(gl2psSplitPrimitive(prim, tree->plane, &frontprim, &backprim)){ + case GL2PS_COINCIDENT: + gl2psAddPrimitiveInList(prim, tree->primitives); + break; + case GL2PS_IN_BACK_OF: + gl2psAddPrimitiveInList(prim, backlist); + break; + case GL2PS_IN_FRONT_OF: + gl2psAddPrimitiveInList(prim, frontlist); + break; + case GL2PS_SPANNING: + gl2psAddPrimitiveInList(backprim, backlist); + gl2psAddPrimitiveInList(frontprim, frontlist); + gl2psFreePrimitive(&prim); + break; + } + } + } + + if(gl2psListNbr(tree->primitives)){ + gl2psListSort(tree->primitives, gl2psTrianglesFirst); + } + + if(gl2psListNbr(frontlist)){ + gl2psListSort(frontlist, gl2psTrianglesFirst); + tree->front = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree)); + gl2psBuildBspTree(tree->front, frontlist); + } + else{ + gl2psListDelete(frontlist); + } + + if(gl2psListNbr(backlist)){ + gl2psListSort(backlist, gl2psTrianglesFirst); + tree->back = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree)); + gl2psBuildBspTree(tree->back, backlist); + } + else{ + gl2psListDelete(backlist); + } + + gl2psListDelete(primitives); +} + +static void gl2psTraverseBspTree(GL2PSbsptree *tree, GL2PSxyz eye, GLfloat epsilon, + GLboolean (*compare)(GLfloat f1, GLfloat f2), + void (*action)(void *data), int inverse) +{ + GLfloat result; + + if(!tree) return; + + result = gl2psComparePointPlane(eye, tree->plane); + + if(GL_TRUE == compare(result, epsilon)){ + gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse); + if(inverse){ + gl2psListActionInverse(tree->primitives, action); + } + else{ + gl2psListAction(tree->primitives, action); + } + gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); + } + else if(GL_TRUE == compare(-epsilon, result)){ + gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); + if(inverse){ + gl2psListActionInverse(tree->primitives, action); + } + else{ + gl2psListAction(tree->primitives, action); + } + gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse); + } + else{ + gl2psTraverseBspTree(tree->front, eye, epsilon, compare, action, inverse); + gl2psTraverseBspTree(tree->back, eye, epsilon, compare, action, inverse); + } +} + +static void gl2psRescaleAndOffset(void) +{ + GL2PSprimitive *prim; + GLfloat minZ, maxZ, rangeZ, scaleZ; + GLfloat factor, units, area, dZ, dZdX, dZdY, maxdZ; + int i, j; + + if(!gl2psListNbr(gl2ps->primitives)) + return; + + /* get z-buffer range */ + prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, 0); + minZ = maxZ = prim->verts[0].xyz[2]; + for(i = 1; i < prim->numverts; i++){ + if(prim->verts[i].xyz[2] < minZ) minZ = prim->verts[i].xyz[2]; + if(prim->verts[i].xyz[2] > maxZ) maxZ = prim->verts[i].xyz[2]; + } + for(i = 1; i < gl2psListNbr(gl2ps->primitives); i++){ + prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, i); + for(j = 0; j < prim->numverts; j++){ + if(prim->verts[j].xyz[2] < minZ) minZ = prim->verts[j].xyz[2]; + if(prim->verts[j].xyz[2] > maxZ) maxZ = prim->verts[j].xyz[2]; + } + } + rangeZ = (maxZ - minZ); + + /* rescale z-buffer coordinate in [0,GL2PS_ZSCALE], to make it of + the same order of magnitude as the x and y coordinates */ + scaleZ = GL2PS_ZERO(rangeZ) ? GL2PS_ZSCALE : (GL2PS_ZSCALE / rangeZ); + /* avoid precision loss (we use floats!) */ + if(scaleZ > 100000.F) scaleZ = 100000.F; + + /* apply offsets */ + for(i = 0; i < gl2psListNbr(gl2ps->primitives); i++){ + prim = *(GL2PSprimitive**)gl2psListPointer(gl2ps->primitives, i); + for(j = 0; j < prim->numverts; j++){ + prim->verts[j].xyz[2] = (prim->verts[j].xyz[2] - minZ) * scaleZ; + } + if((gl2ps->options & GL2PS_SIMPLE_LINE_OFFSET) && + (prim->type == GL2PS_LINE)){ + if(gl2ps->sort == GL2PS_SIMPLE_SORT){ + prim->verts[0].xyz[2] -= GL2PS_ZOFFSET_LARGE; + prim->verts[1].xyz[2] -= GL2PS_ZOFFSET_LARGE; + } + else{ + prim->verts[0].xyz[2] -= GL2PS_ZOFFSET; + prim->verts[1].xyz[2] -= GL2PS_ZOFFSET; + } + } + 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]) * + (prim->verts[1].xyz[1] - prim->verts[0].xyz[1]); + if(!GL2PS_ZERO(area)){ + 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 = + ((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]) * + (prim->verts[1].xyz[2] - prim->verts[0].xyz[2])) / area; + maxdZ = (GLfloat)sqrt(dZdX * dZdX + dZdY * dZdY); + } + else{ + maxdZ = 0.0F; + } + dZ = factor * maxdZ + units; + prim->verts[0].xyz[2] += dZ; + prim->verts[1].xyz[2] += dZ; + prim->verts[2].xyz[2] += dZ; + } + } +} + +/********************************************************************* + * + * 2D sorting routines (for occlusion culling) + * + *********************************************************************/ + +static GLint gl2psGetPlaneFromPoints(GL2PSxyz a, GL2PSxyz b, GL2PSplane plane) +{ + GLfloat n; + + plane[0] = b[1] - a[1]; + plane[1] = a[0] - b[0]; + n = (GLfloat)sqrt(plane[0]*plane[0] + plane[1]*plane[1]); + plane[2] = 0.0F; + if(!GL2PS_ZERO(n)){ + plane[0] /= n; + plane[1] /= n; + plane[3] = -plane[0]*a[0]-plane[1]*a[1]; + return 1; + } + else{ + plane[0] = -1.0F; + plane[1] = 0.0F; + plane[3] = a[0]; + return 0; + } +} + +static void gl2psFreeBspImageTree(GL2PSbsptree2d **tree) +{ + if(*tree){ + if((*tree)->back) gl2psFreeBspImageTree(&(*tree)->back); + if((*tree)->front) gl2psFreeBspImageTree(&(*tree)->front); + gl2psFree(*tree); + *tree = NULL; + } +} + +static GLint gl2psCheckPoint(GL2PSxyz point, GL2PSplane plane) +{ + GLfloat pt_dis; + + pt_dis = gl2psComparePointPlane(point, plane); + if(pt_dis > GL2PS_EPSILON) return GL2PS_POINT_INFRONT; + else if(pt_dis < -GL2PS_EPSILON) return GL2PS_POINT_BACK; + else return GL2PS_POINT_COINCIDENT; +} + +static void gl2psAddPlanesInBspTreeImage(GL2PSprimitive *prim, + GL2PSbsptree2d **tree) +{ + GLint ret = 0; + GLint i; + GLint offset = 0; + GL2PSbsptree2d *head = NULL, *cur = NULL; + + if((*tree == NULL) && (prim->numverts > 2)){ + /* don't cull if transparent + for(i = 0; i < prim->numverts - 1; i++) + if(prim->verts[i].rgba[3] < 1.0F) return; + */ + head = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); + for(i = 0; i < prim->numverts-1; i++){ + if(!gl2psGetPlaneFromPoints(prim->verts[i].xyz, + prim->verts[i+1].xyz, + head->plane)){ + if(prim->numverts-i > 3){ + offset++; + } + else{ + gl2psFree(head); + return; + } + } + else{ + break; + } + } + head->back = NULL; + head->front = NULL; + for(i = 2+offset; i < prim->numverts; i++){ + ret = gl2psCheckPoint(prim->verts[i].xyz, head->plane); + if(ret != GL2PS_POINT_COINCIDENT) break; + } + switch(ret){ + case GL2PS_POINT_INFRONT : + cur = head; + for(i = 1+offset; i < prim->numverts-1; i++){ + if(cur->front == NULL){ + cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); + } + if(gl2psGetPlaneFromPoints(prim->verts[i].xyz, + prim->verts[i+1].xyz, + cur->front->plane)){ + cur = cur->front; + cur->front = NULL; + cur->back = NULL; + } + } + if(cur->front == NULL){ + cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); + } + if(gl2psGetPlaneFromPoints(prim->verts[i].xyz, + prim->verts[offset].xyz, + cur->front->plane)){ + cur->front->front = NULL; + cur->front->back = NULL; + } + else{ + gl2psFree(cur->front); + cur->front = NULL; + } + break; + case GL2PS_POINT_BACK : + for(i = 0; i < 4; i++){ + head->plane[i] = -head->plane[i]; + } + cur = head; + for(i = 1+offset; i < prim->numverts-1; i++){ + if(cur->front == NULL){ + cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); + } + if(gl2psGetPlaneFromPoints(prim->verts[i+1].xyz, + prim->verts[i].xyz, + cur->front->plane)){ + cur = cur->front; + cur->front = NULL; + cur->back = NULL; + } + } + if(cur->front == NULL){ + cur->front = (GL2PSbsptree2d*)gl2psMalloc(sizeof(GL2PSbsptree2d)); + } + if(gl2psGetPlaneFromPoints(prim->verts[offset].xyz, + prim->verts[i].xyz, + cur->front->plane)){ + cur->front->front = NULL; + cur->front->back = NULL; + } + else{ + gl2psFree(cur->front); + cur->front = NULL; + } + break; + default: + gl2psFree(head); + return; + } + (*tree) = head; + } +} + +static GLint gl2psCheckPrimitive(GL2PSprimitive *prim, GL2PSplane plane) +{ + GLint i; + GLint pos; + + pos = gl2psCheckPoint(prim->verts[0].xyz, plane); + for(i = 1; i < prim->numverts; i++){ + pos |= gl2psCheckPoint(prim->verts[i].xyz, plane); + if(pos == (GL2PS_POINT_INFRONT | GL2PS_POINT_BACK)) return GL2PS_SPANNING; + } + if(pos & GL2PS_POINT_INFRONT) return GL2PS_IN_FRONT_OF; + else if(pos & GL2PS_POINT_BACK) return GL2PS_IN_BACK_OF; + else return GL2PS_COINCIDENT; +} + +static GL2PSprimitive *gl2psCreateSplitPrimitive2D(GL2PSprimitive *parent, + GLshort numverts, + GL2PSvertex *vertx) +{ + GLint i; + GL2PSprimitive *child = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); + + if(parent->type == GL2PS_IMAGEMAP){ + child->type = GL2PS_IMAGEMAP; + child->data.image = parent->data.image; + } + else { + 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; + default: child->type = GL2PS_NO_TYPE; break; /* FIXME */ + } + } + child->boundary = 0; /* FIXME: not done! */ + child->culled = parent->culled; + child->offset = parent->offset; + child->pattern = parent->pattern; + child->factor = parent->factor; + child->width = parent->width; + child->numverts = numverts; + child->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex)); + for(i = 0; i < numverts; i++){ + child->verts[i] = vertx[i]; + } + return child; +} + +static void gl2psSplitPrimitive2D(GL2PSprimitive *prim, + GL2PSplane plane, + GL2PSprimitive **front, + GL2PSprimitive **back) +{ + /* cur will hold the position of the current vertex + prev will hold the position of the previous vertex + prev0 will hold the position of the vertex number 0 + 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; + + for(i = 0; i <= prim->numverts; i++){ + v1 = i; + if(v1 == prim->numverts){ + if(prim->numverts < 3) break; + v1 = 0; + v2 = prim->numverts - 1; + cur = prev0; + } + else if(flag){ + cur = gl2psCheckPoint(prim->verts[v1].xyz, plane); + if(i == 0){ + prev0 = cur; + } + } + if(((prev == -1) || (prev == cur) || (prev == 0) || (cur == 0)) && + (i < prim->numverts)){ + if(cur == GL2PS_POINT_INFRONT){ + front_count++; + front_list = (GL2PSvertex*)gl2psRealloc(front_list, + sizeof(GL2PSvertex)*front_count); + front_list[front_count-1] = prim->verts[v1]; + } + else if(cur == GL2PS_POINT_BACK){ + back_count++; + back_list = (GL2PSvertex*)gl2psRealloc(back_list, + sizeof(GL2PSvertex)*back_count); + back_list[back_count-1] = prim->verts[v1]; + } + else{ + front_count++; + front_list = (GL2PSvertex*)gl2psRealloc(front_list, + sizeof(GL2PSvertex)*front_count); + front_list[front_count-1] = prim->verts[v1]; + back_count++; + back_list = (GL2PSvertex*)gl2psRealloc(back_list, + sizeof(GL2PSvertex)*back_count); + back_list[back_count-1] = prim->verts[v1]; + } + flag = 1; + } + else if((prev != cur) && (cur != 0) && (prev != 0)){ + if(v1 != 0){ + v2 = v1-1; + i--; + } + front_count++; + front_list = (GL2PSvertex*)gl2psRealloc(front_list, + sizeof(GL2PSvertex)*front_count); + gl2psCutEdge(&prim->verts[v2], &prim->verts[v1], + plane, &front_list[front_count-1]); + back_count++; + back_list = (GL2PSvertex*)gl2psRealloc(back_list, + sizeof(GL2PSvertex)*back_count); + back_list[back_count-1] = front_list[front_count-1]; + flag = 0; + } + prev = cur; + } + *front = gl2psCreateSplitPrimitive2D(prim, front_count, front_list); + *back = gl2psCreateSplitPrimitive2D(prim, back_count, back_list); + gl2psFree(front_list); + gl2psFree(back_list); +} + +static GLint gl2psAddInBspImageTree(GL2PSprimitive *prim, GL2PSbsptree2d **tree) +{ + 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 || + prim->type == GL2PS_SPECIAL){ + return 1; + } + + if(*tree == NULL){ + if((prim->type != GL2PS_IMAGEMAP) && (GL_FALSE == gl2ps->zerosurfacearea)){ + gl2psAddPlanesInBspTreeImage(gl2ps->primitivetoadd, tree); + } + return 1; + } + else{ + switch(gl2psCheckPrimitive(prim, (*tree)->plane)){ + case GL2PS_IN_BACK_OF: return gl2psAddInBspImageTree(prim, &(*tree)->back); + case GL2PS_IN_FRONT_OF: + if((*tree)->front != NULL) return gl2psAddInBspImageTree(prim, &(*tree)->front); + else return 0; + case GL2PS_SPANNING: + gl2psSplitPrimitive2D(prim, (*tree)->plane, &frontprim, &backprim); + ret = gl2psAddInBspImageTree(backprim, &(*tree)->back); + if((*tree)->front != NULL){ + if(gl2psAddInBspImageTree(frontprim, &(*tree)->front)){ + ret = 1; + } + } + gl2psFree(frontprim->verts); + gl2psFree(frontprim); + gl2psFree(backprim->verts); + gl2psFree(backprim); + return ret; + case GL2PS_COINCIDENT: + if((*tree)->back != NULL){ + gl2ps->zerosurfacearea = GL_TRUE; + ret = gl2psAddInBspImageTree(prim, &(*tree)->back); + gl2ps->zerosurfacearea = GL_FALSE; + if(ret) return ret; + } + if((*tree)->front != NULL){ + gl2ps->zerosurfacearea = GL_TRUE; + ret = gl2psAddInBspImageTree(prim, &(*tree)->front); + gl2ps->zerosurfacearea = GL_FALSE; + if(ret) return ret; + } + if(prim->type == GL2PS_LINE) return 1; + else return 0; + } + } + return 0; +} + +static void gl2psAddInImageTree(void *data) +{ + GL2PSprimitive *prim = *(GL2PSprimitive **)data; + gl2ps->primitivetoadd = prim; + if(prim->type == GL2PS_IMAGEMAP && prim->data.image->format == GL2PS_IMAGEMAP_VISIBLE){ + prim->culled = 1; + } + else if(!gl2psAddInBspImageTree(prim, &gl2ps->imagetree)){ + prim->culled = 1; + } + else if(prim->type == GL2PS_IMAGEMAP){ + prim->data.image->format = GL2PS_IMAGEMAP_VISIBLE; + } +} + +/* Boundary construction */ + +static void gl2psAddBoundaryInList(GL2PSprimitive *prim, GL2PSlist *list) +{ + GL2PSprimitive *b; + GLshort i; + GL2PSxyz c; + + c[0] = c[1] = c[2] = 0.0F; + for(i = 0; i < prim->numverts; i++){ + c[0] += prim->verts[i].xyz[0]; + c[1] += prim->verts[i].xyz[1]; + } + c[0] /= prim->numverts; + c[1] /= prim->numverts; + + for(i = 0; i < prim->numverts; i++){ + if(prim->boundary & (GLint)pow(2., i)){ + b = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); + b->type = GL2PS_LINE; + b->offset = prim->offset; + b->pattern = prim->pattern; + b->factor = prim->factor; + b->culled = prim->culled; + b->width = prim->width; + b->boundary = 0; + b->numverts = 2; + b->verts = (GL2PSvertex*)gl2psMalloc(2 * sizeof(GL2PSvertex)); + +#if 0 /* FIXME: need to work on boundary offset... */ + v[0] = c[0] - prim->verts[i].xyz[0]; + v[1] = c[1] - prim->verts[i].xyz[1]; + v[2] = 0.0F; + norm = gl2psNorm(v); + v[0] /= norm; + v[1] /= norm; + b->verts[0].xyz[0] = prim->verts[i].xyz[0] +0.1*v[0]; + b->verts[0].xyz[1] = prim->verts[i].xyz[1] +0.1*v[1]; + b->verts[0].xyz[2] = prim->verts[i].xyz[2]; + v[0] = c[0] - prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0]; + v[1] = c[1] - prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1]; + norm = gl2psNorm(v); + v[0] /= norm; + v[1] /= norm; + b->verts[1].xyz[0] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0] +0.1*v[0]; + b->verts[1].xyz[1] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1] +0.1*v[1]; + b->verts[1].xyz[2] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[2]; +#else + b->verts[0].xyz[0] = prim->verts[i].xyz[0]; + b->verts[0].xyz[1] = prim->verts[i].xyz[1]; + b->verts[0].xyz[2] = prim->verts[i].xyz[2]; + b->verts[1].xyz[0] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[0]; + b->verts[1].xyz[1] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[1]; + b->verts[1].xyz[2] = prim->verts[gl2psGetIndex(i, prim->numverts)].xyz[2]; +#endif + + b->verts[0].rgba[0] = 0.0F; + b->verts[0].rgba[1] = 0.0F; + b->verts[0].rgba[2] = 0.0F; + b->verts[0].rgba[3] = 0.0F; + b->verts[1].rgba[0] = 0.0F; + b->verts[1].rgba[1] = 0.0F; + b->verts[1].rgba[2] = 0.0F; + b->verts[1].rgba[3] = 0.0F; + gl2psListAdd(list, &b); + } + } + +} + +static void gl2psBuildPolygonBoundary(GL2PSbsptree *tree) +{ + GLint i; + GL2PSprimitive *prim; + + if(!tree) return; + gl2psBuildPolygonBoundary(tree->back); + for(i = 0; i < gl2psListNbr(tree->primitives); i++){ + prim = *(GL2PSprimitive**)gl2psListPointer(tree->primitives, i); + if(prim->boundary) gl2psAddBoundaryInList(prim, tree->primitives); + } + gl2psBuildPolygonBoundary(tree->front); +} + +/********************************************************************* + * + * Feedback buffer parser + * + *********************************************************************/ + +static void gl2psAddPolyPrimitive(GLshort type, GLshort numverts, + GL2PSvertex *verts, GLint offset, + GLushort pattern, GLint factor, + GLfloat width, char boundary) +{ + GL2PSprimitive *prim; + + prim = (GL2PSprimitive*)gl2psMalloc(sizeof(GL2PSprimitive)); + prim->type = type; + prim->numverts = numverts; + prim->verts = (GL2PSvertex*)gl2psMalloc(numverts * sizeof(GL2PSvertex)); + memcpy(prim->verts, verts, numverts * sizeof(GL2PSvertex)); + prim->boundary = boundary; + prim->offset = offset; + prim->pattern = pattern; + prim->factor = factor; + prim->width = width; + prim->culled = 0; + + /* FIXME: here we should have an option to split stretched + tris/quads to enhance SIMPLE_SORT */ + + gl2psListAdd(gl2ps->primitives, &prim); +} + +static GLint gl2psGetVertex(GL2PSvertex *v, GLfloat *p) +{ + GLint i; + + v->xyz[0] = p[0]; + v->xyz[1] = p[1]; + v->xyz[2] = p[2]; + + if(gl2ps->colormode == GL_COLOR_INDEX && gl2ps->colorsize > 0){ + i = (GLint)(p[3] + 0.5); + v->rgba[0] = gl2ps->colormap[i][0]; + v->rgba[1] = gl2ps->colormap[i][1]; + v->rgba[2] = gl2ps->colormap[i][2]; + v->rgba[3] = gl2ps->colormap[i][3]; + return 4; + } + else{ + v->rgba[0] = p[3]; + v->rgba[1] = p[4]; + v->rgba[2] = p[5]; + v->rgba[3] = p[6]; + return 7; + } +} + +static void gl2psParseFeedbackBuffer(GLint used) +{ + char flag; + GLushort pattern = 0; + GLboolean boundary; + GLint i, sizeoffloat, count, v, vtot, offset = 0, factor = 0, auxindex = 0; + GLfloat lwidth = 1.0F, psize = 1.0F; + GLfloat *current; + GL2PSvertex vertices[3]; + GL2PSprimitive *prim; + GL2PSimagemap *node; + + current = gl2ps->feedback; + boundary = gl2ps->boundary = GL_FALSE; + + while(used > 0){ + + if(GL_TRUE == boundary) gl2ps->boundary = GL_TRUE; + + switch((GLint)*current){ + case GL_POINT_TOKEN : + current ++; + used --; + i = gl2psGetVertex(&vertices[0], current); + current += i; + used -= i; + gl2psAddPolyPrimitive(GL2PS_POINT, 1, vertices, 0, + pattern, factor, psize, 0); + break; + case GL_LINE_TOKEN : + case GL_LINE_RESET_TOKEN : + current ++; + used --; + i = gl2psGetVertex(&vertices[0], current); + current += i; + used -= i; + i = gl2psGetVertex(&vertices[1], current); + current += i; + used -= i; + gl2psAddPolyPrimitive(GL2PS_LINE, 2, vertices, 0, + pattern, factor, lwidth, 0); + break; + case GL_POLYGON_TOKEN : + count = (GLint)current[1]; + current += 2; + used -= 2; + v = vtot = 0; + while(count > 0 && used > 0){ + i = gl2psGetVertex(&vertices[v], current); + gl2psAdaptVertexForBlending(&vertices[v]); + current += i; + used -= i; + count --; + vtot++; + if(v == 2){ + if(GL_TRUE == boundary){ + if(!count && vtot == 2) flag = 1|2|4; + else if(!count) flag = 2|4; + else if(vtot == 2) flag = 1|2; + else flag = 2; + } + else + flag = 0; + gl2psAddPolyPrimitive(GL2PS_TRIANGLE, 3, vertices, offset, + pattern, factor, 1, flag); + vertices[1] = vertices[2]; + } + else + v ++; + } + break; + case GL_BITMAP_TOKEN : + case GL_DRAW_PIXEL_TOKEN : + case GL_COPY_PIXEL_TOKEN : + current ++; + used --; + i = gl2psGetVertex(&vertices[0], current); + current += i; + used -= i; + break; + case GL_PASS_THROUGH_TOKEN : + switch((GLint)current[1]){ + case GL2PS_BEGIN_OFFSET_TOKEN : offset = 1; break; + case GL2PS_END_OFFSET_TOKEN : offset = 0; break; + case GL2PS_BEGIN_BOUNDARY_TOKEN : boundary = GL_TRUE; break; + case GL2PS_END_BOUNDARY_TOKEN : boundary = GL_FALSE; break; + 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 : + current += 2; + used -= 2; + pattern = (GLushort)current[1]; + current += 2; + used -= 2; + factor = (GLint)current[1]; + break; + 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; + gl2ps->blendfunc[1] = (GLint)current[1]; + break; + case GL2PS_POINT_SIZE_TOKEN : + current += 2; + used -= 2; + psize = current[1]; + break; + case GL2PS_LINE_WIDTH_TOKEN : + current += 2; + used -= 2; + lwidth = current[1]; + break; + case GL2PS_IMAGEMAP_TOKEN : + prim = (GL2PSprimitive *)gl2psMalloc(sizeof(GL2PSprimitive)); + prim->type = GL2PS_IMAGEMAP; + prim->boundary = 0; + prim->numverts = 4; + prim->verts = (GL2PSvertex *)gl2psMalloc(4 * sizeof(GL2PSvertex)); + prim->culled = 0; + prim->offset = 0; + 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]; + prim->verts[0].xyz[0] = prim->verts[0].xyz[0] - (int)(node->image->width / 2) + 0.5F; + prim->verts[0].xyz[1] = prim->verts[0].xyz[1] - (int)(node->image->height / 2) + 0.5F; + for(i = 1; i < 4; i++){ + for(v = 0; v < 3; v++){ + prim->verts[i].xyz[v] = prim->verts[0].xyz[v]; + prim->verts[i].rgba[v] = prim->verts[0].rgba[v]; + } + prim->verts[i].rgba[v] = prim->verts[0].rgba[v]; + } + prim->verts[1].xyz[0] = prim->verts[1].xyz[0] + node->image->width; + prim->verts[2].xyz[0] = prim->verts[1].xyz[0]; + prim->verts[2].xyz[1] = prim->verts[2].xyz[1] + node->image->height; + prim->verts[3].xyz[1] = prim->verts[2].xyz[1]; + + sizeoffloat = sizeof(GLfloat); + v = 2 * sizeoffloat; + 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) + memcpy(&(((char*)(node->image->pixels))[i + v]), &(current[2]), sizeoffloat); + else + memcpy(&(((char*)(node->image->pixels))[i + v]), &(current[2]), vtot - i); + } + current++; used--; + gl2psListAdd(gl2ps->primitives, &prim); + break; + case GL2PS_DRAW_PIXELS_TOKEN : + case GL2PS_TEXT_TOKEN : + if(auxindex < gl2psListNbr(gl2ps->auxprimitives)) + gl2psListAdd(gl2ps->primitives, + gl2psListPointer(gl2ps->auxprimitives, auxindex++)); + else + gl2psMsg(GL2PS_ERROR, "Wrong number of auxiliary tokens in buffer"); + break; + } + current += 2; + used -= 2; + break; + default : + gl2psMsg(GL2PS_WARNING, "Unknown token in buffer"); + current ++; + used --; + break; + } + } + + gl2psListReset(gl2ps->auxprimitives); +} + +/********************************************************************* + * + * PostScript routines + * + *********************************************************************/ + +static void gl2psWriteByte(unsigned char byte) +{ + unsigned char h = byte / 16; + unsigned char l = byte % 16; + gl2psPrintf("%x%x", h, l); +} + +static void gl2psPrintPostScriptPixmap(GLfloat x, GLfloat y, GL2PSimage *im) +{ + GLuint nbhex, nbyte, nrgb, nbits; + GLuint row, col, ibyte, icase; + GLfloat dr, dg, db, fgrey; + unsigned char red = 0, green = 0, blue = 0, b, grey; + GLuint width = (GLuint)im->width; + GLuint height = (GLuint)im->height; + + /* FIXME: should we define an option for these? Or just keep the + 8-bit per component case? */ + int greyscale = 0; /* set to 1 to output greyscale image */ + int nbit = 8; /* number of bits per color compoment (2, 4 or 8) */ + + 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); + + 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("{ currentfile picstr readhexstring pop }\n"); + gl2psPrintf("image\n"); + for(row = 0; row < height; row++){ + 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); + gl2psWriteByte(grey); + } + gl2psPrintf("\n"); + } + 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; + nbits = nrgb * nbit; + nbyte = nbits / 8; + 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); + gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n"); + gl2psPrintf("false 3\n"); + gl2psPrintf("colorimage\n"); + for(row = 0; row < height; row++){ + icase = 1; + col = 0; + b = 0; + for(ibyte = 0; ibyte < nbyte; ibyte++){ + if(icase == 1) { + if(col < width) { + gl2psGetRGB(im, col, row, &dr, &dg, &db); + } + else { + dr = dg = db = 0; + } + col++; + red = (unsigned char)(3. * dr); + green = (unsigned char)(3. * dg); + blue = (unsigned char)(3. * db); + b = red; + b = (b<<2) + green; + b = (b<<2) + blue; + if(col < width) { + gl2psGetRGB(im, col, row, &dr, &dg, &db); + } + else { + dr = dg = db = 0; + } + col++; + red = (unsigned char)(3. * dr); + green = (unsigned char)(3. * dg); + blue = (unsigned char)(3. * db); + b = (b<<2) + red; + gl2psWriteByte(b); + b = 0; + icase++; + } + else if(icase == 2) { + b = green; + b = (b<<2) + blue; + if(col < width) { + gl2psGetRGB(im, col, row, &dr, &dg, &db); + } + else { + dr = dg = db = 0; + } + col++; + red = (unsigned char)(3. * dr); + green = (unsigned char)(3. * dg); + blue = (unsigned char)(3. * db); + b = (b<<2) + red; + b = (b<<2) + green; + gl2psWriteByte(b); + b = 0; + icase++; + } + else if(icase == 3) { + b = blue; + if(col < width) { + gl2psGetRGB(im, col, row, &dr, &dg, &db); + } + else { + dr = dg = db = 0; + } + col++; + red = (unsigned char)(3. * dr); + green = (unsigned char)(3. * dg); + blue = (unsigned char)(3. * db); + b = (b<<2) + red; + b = (b<<2) + green; + b = (b<<2) + blue; + gl2psWriteByte(b); + b = 0; + icase = 1; + } + } + gl2psPrintf("\n"); + } + } + else if(nbit == 4){ /* color, 4 bits for r and g and b; rgbs following each other */ + nrgb = width * 3; + nbits = nrgb * nbit; + nbyte = nbits / 8; + 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); + gl2psPrintf("{ currentfile rgbstr readhexstring pop }\n"); + gl2psPrintf("false 3\n"); + gl2psPrintf("colorimage\n"); + for(row = 0; row < height; row++){ + col = 0; + icase = 1; + for(ibyte = 0; ibyte < nbyte; ibyte++){ + if(icase == 1) { + if(col < width) { + gl2psGetRGB(im, col, row, &dr, &dg, &db); + } + else { + dr = dg = db = 0; + } + col++; + red = (unsigned char)(15. * dr); + 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; + } + col++; + red = (unsigned char)(15. * dr); + gl2psPrintf("%x%x", blue, red); + icase++; + } + else if(icase == 3) { + green = (unsigned char)(15. * dg); + blue = (unsigned char)(15. * db); + gl2psPrintf("%x%x", green, blue); + icase = 1; + } + } + gl2psPrintf("\n"); + } + } + else{ /* 8 bit for r and g and b */ + 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("{ currentfile rgbstr readhexstring pop }\n"); + gl2psPrintf("false 3\n"); + gl2psPrintf("colorimage\n"); + for(row = 0; row < height; row++){ + for(col = 0; col < width; col++){ + gl2psGetRGB(im, col, row, &dr, &dg, &db); + red = (unsigned char)(255. * dr); + gl2psWriteByte(red); + green = (unsigned char)(255. * dg); + gl2psWriteByte(green); + blue = (unsigned char)(255. * db); + gl2psWriteByte(blue); + } + gl2psPrintf("\n"); + } + } + + gl2psPrintf("grestore\n"); +} + +static void gl2psPrintPostScriptImagemap(GLfloat x, GLfloat y, + 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 0 0 -%d 0 %d ] {<", width, height); + for(i = 0; i < size; i++){ + gl2psWriteByte(*imagemap); + imagemap++; + } + gl2psPrintf(">} imagemask\ngrestore\n"); +} + +static void gl2psPrintPostScriptHeader(void) +{ + time_t now; + + /* Since compression is not part of the PostScript standard, + compressed PostScript files are just gzipped PostScript files + ("ps.gz" or "eps.gz") */ + gl2psPrintGzipHeader(); + + time(&now); + + if(gl2ps->format == GL2PS_PS){ + gl2psPrintf("%%!PS-Adobe-3.0\n"); + } + else{ + gl2psPrintf("%%!PS-Adobe-3.0 EPSF-3.0\n"); + } + + gl2psPrintf("%%%%Title: %s\n" + "%%%%Creator: GL2PS %d.%d.%d%s, %s\n" + "%%%%For: %s\n" + "%%%%CreationDate: %s" + "%%%%LanguageLevel: 3\n" + "%%%%DocumentData: Clean7Bit\n" + "%%%%Pages: 1\n", + gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, + GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, + gl2ps->producer, ctime(&now)); + + if(gl2ps->format == GL2PS_PS){ + gl2psPrintf("%%%%Orientation: %s\n" + "%%%%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[3]); + } + + gl2psPrintf("%%%%BoundingBox: %d %d %d %d\n" + "%%%%EndComments\n", + (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] : + (int)gl2ps->viewport[2], + (gl2ps->options & GL2PS_LANDSCAPE) ? (int)gl2ps->viewport[2] : + (int)gl2ps->viewport[3]); + + /* RGB color: r g b C (replace C by G in output to change from rgb to gray) + Grayscale: r g b G + Font choose: size fontname FC + Text string: (string) x y size fontname S?? + Rotated text string: (string) angle x y size fontname S??R + Point primitive: x y size P + Line width: width W + Line start: x y LS + Line joining last point: x y L + Line end: x y LE + Flat-shaded triangle: x3 y3 x2 y2 x1 y1 T + Smooth-shaded triangle: x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 ST */ + + gl2psPrintf("%%%%BeginProlog\n" + "/gl2psdict 64 dict def gl2psdict begin\n" + "0 setlinecap 0 setlinejoin\n" + "/tryPS3shading %s def %% set to false to force subdivision\n" + "/rThreshold %g def %% red component subdivision threshold\n" + "/gThreshold %g def %% green component subdivision threshold\n" + "/bThreshold %g def %% blue component subdivision threshold\n", + (gl2ps->options & GL2PS_NO_PS3_SHADING) ? "false" : "true", + gl2ps->threshold[0], gl2ps->threshold[1], gl2ps->threshold[2]); + + gl2psPrintf("/BD { bind def } bind def\n" + "/C { setrgbcolor } BD\n" + "/G { 0.082 mul exch 0.6094 mul add exch 0.3086 mul add neg 1.0 add setgray } BD\n" + "/W { setlinewidth } BD\n"); + + gl2psPrintf("/FC { findfont exch /SH exch def SH scalefont setfont } BD\n" + "/SW { dup stringwidth pop } BD\n" + "/S { FC moveto show } BD\n" + "/SBC{ FC moveto SW -2 div 0 rmoveto show } BD\n" + "/SBR{ FC moveto SW neg 0 rmoveto show } BD\n" + "/SCL{ FC moveto 0 SH -2 div rmoveto show } BD\n" + "/SCC{ FC moveto SW -2 div SH -2 div rmoveto show } BD\n" + "/SCR{ FC moveto SW neg SH -2 div rmoveto show } BD\n" + "/STL{ FC moveto 0 SH neg rmoveto show } BD\n" + "/STC{ FC moveto SW -2 div SH neg rmoveto show } BD\n" + "/STR{ FC moveto SW neg SH neg rmoveto show } BD\n"); + + /* 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" + "/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"); + gl2psPrintf("/SCCR{ gsave FCT moveto rotate SW -2 div SH -2 div rmoveto show grestore} BD\n" + "/SCRR{ gsave FCT moveto rotate SW neg SH -2 div rmoveto show grestore} BD\n" + "/STLR{ gsave FCT moveto rotate 0 SH neg rmoveto show grestore } BD\n" + "/STCR{ gsave FCT moveto rotate SW -2 div SH neg rmoveto show grestore } BD\n" + "/STRR{ gsave FCT moveto rotate SW neg SH neg rmoveto show grestore } BD\n"); + + gl2psPrintf("/P { newpath 0.0 360.0 arc closepath fill } BD\n" + "/LS { newpath moveto } BD\n" + "/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 */ + + gl2psPrintf("/STshfill {\n" + " /b1 exch def /g1 exch def /r1 exch def /y1 exch def /x1 exch def\n" + " /b2 exch def /g2 exch def /r2 exch def /y2 exch def /x2 exch def\n" + " /b3 exch def /g3 exch def /r3 exch def /y3 exch def /x3 exch def\n" + " gsave << /ShadingType 4 /ColorSpace [/DeviceRGB]\n" + " /DataSource [ 0 x1 y1 r1 g1 b1 0 x2 y2 r2 g2 b2 0 x3 y3 r3 g3 b3 ] >>\n" + " shfill grestore } BD\n"); + + /* Flat-shaded triangle with middle color: + x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 Tm */ + + gl2psPrintf(/* stack : x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 */ + "/Tm { 3 -1 roll 8 -1 roll 13 -1 roll add add 3 div\n" /* r = (r1+r2+r3)/3 */ + /* stack : x3 y3 g3 b3 x2 y2 g2 b2 x1 y1 g1 b1 r */ + " 3 -1 roll 7 -1 roll 11 -1 roll add add 3 div\n" /* g = (g1+g2+g3)/3 */ + /* stack : x3 y3 b3 x2 y2 b2 x1 y1 b1 r g b */ + " 3 -1 roll 6 -1 roll 9 -1 roll add add 3 div" /* b = (b1+b2+b3)/3 */ + /* stack : x3 y3 x2 y2 x1 y1 r g b */ + " C T } BD\n"); + + /* Split triangle in four sub-triangles (at sides middle points) and call the + STnoshfill procedure on each, interpolating the colors in RGB space: + x3 y3 r3 g3 b3 x2 y2 r2 g2 b2 x1 y1 r1 g1 b1 STsplit + (in procedure comments key: (Vi) = xi yi ri gi bi) */ + + gl2psPrintf("/STsplit {\n" + " 4 index 15 index add 0.5 mul\n" /* x13 = (x1+x3)/2 */ + " 4 index 15 index add 0.5 mul\n" /* y13 = (y1+y3)/2 */ + " 4 index 15 index add 0.5 mul\n" /* r13 = (r1+r3)/2 */ + " 4 index 15 index add 0.5 mul\n" /* g13 = (g1+g3)/2 */ + " 4 index 15 index add 0.5 mul\n" /* b13 = (b1+b3)/2 */ + " 5 copy 5 copy 25 15 roll\n"); + + /* at his point, stack = (V3) (V13) (V13) (V13) (V2) (V1) */ + + gl2psPrintf(" 9 index 30 index add 0.5 mul\n" /* x23 = (x2+x3)/2 */ + " 9 index 30 index add 0.5 mul\n" /* y23 = (y2+y3)/2 */ + " 9 index 30 index add 0.5 mul\n" /* r23 = (r2+r3)/2 */ + " 9 index 30 index add 0.5 mul\n" /* g23 = (g2+g3)/2 */ + " 9 index 30 index add 0.5 mul\n" /* b23 = (b2+b3)/2 */ + " 5 copy 5 copy 35 5 roll 25 5 roll 15 5 roll\n"); + + /* stack = (V3) (V13) (V23) (V13) (V23) (V13) (V23) (V2) (V1) */ + + gl2psPrintf(" 4 index 10 index add 0.5 mul\n" /* x12 = (x1+x2)/2 */ + " 4 index 10 index add 0.5 mul\n" /* y12 = (y1+y2)/2 */ + " 4 index 10 index add 0.5 mul\n" /* r12 = (r1+r2)/2 */ + " 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 */ + + gl2psPrintf("/STnoshfill {\n" + " 2 index 8 index sub abs rThreshold gt\n" /* |r1-r2|>rth */ + " { STsplit }\n" + " { 1 index 7 index sub abs gThreshold gt\n" /* |g1-g2|>gth */ + " { STsplit }\n" + " { dup 6 index sub abs bThreshold gt\n" /* |b1-b2|>bth */ + " { STsplit }\n" + " { 2 index 13 index sub abs rThreshold gt\n" /* |r1-r3|>rht */ + " { STsplit }\n" + " { 1 index 12 index sub abs gThreshold gt\n" /* |g1-g3|>gth */ + " { STsplit }\n" + " { dup 11 index sub abs bThreshold gt\n" /* |b1-b3|>bth */ + " { STsplit }\n" + " { 7 index 13 index sub abs rThreshold gt\n"); /* |r2-r3|>rht */ + gl2psPrintf(" { STsplit }\n" + " { 6 index 12 index sub abs gThreshold gt\n" /* |g2-g3|>gth */ + " { STsplit }\n" + " { 5 index 11 index sub abs bThreshold gt\n" /* |b2-b3|>bth */ + " { STsplit }\n" + " { Tm }\n" /* all colors sufficiently similar */ + " ifelse }\n" + " ifelse }\n" + " ifelse }\n" + " ifelse }\n" + " ifelse }\n" + " ifelse }\n" + " ifelse }\n" + " ifelse }\n" + " ifelse } BD\n"); + + gl2psPrintf("tryPS3shading\n" + "{ /shfill where\n" + " { /ST { STshfill } BD }\n" + " { /ST { STnoshfill } BD }\n" + " ifelse }\n" + "{ /ST { STnoshfill } BD }\n" + "ifelse\n"); + + gl2psPrintf("end\n" + "%%%%EndProlog\n" + "%%%%BeginSetup\n" + "/DeviceRGB setcolorspace\n" + "gl2psdict begin\n" + "%%%%EndSetup\n" + "%%%%Page: 1 1\n" + "%%%%BeginPageSetup\n"); + + if(gl2ps->options & GL2PS_LANDSCAPE){ + gl2psPrintf("%d 0 translate 90 rotate\n", + (int)gl2ps->viewport[3]); + } + + gl2psPrintf("%%%%EndPageSetup\n" + "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], + (int)gl2ps->viewport[0], (int)gl2ps->viewport[3]); + } +} + +static void gl2psPrintPostScriptColor(GL2PSrgba rgba) +{ + if(!gl2psSameColor(gl2ps->lastrgba, rgba)){ + gl2psSetLastColor(rgba); + gl2psPrintf("%g %g %g C\n", rgba[0], rgba[1], rgba[2]); + } +} + +static void gl2psResetPostScriptColor(void) +{ + gl2ps->lastrgba[0] = gl2ps->lastrgba[1] = gl2ps->lastrgba[2] = -1.; +} + +static void gl2psEndPostScriptLine(void) +{ + int i; + if(gl2ps->lastvertex.rgba[0] >= 0.){ + gl2psPrintf("%g %g LE\n", gl2ps->lastvertex.xyz[0], gl2ps->lastvertex.xyz[1]); + for(i = 0; i < 3; i++) + gl2ps->lastvertex.xyz[i] = -1.; + for(i = 0; i < 4; i++) + gl2ps->lastvertex.rgba[i] = -1.; + } +} + +static void gl2psParseStipplePattern(GLushort pattern, GLint factor, + int *nb, int array[10]) +{ + int i, n; + int on[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int off[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + char tmp[16]; + + /* extract the 16 bits from the OpenGL stipple pattern */ + for(n = 15; n >= 0; n--){ + tmp[n] = (char)(pattern & 0x01); + pattern >>= 1; + } + /* compute the on/off pixel sequence */ + n = 0; + for(i = 0; i < 8; i++){ + while(n < 16 && !tmp[n]){ off[i]++; n++; } + while(n < 16 && tmp[n]){ on[i]++; n++; } + if(n >= 15){ i++; break; } + } + + /* store the on/off array from right to left, starting with off + pixels. The PostScript specification allows for at most 11 + elements in the on/off array, so we limit ourselves to 5 on/off + couples (our longest possible array is thus [on4 off4 on3 off3 + on2 off2 on1 off1 on0 off0]) */ + *nb = 0; + for(n = i - 1; n >= 0; n--){ + array[(*nb)++] = factor * on[n]; + array[(*nb)++] = factor * off[n]; + if(*nb == 10) break; + } +} + +static int gl2psPrintPostScriptDash(GLushort pattern, GLint factor, const char *str) +{ + int len = 0, i, n, array[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); + } + else{ + gl2psParseStipplePattern(pattern, factor, &n, array); + len += gl2psPrintf("["); + for(i = 0; i < n; i++){ + if(i) len += gl2psPrintf(" "); + len += gl2psPrintf("%d", array[i]); + } + len += gl2psPrintf("] 0 %s\n", str); + } + + return len; +} + +static void gl2psPrintPostScriptPrimitive(void *data) +{ + int newline; + GL2PSprimitive *prim; + + prim = *(GL2PSprimitive**)data; + + if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return; + + /* Every effort is made to draw lines as connected segments (i.e., + using a single PostScript path): this is the only way to get nice + line joins and to not restart the stippling for every line + segment. So if the primitive to print is not a line we must first + finish the current line (if any): */ + if(prim->type != GL2PS_LINE) gl2psEndPostScriptLine(); + + switch(prim->type){ + case GL2PS_POINT : + gl2psPrintPostScriptColor(prim->verts[0].rgba); + gl2psPrintf("%g %g %g P\n", + prim->verts[0].xyz[0], prim->verts[0].xyz[1], 0.5 * prim->width); + break; + case GL2PS_LINE : + if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) || + !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) || + gl2ps->lastlinewidth != prim->width || + gl2ps->lastpattern != prim->pattern || + gl2ps->lastfactor != prim->factor){ + /* End the current line if the new segment does not start where + the last one ended, or if the color, the width or the + stippling have changed (multi-stroking lines with changing + colors is necessary until we use /shfill for lines; + unfortunately this means that at the moment we can screw up + line stippling for smooth-shaded lines) */ + gl2psEndPostScriptLine(); + newline = 1; + } + else{ + newline = 0; + } + if(gl2ps->lastlinewidth != prim->width){ + gl2ps->lastlinewidth = prim->width; + gl2psPrintf("%g W\n", gl2ps->lastlinewidth); + } + gl2psPrintPostScriptDash(prim->pattern, prim->factor, "setdash"); + gl2psPrintPostScriptColor(prim->verts[0].rgba); + gl2psPrintf("%g %g %s\n", prim->verts[0].xyz[0], prim->verts[0].xyz[1], + newline ? "LS" : "L"); + gl2ps->lastvertex = prim->verts[1]; + break; + case GL2PS_TRIANGLE : + if(!gl2psVertsSameColor(prim)){ + gl2psResetPostScriptColor(); + gl2psPrintf("%g %g %g %g %g %g %g %g %g %g %g %g %g %g %g ST\n", + prim->verts[2].xyz[0], prim->verts[2].xyz[1], + prim->verts[2].rgba[0], prim->verts[2].rgba[1], + prim->verts[2].rgba[2], prim->verts[1].xyz[0], + prim->verts[1].xyz[1], prim->verts[1].rgba[0], + prim->verts[1].rgba[1], prim->verts[1].rgba[2], + prim->verts[0].xyz[0], prim->verts[0].xyz[1], + prim->verts[0].rgba[0], prim->verts[0].rgba[1], + prim->verts[0].rgba[2]); + } + else{ + gl2psPrintPostScriptColor(prim->verts[0].rgba); + gl2psPrintf("%g %g %g %g %g %g T\n", + prim->verts[2].xyz[0], prim->verts[2].xyz[1], + prim->verts[1].xyz[0], prim->verts[1].xyz[1], + prim->verts[0].xyz[0], prim->verts[0].xyz[1]); + } + break; + case GL2PS_QUADRANGLE : + gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print"); + break; + case GL2PS_PIXMAP : + gl2psPrintPostScriptPixmap(prim->verts[0].xyz[0], prim->verts[0].xyz[1], + prim->data.image); + break; + case GL2PS_IMAGEMAP : + if(prim->data.image->type != GL2PS_IMAGEMAP_WRITTEN){ + gl2psPrintPostScriptColor(prim->verts[0].rgba); + gl2psPrintPostScriptImagemap(prim->data.image->pixels[0], + prim->data.image->pixels[1], + prim->data.image->width, prim->data.image->height, + (const unsigned char*)(&(prim->data.image->pixels[2]))); + prim->data.image->type = GL2PS_IMAGEMAP_WRITTEN; + } + break; + case GL2PS_TEXT : + gl2psPrintPostScriptColor(prim->verts[0].rgba); + gl2psPrintf("(%s) ", prim->data.text->str); + if(prim->data.text->angle) + gl2psPrintf("%g ", prim->data.text->angle); + gl2psPrintf("%g %g %d /%s ", + prim->verts[0].xyz[0], prim->verts[0].xyz[1], + prim->data.text->fontsize, prim->data.text->fontname); + switch(prim->data.text->alignment){ + case GL2PS_TEXT_C: + gl2psPrintf(prim->data.text->angle ? "SCCR\n" : "SCC\n"); + break; + case GL2PS_TEXT_CL: + gl2psPrintf(prim->data.text->angle ? "SCLR\n" : "SCL\n"); + break; + case GL2PS_TEXT_CR: + gl2psPrintf(prim->data.text->angle ? "SCRR\n" : "SCR\n"); + break; + case GL2PS_TEXT_B: + gl2psPrintf(prim->data.text->angle ? "SBCR\n" : "SBC\n"); + break; + case GL2PS_TEXT_BR: + gl2psPrintf(prim->data.text->angle ? "SBRR\n" : "SBR\n"); + break; + case GL2PS_TEXT_T: + gl2psPrintf(prim->data.text->angle ? "STCR\n" : "STC\n"); + break; + case GL2PS_TEXT_TL: + gl2psPrintf(prim->data.text->angle ? "STLR\n" : "STL\n"); + break; + case GL2PS_TEXT_TR: + gl2psPrintf(prim->data.text->angle ? "STRR\n" : "STR\n"); + break; + case GL2PS_TEXT_BL: + default: + gl2psPrintf(prim->data.text->angle ? "SR\n" : "S\n"); + break; + } + break; + case GL2PS_SPECIAL : + /* alignment contains the format for which the special output text + is intended */ + if(prim->data.text->alignment == GL2PS_PS || + prim->data.text->alignment == GL2PS_EPS) + gl2psPrintf("%s\n", prim->data.text->str); + break; + default : + break; + } +} + +static void gl2psPrintPostScriptFooter(void) +{ + gl2psPrintf("grestore\n" + "showpage\n" + "cleartomark\n" + "%%%%PageTrailer\n" + "%%%%Trailer\n" + "end\n" + "%%%%EOF\n"); + + gl2psPrintGzipFooter(); +} + +static void gl2psPrintPostScriptBeginViewport(GLint viewport[4]) +{ + GLint index; + GLfloat rgba[4]; + int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; + + glRenderMode(GL_FEEDBACK); + + if(gl2ps->header){ + gl2psPrintPostScriptHeader(); + gl2ps->header = GL_FALSE; + } + + gl2psPrintf("gsave\n" + "1.0 1.0 scale\n"); + + if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ + if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ + glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); + } + else{ + glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); + rgba[0] = gl2ps->colormap[index][0]; + rgba[1] = gl2ps->colormap[index][1]; + rgba[2] = gl2ps->colormap[index][2]; + rgba[3] = 1.0F; + } + 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], + 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) +{ + GLint res; + + res = gl2psPrintPrimitives(); + gl2psPrintf("grestore\n"); + return res; +} + +static void gl2psPrintPostScriptFinalPrimitive(void) +{ + /* End any remaining line, if any */ + gl2psEndPostScriptLine(); +} + +/* definition of the PostScript and Encapsulated PostScript backends */ + +static GL2PSbackend gl2psPS = { + gl2psPrintPostScriptHeader, + gl2psPrintPostScriptFooter, + gl2psPrintPostScriptBeginViewport, + gl2psPrintPostScriptEndViewport, + gl2psPrintPostScriptPrimitive, + gl2psPrintPostScriptFinalPrimitive, + "ps", + "Postscript" +}; + +static GL2PSbackend gl2psEPS = { + gl2psPrintPostScriptHeader, + gl2psPrintPostScriptFooter, + gl2psPrintPostScriptBeginViewport, + gl2psPrintPostScriptEndViewport, + gl2psPrintPostScriptPrimitive, + gl2psPrintPostScriptFinalPrimitive, + "eps", + "Encapsulated Postscript" +}; + +/********************************************************************* + * + * LaTeX routines + * + *********************************************************************/ + +static void gl2psPrintTeXHeader(void) +{ + char name[256]; + time_t now; + int i; + + if(gl2ps->filename && strlen(gl2ps->filename) < 256){ + for(i = (int)strlen(gl2ps->filename) - 1; i >= 0; i--){ + if(gl2ps->filename[i] == '.'){ + strncpy(name, gl2ps->filename, i); + name[i] = '\0'; + break; + } + } + if(i <= 0) strcpy(name, gl2ps->filename); + } + else{ + strcpy(name, "untitled"); + } + + time(&now); + + fprintf(gl2ps->stream, + "%% Title: %s\n" + "%% Creator: GL2PS %d.%d.%d%s, %s\n" + "%% For: %s\n" + "%% CreationDate: %s", + gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, + GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, + gl2ps->producer, ctime(&now)); + + fprintf(gl2ps->stream, + "\\setlength{\\unitlength}{1pt}\n" + "\\begin{picture}(0,0)\n" + "\\includegraphics{%s}\n" + "\\end{picture}%%\n" + "%s\\begin{picture}(%d,%d)(0,0)\n", + name, (gl2ps->options & GL2PS_LANDSCAPE) ? "\\rotatebox{90}{" : "", + (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); +} + +static void gl2psPrintTeXPrimitive(void *data) +{ + GL2PSprimitive *prim; + + prim = *(GL2PSprimitive**)data; + + switch(prim->type){ + case GL2PS_TEXT : + fprintf(gl2ps->stream, "\\fontsize{%d}{0}\n\\selectfont", + prim->data.text->fontsize); + fprintf(gl2ps->stream, "\\put(%g,%g)", + 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, "{"); + break; + case GL2PS_TEXT_CL: + fprintf(gl2ps->stream, "[l]{"); + break; + case GL2PS_TEXT_CR: + fprintf(gl2ps->stream, "[r]{"); + break; + case GL2PS_TEXT_B: + fprintf(gl2ps->stream, "[b]{"); + break; + case GL2PS_TEXT_BR: + fprintf(gl2ps->stream, "[br]{"); + break; + case GL2PS_TEXT_T: + fprintf(gl2ps->stream, "[t]{"); + break; + case GL2PS_TEXT_TL: + fprintf(gl2ps->stream, "[tl]{"); + break; + case GL2PS_TEXT_TR: + fprintf(gl2ps->stream, "[tr]{"); + break; + case GL2PS_TEXT_BL: + default: + fprintf(gl2ps->stream, "[bl]{"); + break; + } + 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); + if(prim->data.text->angle) + fprintf(gl2ps->stream, "}"); + fprintf(gl2ps->stream, "}}\n"); + break; + case GL2PS_SPECIAL : + /* alignment contains the format for which the special output text + is intended */ + if (prim->data.text->alignment == GL2PS_TEX) + fprintf(gl2ps->stream, "%s\n", prim->data.text->str); + break; + default : + break; + } +} + +static void gl2psPrintTeXFooter(void) +{ + fprintf(gl2ps->stream, "\\end{picture}%s\n", + (gl2ps->options & GL2PS_LANDSCAPE) ? "}" : ""); +} + +static void gl2psPrintTeXBeginViewport(GLint viewport[4]) +{ + (void) viewport; /* not used */ + glRenderMode(GL_FEEDBACK); + + if(gl2ps->header){ + gl2psPrintTeXHeader(); + gl2ps->header = GL_FALSE; + } +} + +static GLint gl2psPrintTeXEndViewport(void) +{ + return gl2psPrintPrimitives(); +} + +static void gl2psPrintTeXFinalPrimitive(void) +{ +} + +/* definition of the LaTeX backend */ + +static GL2PSbackend gl2psTEX = { + gl2psPrintTeXHeader, + gl2psPrintTeXFooter, + gl2psPrintTeXBeginViewport, + gl2psPrintTeXEndViewport, + gl2psPrintTeXPrimitive, + gl2psPrintTeXFinalPrimitive, + "tex", + "LaTeX text" +}; + +/********************************************************************* + * + * PDF routines + * + *********************************************************************/ + +static int gl2psPrintPDFCompressorType(void) +{ +#if defined(GL2PS_HAVE_ZLIB) + if(gl2ps->options & GL2PS_COMPRESS){ + return fprintf(gl2ps->stream, "/Filter [/FlateDecode]\n"); + } +#endif + return 0; +} + +static int gl2psPrintPDFStrokeColor(GL2PSrgba rgba) +{ + int i, offs = 0; + + gl2psSetLastColor(rgba); + for(i = 0; i < 3; ++i){ + if(GL2PS_ZERO(rgba[i])) + offs += gl2psPrintf("%.0f ", 0.); + else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting */ + offs += gl2psPrintf("%f ", rgba[i]); + else + offs += gl2psPrintf("%g ", rgba[i]); + } + offs += gl2psPrintf("RG\n"); + return offs; +} + +static int gl2psPrintPDFFillColor(GL2PSrgba rgba) +{ + int i, offs = 0; + + for(i = 0; i < 3; ++i){ + if(GL2PS_ZERO(rgba[i])) + offs += gl2psPrintf("%.0f ", 0.); + else if(rgba[i] < 1e-4 || rgba[i] > 1e6) /* avoid %e formatting */ + offs += gl2psPrintf("%f ", rgba[i]); + else + offs += gl2psPrintf("%g ", rgba[i]); + } + offs += gl2psPrintf("rg\n"); + return offs; +} + +static int gl2psPrintPDFLineWidth(GLfloat lw) +{ + if(GL2PS_ZERO(lw)) + return gl2psPrintf("%.0f w\n", 0.); + else if(lw < 1e-4 || lw > 1e6) /* avoid %e formatting */ + return gl2psPrintf("%f w\n", lw); + else + return gl2psPrintf("%g w\n", lw); +} + +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", + cnt, text->fontsize, x, y, text->str); + } + else{ + rad = (GLfloat)(M_PI * text->angle / 180.0F); + srad = (GLfloat)sin(rad); + crad = (GLfloat)cos(rad); + gl2ps->streamlength += gl2psPrintf + ("BT\n" + "/F%d %d Tf\n" + "%f %f %f %f %f %f Tm\n" + "(%s) Tj\n" + "ET\n", + cnt, text->fontsize, crad, srad, -srad, crad, x, y, text->str); + } +} + +static void gl2psPutPDFImage(GL2PSimage *image, int cnt, GLfloat x, GLfloat y) +{ + gl2ps->streamlength += gl2psPrintf + ("q\n" + "%d 0 0 %d %f %f cm\n" + "/Im%d Do\n" + "Q\n", + (int)image->width, (int)image->height, x, y, cnt); +} + +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; +} + +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->maskshobjno = gro->gsobjno = gro->trgroupobjno = -1; +} + +/* Build up group objects and assign name and object numbers */ + +static void gl2psPDFgroupListInit(void) +{ + int i; + GL2PSprimitive *p = NULL; + GL2PSpdfgroup gro; + int lasttype = GL2PS_NO_TYPE; + GL2PSrgba lastrgba = {-1.0F, -1.0F, -1.0F, -1.0F}; + GLushort lastpattern = 0; + GLint lastfactor = 0; + GLfloat lastwidth = 1; + GL2PStriangle lastt, tmpt; + int lastTriangleWasNotSimpleWithSameColor = 0; + + if(!gl2ps->pdfprimlist) + return; + + gl2ps->pdfgrouplist = gl2psListCreate(500, 500, sizeof(GL2PSpdfgroup)); + gl2psInitTriangle(&lastt); + + for(i = 0; i < gl2psListNbr(gl2ps->pdfprimlist); ++i){ + p = *(GL2PSprimitive**)gl2psListPointer(gl2ps->pdfprimlist, i); + switch(p->type){ + case GL2PS_PIXMAP: + gl2psPDFgroupObjectInit(&gro); + gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); + gro.imno = gl2ps->im_stack++; + gl2psListAdd(gro.ptrlist, &p); + gl2psListAdd(gl2ps->pdfgrouplist, &gro); + break; + case GL2PS_TEXT: + gl2psPDFgroupObjectInit(&gro); + gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); + gro.fontno = gl2ps->font_stack++; + gl2psListAdd(gro.ptrlist, &p); + gl2psListAdd(gl2ps->pdfgrouplist, &gro); + break; + case GL2PS_LINE: + if(lasttype != p->type || lastwidth != p->width || + lastpattern != p->pattern || lastfactor != p->factor || + !gl2psSameColor(p->verts[0].rgba, lastrgba)){ + gl2psPDFgroupObjectInit(&gro); + gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); + gl2psListAdd(gro.ptrlist, &p); + gl2psListAdd(gl2ps->pdfgrouplist, &gro); + } + else{ + gl2psListAdd(gro.ptrlist, &p); + } + lastpattern = p->pattern; + lastfactor = p->factor; + lastwidth = p->width; + lastrgba[0] = p->verts[0].rgba[0]; + lastrgba[1] = p->verts[0].rgba[1]; + lastrgba[2] = p->verts[0].rgba[2]; + break; + case GL2PS_POINT: + if(lasttype != p->type || lastwidth != p->width || + !gl2psSameColor(p->verts[0].rgba, lastrgba)){ + gl2psPDFgroupObjectInit(&gro); + gro.ptrlist = gl2psListCreate(1,2,sizeof(GL2PSprimitive*)); + gl2psListAdd(gro.ptrlist, &p); + gl2psListAdd(gl2ps->pdfgrouplist, &gro); + } + else{ + gl2psListAdd(gro.ptrlist, &p); + } + lastwidth = p->width; + lastrgba[0] = p->verts[0].rgba[0]; + lastrgba[1] = p->verts[0].rgba[1]; + lastrgba[2] = p->verts[0].rgba[2]; + break; + case GL2PS_TRIANGLE: + gl2psFillTriangleFromPrimitive(&tmpt, p, GL_TRUE); + 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 && + lastTriangleWasNotSimpleWithSameColor){ + /* TODO Check here for last alpha */ + gl2psListAdd(gro.ptrlist, &p); + } + else{ + gl2psPDFgroupObjectInit(&gro); + gro.ptrlist = gl2psListCreate(1, 2, sizeof(GL2PSprimitive*)); + gl2psListAdd(gro.ptrlist, &p); + gl2psListAdd(gl2ps->pdfgrouplist, &gro); + } + lastt = tmpt; + break; + default: + break; + } + lasttype = p->type; + } +} + +static void gl2psSortOutTrianglePDFgroup(GL2PSpdfgroup *gro) +{ + GL2PStriangle t; + GL2PSprimitive *prim = NULL; + + if(!gro) + return; + + if(!gl2psListNbr(gro->ptrlist)) + return; + + prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); + + if(prim->type != GL2PS_TRIANGLE) + return; + + gl2psFillTriangleFromPrimitive(&t, prim, GL_TRUE); + + 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){ + gro->gsno = gl2ps->extgs_stack++; + gro->gsobjno = gl2ps->objects_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){ + gro->shno = gl2ps->shader_stack++; + gro->shobjno = gl2ps->objects_stack++; + } + 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->shobjno = gl2ps->objects_stack++; + } + 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->shobjno = gl2ps->objects_stack++; + gro->trgroupno = gl2ps->trgroupobjects_stack++; + gro->trgroupobjno = gl2ps->objects_stack++; + gro->maskshno = gl2ps->mshader_stack++; + gro->maskshobjno = gl2ps->objects_stack++; + } +} + +/* Main stream data */ + +static void gl2psPDFgroupListWriteMainStream(void) +{ + int i, j, lastel; + GL2PSprimitive *prim = NULL, *prev = NULL; + GL2PSpdfgroup *gro; + GL2PStriangle t; + + if(!gl2ps->pdfgrouplist) + return; + + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + + lastel = gl2psListNbr(gro->ptrlist) - 1; + if(lastel < 0) + continue; + + prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, 0); + + switch(prim->type){ + case GL2PS_POINT: + gl2ps->streamlength += gl2psPrintf("1 J\n"); + gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width); + gl2ps->streamlength += gl2psPrintPDFStrokeColor(prim->verts[0].rgba); + 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("0 J\n"); + break; + case GL2PS_LINE: + /* We try to use as few paths as possible to draw lines, in + order to get nice stippling even when the individual segments + are smaller than the stipple */ + gl2ps->streamlength += gl2psPrintPDFLineWidth(prim->width); + 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", + prim->verts[0].xyz[0], prim->verts[0].xyz[1]); + + for(j = 1; j <= lastel; ++j){ + prev = prim; + prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); + if(!gl2psSamePosition(prim->verts[0].xyz, prev->verts[1].xyz)){ + /* 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", + prev->verts[1].xyz[0], prev->verts[1].xyz[1]); + 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 += + 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", + 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){ + prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); + gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); + gl2ps->streamlength + += gl2psPrintf("%f %f m\n" + "%f %f l\n" + "%f %f l\n" + "h f\n", + t.vertex[0].xyz[0], t.vertex[0].xyz[1], + t.vertex[1].xyz[0], t.vertex[1].xyz[1], + t.vertex[2].xyz[0], t.vertex[2].xyz[1]); + } + } + /* 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){ + gl2ps->streamlength += gl2psPrintf("q\n" + "/GS%d gs\n", + gro->gsno); + gl2ps->streamlength += gl2psPrintPDFFillColor(prim->verts[0].rgba); + for(j = 0; j <= lastel; ++j){ + prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); + gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); + gl2ps->streamlength + += gl2psPrintf("%f %f m\n" + "%f %f l\n" + "%f %f l\n" + "h f\n", + t.vertex[0].xyz[0], t.vertex[0].xyz[1], + t.vertex[1].xyz[0], t.vertex[1].xyz[1], + t.vertex[2].xyz[0], t.vertex[2].xyz[1]); + } + gl2ps->streamlength += gl2psPrintf("Q\n"); + } + /* 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){ + 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){ + prim = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); + gl2psFillTriangleFromPrimitive(&t, prim, GL_FALSE); + gl2ps->streamlength + += gl2psPrintf("%f %f m\n" + "%f %f l\n" + "%f %f l\n" + "h f\n", + t.vertex[0].xyz[0], t.vertex[0].xyz[1], + t.vertex[1].xyz[0], t.vertex[1].xyz[1], + t.vertex[2].xyz[0], t.vertex[2].xyz[1]); + } + gl2ps->streamlength += gl2psPrintf("Q\n"); + } + /* Variable color and no alpha: Shader Object for the colored + triangle(s) */ + 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 + for the alpha const */ + 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 + + Xobject + Shader object for the alpha mask */ + 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" + "/Sh%d sh\n" + "Q\n", + gro->gsno, gro->trgroupno, gro->shno); + } + break; + 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], + prim->verts[0].xyz[1]); + } + break; + case GL2PS_TEXT: + 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], + prim->verts[0].xyz[1]); + } + break; + default: + break; + } + } +} + +/* Graphics State names */ + +static int gl2psPDFgroupListWriteGStateResources(void) +{ + GL2PSpdfgroup *gro; + int offs = 0; + int i; + + offs += fprintf(gl2ps->stream, + "/ExtGState\n" + "<<\n" + "/GSa 7 0 R\n"); + 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"); + return offs; +} + +/* Main Shader names */ + +static int gl2psPDFgroupListWriteShaderResources(void) +{ + GL2PSpdfgroup *gro; + int offs = 0; + int i; + + offs += fprintf(gl2ps->stream, + "/Shading\n" + "<<\n"); + 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"); + return offs; +} + +/* Images & Mask Shader XObject names */ + +static int gl2psPDFgroupListWriteXObjectResources(void) +{ + int i; + GL2PSprimitive *p = NULL; + GL2PSpdfgroup *gro; + int offs = 0; + + offs += fprintf(gl2ps->stream, + "/XObject\n" + "<<\n"); + + 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); + switch(p->type){ + case GL2PS_PIXMAP: + gro->imobjno = gl2ps->objects_stack++; + if(GL_RGBA == p->data.image->format) /* reserve one object for image mask */ + gl2ps->objects_stack++; + offs += fprintf(gl2ps->stream, "/Im%d %d 0 R\n", gro->imno, gro->imobjno); + case GL2PS_TRIANGLE: + if(gro->trgroupno >=0) + offs += fprintf(gl2ps->stream, "/TrG%d %d 0 R\n", gro->trgroupno, gro->trgroupobjno); + break; + default: + break; + } + } + offs += fprintf(gl2ps->stream,">>\n"); + return offs; +} + +/* Font names */ + +static int gl2psPDFgroupListWriteFontResources(void) +{ + int i; + GL2PSpdfgroup *gro; + int offs = 0; + + offs += fprintf(gl2ps->stream, "/Font\n<<\n"); + + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist, i); + if(gro->fontno < 0) + continue; + gro->fontobjno = gl2ps->objects_stack++; + offs += fprintf(gl2ps->stream, "/F%d %d 0 R\n", gro->fontno, gro->fontobjno); + } + offs += fprintf(gl2ps->stream, ">>\n"); + + return offs; +} + +static void gl2psPDFgroupListDelete(void) +{ + int i; + GL2PSpdfgroup *gro = NULL; + + if(!gl2ps->pdfgrouplist) + return; + + for(i = 0; i < gl2psListNbr(gl2ps->pdfgrouplist); ++i){ + gro = (GL2PSpdfgroup*)gl2psListPointer(gl2ps->pdfgrouplist,i); + gl2psListDelete(gro->ptrlist); + } + + gl2psListDelete(gl2ps->pdfgrouplist); + gl2ps->pdfgrouplist = NULL; +} + +/* Print 1st PDF object - file info */ + +static int gl2psPrintPDFInfo(void) +{ + int offs; + time_t now; + struct tm *newtime; + + time(&now); + newtime = gmtime(&now); + + offs = fprintf(gl2ps->stream, + "1 0 obj\n" + "<<\n" + "/Title (%s)\n" + "/Creator (GL2PS %d.%d.%d%s, %s)\n" + "/Producer (%s)\n", + gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, + GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, + gl2ps->producer); + + if(!newtime){ + offs += fprintf(gl2ps->stream, + ">>\n" + "endobj\n"); + return offs; + } + + 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_mday, + newtime->tm_hour, + newtime->tm_min, + newtime->tm_sec); + return offs; +} + +/* Create catalog and page structure - 2nd and 3th PDF object */ + +static int gl2psPrintPDFCatalog(void) +{ + return fprintf(gl2ps->stream, + "2 0 obj\n" + "<<\n" + "/Type /Catalog\n" + "/Pages 3 0 R\n" + ">>\n" + "endobj\n"); +} + +static int gl2psPrintPDFPages(void) +{ + return fprintf(gl2ps->stream, + "3 0 obj\n" + "<<\n" + "/Type /Pages\n" + "/Kids [6 0 R]\n" + "/Count 1\n" + ">>\n" + "endobj\n"); +} + +/* Open stream for data - graphical objects, fonts etc. PDF object 4 */ + +static int gl2psOpenPDFDataStream(void) +{ + int offs = 0; + + offs += fprintf(gl2ps->stream, + "4 0 obj\n" + "<<\n" + "/Length 5 0 R\n" ); + offs += gl2psPrintPDFCompressorType(); + offs += fprintf(gl2ps->stream, + ">>\n" + "stream\n"); + return offs; +} + +/* Stream setup - Graphics state, fill background if allowed */ + +static int gl2psOpenPDFDataStreamWritePreface(void) +{ + 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"); + } + return offs; +} + +/* Use the functions above to create the first part of the PDF*/ + +static void gl2psPrintPDFHeader(void) +{ + int offs = 0; + gl2ps->pdfprimlist = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*)); + gl2psPDFstacksInit(); + + gl2ps->xreflist = (int*)gl2psMalloc(sizeof(int) * gl2ps->objects_stack); + +#if defined(GL2PS_HAVE_ZLIB) + if(gl2ps->options & GL2PS_COMPRESS){ + gl2psSetupCompress(); + } +#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(); +} + +/* The central primitive drawing */ + +static void gl2psPrintPDFPrimitive(void *data) +{ + GL2PSprimitive *prim = *(GL2PSprimitive**)data; + + if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) + return; + + prim = gl2psCopyPrimitive(prim); /* deep copy */ + gl2psListAdd(gl2ps->pdfprimlist, &prim); +} + +/* close stream and ... */ + +static int gl2psClosePDFDataStream(void) +{ + int offs = 0; + +#if defined(GL2PS_HAVE_ZLIB) + if(gl2ps->options & GL2PS_COMPRESS){ + if(Z_OK != gl2psDeflate()) + gl2psMsg(GL2PS_ERROR, "Zlib deflate error"); + 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, + "endstream\n" + "endobj\n"); + return offs; +} + +/* ... write the now known length object */ + +static int gl2psPrintPDFDataStreamLength(int val) +{ + return fprintf(gl2ps->stream, + "5 0 obj\n" + "%d\n" + "endobj\n", val); +} + +/* Put the info created before in PDF objects */ + +static int gl2psPrintPDFOpenPage(void) +{ + int offs; + + /* Write fixed part */ + + offs = fprintf(gl2ps->stream, + "6 0 obj\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" + "/ProcSet [/PDF /Text /ImageB /ImageC] %%/ImageI\n"); + + return offs; + + /* End fixed part, proceeds in gl2psPDFgroupListWriteVariableResources() */ +} + +static int gl2psPDFgroupListWriteVariableResources(void) +{ + int offs = 0; + + /* a) Graphics States for shader alpha masks*/ + 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" + ">>\n" + "endobj\n"); + return offs; +} + +/* Standard Graphics State */ + +static int gl2psPrintPDFGSObject(void) +{ + return fprintf(gl2ps->stream, + "7 0 obj\n" + "<<\n" + "/Type /ExtGState\n" + "/SA false\n" + "/SM 0.02\n" + "/OP false\n" + "/op false\n" + "/OPM 0\n" + "/BG2 /Default\n" + "/UCR2 /Default\n" + "/TR2 /Default\n" + ">>\n" + "endobj\n"); +} + +/* Put vertex' edge flag (8bit) and coordinates (32bit) in shader stream */ + +static int gl2psPrintPDFShaderStreamDataCoord(GL2PSvertex *vertex, + int (*action)(unsigned long data, int size), + GLfloat dx, GLfloat dy, + GLfloat xmin, GLfloat ymin) +{ + int offs = 0; + unsigned long imap; + GLfloat diff; + double dmax = ~1UL; + char edgeflag = 0; + + /* FIXME: temp bux fix for 64 bit archs: */ + if(sizeof(unsigned long) == 8) dmax = dmax - 2048.; + + offs += (*action)(edgeflag, 1); + + /* 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); + } + else{ + diff = (vertex->xyz[0] - xmin) / dx; + if(diff > 1) + diff = 1.0F; + else if(diff < 0) + diff = 0.0F; + imap = (unsigned long)(diff * dmax); + offs += (*action)(imap, 4); + + diff = (vertex->xyz[1] - ymin) / dy; + if(diff > 1) + diff = 1.0F; + else if(diff < 0) + diff = 0.0F; + 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, + int (*action)(unsigned long data, int size)) +{ + int offs = 0; + unsigned long imap; + double dmax = ~1UL; + + /* FIXME: temp bux fix for 64 bit archs: */ + if(sizeof(unsigned long) == 8) dmax = dmax - 2048.; + + 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, + int (*action)(unsigned long data, int size), + int sigbyte) +{ + int offs = 0; + unsigned long imap; + double dmax = ~1UL; + + /* FIXME: temp bux fix for 64 bit archs: */ + if(sizeof(unsigned long) == 8) dmax = dmax - 2048.; + + 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, + GLfloat xmin, GLfloat ymin, + int (*action)(unsigned long data, int 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){ + v = triangle->vertex[i]; + 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, + GL2PStriangle *triangles, int cnt) +{ + int i, j; + + *xmin = triangles[0].vertex[0].xyz[0]; + *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]) + *xmin = triangles[i].vertex[j].xyz[0]; + if(*xmax < triangles[i].vertex[j].xyz[0]) + *xmax = triangles[i].vertex[j].xyz[0]; + if(*ymin > triangles[i].vertex[j].xyz[1]) + *ymin = triangles[i].vertex[j].xyz[1]; + if(*ymax < triangles[i].vertex[j].xyz[1]) + *ymax = triangles[i].vertex[j].xyz[1]; + } + } +} + +/* 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, + 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; + break; + case 8: + vertexbytes = 1+4+4+1; + break; + case 16: + vertexbytes = 1+4+4+2; + break; + default: + gray = 8; + vertexbytes = 1+4+4+1; + break; + } + + gl2psPDFRectHull(&xmin, &xmax, &ymin, &ymax, triangles, size); + + offs += fprintf(gl2ps->stream, + "%d 0 obj\n" + "<< " + "/ShadingType 4 " + "/ColorSpace %s " + "/BitsPerCoordinate 32 " + "/BitsPerComponent %d " + "/BitsPerFlag 8 " + "/Decode [%f %f %f %f 0 1 %s] ", + obj, + (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, + gl2psWriteBigEndianCompress, gray); + + if(Z_OK == gl2psDeflate() && 23 + gl2ps->compress->destLen < gl2ps->compress->srcLen){ + offs += gl2psPrintPDFCompressorType(); + offs += fprintf(gl2ps->stream, + "/Length %d " + ">>\n" + "stream\n", + (int)gl2ps->compress->destLen); + offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, + gl2ps->compress->destLen, + 1, gl2ps->stream); + done = 1; + } + gl2psFreeCompress(); + } +#endif + + if(!done){ + /* no compression, or too long after compression, or compress error + -> write non-compressed entry */ + offs += fprintf(gl2ps->stream, + "/Length %d " + ">>\n" + "stream\n", + vertexbytes * 3 * size); + for(i = 0; i < size; ++i) + offs += gl2psPrintPDFShaderStreamData(&triangles[i], + xmax-xmin, ymax-ymin, xmin, ymin, + gl2psWriteBigEndian, gray); + } + + offs += fprintf(gl2ps->stream, + "\nendstream\n" + "endobj\n"); + + return offs; +} + +/* Writes a XObject for a shaded triangle mask */ + +static int gl2psPrintPDFShaderMask(int obj, int childobj) +{ + int offs = 0, len; + + offs += fprintf(gl2ps->stream, + "%d 0 obj\n" + "<<\n" + "/Type /XObject\n" + "/Subtype /Form\n" + "/BBox [ %d %d %d %d ]\n" + "/Group \n<<\n/S /Transparency /CS /DeviceRGB\n" + ">>\n", + obj, + (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], + (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); + + len = (childobj>0) + ? strlen("/TrSh sh\n") + (int)log10((double)childobj)+1 + : strlen("/TrSh0 sh\n"); + + offs += fprintf(gl2ps->stream, + "/Length %d\n" + ">>\n" + "stream\n", + len); + offs += fprintf(gl2ps->stream, + "/TrSh%d sh\n", + childobj); + offs += fprintf(gl2ps->stream, + "endstream\n" + "endobj\n"); + + return offs; +} + +/* Writes a Extended graphics state for a shaded triangle mask if + simplealpha ist true the childobj argument is ignored and a /ca + statement will be written instead */ + +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"); + return offs; +} + +/* a simple graphics state */ + +static int gl2psPrintPDFShaderSimpleExtGS(int obj, GLfloat alpha) +{ + int offs = 0; + + offs += fprintf(gl2ps->stream, + "%d 0 obj\n" + "<<\n" + "/ca %g" + ">>\n" + "endobj\n", + obj, alpha); + return offs; +} + +/* Similar groups of functions for pixmaps and text */ + +static int gl2psPrintPDFPixmapStreamData(GL2PSimage *im, + int (*action)(unsigned long data, int size), + int gray) +{ + int x, y, shift; + GLfloat r, g, b, a; + + if(im->format != GL_RGBA && gray) + return 0; + + if(gray && gray != 8 && gray != 16) + gray = 8; + + gray /= 8; + + shift = (sizeof(unsigned long) - 1) * 8; + + for(y = 0; y < im->height; ++y){ + for(x = 0; x < im->width; ++x){ + a = gl2psGetRGB(im, x, y, &r, &g, &b); + if(im->format == GL_RGBA && gray){ + (*action)((unsigned long)(a * 255) << shift, gray); + } + else{ + (*action)((unsigned long)(r * 255) << shift, 1); + (*action)((unsigned long)(g * 255) << shift, 1); + (*action)((unsigned long)(b * 255) << shift, 1); + } + } + } + + switch(gray){ + case 0: return 3 * im->width * im->height; + case 1: return im->width * im->height; + case 2: return 2 * im->width * im->height; + default: return 3 * im->width * im->height; + } +} + +static int gl2psPrintPDFPixmap(int obj, int childobj, GL2PSimage *im, int gray) +{ + int offs = 0, done = 0, sigbytes = 3; + + if(gray && gray !=8 && gray != 16) + gray = 8; + + if(gray) + sigbytes = gray / 8; + + offs += fprintf(gl2ps->stream, + "%d 0 obj\n" + "<<\n" + "/Type /XObject\n" + "/Subtype /Image\n" + "/Width %d\n" + "/Height %d\n" + "/ColorSpace %s \n" + "/BitsPerComponent 8\n", + obj, + (int)im->width, (int)im->height, + (gray) ? "/DeviceGray" : "/DeviceRGB" ); + if(GL_RGBA == im->format && gray == 0){ + offs += fprintf(gl2ps->stream, + "/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, + "/Length %d " + ">>\n" + "stream\n", + (int)gl2ps->compress->destLen); + offs += gl2ps->compress->destLen * fwrite(gl2ps->compress->dest, gl2ps->compress->destLen, + 1, gl2ps->stream); + done = 1; + } + gl2psFreeCompress(); + } +#endif + + if(!done){ + /* no compression, or too long after compression, or compress error + -> write non-compressed entry */ + offs += fprintf(gl2ps->stream, + "/Length %d " + ">>\n" + "stream\n", + (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" + "/Type /Font\n" + "/Subtype /Type1\n" + "/Name /F%d\n" + "/BaseFont /%s\n" + "/Encoding /MacRomanEncoding\n" + ">>\n" + "endobj\n", + obj, fontnumber, s->fontname); + return offs; +} + +/* Write the physical objects */ + +static int gl2psPDFgroupListWriteObjects(int entryoffs) +{ + int i,j; + GL2PSprimitive *p = NULL; + GL2PSpdfgroup *gro; + int offs = entryoffs; + GL2PStriangle *triangles; + int size = 0; + + if(!gl2ps->pdfgrouplist) + return offs; + + 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); + switch(p->type){ + case GL2PS_POINT: + break; + case GL2PS_LINE: + break; + case GL2PS_TRIANGLE: + size = gl2psListNbr(gro->ptrlist); + triangles = (GL2PStriangle*)gl2psMalloc(sizeof(GL2PStriangle) * size); + for(j = 0; j < size; ++j){ + p = *(GL2PSprimitive**)gl2psListPointer(gro->ptrlist, j); + gl2psFillTriangleFromPrimitive(&triangles[j], p, GL_TRUE); + } + if(triangles[0].prop & T_VAR_COLOR){ + gl2ps->xreflist[gro->shobjno] = offs; + offs += gl2psPrintPDFShader(gro->shobjno, triangles, size, 0); + } + if(triangles[0].prop & T_ALPHA_LESS_1){ + gl2ps->xreflist[gro->gsobjno] = offs; + offs += gl2psPrintPDFShaderSimpleExtGS(gro->gsobjno, triangles[0].vertex[0].rgba[3]); + } + if(triangles[0].prop & T_VAR_ALPHA){ + gl2ps->xreflist[gro->gsobjno] = offs; + offs += gl2psPrintPDFShaderExtGS(gro->gsobjno, gro->trgroupobjno); + gl2ps->xreflist[gro->trgroupobjno] = offs; + offs += gl2psPrintPDFShaderMask(gro->trgroupobjno, gro->maskshno); + gl2ps->xreflist[gro->maskshobjno] = offs; + offs += gl2psPrintPDFShader(gro->maskshobjno, triangles, size, 8); + } + gl2psFree(triangles); + break; + case GL2PS_PIXMAP: + gl2ps->xreflist[gro->imobjno] = offs; + offs += gl2psPrintPDFPixmap(gro->imobjno, gro->imobjno+1, p->data.image, 0); + if(p->data.image->format == GL_RGBA){ + gl2ps->xreflist[gro->imobjno+1] = offs; + offs += gl2psPrintPDFPixmap(gro->imobjno+1, -1, p->data.image, 8); + } + break; + case GL2PS_TEXT: + gl2ps->xreflist[gro->fontobjno] = offs; + offs += gl2psPrintPDFText(gro->fontobjno,p->data.text,gro->fontno); + break; + case GL2PS_SPECIAL : + /* alignment contains the format for which the special output text + is intended */ + if(p->data.text->alignment == GL2PS_PDF) + offs += fprintf(gl2ps->stream, "%s\n", p->data.text->str); + break; + default: + break; + } + } + return offs; +} + +/* All variable data has been written at this point and all required + functioninality has been gathered, so we can write now file footer + with cross reference table and trailer */ + +static void gl2psPrintPDFFooter(void) +{ + int i, offs; + + gl2psPDFgroupListInit(); + gl2psPDFgroupListWriteMainStream(); + + 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] = + gl2psPDFgroupListWriteObjects(gl2ps->xreflist[8]); + + /* Start cross reference table. The file has to been opened in + binary mode to preserve the 20 digit string length! */ + fprintf(gl2ps->stream, + "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" + "/Size %d\n" + "/Info 1 0 R\n" + "/Root 2 0 R\n" + ">>\n" + "startxref\n%d\n" + "%%%%EOF\n", + gl2ps->objects_stack, gl2ps->xreflist[gl2ps->objects_stack]); + + /* 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(); + gl2psFree(gl2ps->compress); + gl2ps->compress = NULL; + } +#endif +} + +/* PDF begin viewport */ + +static void gl2psPrintPDFBeginViewport(GLint viewport[4]) +{ + int offs = 0; + 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); + } + else{ + glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); + rgba[0] = gl2ps->colormap[index][0]; + rgba[1] = gl2ps->colormap[index][1]; + rgba[2] = gl2ps->colormap[index][2]; + rgba[3] = 1.0F; + } + offs += gl2psPrintPDFFillColor(rgba); + offs += gl2psPrintf("%d %d %d %d re\n" + "W\n" + "f\n", + x, y, w, h); + } + else{ + offs += gl2psPrintf("%d %d %d %d re\n" + "W\n" + "n\n", + x, y, w, h); + } + + gl2ps->streamlength += offs; +} + +static GLint gl2psPrintPDFEndViewport(void) +{ + GLint res; + + res = gl2psPrintPrimitives(); + gl2ps->streamlength += gl2psPrintf("Q\n"); + return res; +} + +static void gl2psPrintPDFFinalPrimitive(void) +{ +} + +/* definition of the PDF backend */ + +static GL2PSbackend gl2psPDF = { + gl2psPrintPDFHeader, + gl2psPrintPDFFooter, + gl2psPrintPDFBeginViewport, + gl2psPrintPDFEndViewport, + gl2psPrintPDFPrimitive, + gl2psPrintPDFFinalPrimitive, + "pdf", + "Portable Document Format" +}; + +/********************************************************************* + * + * SVG routines + * + *********************************************************************/ + +static void gl2psSVGGetCoordsAndColors(int n, GL2PSvertex *verts, + GL2PSxyz *xyz, GL2PSrgba *rgba) +{ + int i, j; + + for(i = 0; i < n; i++){ + xyz[i][0] = verts[i].xyz[0]; + xyz[i][1] = gl2ps->viewport[3] - verts[i].xyz[1]; + xyz[i][2] = 0.0F; + for(j = 0; j < 4; j++) + rgba[i][j] = verts[i].rgba[j]; + } +} + +static void gl2psSVGGetColorString(GL2PSrgba rgba, char str[32]) +{ + int r = (int)(255. * rgba[0]); + int g = (int)(255. * rgba[1]); + int b = (int)(255. * rgba[2]); + int rc = (r < 0) ? 0 : (r > 255) ? 255 : r; + int gc = (g < 0) ? 0 : (g > 255) ? 255 : g; + int bc = (b < 0) ? 0 : (b > 255) ? 255 : b; + sprintf(str, "#%2.2x%2.2x%2.2x", rc, gc, bc); +} + +static void gl2psPrintSVGHeader(void) +{ + 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]; + width = (int)gl2ps->viewport[3]; + height = (int)gl2ps->viewport[2]; + } + else{ + x = (int)gl2ps->viewport[0]; + y = (int)gl2ps->viewport[1]; + width = (int)gl2ps->viewport[2]; + height = (int)gl2ps->viewport[3]; + } + + /* Compressed SVG files (.svgz) are simply gzipped SVG files */ + gl2psPrintGzipHeader(); + + gl2psPrintf("\n"); + gl2psPrintf("\n", + width, height, x, y, width, height); + gl2psPrintf("%s\n", gl2ps->title); + gl2psPrintf("\n"); + gl2psPrintf("Creator: GL2PS %d.%d.%d%s, %s\n" + "For: %s\n" + "CreationDate: %s", + GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, GL2PS_PATCH_VERSION, + GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, gl2ps->producer, ctime(&now)); + gl2psPrintf("\n"); + gl2psPrintf("\n"); + gl2psPrintf("\n"); + + if(gl2ps->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[3]); + } + + /* group all the primitives and disable antialiasing */ + gl2psPrintf("\n"); +} + +static void gl2psPrintSVGSmoothTriangle(GL2PSxyz xyz[3], GL2PSrgba rgba[3]) +{ + int i; + GL2PSxyz xyz2[3]; + GL2PSrgba rgba2[3]; + char col[32]; + + /* Apparently there is no easy way to do Gouraud shading in SVG + without explicitly pre-defining gradients, so for now we just do + recursive subdivision */ + + if(gl2psSameColorThreshold(3, rgba, gl2ps->threshold)){ + gl2psSVGGetColorString(rgba[0], col); + gl2psPrintf("\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[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[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[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[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[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[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[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[2][i] = 0.5F * (rgba[0][i] + rgba[2][i]); + } + gl2psPrintSVGSmoothTriangle(xyz2, rgba2); + } +} + +static void gl2psPrintSVGDash(GLushort pattern, GLint factor) +{ + int i, n, array[10]; + + if(!pattern || !factor) return; /* solid line */ + + gl2psParseStipplePattern(pattern, factor, &n, array); + gl2psPrintf("stroke-dasharray=\""); + for(i = 0; i < n; i++){ + if(i) gl2psPrintf(","); + gl2psPrintf("%d", array[i]); + } + gl2psPrintf("\" "); +} + +static void gl2psEndSVGLine(void) +{ + int i; + if(gl2ps->lastvertex.rgba[0] >= 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.; + for(i = 0; i < 4; i++) + gl2ps->lastvertex.rgba[i] = -1.; + } +} + +static void gl2psPrintSVGPixmap(GLfloat x, GLfloat y, GL2PSimage *pixmap) +{ +#if defined(GL2PS_HAVE_LIBPNG) + GL2PSlist *png; + unsigned char c; + int i; + + /* The only image types supported by the SVG standard are JPEG, PNG + and SVG. Here we choose PNG, and since we want to embed the image + directly in the SVG stream (and not link to an external image + file), we need to encode the pixmap into PNG in memory, then + encode it into base64. */ + + png = gl2psListCreate(pixmap->width * pixmap->height * 3, 1000, + sizeof(unsigned char)); + gl2psConvertPixmapToPNG(pixmap, png); + gl2psListEncodeBase64(png); + gl2psPrintf("height, pixmap->width, pixmap->height); + gl2psPrintf("xlink:href=\"data:image/png;base64,"); + for(i = 0; i < gl2psListNbr(png); i++){ + gl2psListRead(png, i, &c); + gl2psPrintf("%c", c); + } + gl2psPrintf("\"/>\n"); + gl2psListDelete(png); +#else + (void) x; (void) y; (void) pixmap; /* not used */ + gl2psMsg(GL2PS_WARNING, "GL2PS must be compiled with PNG support in " + "order to embed images in SVG streams"); +#endif +} + +static void gl2psPrintSVGPrimitive(void *data) +{ + GL2PSprimitive *prim; + GL2PSxyz xyz[4]; + GL2PSrgba rgba[4]; + char col[32]; + int newline; + + prim = *(GL2PSprimitive**)data; + + if((gl2ps->options & GL2PS_OCCLUSION_CULL) && prim->culled) return; + + /* We try to draw connected lines as a single path to get nice line + joins and correct stippling. So if the primitive to print is not + a line we must first finish the current line (if any): */ + if(prim->type != GL2PS_LINE) gl2psEndSVGLine(); + + gl2psSVGGetCoordsAndColors(prim->numverts, prim->verts, xyz, rgba); + + switch(prim->type){ + case GL2PS_POINT : + gl2psSVGGetColorString(rgba[0], col); + gl2psPrintf("\n", + xyz[0][0], xyz[0][1], 0.5 * prim->width); + break; + case GL2PS_LINE : + if(!gl2psSamePosition(gl2ps->lastvertex.xyz, prim->verts[0].xyz) || + !gl2psSameColor(gl2ps->lastrgba, prim->verts[0].rgba) || + gl2ps->lastlinewidth != prim->width || + gl2ps->lastpattern != prim->pattern || + gl2ps->lastfactor != prim->factor){ + /* End the current line if the new segment does not start where + the last one ended, or if the color, the width or the + stippling have changed (we will need to use multi-point + gradients for smooth-shaded lines) */ + gl2psEndSVGLine(); + newline = 1; + } + else{ + newline = 0; + } + gl2ps->lastvertex = prim->verts[1]; + gl2psSetLastColor(prim->verts[0].rgba); + gl2ps->lastlinewidth = prim->width; + gl2ps->lastpattern = prim->pattern; + 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); + gl2psPrintf("points=\"%g,%g ", xyz[0][0], xyz[0][1]); + } + else{ + gl2psPrintf("%g,%g ", xyz[0][0], xyz[0][1]); + } + break; + case GL2PS_TRIANGLE : + gl2psPrintSVGSmoothTriangle(xyz, rgba); + break; + case GL2PS_QUADRANGLE : + gl2psMsg(GL2PS_WARNING, "There should not be any quad left to print"); + break; + case GL2PS_PIXMAP : + gl2psPrintSVGPixmap(xyz[0][0], xyz[0][1], prim->data.image); + break; + case GL2PS_TEXT : + gl2psSVGGetColorString(prim->verts[0].rgba, col); + gl2psPrintf("data.text->fontsize); + 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")) + gl2psPrintf("font-family=\"Times\" font-weight=\"bold\">"); + else if(!strcmp(prim->data.text->fontname, "Times-Italic")) + gl2psPrintf("font-family=\"Times\" font-style=\"italic\">"); + else if(!strcmp(prim->data.text->fontname, "Times-BoldItalic")) + gl2psPrintf("font-family=\"Times\" font-style=\"italic\" font-weight=\"bold\">"); + else if(!strcmp(prim->data.text->fontname, "Helvetica-Bold")) + gl2psPrintf("font-family=\"Helvetica\" font-weight=\"bold\">"); + else if(!strcmp(prim->data.text->fontname, "Helvetica-Oblique")) + gl2psPrintf("font-family=\"Helvetica\" font-style=\"oblique\">"); + else if(!strcmp(prim->data.text->fontname, "Helvetica-BoldOblique")) + gl2psPrintf("font-family=\"Helvetica\" font-style=\"oblique\" font-weight=\"bold\">"); + else if(!strcmp(prim->data.text->fontname, "Courier-Bold")) + gl2psPrintf("font-family=\"Courier\" font-weight=\"bold\">"); + else if(!strcmp(prim->data.text->fontname, "Courier-Oblique")) + gl2psPrintf("font-family=\"Courier\" font-style=\"oblique\">"); + else if(!strcmp(prim->data.text->fontname, "Courier-BoldOblique")) + gl2psPrintf("font-family=\"Courier\" font-style=\"oblique\" font-weight=\"bold\">"); + else + gl2psPrintf("font-family=\"%s\">", prim->data.text->fontname); + gl2psPrintf("%s\n", prim->data.text->str); + break; + case GL2PS_SPECIAL : + /* alignment contains the format for which the special output text + is intended */ + if(prim->data.text->alignment == GL2PS_SVG) + gl2psPrintf("%s\n", prim->data.text->str); + break; + default : + break; + } +} + +static void gl2psPrintSVGFooter(void) +{ + gl2psPrintf("\n"); + gl2psPrintf("\n"); + + gl2psPrintGzipFooter(); +} + +static void gl2psPrintSVGBeginViewport(GLint viewport[4]) +{ + GLint index; + char col[32]; + GLfloat rgba[4]; + int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; + + glRenderMode(GL_FEEDBACK); + + if(gl2ps->header){ + gl2psPrintSVGHeader(); + gl2ps->header = GL_FALSE; + } + + if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ + if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ + glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); + } + else{ + glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); + rgba[0] = gl2ps->colormap[index][0]; + rgba[1] = gl2ps->colormap[index][1]; + rgba[2] = gl2ps->colormap[index][2]; + 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), + 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), + x, gl2ps->viewport[3] - (y + h)); + gl2psPrintf("\n"); + gl2psPrintf("\n", x, y, w, h); +} + +static GLint gl2psPrintSVGEndViewport(void) +{ + GLint res; + + res = gl2psPrintPrimitives(); + gl2psPrintf("\n"); + return res; +} + +static void gl2psPrintSVGFinalPrimitive(void) +{ + /* End any remaining line, if any */ + gl2psEndSVGLine(); +} + +/* definition of the SVG backend */ + +static GL2PSbackend gl2psSVG = { + gl2psPrintSVGHeader, + gl2psPrintSVGFooter, + gl2psPrintSVGBeginViewport, + gl2psPrintSVGEndViewport, + gl2psPrintSVGPrimitive, + gl2psPrintSVGFinalPrimitive, + "svg", + "Scalable Vector Graphics" +}; + +/********************************************************************* + * + * PGF routines + * + *********************************************************************/ + +static void gl2psPrintPGFColor(GL2PSrgba rgba) +{ + if(!gl2psSameColor(gl2ps->lastrgba, rgba)){ + gl2psSetLastColor(rgba); + fprintf(gl2ps->stream, "\\color[rgb]{%f,%f,%f}\n", rgba[0], rgba[1], rgba[2]); + } +} + +static void gl2psPrintPGFHeader(void) +{ + time_t now; + + time(&now); + + fprintf(gl2ps->stream, + "%% Title: %s\n" + "%% Creator: GL2PS %d.%d.%d%s, %s\n" + "%% For: %s\n" + "%% CreationDate: %s", + gl2ps->title, GL2PS_MAJOR_VERSION, GL2PS_MINOR_VERSION, + GL2PS_PATCH_VERSION, GL2PS_EXTRA_VERSION, GL2PS_COPYRIGHT, + gl2ps->producer, ctime(&now)); + + fprintf(gl2ps->stream, "\\begin{pgfpicture}\n"); + if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ + gl2psPrintPGFColor(gl2ps->bgcolor); + fprintf(gl2ps->stream, + "\\pgfpathrectanglecorners{" + "\\pgfpoint{%dpt}{%dpt}}{\\pgfpoint{%dpt}{%dpt}}\n" + "\\pgfusepath{fill}\n", + (int)gl2ps->viewport[0], (int)gl2ps->viewport[1], + (int)gl2ps->viewport[2], (int)gl2ps->viewport[3]); + } +} + +static void gl2psPrintPGFDash(GLushort pattern, GLint factor) +{ + int i, n, array[10]; + + if(pattern == gl2ps->lastpattern && factor == gl2ps->lastfactor) + return; + + gl2ps->lastpattern = pattern; + gl2ps->lastfactor = factor; + + if(!pattern || !factor){ + /* solid line */ + fprintf(gl2ps->stream, "\\pgfsetdash{}{0pt}\n"); + } + else{ + gl2psParseStipplePattern(pattern, factor, &n, array); + fprintf(gl2ps->stream, "\\pgfsetdash{"); + for(i = 0; i < n; i++) fprintf(gl2ps->stream, "{%dpt}", array[i]); + fprintf(gl2ps->stream, "}{0pt}\n"); + } +} + +static const char *gl2psPGFTextAlignment(int align) +{ + switch(align){ + case GL2PS_TEXT_C : return "center"; + case GL2PS_TEXT_CL : return "west"; + case GL2PS_TEXT_CR : return "east"; + case GL2PS_TEXT_B : return "south"; + case GL2PS_TEXT_BR : return "south east"; + case GL2PS_TEXT_T : return "north"; + case GL2PS_TEXT_TL : return "north west"; + case GL2PS_TEXT_TR : return "north east"; + case GL2PS_TEXT_BL : + default : return "south west"; + } +} + +static void gl2psPrintPGFPrimitive(void *data) +{ + GL2PSprimitive *prim; + + prim = *(GL2PSprimitive**)data; + + switch(prim->type){ + case GL2PS_POINT : + /* Points in openGL are rectangular */ + gl2psPrintPGFColor(prim->verts[0].rgba); + fprintf(gl2ps->stream, + "\\pgfpathrectangle{\\pgfpoint{%fpt}{%fpt}}" + "{\\pgfpoint{%fpt}{%fpt}}\n\\pgfusepath{fill}\n", + prim->verts[0].xyz[0]-0.5*prim->width, + prim->verts[0].xyz[1]-0.5*prim->width, + prim->width,prim->width); + break; + case GL2PS_LINE : + gl2psPrintPGFColor(prim->verts[0].rgba); + if(gl2ps->lastlinewidth != prim->width){ + gl2ps->lastlinewidth = prim->width; + fprintf(gl2ps->stream, "\\pgfsetlinewidth{%fpt}\n", gl2ps->lastlinewidth); + } + gl2psPrintPGFDash(prim->pattern, prim->factor); + fprintf(gl2ps->stream, + "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n" + "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" + "\\pgfusepath{stroke}\n", + prim->verts[1].xyz[0], prim->verts[1].xyz[1], + prim->verts[0].xyz[0], prim->verts[0].xyz[1]); + break; + case GL2PS_TRIANGLE : + if(gl2ps->lastlinewidth != 0){ + gl2ps->lastlinewidth = 0; + fprintf(gl2ps->stream, "\\pgfsetlinewidth{0.01pt}\n"); + } + gl2psPrintPGFColor(prim->verts[0].rgba); + fprintf(gl2ps->stream, + "\\pgfpathmoveto{\\pgfpoint{%fpt}{%fpt}}\n" + "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" + "\\pgflineto{\\pgfpoint{%fpt}{%fpt}}\n" + "\\pgfpathclose\n" + "\\pgfusepath{fill,stroke}\n", + prim->verts[2].xyz[0], prim->verts[2].xyz[1], + prim->verts[1].xyz[0], prim->verts[1].xyz[1], + prim->verts[0].xyz[0], prim->verts[0].xyz[1]); + break; + case GL2PS_TEXT : + fprintf(gl2ps->stream, "{\n\\pgftransformshift{\\pgfpoint{%fpt}{%fpt}}\n", + prim->verts[0].xyz[0], prim->verts[0].xyz[1]); + + if(prim->data.text->angle) + fprintf(gl2ps->stream, "\\pgftransformrotate{%f}{", prim->data.text->angle); + + fprintf(gl2ps->stream, "\\pgfnode{rectangle}{%s}{\\fontsize{%d}{0}\\selectfont", + gl2psPGFTextAlignment(prim->data.text->alignment), + prim->data.text->fontsize); + + 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); + + fprintf(gl2ps->stream, "}{}{\\pgfusepath{discard}}}\n"); + break; + case GL2PS_SPECIAL : + /* alignment contains the format for which the special output text + is intended */ + if (prim->data.text->alignment == GL2PS_PGF) + fprintf(gl2ps->stream, "%s\n", prim->data.text->str); + break; + default : + break; + } +} + +static void gl2psPrintPGFFooter(void) +{ + fprintf(gl2ps->stream, "\\end{pgfpicture}\n"); +} + +static void gl2psPrintPGFBeginViewport(GLint viewport[4]) +{ + GLint index; + GLfloat rgba[4]; + int x = viewport[0], y = viewport[1], w = viewport[2], h = viewport[3]; + + glRenderMode(GL_FEEDBACK); + + if(gl2ps->header){ + gl2psPrintPGFHeader(); + gl2ps->header = GL_FALSE; + } + + fprintf(gl2ps->stream, "\\begin{pgfscope}\n"); + if(gl2ps->options & GL2PS_DRAW_BACKGROUND){ + if(gl2ps->colormode == GL_RGBA || gl2ps->colorsize == 0){ + glGetFloatv(GL_COLOR_CLEAR_VALUE, rgba); + } + else{ + glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); + rgba[0] = gl2ps->colormap[index][0]; + rgba[1] = gl2ps->colormap[index][1]; + rgba[2] = gl2ps->colormap[index][2]; + rgba[3] = 1.0F; + } + gl2psPrintPGFColor(rgba); + fprintf(gl2ps->stream, + "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}" + "{\\pgfpoint{%dpt}{%dpt}}\n" + "\\pgfusepath{fill}\n", + x, y, w, h); + } + + fprintf(gl2ps->stream, + "\\pgfpathrectangle{\\pgfpoint{%dpt}{%dpt}}" + "{\\pgfpoint{%dpt}{%dpt}}\n" + "\\pgfusepath{clip}\n", + x, y, w, h); +} + +static GLint gl2psPrintPGFEndViewport(void) +{ + GLint res; + res = gl2psPrintPrimitives(); + fprintf(gl2ps->stream, "\\end{pgfscope}\n"); + return res; +} + +static void gl2psPrintPGFFinalPrimitive(void) +{ +} + +/* definition of the PGF backend */ + +static GL2PSbackend gl2psPGF = { + gl2psPrintPGFHeader, + gl2psPrintPGFFooter, + gl2psPrintPGFBeginViewport, + gl2psPrintPGFEndViewport, + gl2psPrintPGFPrimitive, + gl2psPrintPGFFinalPrimitive, + "tex", + "PGF Latex Graphics" +}; + +/********************************************************************* + * + * General primitive printing routine + * + *********************************************************************/ + +/* Warning: the ordering of the backends must match the format + #defines in gl2ps.h */ + +static GL2PSbackend *gl2psbackends[] = { + &gl2psPS, /* 0 */ + &gl2psEPS, /* 1 */ + &gl2psTEX, /* 2 */ + &gl2psPDF, /* 3 */ + &gl2psSVG, /* 4 */ + &gl2psPGF /* 5 */ +}; + +static void gl2psComputeTightBoundingBox(void *data) +{ + GL2PSprimitive *prim; + int i; + + prim = *(GL2PSprimitive**)data; + + for(i = 0; i < prim->numverts; i++){ + if(prim->verts[i].xyz[0] < gl2ps->viewport[0]) + gl2ps->viewport[0] = (GLint)prim->verts[i].xyz[0]; + if(prim->verts[i].xyz[0] > gl2ps->viewport[2]) + gl2ps->viewport[2] = (GLint)(prim->verts[i].xyz[0] + 0.5F); + if(prim->verts[i].xyz[1] < gl2ps->viewport[1]) + gl2ps->viewport[1] = (GLint)prim->verts[i].xyz[1]; + if(prim->verts[i].xyz[1] > gl2ps->viewport[3]) + gl2ps->viewport[3] = (GLint)(prim->verts[i].xyz[1] + 0.5F); + } +} + +static GLint gl2psPrintPrimitives(void) +{ + GL2PSbsptree *root; + GL2PSxyz eye = {0.0F, 0.0F, 100.0F * GL2PS_ZSCALE}; + GLint used; + + used = glRenderMode(GL_RENDER); + + if(used < 0){ + gl2psMsg(GL2PS_INFO, "OpenGL feedback buffer overflow"); + return GL2PS_OVERFLOW; + } + + if(used > 0) + gl2psParseFeedbackBuffer(used); + + gl2psRescaleAndOffset(); + + if(gl2ps->header){ + if(gl2psListNbr(gl2ps->primitives) && + (gl2ps->options & GL2PS_TIGHT_BOUNDING_BOX)){ + gl2ps->viewport[0] = gl2ps->viewport[1] = 100000; + gl2ps->viewport[2] = gl2ps->viewport[3] = -100000; + gl2psListAction(gl2ps->primitives, gl2psComputeTightBoundingBox); + } + (gl2psbackends[gl2ps->format]->printHeader)(); + gl2ps->header = GL_FALSE; + } + + if(!gl2psListNbr(gl2ps->primitives)){ + /* empty feedback buffer and/or nothing else to print */ + return GL2PS_NO_FEEDBACK; + } + + switch(gl2ps->sort){ + case GL2PS_NO_SORT : + gl2psListAction(gl2ps->primitives, gl2psbackends[gl2ps->format]->printPrimitive); + gl2psListAction(gl2ps->primitives, gl2psFreePrimitive); + /* reset the primitive list, waiting for the next viewport */ + gl2psListReset(gl2ps->primitives); + break; + case GL2PS_SIMPLE_SORT : + gl2psListSort(gl2ps->primitives, gl2psCompareDepth); + if(gl2ps->options & GL2PS_OCCLUSION_CULL){ + gl2psListActionInverse(gl2ps->primitives, gl2psAddInImageTree); + gl2psFreeBspImageTree(&gl2ps->imagetree); + } + gl2psListAction(gl2ps->primitives, gl2psbackends[gl2ps->format]->printPrimitive); + gl2psListAction(gl2ps->primitives, gl2psFreePrimitive); + /* reset the primitive list, waiting for the next viewport */ + gl2psListReset(gl2ps->primitives); + break; + case GL2PS_BSP_SORT : + root = (GL2PSbsptree*)gl2psMalloc(sizeof(GL2PSbsptree)); + gl2psBuildBspTree(root, gl2ps->primitives); + if(GL_TRUE == gl2ps->boundary) gl2psBuildPolygonBoundary(root); + if(gl2ps->options & GL2PS_OCCLUSION_CULL){ + gl2psTraverseBspTree(root, eye, -GL2PS_EPSILON, gl2psLess, + gl2psAddInImageTree, 1); + gl2psFreeBspImageTree(&gl2ps->imagetree); + } + gl2psTraverseBspTree(root, eye, GL2PS_EPSILON, gl2psGreater, + gl2psbackends[gl2ps->format]->printPrimitive, 0); + gl2psFreeBspTree(&root); + /* reallocate the primitive list (it's been deleted by + gl2psBuildBspTree) in case there is another viewport */ + gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*)); + break; + } + gl2psbackends[gl2ps->format]->printFinalPrimitive(); + + return GL2PS_SUCCESS; +} + +/********************************************************************* + * + * Public routines + * + *********************************************************************/ + +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 nr, GLint ng, GLint nb, GLint buffersize, + FILE *stream, const char *filename) +{ + GLint index; + int i; + + if(gl2ps){ + gl2psMsg(GL2PS_ERROR, "gl2psBeginPage called in wrong program state"); + return GL2PS_ERROR; + } + + gl2ps = (GL2PScontext*)gl2psMalloc(sizeof(GL2PScontext)); + + if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0]))){ + gl2ps->format = format; + } + else { + gl2psMsg(GL2PS_ERROR, "Unknown output format: %d", format); + gl2psFree(gl2ps); + gl2ps = NULL; + return GL2PS_ERROR; + } + + switch(sort){ + case GL2PS_NO_SORT : + case GL2PS_SIMPLE_SORT : + case GL2PS_BSP_SORT : + gl2ps->sort = sort; + break; + default : + gl2psMsg(GL2PS_ERROR, "Unknown sorting algorithm: %d", sort); + gl2psFree(gl2ps); + gl2ps = NULL; + return GL2PS_ERROR; + } + + if(stream){ + gl2ps->stream = stream; + } + else{ + gl2psMsg(GL2PS_ERROR, "Bad file pointer"); + gl2psFree(gl2ps); + gl2ps = NULL; + return GL2PS_ERROR; + } + + gl2ps->header = GL_TRUE; + gl2ps->maxbestroot = 10; + gl2ps->options = options; + gl2ps->compress = NULL; + gl2ps->imagemap_head = NULL; + gl2ps->imagemap_tail = NULL; + + if(gl2ps->options & GL2PS_USE_CURRENT_VIEWPORT){ + glGetIntegerv(GL_VIEWPORT, gl2ps->viewport); + } + else{ + for(i = 0; i < 4; i++){ + gl2ps->viewport[i] = viewport[i]; + } + } + + 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[2], gl2ps->viewport[3]); + gl2psFree(gl2ps); + gl2ps = NULL; + return GL2PS_ERROR; + } + + gl2ps->threshold[0] = nr ? 1.0F / (GLfloat)nr : 0.064F; + gl2ps->threshold[1] = ng ? 1.0F / (GLfloat)ng : 0.034F; + gl2ps->threshold[2] = nb ? 1.0F / (GLfloat)nb : 0.100F; + gl2ps->colormode = colormode; + gl2ps->buffersize = buffersize > 0 ? buffersize : 2048 * 2048; + for(i = 0; i < 3; i++){ + gl2ps->lastvertex.xyz[i] = -1.0F; + } + for(i = 0; i < 4; i++){ + gl2ps->lastvertex.rgba[i] = -1.0F; + gl2ps->lastrgba[i] = -1.0F; + } + gl2ps->lastlinewidth = -1.0F; + gl2ps->lastpattern = 0; + gl2ps->lastfactor = 0; + gl2ps->imagetree = NULL; + gl2ps->primitivetoadd = NULL; + 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); + glGetIntegerv(GL_BLEND_SRC, &gl2ps->blendfunc[0]); + glGetIntegerv(GL_BLEND_DST, &gl2ps->blendfunc[1]); + + if(gl2ps->colormode == GL_RGBA){ + gl2ps->colorsize = 0; + gl2ps->colormap = NULL; + glGetFloatv(GL_COLOR_CLEAR_VALUE, gl2ps->bgcolor); + } + else if(gl2ps->colormode == GL_COLOR_INDEX){ + if(!colorsize || !colormap){ + gl2psMsg(GL2PS_ERROR, "Missing colormap for GL_COLOR_INDEX rendering"); + gl2psFree(gl2ps); + gl2ps = NULL; + return GL2PS_ERROR; + } + gl2ps->colorsize = colorsize; + gl2ps->colormap = (GL2PSrgba*)gl2psMalloc(gl2ps->colorsize * sizeof(GL2PSrgba)); + memcpy(gl2ps->colormap, colormap, gl2ps->colorsize * sizeof(GL2PSrgba)); + glGetIntegerv(GL_INDEX_CLEAR_VALUE, &index); + gl2ps->bgcolor[0] = gl2ps->colormap[index][0]; + gl2ps->bgcolor[1] = gl2ps->colormap[index][1]; + gl2ps->bgcolor[2] = gl2ps->colormap[index][2]; + gl2ps->bgcolor[3] = 1.0F; + } + else{ + gl2psMsg(GL2PS_ERROR, "Unknown color mode in gl2psBeginPage"); + gl2psFree(gl2ps); + gl2ps = NULL; + return GL2PS_ERROR; + } + + if(!title){ + gl2ps->title = (char*)gl2psMalloc(sizeof(char)); + gl2ps->title[0] = '\0'; + } + else{ + 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'; + } + else{ + 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'; + } + else{ + gl2ps->filename = (char*)gl2psMalloc((strlen(filename)+1)*sizeof(char)); + strcpy(gl2ps->filename, filename); + } + + gl2ps->primitives = gl2psListCreate(500, 500, sizeof(GL2PSprimitive*)); + 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); + + return GL2PS_SUCCESS; +} + +GL2PSDLL_API GLint gl2psEndPage(void) +{ + GLint res; + + if(!gl2ps) return GL2PS_UNINITIALIZED; + + res = gl2psPrintPrimitives(); + + if(res != GL2PS_OVERFLOW) + (gl2psbackends[gl2ps->format]->printFooter)(); + + fflush(gl2ps->stream); + + gl2psListDelete(gl2ps->primitives); + gl2psListDelete(gl2ps->auxprimitives); + gl2psFreeImagemap(gl2ps->imagemap_head); + gl2psFree(gl2ps->colormap); + gl2psFree(gl2ps->title); + gl2psFree(gl2ps->producer); + gl2psFree(gl2ps->filename); + gl2psFree(gl2ps->feedback); + gl2psFree(gl2ps); + gl2ps = NULL; + + return res; +} + +GL2PSDLL_API GLint gl2psBeginViewport(GLint viewport[4]) +{ + if(!gl2ps) return GL2PS_UNINITIALIZED; + + (gl2psbackends[gl2ps->format]->beginViewport)(viewport); + + return GL2PS_SUCCESS; +} + +GL2PSDLL_API GLint gl2psEndViewport(void) +{ + GLint res; + + if(!gl2ps) return GL2PS_UNINITIALIZED; + + res = (gl2psbackends[gl2ps->format]->endViewport)(); + + /* reset last used colors, line widths */ + gl2ps->lastlinewidth = -1.0F; + + return res; +} + +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); +} + +GL2PSDLL_API GLint gl2psText(const char *str, const char *fontname, GLshort fontsize) +{ + return gl2psAddText(GL2PS_TEXT, str, fontname, fontsize, GL2PS_TEXT_BL, 0.0F); +} + +GL2PSDLL_API GLint gl2psSpecial(GLint format, const char *str) +{ + return gl2psAddText(GL2PS_SPECIAL, str, "", 0, format, 0.0F); +} + +GL2PSDLL_API GLint gl2psDrawPixels(GLsizei width, GLsizei height, + GLint xorig, GLint yorig, + GLenum format, GLenum type, + const void *pixels) +{ + int size, i; + const GLfloat *piv; + GLfloat pos[4], zoom_x, zoom_y; + GL2PSprimitive *prim; + GLboolean valid; + + if(!gl2ps || !pixels) return GL2PS_UNINITIALIZED; + + if((width <= 0) || (height <= 0)) return GL2PS_ERROR; + + if(gl2ps->options & GL2PS_NO_PIXMAP) return GL2PS_SUCCESS; + + if((format != GL_RGB && format != GL_RGBA) || type != GL_FLOAT){ + gl2psMsg(GL2PS_ERROR, "gl2psDrawPixels only implemented for " + "GL_RGB/GL_RGBA, GL_FLOAT pixels"); + return GL2PS_ERROR; + } + + glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid); + 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; + prim->boundary = 0; + prim->numverts = 1; + prim->verts = (GL2PSvertex*)gl2psMalloc(sizeof(GL2PSvertex)); + prim->verts[0].xyz[0] = pos[0] + xorig; + prim->verts[0].xyz[1] = pos[1] + yorig; + prim->verts[0].xyz[2] = pos[2]; + prim->culled = 0; + prim->offset = 0; + prim->pattern = 0; + prim->factor = 0; + prim->width = 1; + glGetFloatv(GL_CURRENT_RASTER_COLOR, prim->verts[0].rgba); + 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; + + switch(format){ + case GL_RGBA: + if(gl2ps->options & GL2PS_NO_BLENDING || !gl2ps->blending){ + /* special case: blending turned off */ + prim->data.image->format = GL_RGB; + size = height * width * 3; + prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat)); + piv = (const GLfloat*)pixels; + for(i = 0; i < size; ++i, ++piv){ + prim->data.image->pixels[i] = *piv; + if(!((i + 1) % 3)) + ++piv; + } + } + else{ + size = height * width * 4; + prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat)); + memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat)); + } + break; + case GL_RGB: + default: + size = height * width * 3; + prim->data.image->pixels = (GLfloat*)gl2psMalloc(size * sizeof(GLfloat)); + memcpy(prim->data.image->pixels, pixels, size * sizeof(GLfloat)); + break; + } + + gl2psListAdd(gl2ps->auxprimitives, &prim); + glPassThrough(GL2PS_DRAW_PIXELS_TOKEN); + + return GL2PS_SUCCESS; +} + +GL2PSDLL_API GLint gl2psDrawImageMap(GLsizei width, GLsizei height, + const GLfloat position[3], + 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); + glVertex3f(position[0], position[1],position[2]); + glEnd(); + glPassThrough((GLfloat)width); + glPassThrough((GLfloat)height); + for(i = 0; i < size; i += sizeoffloat){ + const float *value = (const float*)imagemap; + glPassThrough(*value); + imagemap += sizeoffloat; + } + return GL2PS_SUCCESS; +} + +GL2PSDLL_API GLint gl2psEnable(GLint mode) +{ + GLint tmp; + + if(!gl2ps) return GL2PS_UNINITIALIZED; + + switch(mode){ + case GL2PS_POLYGON_OFFSET_FILL : + glPassThrough(GL2PS_BEGIN_OFFSET_TOKEN); + glGetFloatv(GL_POLYGON_OFFSET_FACTOR, &gl2ps->offset[0]); + glGetFloatv(GL_POLYGON_OFFSET_UNITS, &gl2ps->offset[1]); + break; + case GL2PS_POLYGON_BOUNDARY : + glPassThrough(GL2PS_BEGIN_BOUNDARY_TOKEN); + break; + case GL2PS_LINE_STIPPLE : + glPassThrough(GL2PS_BEGIN_STIPPLE_TOKEN); + glGetIntegerv(GL_LINE_STIPPLE_PATTERN, &tmp); + glPassThrough((GLfloat)tmp); + glGetIntegerv(GL_LINE_STIPPLE_REPEAT, &tmp); + glPassThrough((GLfloat)tmp); + break; + case GL2PS_BLEND : + glPassThrough(GL2PS_BEGIN_BLEND_TOKEN); + break; + default : + gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psEnable: %d", mode); + return GL2PS_WARNING; + } + + return GL2PS_SUCCESS; +} + +GL2PSDLL_API GLint gl2psDisable(GLint mode) +{ + if(!gl2ps) return GL2PS_UNINITIALIZED; + + switch(mode){ + case GL2PS_POLYGON_OFFSET_FILL : + glPassThrough(GL2PS_END_OFFSET_TOKEN); + break; + case GL2PS_POLYGON_BOUNDARY : + glPassThrough(GL2PS_END_BOUNDARY_TOKEN); + break; + case GL2PS_LINE_STIPPLE : + glPassThrough(GL2PS_END_STIPPLE_TOKEN); + break; + case GL2PS_BLEND : + glPassThrough(GL2PS_END_BLEND_TOKEN); + break; + default : + gl2psMsg(GL2PS_WARNING, "Unknown mode in gl2psDisable: %d", mode); + return GL2PS_WARNING; + } + + return GL2PS_SUCCESS; +} + +GL2PSDLL_API GLint gl2psPointSize(GLfloat value) +{ + if(!gl2ps) return GL2PS_UNINITIALIZED; + + glPassThrough(GL2PS_POINT_SIZE_TOKEN); + glPassThrough(value); + + return GL2PS_SUCCESS; +} + +GL2PSDLL_API GLint gl2psLineWidth(GLfloat value) +{ + if(!gl2ps) return GL2PS_UNINITIALIZED; + + glPassThrough(GL2PS_LINE_WIDTH_TOKEN); + glPassThrough(value); + + return GL2PS_SUCCESS; +} + +GL2PSDLL_API GLint gl2psBlendFunc(GLenum sfactor, GLenum dfactor) +{ + if(!gl2ps) return GL2PS_UNINITIALIZED; + + if(GL_FALSE == gl2psSupportedBlendMode(sfactor, dfactor)) + return GL2PS_WARNING; + + glPassThrough(GL2PS_SRC_BLEND_TOKEN); + glPassThrough((GLfloat)sfactor); + glPassThrough(GL2PS_DST_BLEND_TOKEN); + glPassThrough((GLfloat)dfactor); + + return GL2PS_SUCCESS; +} + +GL2PSDLL_API GLint gl2psSetOptions(GLint options) +{ + if(!gl2ps) return GL2PS_UNINITIALIZED; + + gl2ps->options = options; + + return GL2PS_SUCCESS; +} + +GL2PSDLL_API GLint gl2psGetOptions(GLint *options) +{ + if(!gl2ps) { + *options = 0; + return GL2PS_UNINITIALIZED; + } + + *options = gl2ps->options; + + return GL2PS_SUCCESS; +} + +GL2PSDLL_API const char *gl2psGetFileExtension(GLint format) +{ + if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0]))) + return gl2psbackends[format]->file_extension; + else + return "Unknown format"; +} + +GL2PSDLL_API const char *gl2psGetFormatDescription(GLint format) +{ + if(format >= 0 && format < (GLint)(sizeof(gl2psbackends) / sizeof(gl2psbackends[0]))) + return gl2psbackends[format]->description; + else + return "Unknown format"; +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/gl2ps.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/gl2ps.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,200 @@ +/* + * GL2PS, an OpenGL to PostScript Printing Library + * Copyright (C) 1999-2011 C. Geuzaine + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of either: + * + * a) the GNU Library General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your + * option) any later version; or + * + * b) the GL2PS License as published by Christophe Geuzaine, either + * version 2 of the License, or (at your option) any later version. + * + * This program 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 either + * the GNU Library General Public License or the GL2PS License for + * more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library in the file named "COPYING.LGPL"; + * if not, write to the Free Software Foundation, Inc., 675 Mass Ave, + * Cambridge, MA 02139, USA. + * + * You should have received a copy of the GL2PS License with this + * library in the file named "COPYING.GL2PS"; if not, I will be glad + * to provide one. + * + * For the latest info about gl2ps and a full list of contributors, + * see http://www.geuz.org/gl2ps/. + * + * Please report all bugs and problems to . + */ + +#ifndef __GL2PS_H__ +#define __GL2PS_H__ + +#include +#include + +/* Define GL2PSDLL at compile time to build a Windows DLL */ + +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__) +# if defined(_MSC_VER) +# pragma warning(disable:4115) +# pragma warning(disable:4996) +# endif +# define WIN32_LEAN_AND_MEAN +# include +# if defined(GL2PSDLL) +# if defined(GL2PSDLL_EXPORTS) +# define GL2PSDLL_API __declspec(dllexport) +# else +# define GL2PSDLL_API __declspec(dllimport) +# endif +# else +# define GL2PSDLL_API +# endif +#else +# define GL2PSDLL_API +#endif + +#if defined(__APPLE__) || defined(HAVE_OPENGL_GL_H) +# include +#else +# include +#endif + +/* Support for compressed PostScript/PDF/SVG and for embedded PNG + images in SVG */ + +#if defined(HAVE_ZLIB) || defined(HAVE_LIBZ) +# define GL2PS_HAVE_ZLIB +# if defined(HAVE_LIBPNG) || defined(HAVE_PNG) +# define GL2PS_HAVE_LIBPNG +# endif +#endif + +/* Version number */ + +#define GL2PS_MAJOR_VERSION 1 +#define GL2PS_MINOR_VERSION 3 +#define GL2PS_PATCH_VERSION 6 +#define GL2PS_EXTRA_VERSION "" + +#define GL2PS_VERSION (GL2PS_MAJOR_VERSION + \ + 0.01 * GL2PS_MINOR_VERSION + \ + 0.0001 * GL2PS_PATCH_VERSION) + +#define GL2PS_COPYRIGHT "(C) 1999-2011 C. Geuzaine" + +/* Output file formats (the values and the ordering are important!) */ + +#define GL2PS_PS 0 +#define GL2PS_EPS 1 +#define GL2PS_TEX 2 +#define GL2PS_PDF 3 +#define GL2PS_SVG 4 +#define GL2PS_PGF 5 + +/* Sorting algorithms */ + +#define GL2PS_NO_SORT 1 +#define GL2PS_SIMPLE_SORT 2 +#define GL2PS_BSP_SORT 3 + +/* Message levels and error codes */ + +#define GL2PS_SUCCESS 0 +#define GL2PS_INFO 1 +#define GL2PS_WARNING 2 +#define GL2PS_ERROR 3 +#define GL2PS_NO_FEEDBACK 4 +#define GL2PS_OVERFLOW 5 +#define GL2PS_UNINITIALIZED 6 + +/* Options for gl2psBeginPage */ + +#define GL2PS_NONE 0 +#define GL2PS_DRAW_BACKGROUND (1<<0) +#define GL2PS_SIMPLE_LINE_OFFSET (1<<1) +#define GL2PS_SILENT (1<<2) +#define GL2PS_BEST_ROOT (1<<3) +#define GL2PS_OCCLUSION_CULL (1<<4) +#define GL2PS_NO_TEXT (1<<5) +#define GL2PS_LANDSCAPE (1<<6) +#define GL2PS_NO_PS3_SHADING (1<<7) +#define GL2PS_NO_PIXMAP (1<<8) +#define GL2PS_USE_CURRENT_VIEWPORT (1<<9) +#define GL2PS_COMPRESS (1<<10) +#define GL2PS_NO_BLENDING (1<<11) +#define GL2PS_TIGHT_BOUNDING_BOX (1<<12) + +/* Arguments for gl2psEnable/gl2psDisable */ + +#define GL2PS_POLYGON_OFFSET_FILL 1 +#define GL2PS_POLYGON_BOUNDARY 2 +#define GL2PS_LINE_STIPPLE 3 +#define GL2PS_BLEND 4 + +/* Text alignment (o=raster position; default mode is BL): + +---+ +---+ +---+ +---+ +---+ +---+ +-o-+ o---+ +---o + | o | o | | o | | | | | | | | | | | | + +---+ +---+ +---+ +-o-+ o---+ +---o +---+ +---+ +---+ + C CL CR B BL BR T TL TR */ + +#define GL2PS_TEXT_C 1 +#define GL2PS_TEXT_CL 2 +#define GL2PS_TEXT_CR 3 +#define GL2PS_TEXT_B 4 +#define GL2PS_TEXT_BL 5 +#define GL2PS_TEXT_BR 6 +#define GL2PS_TEXT_T 7 +#define GL2PS_TEXT_TL 8 +#define GL2PS_TEXT_TR 9 + +typedef GLfloat GL2PSrgba[4]; + +#if defined(__cplusplus) +extern "C" { +#endif + +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 nr, GLint ng, GLint nb, GLint buffersize, + FILE *stream, const char *filename); +GL2PSDLL_API GLint gl2psEndPage(void); +GL2PSDLL_API GLint gl2psSetOptions(GLint options); +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, + GLshort fontsize); +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, + GLint xorig, GLint yorig, + GLenum format, GLenum type, const void *pixels); +GL2PSDLL_API GLint gl2psEnable(GLint mode); +GL2PSDLL_API GLint gl2psDisable(GLint mode); +GL2PSDLL_API GLint gl2psPointSize(GLfloat value); +GL2PSDLL_API GLint gl2psLineWidth(GLfloat value); +GL2PSDLL_API GLint gl2psBlendFunc(GLenum sfactor, GLenum dfactor); + +/* undocumented */ +GL2PSDLL_API GLint gl2psDrawImageMap(GLsizei width, GLsizei height, + const GLfloat position[3], + const unsigned char *imagemap); +GL2PSDLL_API const char *gl2psGetFileExtension(GLint format); +GL2PSDLL_API const char *gl2psGetFormatDescription(GLint format); + +#if defined(__cplusplus) +} +#endif + +#endif /* __GL2PS_H__ */ diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/gripes.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/gripes.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,238 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "defun.h" +#include "error.h" +#include "gripes.h" +#include "oct-obj.h" +#include "utils.h" + +void +gripe_not_supported (const char *fcn) +{ + error ("%s: not supported on this system", fcn); +} + +void +gripe_not_implemented (const char *fcn) +{ + error ("%s: not implemented", fcn); +} + +void +gripe_string_invalid (void) +{ + error ("std::string constant used in invalid context"); +} + +void +gripe_range_invalid (void) +{ + error ("range constant used in invalid context"); +} + +void +gripe_nonconformant (void) +{ + error ("nonconformant matrices"); +} + +void +gripe_nonconformant (octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2) +{ + error ("nonconformant matrices (op1 is %dx%d, op2 is %dx%d)", + r1, c1, r2, c2); +} + +void +gripe_empty_arg (const char *name, bool is_error) +{ + if (is_error) + error ("%s: empty matrix is invalid as an argument", name); + else + warning ("%s: argument is empty matrix", name); +} + +void +gripe_square_matrix_required (const char *name) +{ + error ("%s: argument must be a square matrix", name); +} + +void +gripe_user_supplied_eval (const char *name) +{ + error ("%s: evaluation of user-supplied function failed", name); +} + +void +gripe_user_returned_invalid (const char *name) +{ + error ("%s: user-supplied function returned invalid value", name); +} + +void +gripe_invalid_conversion (const std::string& from, const std::string& to) +{ + error ("invalid conversion from %s to %s", from.c_str (), to.c_str ()); +} + +void +gripe_invalid_value_specified (const char *name) +{ + warning ("invalid value specified for `%s'", name); +} + +void +gripe_2_or_3_dim_plot (void) +{ + error ("plot: can only plot in 2 or 3 dimensions"); +} + +void +gripe_unrecognized_float_fmt (void) +{ + error ("unrecognized floating point format requested"); +} + +void +gripe_unrecognized_data_fmt (const char *warn_for) +{ + error ("%s: unrecognized data format requested", warn_for); +} + +void +gripe_data_conversion (const char *from, const char *to) +{ + error ("unable to convert from %s to %s format", from, to); +} + +void +gripe_wrong_type_arg (const char *name, const char *s, bool is_error) +{ + if (is_error) + error ("%s: wrong type argument `%s'", name, s); + else + warning ("%s: wrong type argument `%s'", name, s); +} + +void +gripe_wrong_type_arg (const char *name, const std::string& s, bool is_error) +{ + gripe_wrong_type_arg (name, s.c_str (), is_error); +} + +void +gripe_wrong_type_arg (const char *name, const octave_value& tc, + bool is_error) +{ + std::string type = tc.type_name (); + + gripe_wrong_type_arg (name, type, is_error); +} + +void +gripe_wrong_type_arg (const std::string& name, const octave_value& tc, + bool is_error) +{ + gripe_wrong_type_arg (name.c_str (), tc, is_error); +} + +void +gripe_wrong_type_arg_for_unary_op (const octave_value& op) +{ + std::string type = op.type_name (); + error ("invalid operand `%s' for unary operator", type.c_str ()); +} + +void +gripe_wrong_type_arg_for_binary_op (const octave_value& op) +{ + std::string type = op.type_name (); + error ("invalid operand `%s' for binary operator", type.c_str ()); +} + +void +gripe_implicit_conversion (const char *id, const char *from, const char *to) +{ + warning_with_id (id, "implicit conversion from %s to %s", from, to); +} + +void +gripe_implicit_conversion (const std::string& id, + const std::string& from, const std::string& to) +{ + warning_with_id (id.c_str (), + "implicit conversion from %s to %s", + from.c_str (), to.c_str ()); +} + +void +gripe_divide_by_zero (void) +{ + warning_with_id ("Octave:divide-by-zero", "division by zero"); +} + +void +gripe_logical_conversion (void) +{ + warning_with_id ("Octave:logical-conversion", + "value not equal to 1 or 0 converted to logical 1"); +} + +void +gripe_library_execution_error (void) +{ + octave_exception_state = octave_no_exception; + + if (! error_state) + error ("caught execution error in library function"); +} + +void +gripe_invalid_inquiry_subscript (void) +{ + error ("invalid dimension inquiry of a non-existent value"); +} + +void +gripe_indexed_cs_list (void) +{ + error ("a cs-list cannot be further indexed"); +} + +void +gripe_nonbraced_cs_list_assignment (void) +{ + error ("invalid assignment to cs-list outside multiple assignment"); +} + +void +gripe_warn_complex_cmp (void) +{ + warning_with_id ("Octave:matlab-incompatible", + "potential Matlab compatibility problem: comparing complex numbers"); +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/gripes.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/gripes.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,130 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_gripes_h) +#define octave_gripes_h 1 + +#include + +#include "lo-array-gripes.h" + +class octave_value; + +extern OCTINTERP_API void +gripe_not_supported (const char *); + +extern OCTINTERP_API void +gripe_not_implemented (const char *); + +extern OCTINTERP_API void +gripe_string_invalid (void); + +extern OCTINTERP_API void +gripe_range_invalid (void); + +extern OCTINTERP_API void +gripe_nonconformant (void); + +extern OCTINTERP_API void +gripe_nonconformant (octave_idx_type r1, octave_idx_type c1, octave_idx_type r2, octave_idx_type c2); + +extern OCTINTERP_API void +gripe_empty_arg (const char *name, bool is_error); + +extern OCTINTERP_API void +gripe_square_matrix_required (const char *name); + +extern OCTINTERP_API void +gripe_user_supplied_eval (const char *name); + +extern OCTINTERP_API void +gripe_user_returned_invalid (const char *name); + +extern OCTINTERP_API void +gripe_invalid_conversion (const std::string& from, const std::string& to); + +extern OCTINTERP_API void +gripe_invalid_value_specified (const char *name); + +extern OCTINTERP_API void +gripe_2_or_3_dim_plot (void); + +extern OCTINTERP_API void +gripe_unrecognized_float_fmt (void); + +extern OCTINTERP_API void +gripe_unrecognized_data_fmt (const char *warn_for); + +extern OCTINTERP_API void +gripe_data_conversion (const char *from, const char *to); + +extern OCTINTERP_API void +gripe_wrong_type_arg (const char *name, const char *s, + bool is_error = true); + +extern OCTINTERP_API void +gripe_wrong_type_arg (const char *name, const std::string& s, + bool is_error = true); + +extern OCTINTERP_API void +gripe_wrong_type_arg (const char *name, const octave_value& tc, + bool is_error = true); + +extern OCTINTERP_API void +gripe_wrong_type_arg (const std::string& name, const octave_value& tc, + bool is_error = true); + +extern OCTINTERP_API void +gripe_wrong_type_arg_for_unary_op (const octave_value& op); + +extern OCTINTERP_API void +gripe_wrong_type_arg_for_binary_op (const octave_value& op); + +extern OCTINTERP_API void +gripe_implicit_conversion (const char *id, const char *from, const char *to); + +extern OCTINTERP_API void +gripe_implicit_conversion (const std::string& id, const std::string& from, + const std::string& to); + +extern OCTINTERP_API void +gripe_divide_by_zero (void); + +extern OCTINTERP_API void +gripe_logical_conversion (void); + +extern OCTINTERP_API void +gripe_library_execution_error (void); + +extern OCTINTERP_API void +gripe_invalid_inquiry_subscript (void); + +extern OCTINTERP_API void +gripe_indexed_cs_list (void); + +extern OCTINTERP_API void +gripe_nonbraced_cs_list_assignment (void); + +extern OCTINTERP_API void +gripe_warn_complex_cmp (void); + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/jit-ir.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/jit-ir.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,649 @@ +/* + +Copyright (C) 2012 Max Brister + +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 +. + +*/ + +// defines required by llvm +#define __STDC_LIMIT_MACROS +#define __STDC_CONSTANT_MACROS + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_LLVM + +#include "jit-ir.h" + +#include +#include + +#include "error.h" +#include "pt-jit.h" + +// -------------------- jit_use -------------------- +jit_block * +jit_use::user_parent (void) const +{ + return muser->parent (); +} + +// -------------------- jit_value -------------------- +jit_value::~jit_value (void) +{} + +jit_block * +jit_value::first_use_block (void) +{ + jit_use *use = first_use (); + while (use) + { + if (! isa (use->user ())) + return use->user_parent (); + + use = use->next (); + } + + return 0; +} + +void +jit_value::replace_with (jit_value *value) +{ + while (first_use ()) + { + jit_instruction *user = first_use ()->user (); + size_t idx = first_use ()->index (); + user->stash_argument (idx, value); + } +} + +#define JIT_METH(clname) \ + void \ + jit_ ## clname::accept (jit_ir_walker& walker) \ + { \ + walker.visit (*this); \ + } + +JIT_VISIT_IR_NOTEMPLATE +#undef JIT_METH + +std::ostream& +operator<< (std::ostream& os, const jit_value& value) +{ + return value.short_print (os); +} + +std::ostream& +jit_print (std::ostream& os, jit_value *avalue) +{ + if (avalue) + return avalue->print (os); + return os << "NULL"; +} + +// -------------------- jit_instruction -------------------- +void +jit_instruction::remove (void) +{ + if (mparent) + mparent->remove (mlocation); + resize_arguments (0); +} + +llvm::BasicBlock * +jit_instruction::parent_llvm (void) const +{ + return mparent->to_llvm (); +} + +std::ostream& +jit_instruction::short_print (std::ostream& os) const +{ + if (type ()) + jit_print (os, type ()) << ": "; + return os << "#" << mid; +} + +void +jit_instruction::do_construct_ssa (size_t start, size_t end) +{ + for (size_t i = start; i < end; ++i) + { + jit_value *arg = argument (i); + jit_variable *var = dynamic_cast (arg); + if (var && var->has_top ()) + stash_argument (i, var->top ()); + } +} + +// -------------------- jit_block -------------------- +void +jit_block::replace_with (jit_value *value) +{ + assert (isa (value)); + jit_block *block = static_cast (value); + + jit_value::replace_with (block); + + while (ILIST_T::first_use ()) + { + jit_phi_incomming *incomming = ILIST_T::first_use (); + incomming->stash_value (block); + } +} + +void +jit_block::replace_in_phi (jit_block *ablock, jit_block *with) +{ + jit_phi_incomming *node = ILIST_T::first_use (); + while (node) + { + jit_phi_incomming *prev = node; + node = node->next (); + + if (prev->user_parent () == ablock) + prev->stash_value (with); + } +} + +jit_block * +jit_block::maybe_merge () +{ + if (successor_count () == 1 && successor (0) != this + && (successor (0)->use_count () == 1 || instructions.size () == 1)) + { + jit_block *to_merge = successor (0); + merge (*to_merge); + return to_merge; + } + + return 0; +} + +void +jit_block::merge (jit_block& block) +{ + // the merge block will contain a new terminator + jit_terminator *old_term = terminator (); + if (old_term) + old_term->remove (); + + bool was_empty = end () == begin (); + iterator merge_begin = end (); + if (! was_empty) + --merge_begin; + + instructions.splice (end (), block.instructions); + if (was_empty) + merge_begin = begin (); + else + ++merge_begin; + + // now merge_begin points to the start of the new instructions, we must + // update their parent information + for (iterator iter = merge_begin; iter != end (); ++iter) + { + jit_instruction *instr = *iter; + instr->stash_parent (this, iter); + } + + block.replace_with (this); +} + +jit_instruction * +jit_block::prepend (jit_instruction *instr) +{ + instructions.push_front (instr); + instr->stash_parent (this, instructions.begin ()); + return instr; +} + +jit_instruction * +jit_block::prepend_after_phi (jit_instruction *instr) +{ + // FIXME: Make this O(1) + for (iterator iter = begin (); iter != end (); ++iter) + { + jit_instruction *temp = *iter; + if (! isa (temp)) + { + insert_before (iter, instr); + return instr; + } + } + + return append (instr); +} + +void +jit_block::internal_append (jit_instruction *instr) +{ + instructions.push_back (instr); + instr->stash_parent (this, --instructions.end ()); +} + +jit_instruction * +jit_block::insert_before (iterator loc, jit_instruction *instr) +{ + iterator iloc = instructions.insert (loc, instr); + instr->stash_parent (this, iloc); + return instr; +} + +jit_instruction * +jit_block::insert_after (iterator loc, jit_instruction *instr) +{ + ++loc; + iterator iloc = instructions.insert (loc, instr); + instr->stash_parent (this, iloc); + return instr; +} + +jit_terminator * +jit_block::terminator (void) const +{ + assert (this); + if (instructions.empty ()) + return 0; + + jit_instruction *last = instructions.back (); + return dynamic_cast (last); +} + +bool +jit_block::branch_alive (jit_block *asucc) const +{ + return terminator ()->alive (asucc); +} + +jit_block * +jit_block::successor (size_t i) const +{ + jit_terminator *term = terminator (); + return term->successor (i); +} + +size_t +jit_block::successor_count (void) const +{ + jit_terminator *term = terminator (); + return term ? term->successor_count () : 0; +} + +llvm::BasicBlock * +jit_block::to_llvm (void) const +{ + return llvm::cast (llvm_value); +} + +std::ostream& +jit_block::print_dom (std::ostream& os) const +{ + short_print (os); + os << ":\n"; + os << " mid: " << mid << std::endl; + os << " predecessors: "; + for (jit_use *use = first_use (); use; use = use->next ()) + os << *use->user_parent () << " "; + os << std::endl; + + os << " successors: "; + for (size_t i = 0; i < successor_count (); ++i) + os << *successor (i) << " "; + os << std::endl; + + os << " idom: "; + if (idom) + os << *idom; + else + os << "NULL"; + os << std::endl; + os << " df: "; + for (df_iterator iter = df_begin (); iter != df_end (); ++iter) + os << **iter << " "; + os << std::endl; + + os << " dom_succ: "; + for (size_t i = 0; i < dom_succ.size (); ++i) + os << *dom_succ[i] << " "; + + return os << std::endl; +} + +void +jit_block::compute_df (size_t avisit_count) +{ + if (visited (avisit_count)) + return; + + if (use_count () >= 2) + { + for (jit_use *use = first_use (); use; use = use->next ()) + { + jit_block *runner = use->user_parent (); + while (runner != idom) + { + runner->mdf.insert (this); + runner = runner->idom; + } + } + } + + for (size_t i = 0; i < successor_count (); ++i) + successor (i)->compute_df (avisit_count); +} + +bool +jit_block::update_idom (size_t avisit_count) +{ + if (visited (avisit_count) || ! use_count ()) + return false; + + bool changed = false; + for (jit_use *use = first_use (); use; use = use->next ()) + { + jit_block *pred = use->user_parent (); + changed = pred->update_idom (avisit_count) || changed; + } + + jit_use *use = first_use (); + jit_block *new_idom = use->user_parent (); + use = use->next (); + + for (; use; use = use->next ()) + { + jit_block *pred = use->user_parent (); + jit_block *pidom = pred->idom; + if (pidom) + new_idom = idom_intersect (pidom, new_idom); + } + + if (idom != new_idom) + { + idom = new_idom; + return true; + } + + return changed; +} + +void +jit_block::pop_all (void) +{ + for (iterator iter = begin (); iter != end (); ++iter) + { + jit_instruction *instr = *iter; + instr->pop_variable (); + } +} + +jit_block * +jit_block::maybe_split (jit_convert& convert, jit_block *asuccessor) +{ + if (successor_count () > 1) + { + jit_terminator *term = terminator (); + size_t idx = term->successor_index (asuccessor); + jit_block *split = convert.create ("phi_split", mvisit_count); + + // try to place splits where they make sense + if (id () < asuccessor->id ()) + convert.insert_before (asuccessor, split); + else + convert.insert_after (this, split); + + term->stash_argument (idx, split); + jit_branch *br = split->append (convert.create (asuccessor)); + replace_in_phi (asuccessor, split); + + if (alive ()) + { + split->mark_alive (); + br->infer (); + } + + return split; + } + + return this; +} + +void +jit_block::create_dom_tree (size_t avisit_count) +{ + if (visited (avisit_count)) + return; + + if (idom != this) + idom->dom_succ.push_back (this); + + for (size_t i = 0; i < successor_count (); ++i) + successor (i)->create_dom_tree (avisit_count); +} + +jit_block * +jit_block::idom_intersect (jit_block *i, jit_block *j) +{ + while (i && j && i != j) + { + while (i && i->id () > j->id ()) + i = i->idom; + + while (i && j && j->id () > i->id ()) + j = j->idom; + } + + return i ? i : j; +} + +// -------------------- jit_phi_incomming -------------------- + +jit_block * +jit_phi_incomming::user_parent (void) const +{ return muser->parent (); } + +// -------------------- jit_phi -------------------- +bool +jit_phi::prune (void) +{ + jit_block *p = parent (); + size_t new_idx = 0; + jit_value *unique = argument (1); + + for (size_t i = 0; i < argument_count (); ++i) + { + jit_block *inc = incomming (i); + if (inc->branch_alive (p)) + { + if (unique != argument (i)) + unique = 0; + + if (new_idx != i) + { + stash_argument (new_idx, argument (i)); + mincomming[new_idx].stash_value (inc); + } + + ++new_idx; + } + } + + if (new_idx != argument_count ()) + { + resize_arguments (new_idx); + mincomming.resize (new_idx); + } + + assert (argument_count () > 0); + if (unique) + { + replace_with (unique); + return true; + } + + return false; +} + +bool +jit_phi::infer (void) +{ + jit_block *p = parent (); + if (! p->alive ()) + return false; + + jit_type *infered = 0; + for (size_t i = 0; i < argument_count (); ++i) + { + jit_block *inc = incomming (i); + if (inc->branch_alive (p)) + infered = jit_typeinfo::join (infered, argument_type (i)); + } + + if (infered != type ()) + { + stash_type (infered); + return true; + } + + return false; +} + +llvm::PHINode * +jit_phi::to_llvm (void) const +{ + return llvm::cast (jit_value::to_llvm ()); +} + +// -------------------- jit_terminator -------------------- +size_t +jit_terminator::successor_index (const jit_block *asuccessor) const +{ + size_t scount = successor_count (); + for (size_t i = 0; i < scount; ++i) + if (successor (i) == asuccessor) + return i; + + panic_impossible (); +} + +bool +jit_terminator::infer (void) +{ + if (! parent ()->alive ()) + return false; + + bool changed = false; + for (size_t i = 0; i < malive.size (); ++i) + if (! malive[i] && check_alive (i)) + { + changed = true; + malive[i] = true; + successor (i)->mark_alive (); + } + + return changed; +} + +llvm::TerminatorInst * +jit_terminator::to_llvm (void) const +{ + return llvm::cast (jit_value::to_llvm ()); +} + +// -------------------- jit_call -------------------- +bool +jit_call::infer (void) +{ + // FIXME: explain algorithm + for (size_t i = 0; i < argument_count (); ++i) + { + already_infered[i] = argument_type (i); + if (! already_infered[i]) + return false; + } + + jit_type *infered = moperation.result (already_infered); + if (! infered && use_count ()) + { + std::stringstream ss; + ss << "Missing overload in type inference for "; + print (ss, 0); + throw jit_fail_exception (ss.str ()); + } + + if (infered != type ()) + { + stash_type (infered); + return true; + } + + return false; +} + +// -------------------- jit_magic_end -------------------- +jit_magic_end::jit_magic_end (const std::vector& full_context) +{ + // for now we only support end in 1 dimensional indexing + resize_arguments (full_context.size ()); + + size_t i; + std::vector::const_iterator iter; + for (iter = full_context.begin (), i = 0; iter != full_context.end (); ++iter, + ++i) + { + if (iter->count != 1) + throw jit_fail_exception ("end is only supported in linear contexts"); + stash_argument (i, iter->value); + } +} + +const jit_function& +jit_magic_end::overload () const +{ + jit_value *ctx = resolve_context (); + if (ctx) + return jit_typeinfo::end (ctx->type ()); + + static jit_function null_ret; + return null_ret; +} + +jit_value * +jit_magic_end::resolve_context (void) const +{ + // FIXME: We need to have a way of marking functions so we can skip them here + return argument_count () ? argument (0) : 0; +} + +bool +jit_magic_end::infer (void) +{ + jit_type *new_type = overload ().result (); + if (new_type != type ()) + { + stash_type (new_type); + return true; + } + + return false; +} + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/jit-ir.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/jit-ir.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,1302 @@ +/* + +Copyright (C) 2012 Max Brister + +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 (octave_jit_ir_h) +#define octave_jit_ir_h 1 + +#ifdef HAVE_LLVM + +#include +#include +#include + +#include "jit-typeinfo.h" + +// The low level octave jit ir +// this ir is close to llvm, but contains information for doing type inference. +// We convert the octave parse tree to this IR directly. + +#define JIT_VISIT_IR_NOTEMPLATE \ + JIT_METH(block); \ + JIT_METH(branch); \ + JIT_METH(cond_branch); \ + JIT_METH(call); \ + JIT_METH(extract_argument); \ + JIT_METH(store_argument); \ + JIT_METH(phi); \ + JIT_METH(variable); \ + JIT_METH(error_check); \ + JIT_METH(assign) \ + JIT_METH(argument) \ + JIT_METH(magic_end) + +#define JIT_VISIT_IR_CONST \ + JIT_METH(const_bool); \ + JIT_METH(const_scalar); \ + JIT_METH(const_complex); \ + JIT_METH(const_index); \ + JIT_METH(const_string); \ + JIT_METH(const_range) + +#define JIT_VISIT_IR_CLASSES \ + JIT_VISIT_IR_NOTEMPLATE \ + JIT_VISIT_IR_CONST + +// forward declare all ir classes +#define JIT_METH(cname) \ + class jit_ ## cname; + +JIT_VISIT_IR_NOTEMPLATE + +#undef JIT_METH + +class jit_convert; + +// ABCs which aren't included in JIT_VISIT_IR_ALL +class jit_instruction; +class jit_terminator; + +template +class jit_const; + +typedef jit_const jit_const_bool; +typedef jit_const jit_const_scalar; +typedef jit_const jit_const_complex; +typedef jit_const jit_const_index; + +typedef jit_const jit_const_string; +typedef jit_const +jit_const_range; + +class jit_ir_walker; +class jit_use; + +class +jit_value : public jit_internal_list +{ +public: + jit_value (void) : llvm_value (0), ty (0), mlast_use (0), + min_worklist (false) {} + + virtual ~jit_value (void); + + bool in_worklist (void) const + { + return min_worklist; + } + + void stash_in_worklist (bool ain_worklist) + { + min_worklist = ain_worklist; + } + + // The block of the first use which is not a jit_error_check + // So this is not necessarily first_use ()->parent (). + jit_block *first_use_block (void); + + // replace all uses with + virtual void replace_with (jit_value *value); + + jit_type *type (void) const { return ty; } + + llvm::Type *type_llvm (void) const + { + return ty ? ty->to_llvm () : 0; + } + + const std::string& type_name (void) const + { + return ty->name (); + } + + void stash_type (jit_type *new_ty) { ty = new_ty; } + + std::string print_string (void) + { + std::stringstream ss; + print (ss); + return ss.str (); + } + + jit_instruction *last_use (void) const { return mlast_use; } + + void stash_last_use (jit_instruction *alast_use) + { + mlast_use = alast_use; + } + + virtual bool needs_release (void) const { return false; } + + virtual std::ostream& print (std::ostream& os, size_t indent = 0) const = 0; + + virtual std::ostream& short_print (std::ostream& os) const + { return print (os); } + + virtual void accept (jit_ir_walker& walker) = 0; + + bool has_llvm (void) const + { + return llvm_value; + } + + llvm::Value *to_llvm (void) const + { + assert (llvm_value); + return llvm_value; + } + + void stash_llvm (llvm::Value *compiled) + { + llvm_value = compiled; + } + +protected: + std::ostream& print_indent (std::ostream& os, size_t indent = 0) const + { + for (size_t i = 0; i < indent * 8; ++i) + os << " "; + return os; + } + + llvm::Value *llvm_value; +private: + jit_type *ty; + jit_instruction *mlast_use; + bool min_worklist; +}; + +std::ostream& operator<< (std::ostream& os, const jit_value& value); +std::ostream& jit_print (std::ostream& os, jit_value *avalue); + +class +jit_use : public jit_internal_node +{ +public: + jit_use (void) : muser (0), mindex (0) {} + + // we should really have a move operator, but not until c++11 :( + jit_use (const jit_use& use) : muser (0), mindex (0) + { + *this = use; + } + + jit_use& operator= (const jit_use& use) + { + stash_value (use.value (), use.user (), use.index ()); + return *this; + } + + size_t index (void) const { return mindex; } + + jit_instruction *user (void) const { return muser; } + + jit_block *user_parent (void) const; + + std::list user_parent_location (void) const; + + void stash_value (jit_value *avalue, jit_instruction *auser = 0, + size_t aindex = -1) + { + jit_internal_node::stash_value (avalue); + mindex = aindex; + muser = auser; + } +private: + jit_instruction *muser; + size_t mindex; +}; + +class +jit_instruction : public jit_value +{ +public: + // FIXME: this code could be so much pretier with varadic templates... + jit_instruction (void) : mid (next_id ()), mparent (0) + {} + + jit_instruction (size_t nargs) : mid (next_id ()), mparent (0) + { + already_infered.reserve (nargs); + marguments.reserve (nargs); + } + +#define STASH_ARG(i) stash_argument (i, arg ## i); +#define JIT_INSTRUCTION_CTOR(N) \ + jit_instruction (OCT_MAKE_DECL_LIST (jit_value *, arg, N)) \ + : already_infered (N), marguments (N), mid (next_id ()), mparent (0) \ + { \ + OCT_ITERATE_MACRO (STASH_ARG, N); \ + } + + JIT_INSTRUCTION_CTOR(1) + JIT_INSTRUCTION_CTOR(2) + JIT_INSTRUCTION_CTOR(3) + JIT_INSTRUCTION_CTOR(4) + +#undef STASH_ARG +#undef JIT_INSTRUCTION_CTOR + + jit_instruction (const std::vector& aarguments) + : already_infered (aarguments.size ()), marguments (aarguments.size ()), + mid (next_id ()), mparent (0) + { + for (size_t i = 0; i < aarguments.size (); ++i) + stash_argument (i, aarguments[i]); + } + + static void reset_ids (void) + { + next_id (true); + } + + jit_value *argument (size_t i) const + { + return marguments[i].value (); + } + + llvm::Value *argument_llvm (size_t i) const + { + assert (argument (i)); + return argument (i)->to_llvm (); + } + + jit_type *argument_type (size_t i) const + { + return argument (i)->type (); + } + + llvm::Type *argument_type_llvm (size_t i) const + { + assert (argument (i)); + return argument_type (i)->to_llvm (); + } + + std::ostream& print_argument (std::ostream& os, size_t i) const + { + if (argument (i)) + return argument (i)->short_print (os); + else + return os << "NULL"; + } + + void stash_argument (size_t i, jit_value *arg) + { + marguments[i].stash_value (arg, this, i); + } + + void push_argument (jit_value *arg) + { + marguments.push_back (jit_use ()); + stash_argument (marguments.size () - 1, arg); + already_infered.push_back (0); + } + + size_t argument_count (void) const + { + return marguments.size (); + } + + void resize_arguments (size_t acount, jit_value *adefault = 0) + { + size_t old = marguments.size (); + marguments.resize (acount); + already_infered.resize (acount); + + if (adefault) + for (size_t i = old; i < acount; ++i) + stash_argument (i, adefault); + } + + const std::vector& arguments (void) const { return marguments; } + + // argument types which have been infered already + const std::vector& argument_types (void) const + { return already_infered; } + + virtual void push_variable (void) {} + + virtual void pop_variable (void) {} + + virtual void construct_ssa (void) + { + do_construct_ssa (0, argument_count ()); + } + + virtual bool infer (void) { return false; } + + void remove (void); + + virtual std::ostream& short_print (std::ostream& os) const; + + jit_block *parent (void) const { return mparent; } + + std::list::iterator location (void) const + { + return mlocation; + } + + llvm::BasicBlock *parent_llvm (void) const; + + void stash_parent (jit_block *aparent, + std::list::iterator alocation) + { + mparent = aparent; + mlocation = alocation; + } + + size_t id (void) const { return mid; } +protected: + + // Do SSA replacement on arguments in [start, end) + void do_construct_ssa (size_t start, size_t end); + + std::vector already_infered; +private: + static size_t next_id (bool reset = false) + { + static size_t ret = 0; + if (reset) + return ret = 0; + + return ret++; + } + + std::vector marguments; + + size_t mid; + jit_block *mparent; + std::list::iterator mlocation; +}; + +// defnie accept methods for subclasses +#define JIT_VALUE_ACCEPT \ + virtual void accept (jit_ir_walker& walker); + +// for use as a dummy argument during conversion to LLVM +class +jit_argument : public jit_value +{ +public: + jit_argument (jit_type *atype, llvm::Value *avalue) + { + stash_type (atype); + stash_llvm (avalue); + } + + virtual std::ostream& print (std::ostream& os, size_t indent = 0) const + { + print_indent (os, indent); + return jit_print (os, type ()) << ": DUMMY"; + } + + JIT_VALUE_ACCEPT; +}; + +template +class +jit_const : public jit_value +{ +public: + typedef PASS_T pass_t; + + jit_const (PASS_T avalue) : mvalue (avalue) + { + stash_type (EXTRACT_T ()); + } + + PASS_T value (void) const { return mvalue; } + + virtual std::ostream& print (std::ostream& os, size_t indent = 0) const + { + print_indent (os, indent); + jit_print (os, type ()) << ": "; + if (QUOTE) + os << "\""; + os << mvalue; + if (QUOTE) + os << "\""; + return os; + } + + JIT_VALUE_ACCEPT; +private: + T mvalue; +}; + +class jit_phi_incomming; + +class +jit_block : public jit_value, public jit_internal_list +{ + typedef jit_internal_list ILIST_T; +public: + typedef std::list instruction_list; + typedef instruction_list::iterator iterator; + typedef instruction_list::const_iterator const_iterator; + + typedef std::set df_set; + typedef df_set::const_iterator df_iterator; + + static const size_t NO_ID = static_cast (-1); + + jit_block (const std::string& aname, size_t avisit_count = 0) + : mvisit_count (avisit_count), mid (NO_ID), idom (0), mname (aname), + malive (false) + {} + + virtual void replace_with (jit_value *value); + + void replace_in_phi (jit_block *ablock, jit_block *with); + + // we have a new internal list, but we want to stay compatable with jit_value + jit_use *first_use (void) const { return jit_value::first_use (); } + + size_t use_count (void) const { return jit_value::use_count (); } + + // if a block is alive, then it might be visited during execution + bool alive (void) const { return malive; } + + void mark_alive (void) { malive = true; } + + // If we can merge with a successor, do so and return the now empty block + jit_block *maybe_merge (); + + // merge another block into this block, leaving the merge block empty + void merge (jit_block& merge); + + const std::string& name (void) const { return mname; } + + jit_instruction *prepend (jit_instruction *instr); + + jit_instruction *prepend_after_phi (jit_instruction *instr); + + template + T *append (T *instr) + { + internal_append (instr); + return instr; + } + + jit_instruction *insert_before (iterator loc, jit_instruction *instr); + + jit_instruction *insert_before (jit_instruction *loc, jit_instruction *instr) + { + return insert_before (loc->location (), instr); + } + + jit_instruction *insert_after (iterator loc, jit_instruction *instr); + + jit_instruction *insert_after (jit_instruction *loc, jit_instruction *instr) + { + return insert_after (loc->location (), instr); + } + + iterator remove (iterator iter) + { + jit_instruction *instr = *iter; + iter = instructions.erase (iter); + instr->stash_parent (0, instructions.end ()); + return iter; + } + + jit_terminator *terminator (void) const; + + // is the jump from pred alive? + bool branch_alive (jit_block *asucc) const; + + jit_block *successor (size_t i) const; + + size_t successor_count (void) const; + + iterator begin (void) { return instructions.begin (); } + + const_iterator begin (void) const { return instructions.begin (); } + + iterator end (void) { return instructions.end (); } + + const_iterator end (void) const { return instructions.end (); } + + iterator phi_begin (void); + + iterator phi_end (void); + + iterator nonphi_begin (void); + + // must label before id is valid + size_t id (void) const { return mid; } + + // dominance frontier + const df_set& df (void) const { return mdf; } + + df_iterator df_begin (void) const { return mdf.begin (); } + + df_iterator df_end (void) const { return mdf.end (); } + + // label with a RPO walk + void label (void) + { + size_t number = 0; + label (mvisit_count, number); + } + + void label (size_t avisit_count, size_t& number) + { + if (visited (avisit_count)) + return; + + for (jit_use *use = first_use (); use; use = use->next ()) + { + jit_block *pred = use->user_parent (); + pred->label (avisit_count, number); + } + + mid = number++; + } + + // See for idom computation algorithm + // Cooper, Keith D.; Harvey, Timothy J; and Kennedy, Ken (2001). + // "A Simple, Fast Dominance Algorithm" + void compute_idom (jit_block *entry_block) + { + bool changed; + entry_block->idom = entry_block; + do + changed = update_idom (mvisit_count); + while (changed); + } + + // compute dominance frontier + void compute_df (void) + { + compute_df (mvisit_count); + } + + void create_dom_tree (void) + { + create_dom_tree (mvisit_count); + } + + jit_block *dom_successor (size_t idx) const + { + return dom_succ[idx]; + } + + size_t dom_successor_count (void) const + { + return dom_succ.size (); + } + + // call pop_varaible on all instructions + void pop_all (void); + + virtual std::ostream& print (std::ostream& os, size_t indent = 0) const + { + print_indent (os, indent); + short_print (os) << ": %pred = "; + for (jit_use *use = first_use (); use; use = use->next ()) + { + jit_block *pred = use->user_parent (); + os << *pred; + if (use->next ()) + os << ", "; + } + os << std::endl; + + for (const_iterator iter = begin (); iter != end (); ++iter) + { + jit_instruction *instr = *iter; + instr->print (os, indent + 1) << std::endl; + } + return os; + } + + // ... + jit_block *maybe_split (jit_convert& convert, jit_block *asuccessor); + + jit_block *maybe_split (jit_convert& convert, jit_block& asuccessor) + { + return maybe_split (convert, &asuccessor); + } + + // print dominator infomration + std::ostream& print_dom (std::ostream& os) const; + + virtual std::ostream& short_print (std::ostream& os) const + { + os << mname; + if (mid != NO_ID) + os << mid; + return os; + } + + llvm::BasicBlock *to_llvm (void) const; + + std::list::iterator location (void) const + { return mlocation; } + + void stash_location (std::list::iterator alocation) + { mlocation = alocation; } + + // used to prevent visiting the same node twice in the graph + size_t visit_count (void) const { return mvisit_count; } + + // check if this node has been visited yet at the given visit count. If we + // have not been visited yet, mark us as visited. + bool visited (size_t avisit_count) + { + if (mvisit_count <= avisit_count) + { + mvisit_count = avisit_count + 1; + return false; + } + + return true; + } + + JIT_VALUE_ACCEPT; +private: + void internal_append (jit_instruction *instr); + + void compute_df (size_t avisit_count); + + bool update_idom (size_t avisit_count); + + void create_dom_tree (size_t avisit_count); + + static jit_block *idom_intersect (jit_block *i, jit_block *j); + + size_t mvisit_count; + size_t mid; + jit_block *idom; + df_set mdf; + std::vector dom_succ; + std::string mname; + instruction_list instructions; + bool malive; + std::list::iterator mlocation; +}; + +// keeps track of phi functions that use a block on incomming edges +class +jit_phi_incomming : public jit_internal_node +{ +public: + jit_phi_incomming (void) : muser (0) {} + + jit_phi_incomming (jit_phi *auser) : muser (auser) {} + + jit_phi_incomming (const jit_phi_incomming& use) : jit_internal_node () + { + *this = use; + } + + jit_phi_incomming& operator= (const jit_phi_incomming& use) + { + stash_value (use.value ()); + muser = use.muser; + return *this; + } + + jit_phi *user (void) const { return muser; } + + jit_block *user_parent (void) const; +private: + jit_phi *muser; +}; + +// A non-ssa variable +class +jit_variable : public jit_value +{ +public: + jit_variable (const std::string& aname) : mname (aname), mlast_use (0) {} + + const std::string &name (void) const { return mname; } + + // manipulate the value_stack, for use during SSA construction. The top of the + // value stack represents the current value for this variable + bool has_top (void) const + { + return ! value_stack.empty (); + } + + jit_value *top (void) const + { + return value_stack.top (); + } + + void push (jit_instruction *v) + { + value_stack.push (v); + mlast_use = v; + } + + void pop (void) + { + value_stack.pop (); + } + + jit_instruction *last_use (void) const + { + return mlast_use; + } + + void stash_last_use (jit_instruction *instr) + { + mlast_use = instr; + } + + // blocks in which we are used + void use_blocks (jit_block::df_set& result) + { + jit_use *use = first_use (); + while (use) + { + result.insert (use->user_parent ()); + use = use->next (); + } + } + + virtual std::ostream& print (std::ostream& os, size_t indent = 0) const + { + return print_indent (os, indent) << mname; + } + + JIT_VALUE_ACCEPT; +private: + std::string mname; + std::stack value_stack; + jit_instruction *mlast_use; +}; + +class +jit_assign_base : public jit_instruction +{ +public: + jit_assign_base (jit_variable *adest) : jit_instruction (), mdest (adest) {} + + jit_assign_base (jit_variable *adest, size_t npred) : jit_instruction (npred), + mdest (adest) {} + + jit_assign_base (jit_variable *adest, jit_value *arg0, jit_value *arg1) + : jit_instruction (arg0, arg1), mdest (adest) {} + + jit_variable *dest (void) const { return mdest; } + + virtual void push_variable (void) + { + mdest->push (this); + } + + virtual void pop_variable (void) + { + mdest->pop (); + } + + virtual std::ostream& short_print (std::ostream& os) const + { + if (type ()) + jit_print (os, type ()) << ": "; + + dest ()->short_print (os); + return os << "#" << id (); + } +private: + jit_variable *mdest; +}; + +class +jit_assign : public jit_assign_base +{ +public: + jit_assign (jit_variable *adest, jit_value *asrc) + : jit_assign_base (adest, adest, asrc), martificial (false) {} + + jit_value *overwrite (void) const + { + return argument (0); + } + + jit_value *src (void) const + { + return argument (1); + } + + // variables don't get modified in an SSA, but COW requires we modify + // variables. An artificial assign is for when a variable gets modified. We + // need an assign in the SSA, but the reference counts shouldn't be updated. + bool artificial (void) const { return martificial; } + + void mark_artificial (void) { martificial = true; } + + virtual bool infer (void) + { + jit_type *stype = src ()->type (); + if (stype != type()) + { + stash_type (stype); + return true; + } + + return false; + } + + virtual std::ostream& print (std::ostream& os, size_t indent = 0) const + { + print_indent (os, indent) << *this << " = " << *src (); + + if (artificial ()) + os << " [artificial]"; + + return os; + } + + JIT_VALUE_ACCEPT; +private: + bool martificial; +}; + +class +jit_phi : public jit_assign_base +{ +public: + jit_phi (jit_variable *adest, size_t npred) + : jit_assign_base (adest, npred) + { + mincomming.reserve (npred); + } + + // removes arguments form dead incomming jumps + bool prune (void); + + void add_incomming (jit_block *from, jit_value *value) + { + push_argument (value); + mincomming.push_back (jit_phi_incomming (this)); + mincomming[mincomming.size () - 1].stash_value (from); + } + + jit_block *incomming (size_t i) const + { + return mincomming[i].value (); + } + + llvm::BasicBlock *incomming_llvm (size_t i) const + { + return incomming (i)->to_llvm (); + } + + virtual void construct_ssa (void) {} + + virtual bool infer (void); + + virtual std::ostream& print (std::ostream& os, size_t indent = 0) const + { + std::stringstream ss; + print_indent (ss, indent); + short_print (ss) << " phi "; + std::string ss_str = ss.str (); + std::string indent_str (ss_str.size (), ' '); + os << ss_str; + + for (size_t i = 0; i < argument_count (); ++i) + { + if (i > 0) + os << indent_str; + os << "| "; + + os << *incomming (i) << " -> "; + os << *argument (i); + + if (i + 1 < argument_count ()) + os << std::endl; + } + + return os; + } + + llvm::PHINode *to_llvm (void) const; + + JIT_VALUE_ACCEPT; +private: + std::vector mincomming; +}; + +class +jit_terminator : public jit_instruction +{ +public: +#define JIT_TERMINATOR_CONST(N) \ + jit_terminator (size_t asuccessor_count, \ + OCT_MAKE_DECL_LIST (jit_value *, arg, N)) \ + : jit_instruction (OCT_MAKE_ARG_LIST (arg, N)), \ + malive (asuccessor_count, false) {} + + JIT_TERMINATOR_CONST (1) + JIT_TERMINATOR_CONST (2) + JIT_TERMINATOR_CONST (3) + +#undef JIT_TERMINATOR_CONST + + jit_block *successor (size_t idx = 0) const + { + return static_cast (argument (idx)); + } + + llvm::BasicBlock *successor_llvm (size_t idx = 0) const + { + return successor (idx)->to_llvm (); + } + + size_t successor_index (const jit_block *asuccessor) const; + + std::ostream& print_successor (std::ostream& os, size_t idx = 0) const + { + if (alive (idx)) + os << "[live] "; + else + os << "[dead] "; + + return successor (idx)->short_print (os); + } + + // Check if the jump to successor is live + bool alive (const jit_block *asuccessor) const + { + return alive (successor_index (asuccessor)); + } + + bool alive (size_t idx) const { return malive[idx]; } + + bool alive (int idx) const { return malive[idx]; } + + size_t successor_count (void) const { return malive.size (); } + + virtual bool infer (void); + + llvm::TerminatorInst *to_llvm (void) const; +protected: + virtual bool check_alive (size_t) const { return true; } +private: + std::vector malive; +}; + +class +jit_branch : public jit_terminator +{ +public: + jit_branch (jit_block *succ) : jit_terminator (1, succ) {} + + virtual size_t successor_count (void) const { return 1; } + + virtual std::ostream& print (std::ostream& os, size_t indent = 0) const + { + print_indent (os, indent) << "branch: "; + return print_successor (os); + } + + JIT_VALUE_ACCEPT; +}; + +class +jit_cond_branch : public jit_terminator +{ +public: + jit_cond_branch (jit_value *c, jit_block *ctrue, jit_block *cfalse) + : jit_terminator (2, ctrue, cfalse, c) {} + + jit_value *cond (void) const { return argument (2); } + + std::ostream& print_cond (std::ostream& os) const + { + return cond ()->short_print (os); + } + + llvm::Value *cond_llvm (void) const + { + return cond ()->to_llvm (); + } + + virtual size_t successor_count (void) const { return 2; } + + virtual std::ostream& print (std::ostream& os, size_t indent = 0) const + { + print_indent (os, indent) << "cond_branch: "; + print_cond (os) << ", "; + print_successor (os, 0) << ", "; + return print_successor (os, 1); + } + + JIT_VALUE_ACCEPT; +}; + +class +jit_call : public jit_instruction +{ +public: +#define JIT_CALL_CONST(N) \ + jit_call (const jit_operation& aoperation, \ + OCT_MAKE_DECL_LIST (jit_value *, arg, N)) \ + : jit_instruction (OCT_MAKE_ARG_LIST (arg, N)), moperation (aoperation) {} \ + \ + jit_call (const jit_operation& (*aoperation) (void), \ + OCT_MAKE_DECL_LIST (jit_value *, arg, N)) \ + : jit_instruction (OCT_MAKE_ARG_LIST (arg, N)), moperation (aoperation ()) \ + {} + + JIT_CALL_CONST (1) + JIT_CALL_CONST (2) + JIT_CALL_CONST (3) + JIT_CALL_CONST (4) + +#undef JIT_CALL_CONST + + jit_call (const jit_operation& aoperation, + const std::vector& args) + : jit_instruction (args), moperation (aoperation) + {} + + const jit_operation& operation (void) const { return moperation; } + + bool can_error (void) const + { + return overload ().can_error (); + } + + const jit_function& overload (void) const + { + return moperation.overload (argument_types ()); + } + + virtual bool needs_release (void) const + { + return type () && jit_typeinfo::get_release (type ()).valid (); + } + + virtual std::ostream& print (std::ostream& os, size_t indent = 0) const + { + print_indent (os, indent); + + if (use_count ()) + short_print (os) << " = "; + os << "call " << moperation.name () << " ("; + + for (size_t i = 0; i < argument_count (); ++i) + { + print_argument (os, i); + if (i + 1 < argument_count ()) + os << ", "; + } + return os << ")"; + } + + virtual bool infer (void); + + JIT_VALUE_ACCEPT; +private: + const jit_operation& moperation; +}; + +// FIXME: This is just ugly... +// checks error_state, if error_state is false then goto the normal branche, +// otherwise goto the error branch +class +jit_error_check : public jit_terminator +{ +public: + jit_error_check (jit_call *acheck_for, jit_block *normal, jit_block *error) + : jit_terminator (2, error, normal, acheck_for) {} + + jit_call *check_for (void) const + { + return static_cast (argument (2)); + } + + virtual std::ostream& print (std::ostream& os, size_t indent = 0) const + { + print_indent (os, indent) << "error_check " << *check_for () << ", "; + print_successor (os, 1) << ", "; + return print_successor (os, 0); + } + + JIT_VALUE_ACCEPT; +protected: + virtual bool check_alive (size_t idx) const + { + return idx == 1 ? true : check_for ()->can_error (); + } +}; + +// for now only handles the 1D case +class +jit_magic_end : public jit_instruction +{ +public: + class + context + { + public: + context (void) : value (0), index (0), count (0) + {} + + context (jit_value *avalue, size_t aindex, size_t acount) + : value (avalue), index (aindex), count (acount) + {} + + jit_value *value; + size_t index; + size_t count; + }; + + jit_magic_end (const std::vector& full_context); + + const jit_function& overload () const; + + jit_value *resolve_context (void) const; + + virtual bool infer (void); + + virtual std::ostream& short_print (std::ostream& os) const + { + return os << "magic_end"; + } + + virtual std::ostream& print (std::ostream& os, size_t indent = 0) const + { + return short_print (print_indent (os, indent)); + } + + JIT_VALUE_ACCEPT; +}; + +class +jit_extract_argument : public jit_assign_base +{ +public: + jit_extract_argument (jit_type *atype, jit_variable *adest) + : jit_assign_base (adest) + { + stash_type (atype); + } + + const std::string& name (void) const + { + return dest ()->name (); + } + + const jit_function& overload (void) const + { + return jit_typeinfo::cast (type (), jit_typeinfo::get_any ()); + } + + virtual std::ostream& print (std::ostream& os, size_t indent = 0) const + { + print_indent (os, indent); + + return short_print (os) << " = extract " << name (); + } + + JIT_VALUE_ACCEPT; +}; + +class +jit_store_argument : public jit_instruction +{ +public: + jit_store_argument (jit_variable *var) + : jit_instruction (var), dest (var) + {} + + const std::string& name (void) const + { + return dest->name (); + } + + const jit_function& overload (void) const + { + return jit_typeinfo::cast (jit_typeinfo::get_any (), result_type ()); + } + + jit_value *result (void) const + { + return argument (0); + } + + jit_type *result_type (void) const + { + return result ()->type (); + } + + llvm::Value *result_llvm (void) const + { + return result ()->to_llvm (); + } + + virtual std::ostream& print (std::ostream& os, size_t indent = 0) const + { + jit_value *res = result (); + print_indent (os, indent) << "store "; + dest->short_print (os); + + if (! isa (res)) + { + os << " = "; + res->short_print (os); + } + + return os; + } + + JIT_VALUE_ACCEPT; +private: + jit_variable *dest; +}; + +class +jit_ir_walker +{ +public: + virtual ~jit_ir_walker () {} + +#define JIT_METH(clname) \ + virtual void visit (jit_ ## clname&) = 0; + + JIT_VISIT_IR_CLASSES; + +#undef JIT_METH +}; + +template +void +jit_const::accept (jit_ir_walker& walker) +{ + walker.visit (*this); +} + +#undef JIT_VALUE_ACCEPT + +#endif +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/jit-typeinfo.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/jit-typeinfo.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,2071 @@ +/* + +Copyright (C) 2012 Max Brister + +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 +. + +*/ + +// defines required by llvm +#define __STDC_LIMIT_MACROS +#define __STDC_CONSTANT_MACROS + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_LLVM + +#include "jit-typeinfo.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "jit-ir.h" +#include "ov.h" +#include "ov-builtin.h" +#include "ov-complex.h" +#include "ov-scalar.h" +#include "pager.h" + +static llvm::LLVMContext& context = llvm::getGlobalContext (); + +jit_typeinfo *jit_typeinfo::instance = 0; + +std::ostream& jit_print (std::ostream& os, jit_type *atype) +{ + if (! atype) + return os << "null"; + return os << atype->name (); +} + +// function that jit code calls +extern "C" void +octave_jit_print_any (const char *name, octave_base_value *obv) +{ + obv->print_with_name (octave_stdout, name, true); +} + +extern "C" void +octave_jit_print_scalar (const char *name, double value) +{ + // FIXME: We should avoid allocating a new octave_scalar each time + octave_value ov (value); + ov.print_with_name (octave_stdout, name); +} + +extern "C" octave_base_value* +octave_jit_binary_any_any (octave_value::binary_op op, octave_base_value *lhs, + octave_base_value *rhs) +{ + octave_value olhs (lhs, true); + octave_value orhs (rhs, true); + octave_value result = do_binary_op (op, olhs, orhs); + octave_base_value *rep = result.internal_rep (); + rep->grab (); + return rep; +} + +extern "C" octave_idx_type +octave_jit_compute_nelem (double base, double limit, double inc) +{ + Range rng = Range (base, limit, inc); + return rng.nelem (); +} + +extern "C" void +octave_jit_release_any (octave_base_value *obv) +{ + obv->release (); +} + +extern "C" void +octave_jit_release_matrix (jit_matrix *m) +{ + delete m->array; +} + +extern "C" octave_base_value * +octave_jit_grab_any (octave_base_value *obv) +{ + obv->grab (); + return obv; +} + +extern "C" void +octave_jit_grab_matrix (jit_matrix *result, jit_matrix *m) +{ + *result = *m->array; +} + +extern "C" octave_base_value * +octave_jit_cast_any_matrix (jit_matrix *m) +{ + octave_value ret (*m->array); + octave_base_value *rep = ret.internal_rep (); + rep->grab (); + delete m->array; + + return rep; +} + +extern "C" void +octave_jit_cast_matrix_any (jit_matrix *ret, octave_base_value *obv) +{ + NDArray m = obv->array_value (); + *ret = m; + obv->release (); +} + +extern "C" octave_base_value * +octave_jit_cast_any_range (jit_range *rng) +{ + Range temp (*rng); + octave_value ret (temp); + octave_base_value *rep = ret.internal_rep (); + rep->grab (); + + return rep; +} +extern "C" void +octave_jit_cast_range_any (jit_range *ret, octave_base_value *obv) +{ + + jit_range r (obv->range_value ()); + *ret = r; + obv->release (); +} + +extern "C" double +octave_jit_cast_scalar_any (octave_base_value *obv) +{ + double ret = obv->double_value (); + obv->release (); + return ret; +} + +extern "C" octave_base_value * +octave_jit_cast_any_scalar (double value) +{ + return new octave_scalar (value); +} + +extern "C" Complex +octave_jit_cast_complex_any (octave_base_value *obv) +{ + Complex ret = obv->complex_value (); + obv->release (); + return ret; +} + +extern "C" octave_base_value * +octave_jit_cast_any_complex (Complex c) +{ + if (c.imag () == 0) + return new octave_scalar (c.real ()); + else + return new octave_complex (c); +} + +extern "C" void +octave_jit_gripe_nan_to_logical_conversion (void) +{ + try + { + gripe_nan_to_logical_conversion (); + } + catch (const octave_execution_exception&) + { + gripe_library_execution_error (); + } +} + +extern "C" void +octave_jit_ginvalid_index (void) +{ + try + { + gripe_invalid_index (); + } + catch (const octave_execution_exception&) + { + gripe_library_execution_error (); + } +} + +extern "C" void +octave_jit_gindex_range (int nd, int dim, octave_idx_type iext, + octave_idx_type ext) +{ + try + { + gripe_index_out_of_range (nd, dim, iext, ext); + } + catch (const octave_execution_exception&) + { + gripe_library_execution_error (); + } +} + +extern "C" void +octave_jit_paren_subsasgn_impl (jit_matrix *ret, jit_matrix *mat, + octave_idx_type index, double value) +{ + NDArray *array = mat->array; + if (array->nelem () < index) + array->resize1 (index); + + double *data = array->fortran_vec (); + data[index - 1] = value; + + mat->update (); + *ret = *mat; +} + +static void +make_indices (double *indices, octave_idx_type idx_count, + Array& result) +{ + result.resize (dim_vector (1, idx_count)); + for (octave_idx_type i = 0; i < idx_count; ++i) + result(i) = idx_vector (indices[i]); +} + +extern "C" double +octave_jit_paren_scalar (jit_matrix *mat, double *indicies, + octave_idx_type idx_count) +{ + // FIXME: Replace this with a more optimal version + try + { + Array idx; + make_indices (indicies, idx_count, idx); + + Array ret = mat->array->index (idx); + return ret.xelem (0); + } + catch (const octave_execution_exception&) + { + gripe_library_execution_error (); + return 0; + } +} + +extern "C" void +octave_jit_paren_scalar_subsasgn (jit_matrix *ret, jit_matrix *mat, + double *indices, octave_idx_type idx_count, + double value) +{ + // FIXME: Replace this with a more optimal version + try + { + Array idx; + make_indices (indices, idx_count, idx); + + Matrix temp (1, 1); + temp.xelem(0) = value; + mat->array->assign (idx, temp); + ret->update (mat->array); + } + catch (const octave_execution_exception&) + { + gripe_library_execution_error (); + } +} + +extern "C" void +octave_jit_paren_subsasgn_matrix_range (jit_matrix *result, jit_matrix *mat, + jit_range *index, double value) +{ + NDArray *array = mat->array; + bool done = false; + + // optimize for the simple case (no resizing and no errors) + if (*array->jit_ref_count () == 1 + && index->all_elements_are_ints ()) + { + // this code is similar to idx_vector::fill, but we avoid allocating an + // idx_vector and its associated rep + octave_idx_type start = static_cast (index->base) - 1; + octave_idx_type step = static_cast (index->inc); + octave_idx_type nelem = index->nelem; + octave_idx_type final = start + nelem * step; + if (step < 0) + { + step = -step; + std::swap (final, start); + } + + if (start >= 0 && final < mat->slice_len) + { + done = true; + + double *data = array->jit_slice_data (); + if (step == 1) + std::fill (data + start, data + start + nelem, value); + else + { + for (octave_idx_type i = start; i < final; i += step) + data[i] = value; + } + } + } + + if (! done) + { + idx_vector idx (*index); + NDArray avalue (dim_vector (1, 1)); + avalue.xelem (0) = value; + array->assign (idx, avalue); + } + + result->update (array); +} + +extern "C" Complex +octave_jit_complex_div (Complex lhs, Complex rhs) +{ + // see src/OPERATORS/op-cs-cs.cc + if (rhs == 0.0) + gripe_divide_by_zero (); + + return lhs / rhs; +} + +// FIXME: CP form src/xpow.cc +static inline int +xisint (double x) +{ + return (D_NINT (x) == x + && ((x >= 0 && x < INT_MAX) + || (x <= 0 && x > INT_MIN))); +} + +extern "C" Complex +octave_jit_pow_scalar_scalar (double lhs, double rhs) +{ + // FIXME: almost CP from src/xpow.cc + if (lhs < 0.0 && ! xisint (rhs)) + return std::pow (Complex (lhs), rhs); + return std::pow (lhs, rhs); +} + +extern "C" Complex +octave_jit_pow_complex_complex (Complex lhs, Complex rhs) +{ + if (lhs.imag () == 0 && rhs.imag () == 0) + return octave_jit_pow_scalar_scalar (lhs.real (), rhs.real ()); + return std::pow (lhs, rhs); +} + +extern "C" Complex +octave_jit_pow_complex_scalar (Complex lhs, double rhs) +{ + if (lhs.imag () == 0) + return octave_jit_pow_scalar_scalar (lhs.real (), rhs); + return std::pow (lhs, rhs); +} + +extern "C" Complex +octave_jit_pow_scalar_complex (double lhs, Complex rhs) +{ + if (rhs.imag () == 0) + return octave_jit_pow_scalar_scalar (lhs, rhs.real ()); + return std::pow (lhs, rhs); +} + +extern "C" void +octave_jit_print_matrix (jit_matrix *m) +{ + std::cout << *m << std::endl; +} + +static void +gripe_bad_result (void) +{ + error ("incorrect type information given to the JIT compiler"); +} + +// FIXME: Add support for multiple outputs +extern "C" octave_base_value * +octave_jit_call (octave_builtin::fcn fn, size_t nargin, + octave_base_value **argin, jit_type *result_type) +{ + octave_value_list ovl (nargin); + for (size_t i = 0; i < nargin; ++i) + ovl.xelem (i) = octave_value (argin[i]); + + ovl = fn (ovl, 1); + + // These type checks are not strictly required, but I'm guessing that + // incorrect types will be entered on occasion. This will be very difficult to + // debug unless we do the sanity check here. + if (result_type) + { + if (ovl.length () != 1) + { + gripe_bad_result (); + return 0; + } + + octave_value& result = ovl.xelem (0); + jit_type *jtype = jit_typeinfo::join (jit_typeinfo::type_of (result), + result_type); + if (jtype != result_type) + { + gripe_bad_result (); + return 0; + } + + octave_base_value *ret = result.internal_rep (); + ret->grab (); + return ret; + } + + if (! (ovl.length () == 0 + || (ovl.length () == 1 && ovl.xelem (0).is_undefined ()))) + gripe_bad_result (); + + return 0; +} + +// -------------------- jit_range -------------------- +bool +jit_range::all_elements_are_ints () const +{ + Range r (*this); + return r.all_elements_are_ints (); +} + +std::ostream& +operator<< (std::ostream& os, const jit_range& rng) +{ + return os << "Range[" << rng.base << ", " << rng.limit << ", " << rng.inc + << ", " << rng.nelem << "]"; +} + +// -------------------- jit_matrix -------------------- + +std::ostream& +operator<< (std::ostream& os, const jit_matrix& mat) +{ + return os << "Matrix[" << mat.ref_count << ", " << mat.slice_data << ", " + << mat.slice_len << ", " << mat.dimensions << ", " + << mat.array << "]"; +} + +// -------------------- jit_type -------------------- +jit_type::jit_type (const std::string& aname, jit_type *aparent, + llvm::Type *allvm_type, int aid) : + mname (aname), mparent (aparent), llvm_type (allvm_type), mid (aid), + mdepth (aparent ? aparent->mdepth + 1 : 0) +{ + std::memset (msret, 0, sizeof (msret)); + std::memset (mpointer_arg, 0, sizeof (mpointer_arg)); + std::memset (mpack, 0, sizeof (mpack)); + std::memset (munpack, 0, sizeof (munpack)); + + for (size_t i = 0; i < jit_convention::length; ++i) + mpacked_type[i] = llvm_type; +} + +llvm::Type * +jit_type::to_llvm_arg (void) const +{ + return llvm_type ? llvm_type->getPointerTo () : 0; +} + +// -------------------- jit_function -------------------- +jit_function::jit_function () : module (0), llvm_function (0), mresult (0), + call_conv (jit_convention::length), + mcan_error (false) +{} + +jit_function::jit_function (llvm::Module *amodule, + jit_convention::type acall_conv, + const llvm::Twine& aname, jit_type *aresult, + const std::vector& aargs) + : module (amodule), mresult (aresult), args (aargs), call_conv (acall_conv), + mcan_error (false) +{ + llvm::SmallVector llvm_args; + + llvm::Type *rtype = llvm::Type::getVoidTy (context); + if (mresult) + { + rtype = mresult->packed_type (call_conv); + if (sret ()) + { + llvm_args.push_back (rtype->getPointerTo ()); + rtype = llvm::Type::getVoidTy (context); + } + } + + for (std::vector::const_iterator iter = args.begin (); + iter != args.end (); ++iter) + { + jit_type *ty = *iter; + assert (ty); + llvm::Type *argty = ty->packed_type (call_conv); + if (ty->pointer_arg (call_conv)) + argty = argty->getPointerTo (); + + llvm_args.push_back (argty); + } + + // we mark all functinos as external linkage because this prevents llvm + // from getting rid of always inline functions + llvm::FunctionType *ft = llvm::FunctionType::get (rtype, llvm_args, false); + llvm_function = llvm::Function::Create (ft, llvm::Function::ExternalLinkage, + aname, module); + if (call_conv == jit_convention::internal) + llvm_function->addFnAttr (llvm::Attribute::AlwaysInline); +} + +jit_function::jit_function (const jit_function& fn, jit_type *aresult, + const std::vector& aargs) + : module (fn.module), llvm_function (fn.llvm_function), mresult (aresult), + args (aargs), call_conv (fn.call_conv), mcan_error (fn.mcan_error) +{ +} + +jit_function::jit_function (const jit_function& fn) + : module (fn.module), llvm_function (fn.llvm_function), mresult (fn.mresult), + args (fn.args), call_conv (fn.call_conv), mcan_error (fn.mcan_error) +{} + +std::string +jit_function::name (void) const +{ + return llvm_function->getName (); +} + +llvm::BasicBlock * +jit_function::new_block (const std::string& aname, + llvm::BasicBlock *insert_before) +{ + return llvm::BasicBlock::Create (context, aname, llvm_function, + insert_before); +} + +llvm::Value * +jit_function::call (llvm::IRBuilderD& builder, + const std::vector& in_args) const +{ + if (! valid ()) + throw jit_fail_exception ("Call not implemented"); + + assert (in_args.size () == args.size ()); + std::vector llvm_args (args.size ()); + for (size_t i = 0; i < in_args.size (); ++i) + llvm_args[i] = in_args[i]->to_llvm (); + + return call (builder, llvm_args); +} + +llvm::Value * +jit_function::call (llvm::IRBuilderD& builder, + const std::vector& in_args) const +{ + if (! valid ()) + throw jit_fail_exception ("Call not implemented"); + + assert (in_args.size () == args.size ()); + llvm::Function *stacksave + = llvm::Intrinsic::getDeclaration (module, llvm::Intrinsic::stacksave); + llvm::SmallVector llvm_args; + llvm_args.reserve (in_args.size () + sret ()); + + llvm::Value *sret_mem = 0; + llvm::Value *saved_stack = 0; + if (sret ()) + { + saved_stack = builder.CreateCall (stacksave); + sret_mem = builder.CreateAlloca (mresult->packed_type (call_conv)); + llvm_args.push_back (sret_mem); + } + + for (size_t i = 0; i < in_args.size (); ++i) + { + llvm::Value *arg = in_args[i]; + jit_type::convert_fn convert = args[i]->pack (call_conv); + if (convert) + arg = convert (builder, arg); + + if (args[i]->pointer_arg (call_conv)) + { + if (! saved_stack) + saved_stack = builder.CreateCall (stacksave); + + arg = builder.CreateAlloca (args[i]->to_llvm ()); + builder.CreateStore (in_args[i], arg); + } + + llvm_args.push_back (arg); + } + + llvm::Value *ret = builder.CreateCall (llvm_function, llvm_args); + if (sret_mem) + ret = builder.CreateLoad (sret_mem); + + if (mresult) + { + jit_type::convert_fn unpack = mresult->unpack (call_conv); + if (unpack) + ret = unpack (builder, ret); + } + + if (saved_stack) + { + llvm::Function *stackrestore + = llvm::Intrinsic::getDeclaration (module, + llvm::Intrinsic::stackrestore); + builder.CreateCall (stackrestore, saved_stack); + } + + return ret; +} + +llvm::Value * +jit_function::argument (llvm::IRBuilderD& builder, size_t idx) const +{ + assert (idx < args.size ()); + + // FIXME: We should be treating arguments like a list, not a vector. Shouldn't + // matter much for now, as the number of arguments shouldn't be much bigger + // than 4 + llvm::Function::arg_iterator iter = llvm_function->arg_begin (); + if (sret ()) + ++iter; + + for (size_t i = 0; i < idx; ++i, ++iter); + + if (args[idx]->pointer_arg (call_conv)) + return builder.CreateLoad (iter); + + return iter; +} + +void +jit_function::do_return (llvm::IRBuilderD& builder, llvm::Value *rval) +{ + assert (! rval == ! mresult); + + if (rval) + { + jit_type::convert_fn convert = mresult->pack (call_conv); + if (convert) + rval = convert (builder, rval); + + if (sret ()) + builder.CreateStore (rval, llvm_function->arg_begin ()); + else + builder.CreateRet (rval); + } + else + builder.CreateRetVoid (); + + llvm::verifyFunction (*llvm_function); +} + +void +jit_function::do_add_mapping (llvm::ExecutionEngine *engine, void *fn) +{ + assert (valid ()); + engine->addGlobalMapping (llvm_function, fn); +} + +std::ostream& +operator<< (std::ostream& os, const jit_function& fn) +{ + llvm::Function *lfn = fn.to_llvm (); + os << "jit_function: cc=" << fn.call_conv; + llvm::raw_os_ostream llvm_out (os); + lfn->print (llvm_out); + llvm_out.flush (); + return os; +} + +// -------------------- jit_operation -------------------- +jit_operation::~jit_operation (void) +{ + for (generated_map::iterator iter = generated.begin (); + iter != generated.end (); ++iter) + { + delete iter->first; + delete iter->second; + } +} + +void +jit_operation::add_overload (const jit_function& func, + const std::vector& args) +{ + if (args.size () >= overloads.size ()) + overloads.resize (args.size () + 1); + + Array& over = overloads[args.size ()]; + dim_vector dv (over.dims ()); + Array idx = to_idx (args); + bool must_resize = false; + + if (dv.length () != idx.numel ()) + { + dv.resize (idx.numel ()); + must_resize = true; + } + + for (octave_idx_type i = 0; i < dv.length (); ++i) + if (dv(i) <= idx(i)) + { + must_resize = true; + dv(i) = idx(i) + 1; + } + + if (must_resize) + over.resize (dv); + + over(idx) = func; +} + +const jit_function& +jit_operation::overload (const std::vector& types) const +{ + static jit_function null_overload; + for (size_t i =0; i < types.size (); ++i) + if (! types[i]) + return null_overload; + + if (types.size () >= overloads.size ()) + return do_generate (types); + + const Array& over = overloads[types.size ()]; + dim_vector dv (over.dims ()); + Array idx = to_idx (types); + for (octave_idx_type i = 0; i < dv.length (); ++i) + if (idx(i) >= dv(i)) + return do_generate (types); + + const jit_function& ret = over(idx); + if (! ret.valid ()) + return do_generate (types); + + return ret; +} + +Array +jit_operation::to_idx (const std::vector& types) const +{ + octave_idx_type numel = types.size (); + if (numel == 1) + numel = 2; + + Array idx (dim_vector (1, numel)); + for (octave_idx_type i = 0; i < static_cast (types.size ()); + ++i) + idx(i) = types[i]->type_id (); + + if (types.size () == 1) + { + idx(1) = idx(0); + idx(0) = 0; + } + + return idx; +} + +const jit_function& +jit_operation::do_generate (const signature_vec& types) const +{ + static jit_function null_overload; + generated_map::const_iterator find = generated.find (&types); + if (find != generated.end ()) + { + if (find->second) + return *find->second; + else + return null_overload; + } + + jit_function *ret = generate (types); + generated[new signature_vec (types)] = ret; + return ret ? *ret : null_overload; +} + +jit_function * +jit_operation::generate (const signature_vec& types) const +{ + return 0; +} + +bool +jit_operation::signature_cmp +::operator() (const signature_vec *lhs, const signature_vec *rhs) +{ + const signature_vec& l = *lhs; + const signature_vec& r = *rhs; + + if (l.size () < r.size ()) + return true; + else if (l.size () > r.size ()) + return false; + + for (size_t i = 0; i < l.size (); ++i) + { + if (l[i]->type_id () < r[i]->type_id ()) + return true; + else if (l[i]->type_id () > r[i]->type_id ()) + return false; + } + + return false; +} + +// -------------------- jit_index_operation -------------------- +jit_function * +jit_index_operation::generate (const signature_vec& types) const +{ + if (types.size () > 2 && types[0] == jit_typeinfo::get_matrix ()) + { + // indexing a matrix with scalars + jit_type *scalar = jit_typeinfo::get_scalar (); + for (size_t i = 1; i < types.size (); ++i) + if (types[i] != scalar) + return 0; + + return generate_matrix (types); + } + + return 0; +} + +llvm::Value * +jit_index_operation::create_arg_array (llvm::IRBuilderD& builder, + const jit_function &fn, size_t start_idx, + size_t end_idx) const +{ + size_t n = end_idx - start_idx; + llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm (); + llvm::ArrayType *array_t = llvm::ArrayType::get (scalar_t, n); + llvm::Value *array = llvm::UndefValue::get (array_t); + for (size_t i = start_idx; i < end_idx; ++i) + { + llvm::Value *idx = fn.argument (builder, i); + array = builder.CreateInsertValue (array, idx, i - start_idx); + } + + llvm::Value *array_mem = builder.CreateAlloca (array_t); + builder.CreateStore (array, array_mem); + return builder.CreateBitCast (array_mem, scalar_t->getPointerTo ()); +} + +// -------------------- jit_paren_subsref -------------------- +jit_function * +jit_paren_subsref::generate_matrix (const signature_vec& types) const +{ + std::stringstream ss; + ss << "jit_paren_subsref_matrix_scalar" << (types.size () - 1); + + jit_type *scalar = jit_typeinfo::get_scalar (); + jit_function *fn = new jit_function (module, jit_convention::internal, + ss.str (), scalar, types); + fn->mark_can_error (); + llvm::BasicBlock *body = fn->new_block (); + llvm::IRBuilder<> builder (body); + + llvm::Value *array = create_arg_array (builder, *fn, 1, types.size ()); + jit_type *index = jit_typeinfo::get_index (); + llvm::Value *nelem = llvm::ConstantInt::get (index->to_llvm (), + types.size () - 1); + llvm::Value *mat = fn->argument (builder, 0); + llvm::Value *ret = paren_scalar.call (builder, mat, array, nelem); + fn->do_return (builder, ret); + return fn; +} + +void +jit_paren_subsref::do_initialize (void) +{ + std::vector types (3); + types[0] = jit_typeinfo::get_matrix (); + types[1] = jit_typeinfo::get_scalar_ptr (); + types[2] = jit_typeinfo::get_index (); + + jit_type *scalar = jit_typeinfo::get_scalar (); + paren_scalar = jit_function (module, jit_convention::external, + "octave_jit_paren_scalar", scalar, types); + paren_scalar.add_mapping (engine, &octave_jit_paren_scalar); + paren_scalar.mark_can_error (); +} + +// -------------------- jit_paren_subsasgn -------------------- +jit_function * +jit_paren_subsasgn::generate_matrix (const signature_vec& types) const +{ + std::stringstream ss; + ss << "jit_paren_subsasgn_matrix_scalar" << (types.size () - 2); + + jit_type *matrix = jit_typeinfo::get_matrix (); + jit_function *fn = new jit_function (module, jit_convention::internal, + ss.str (), matrix, types); + fn->mark_can_error (); + llvm::BasicBlock *body = fn->new_block (); + llvm::IRBuilder<> builder (body); + + llvm::Value *array = create_arg_array (builder, *fn, 1, types.size () - 1); + jit_type *index = jit_typeinfo::get_index (); + llvm::Value *nelem = llvm::ConstantInt::get (index->to_llvm (), + types.size () - 2); + + llvm::Value *mat = fn->argument (builder, 0); + llvm::Value *value = fn->argument (builder, types.size () - 1); + llvm::Value *ret = paren_scalar.call (builder, mat, array, nelem, value); + fn->do_return (builder, ret); + return fn; +} + +void +jit_paren_subsasgn::do_initialize (void) +{ + if (paren_scalar.valid ()) + return; + + jit_type *matrix = jit_typeinfo::get_matrix (); + std::vector types (4); + types[0] = matrix; + types[1] = jit_typeinfo::get_scalar_ptr (); + types[2] = jit_typeinfo::get_index (); + types[3] = jit_typeinfo::get_scalar (); + + paren_scalar = jit_function (module, jit_convention::external, + "octave_jit_paren_scalar", matrix, types); + paren_scalar.add_mapping (engine, &octave_jit_paren_scalar_subsasgn); + paren_scalar.mark_can_error (); +} + +// -------------------- jit_typeinfo -------------------- +void +jit_typeinfo::initialize (llvm::Module *m, llvm::ExecutionEngine *e) +{ + new jit_typeinfo (m, e); +} + +jit_typeinfo::jit_typeinfo (llvm::Module *m, llvm::ExecutionEngine *e) + : module (m), engine (e), next_id (0), + builder (*new llvm::IRBuilderD (context)) +{ + instance = this; + + // FIXME: We should be registering types like in octave_value_typeinfo + llvm::Type *any_t = llvm::StructType::create (context, "octave_base_value"); + any_t = any_t->getPointerTo (); + + llvm::Type *scalar_t = llvm::Type::getDoubleTy (context); + llvm::Type *bool_t = llvm::Type::getInt1Ty (context); + llvm::Type *string_t = llvm::Type::getInt8Ty (context); + string_t = string_t->getPointerTo (); + llvm::Type *index_t = llvm::Type::getIntNTy (context, + sizeof(octave_idx_type) * 8); + + llvm::StructType *range_t = llvm::StructType::create (context, "range"); + std::vector range_contents (4, scalar_t); + range_contents[3] = index_t; + range_t->setBody (range_contents); + + llvm::Type *refcount_t = llvm::Type::getIntNTy (context, sizeof(int) * 8); + + llvm::StructType *matrix_t = llvm::StructType::create (context, "matrix"); + llvm::Type *matrix_contents[5]; + matrix_contents[0] = refcount_t->getPointerTo (); + matrix_contents[1] = scalar_t->getPointerTo (); + matrix_contents[2] = index_t; + matrix_contents[3] = index_t->getPointerTo (); + matrix_contents[4] = string_t; + matrix_t->setBody (llvm::makeArrayRef (matrix_contents, 5)); + + llvm::Type *complex_t = llvm::VectorType::get (scalar_t, 2); + + // complex_ret is what is passed to C functions in order to get calling + // convention right + complex_ret = llvm::StructType::create (context, "complex_ret"); + llvm::Type *complex_ret_contents[] = {scalar_t, scalar_t}; + complex_ret->setBody (complex_ret_contents); + + // create types + any = new_type ("any", 0, any_t); + matrix = new_type ("matrix", any, matrix_t); + complex = new_type ("complex", any, complex_t); + scalar = new_type ("scalar", complex, scalar_t); + scalar_ptr = new_type ("scalar_ptr", 0, scalar_t->getPointerTo ()); + range = new_type ("range", any, range_t); + string = new_type ("string", any, string_t); + boolean = new_type ("bool", any, bool_t); + index = new_type ("index", any, index_t); + + create_int (8); + create_int (16); + create_int (32); + create_int (64); + + casts.resize (next_id + 1); + identities.resize (next_id + 1); + + // specify calling conventions + // FIXME: We should detect architecture and do something sane based on that + // here we assume x86 or x86_64 + matrix->mark_sret (); + matrix->mark_pointer_arg (); + + range->mark_sret (); + range->mark_pointer_arg (); + + complex->set_pack (jit_convention::external, &jit_typeinfo::pack_complex); + complex->set_unpack (jit_convention::external, &jit_typeinfo::unpack_complex); + complex->set_packed_type (jit_convention::external, complex_ret); + + if (sizeof (void *) == 4) + complex->mark_sret (); + + paren_subsref_fn.initialize (module, engine); + paren_subsasgn_fn.initialize (module, engine); + + // bind global variables + lerror_state = new llvm::GlobalVariable (*module, bool_t, false, + llvm::GlobalValue::ExternalLinkage, + 0, "error_state"); + engine->addGlobalMapping (lerror_state, + reinterpret_cast (&error_state)); + + // any with anything is an any op + jit_function fn; + jit_type *binary_op_type = intN (sizeof (octave_value::binary_op) * 8); + llvm::Type *llvm_bo_type = binary_op_type->to_llvm (); + jit_function any_binary = create_function (jit_convention::external, + "octave_jit_binary_any_any", + any, binary_op_type, any, any); + any_binary.add_mapping (engine, &octave_jit_binary_any_any); + any_binary.mark_can_error (); + binary_ops.resize (octave_value::num_binary_ops); + for (size_t i = 0; i < octave_value::num_binary_ops; ++i) + { + octave_value::binary_op op = static_cast (i); + std::string op_name = octave_value::binary_op_as_string (op); + binary_ops[i].stash_name ("binary" + op_name); + } + + for (int op = 0; op < octave_value::num_binary_ops; ++op) + { + llvm::Twine fn_name ("octave_jit_binary_any_any_"); + fn_name = fn_name + llvm::Twine (op); + + fn = create_function (jit_convention::internal, fn_name, any, any, any); + fn.mark_can_error (); + llvm::BasicBlock *block = fn.new_block (); + builder.SetInsertPoint (block); + llvm::APInt op_int(sizeof (octave_value::binary_op) * 8, op, + std::numeric_limits::is_signed); + llvm::Value *op_as_llvm = llvm::ConstantInt::get (llvm_bo_type, op_int); + llvm::Value *ret = any_binary.call (builder, op_as_llvm, + fn.argument (builder, 0), + fn.argument (builder, 1)); + fn.do_return (builder, ret); + binary_ops[op].add_overload (fn); + } + + // grab any + fn = create_function (jit_convention::external, "octave_jit_grab_any", any, + any); + fn.add_mapping (engine, &octave_jit_grab_any); + grab_fn.add_overload (fn); + grab_fn.stash_name ("grab"); + + // grab matrix + fn = create_function (jit_convention::external, "octave_jit_grab_matrix", + matrix, matrix); + fn.add_mapping (engine, &octave_jit_grab_matrix); + grab_fn.add_overload (fn); + + // release any + fn = create_function (jit_convention::external, "octave_jit_release_any", 0, + any); + fn.add_mapping (engine, &octave_jit_release_any); + release_fn.add_overload (fn); + release_fn.stash_name ("release"); + + // release matrix + fn = create_function (jit_convention::external, "octave_jit_release_matrix", + 0, matrix); + fn.add_mapping (engine, &octave_jit_release_matrix); + release_fn.add_overload (fn); + + // release scalar + fn = create_identity (scalar); + release_fn.add_overload (fn); + + // release complex + fn = create_identity (complex); + release_fn.add_overload (fn); + + // release index + fn = create_identity (index); + release_fn.add_overload (fn); + + // now for binary scalar operations + // FIXME: Finish all operations + add_binary_op (scalar, octave_value::op_add, llvm::Instruction::FAdd); + add_binary_op (scalar, octave_value::op_sub, llvm::Instruction::FSub); + add_binary_op (scalar, octave_value::op_mul, llvm::Instruction::FMul); + add_binary_op (scalar, octave_value::op_el_mul, llvm::Instruction::FMul); + + add_binary_fcmp (scalar, octave_value::op_lt, llvm::CmpInst::FCMP_ULT); + add_binary_fcmp (scalar, octave_value::op_le, llvm::CmpInst::FCMP_ULE); + add_binary_fcmp (scalar, octave_value::op_eq, llvm::CmpInst::FCMP_UEQ); + add_binary_fcmp (scalar, octave_value::op_ge, llvm::CmpInst::FCMP_UGE); + add_binary_fcmp (scalar, octave_value::op_gt, llvm::CmpInst::FCMP_UGT); + add_binary_fcmp (scalar, octave_value::op_ne, llvm::CmpInst::FCMP_UNE); + + jit_function gripe_div0 = create_function (jit_convention::external, + "gripe_divide_by_zero", 0); + gripe_div0.add_mapping (engine, &gripe_divide_by_zero); + gripe_div0.mark_can_error (); + + // divide is annoying because it might error + fn = create_function (jit_convention::internal, + "octave_jit_div_scalar_scalar", scalar, scalar, scalar); + fn.mark_can_error (); + + llvm::BasicBlock *body = fn.new_block (); + builder.SetInsertPoint (body); + { + llvm::BasicBlock *warn_block = fn.new_block ("warn"); + llvm::BasicBlock *normal_block = fn.new_block ("normal"); + + llvm::Value *zero = llvm::ConstantFP::get (scalar_t, 0); + llvm::Value *check = builder.CreateFCmpUEQ (zero, fn.argument (builder, 1)); + builder.CreateCondBr (check, warn_block, normal_block); + + builder.SetInsertPoint (warn_block); + gripe_div0.call (builder); + builder.CreateBr (normal_block); + + builder.SetInsertPoint (normal_block); + llvm::Value *ret = builder.CreateFDiv (fn.argument (builder, 0), + fn.argument (builder, 1)); + fn.do_return (builder, ret); + } + binary_ops[octave_value::op_div].add_overload (fn); + binary_ops[octave_value::op_el_div].add_overload (fn); + + // ldiv is the same as div with the operators reversed + fn = mirror_binary (fn); + binary_ops[octave_value::op_ldiv].add_overload (fn); + binary_ops[octave_value::op_el_ldiv].add_overload (fn); + + // In general, the result of scalar ^ scalar is a complex number. We might be + // able to improve on this if we keep track of the range of values varaibles + // can take on. + fn = create_function (jit_convention::external, + "octave_jit_pow_scalar_scalar", complex, scalar, + scalar); + fn.add_mapping (engine, &octave_jit_pow_scalar_scalar); + binary_ops[octave_value::op_pow].add_overload (fn); + binary_ops[octave_value::op_el_pow].add_overload (fn); + + // now for binary complex operations + add_binary_op (complex, octave_value::op_add, llvm::Instruction::FAdd); + add_binary_op (complex, octave_value::op_sub, llvm::Instruction::FSub); + + fn = create_function (jit_convention::internal, + "octave_jit_*_complex_complex", complex, complex, + complex); + body = fn.new_block (); + builder.SetInsertPoint (body); + { + // (x0*x1 - y0*y1, x0*y1 + y0*x1) = (x0,y0) * (x1,y1) + // We compute this in one vectorized multiplication, a subtraction, and an + // addition. + llvm::Value *lhs = fn.argument (builder, 0); + llvm::Value *rhs = fn.argument (builder, 1); + + // FIXME: We need a better way of doing this, working with llvm's IR + // directly is sort of a pain. + llvm::Value *zero = builder.getInt32 (0); + llvm::Value *one = builder.getInt32 (1); + llvm::Value *two = builder.getInt32 (2); + llvm::Value *three = builder.getInt32 (3); + + llvm::Type *vec4 = llvm::VectorType::get (scalar_t, 4); + llvm::Value *mlhs = llvm::UndefValue::get (vec4); + llvm::Value *mrhs = mlhs; + + llvm::Value *temp = complex_real (lhs); + mlhs = builder.CreateInsertElement (mlhs, temp, zero); + mlhs = builder.CreateInsertElement (mlhs, temp, two); + temp = complex_imag (lhs); + mlhs = builder.CreateInsertElement (mlhs, temp, one); + mlhs = builder.CreateInsertElement (mlhs, temp, three); + + temp = complex_real (rhs); + mrhs = builder.CreateInsertElement (mrhs, temp, zero); + mrhs = builder.CreateInsertElement (mrhs, temp, three); + temp = complex_imag (rhs); + mrhs = builder.CreateInsertElement (mrhs, temp, one); + mrhs = builder.CreateInsertElement (mrhs, temp, two); + + llvm::Value *mres = builder.CreateFMul (mlhs, mrhs); + llvm::Value *tlhs = builder.CreateExtractElement (mres, zero); + llvm::Value *trhs = builder.CreateExtractElement (mres, one); + llvm::Value *ret_real = builder.CreateFSub (tlhs, trhs); + + tlhs = builder.CreateExtractElement (mres, two); + trhs = builder.CreateExtractElement (mres, three); + llvm::Value *ret_imag = builder.CreateFAdd (tlhs, trhs); + fn.do_return (builder, complex_new (ret_real, ret_imag)); + } + + binary_ops[octave_value::op_mul].add_overload (fn); + binary_ops[octave_value::op_el_mul].add_overload (fn); + + jit_function complex_div = create_function (jit_convention::external, + "octave_jit_complex_div", + complex, complex, complex); + complex_div.add_mapping (engine, &octave_jit_complex_div); + complex_div.mark_can_error (); + binary_ops[octave_value::op_div].add_overload (fn); + binary_ops[octave_value::op_ldiv].add_overload (fn); + + fn = mirror_binary (complex_div); + binary_ops[octave_value::op_ldiv].add_overload (fn); + binary_ops[octave_value::op_el_ldiv].add_overload (fn); + + fn = create_function (jit_convention::external, + "octave_jit_pow_complex_complex", complex, complex, + complex); + fn.add_mapping (engine, &octave_jit_pow_complex_complex); + binary_ops[octave_value::op_pow].add_overload (fn); + binary_ops[octave_value::op_el_pow].add_overload (fn); + + fn = create_function (jit_convention::internal, + "octave_jit_*_scalar_complex", complex, scalar, + complex); + jit_function mul_scalar_complex = fn; + body = fn.new_block (); + builder.SetInsertPoint (body); + { + llvm::Value *lhs = fn.argument (builder, 0); + llvm::Value *tlhs = complex_new (lhs, lhs); + llvm::Value *rhs = fn.argument (builder, 1); + fn.do_return (builder, builder.CreateFMul (tlhs, rhs)); + } + binary_ops[octave_value::op_mul].add_overload (fn); + binary_ops[octave_value::op_el_mul].add_overload (fn); + + + fn = mirror_binary (mul_scalar_complex); + binary_ops[octave_value::op_mul].add_overload (fn); + binary_ops[octave_value::op_el_mul].add_overload (fn); + + fn = create_function (jit_convention::internal, "octave_jit_+_scalar_complex", + complex, scalar, complex); + body = fn.new_block (); + builder.SetInsertPoint (body); + { + llvm::Value *lhs = fn.argument (builder, 0); + llvm::Value *rhs = fn.argument (builder, 1); + llvm::Value *real = builder.CreateFAdd (lhs, complex_real (rhs)); + fn.do_return (builder, complex_real (rhs, real)); + } + binary_ops[octave_value::op_add].add_overload (fn); + + fn = mirror_binary (fn); + binary_ops[octave_value::op_add].add_overload (fn); + + fn = create_function (jit_convention::internal, "octave_jit_-_complex_scalar", + complex, complex, scalar); + body = fn.new_block (); + builder.SetInsertPoint (body); + { + llvm::Value *lhs = fn.argument (builder, 0); + llvm::Value *rhs = fn.argument (builder, 1); + llvm::Value *real = builder.CreateFSub (complex_real (lhs), rhs); + fn.do_return (builder, complex_real (lhs, real)); + } + binary_ops[octave_value::op_sub].add_overload (fn); + + fn = create_function (jit_convention::internal, "octave_jit_-_scalar_complex", + complex, scalar, complex); + body = fn.new_block (); + builder.SetInsertPoint (body); + { + llvm::Value *lhs = fn.argument (builder, 0); + llvm::Value *rhs = fn.argument (builder, 1); + llvm::Value *real = builder.CreateFSub (lhs, complex_real (rhs)); + fn.do_return (builder, complex_real (rhs, real)); + } + binary_ops[octave_value::op_sub].add_overload (fn); + + fn = create_function (jit_convention::external, + "octave_jit_pow_scalar_complex", complex, scalar, + complex); + fn.add_mapping (engine, &octave_jit_pow_scalar_complex); + binary_ops[octave_value::op_pow].add_overload (fn); + binary_ops[octave_value::op_el_pow].add_overload (fn); + + fn = create_function (jit_convention::external, + "octave_jit_pow_complex_scalar", complex, complex, + scalar); + fn.add_mapping (engine, &octave_jit_pow_complex_scalar); + binary_ops[octave_value::op_pow].add_overload (fn); + binary_ops[octave_value::op_el_pow].add_overload (fn); + + // now for binary index operators + add_binary_op (index, octave_value::op_add, llvm::Instruction::Add); + + // and binary bool operators + add_binary_op (boolean, octave_value::op_el_or, llvm::Instruction::Or); + add_binary_op (boolean, octave_value::op_el_and, llvm::Instruction::And); + + // now for printing functions + print_fn.stash_name ("print"); + add_print (any, reinterpret_cast (&octave_jit_print_any)); + add_print (scalar, reinterpret_cast (&octave_jit_print_scalar)); + + // initialize for loop + for_init_fn.stash_name ("for_init"); + + fn = create_function (jit_convention::internal, "octave_jit_for_range_init", + index, range); + body = fn.new_block (); + builder.SetInsertPoint (body); + { + llvm::Value *zero = llvm::ConstantInt::get (index_t, 0); + fn.do_return (builder, zero); + } + for_init_fn.add_overload (fn); + + // bounds check for for loop + for_check_fn.stash_name ("for_check"); + + fn = create_function (jit_convention::internal, "octave_jit_for_range_check", + boolean, range, index); + body = fn.new_block (); + builder.SetInsertPoint (body); + { + llvm::Value *nelem + = builder.CreateExtractValue (fn.argument (builder, 0), 3); + llvm::Value *idx = fn.argument (builder, 1); + llvm::Value *ret = builder.CreateICmpULT (idx, nelem); + fn.do_return (builder, ret); + } + for_check_fn.add_overload (fn); + + // index variabe for for loop + for_index_fn.stash_name ("for_index"); + + fn = create_function (jit_convention::internal, "octave_jit_for_range_idx", + scalar, range, index); + body = fn.new_block (); + builder.SetInsertPoint (body); + { + llvm::Value *idx = fn.argument (builder, 1); + llvm::Value *didx = builder.CreateSIToFP (idx, scalar_t); + llvm::Value *rng = fn.argument (builder, 0); + llvm::Value *base = builder.CreateExtractValue (rng, 0); + llvm::Value *inc = builder.CreateExtractValue (rng, 2); + + llvm::Value *ret = builder.CreateFMul (didx, inc); + ret = builder.CreateFAdd (base, ret); + fn.do_return (builder, ret); + } + for_index_fn.add_overload (fn); + + // logically true + logically_true_fn.stash_name ("logically_true"); + + jit_function gripe_nantl + = create_function (jit_convention::external, + "octave_jit_gripe_nan_to_logical_conversion", 0); + gripe_nantl.add_mapping (engine, &octave_jit_gripe_nan_to_logical_conversion); + gripe_nantl.mark_can_error (); + + fn = create_function (jit_convention::internal, + "octave_jit_logically_true_scalar", boolean, scalar); + fn.mark_can_error (); + + body = fn.new_block (); + builder.SetInsertPoint (body); + { + llvm::BasicBlock *error_block = fn.new_block ("error"); + llvm::BasicBlock *normal_block = fn.new_block ("normal"); + + llvm::Value *check = builder.CreateFCmpUNE (fn.argument (builder, 0), + fn.argument (builder, 0)); + builder.CreateCondBr (check, error_block, normal_block); + + builder.SetInsertPoint (error_block); + gripe_nantl.call (builder); + builder.CreateBr (normal_block); + builder.SetInsertPoint (normal_block); + + llvm::Value *zero = llvm::ConstantFP::get (scalar_t, 0); + llvm::Value *ret = builder.CreateFCmpONE (fn.argument (builder, 0), zero); + fn.do_return (builder, ret); + } + logically_true_fn.add_overload (fn); + + // logically_true boolean + fn = create_identity (boolean); + logically_true_fn.add_overload (fn); + + // make_range + // FIXME: May be benificial to implement all in LLVM + make_range_fn.stash_name ("make_range"); + jit_function compute_nelem + = create_function (jit_convention::external, "octave_jit_compute_nelem", + index, scalar, scalar, scalar); + compute_nelem.add_mapping (engine, &octave_jit_compute_nelem); + + fn = create_function (jit_convention::internal, "octave_jit_make_range", + range, scalar, scalar, scalar); + body = fn.new_block (); + builder.SetInsertPoint (body); + { + llvm::Value *base = fn.argument (builder, 0); + llvm::Value *limit = fn.argument (builder, 1); + llvm::Value *inc = fn.argument (builder, 2); + llvm::Value *nelem = compute_nelem.call (builder, base, limit, inc); + + llvm::Value *dzero = llvm::ConstantFP::get (scalar_t, 0); + llvm::Value *izero = llvm::ConstantInt::get (index_t, 0); + llvm::Value *rng = llvm::ConstantStruct::get (range_t, dzero, dzero, dzero, + izero, NULL); + rng = builder.CreateInsertValue (rng, base, 0); + rng = builder.CreateInsertValue (rng, limit, 1); + rng = builder.CreateInsertValue (rng, inc, 2); + rng = builder.CreateInsertValue (rng, nelem, 3); + fn.do_return (builder, rng); + } + make_range_fn.add_overload (fn); + + // paren_subsref + jit_type *jit_int = intN (sizeof (int) * 8); + llvm::Type *int_t = jit_int->to_llvm (); + jit_function ginvalid_index + = create_function (jit_convention::external, "octave_jit_ginvalid_index", + 0); + ginvalid_index.add_mapping (engine, &octave_jit_ginvalid_index); + jit_function gindex_range = create_function (jit_convention::external, + "octave_jit_gindex_range", + 0, jit_int, jit_int, index, + index); + gindex_range.add_mapping (engine, &octave_jit_gindex_range); + + fn = create_function (jit_convention::internal, "()subsref", scalar, matrix, + scalar); + fn.mark_can_error (); + + body = fn.new_block (); + builder.SetInsertPoint (body); + { + llvm::Value *one = llvm::ConstantInt::get (index_t, 1); + llvm::Value *ione; + if (index_t == int_t) + ione = one; + else + ione = llvm::ConstantInt::get (int_t, 1); + + llvm::Value *undef = llvm::UndefValue::get (scalar_t); + llvm::Value *mat = fn.argument (builder, 0); + llvm::Value *idx = fn.argument (builder, 1); + + // convert index to scalar to integer, and check index >= 1 + llvm::Value *int_idx = builder.CreateFPToSI (idx, index_t); + llvm::Value *check_idx = builder.CreateSIToFP (int_idx, scalar_t); + llvm::Value *cond0 = builder.CreateFCmpUNE (idx, check_idx); + llvm::Value *cond1 = builder.CreateICmpSLT (int_idx, one); + llvm::Value *cond = builder.CreateOr (cond0, cond1); + + llvm::BasicBlock *done = fn.new_block ("done"); + llvm::BasicBlock *conv_error = fn.new_block ("conv_error", done); + llvm::BasicBlock *normal = fn.new_block ("normal", done); + builder.CreateCondBr (cond, conv_error, normal); + + builder.SetInsertPoint (conv_error); + ginvalid_index.call (builder); + builder.CreateBr (done); + + builder.SetInsertPoint (normal); + llvm::Value *len = builder.CreateExtractValue (mat, + llvm::ArrayRef (2)); + cond = builder.CreateICmpSGT (int_idx, len); + + + llvm::BasicBlock *bounds_error = fn.new_block ("bounds_error", done); + llvm::BasicBlock *success = fn.new_block ("success", done); + builder.CreateCondBr (cond, bounds_error, success); + + builder.SetInsertPoint (bounds_error); + gindex_range.call (builder, ione, ione, int_idx, len); + builder.CreateBr (done); + + builder.SetInsertPoint (success); + llvm::Value *data = builder.CreateExtractValue (mat, + llvm::ArrayRef (1)); + llvm::Value *gep = builder.CreateInBoundsGEP (data, int_idx); + llvm::Value *ret = builder.CreateLoad (gep); + builder.CreateBr (done); + + builder.SetInsertPoint (done); + + llvm::PHINode *merge = llvm::PHINode::Create (scalar_t, 3); + builder.Insert (merge); + merge->addIncoming (undef, conv_error); + merge->addIncoming (undef, bounds_error); + merge->addIncoming (ret, success); + fn.do_return (builder, merge); + } + paren_subsref_fn.add_overload (fn); + + // paren subsasgn + paren_subsasgn_fn.stash_name ("()subsasgn"); + + jit_function resize_paren_subsasgn + = create_function (jit_convention::external, + "octave_jit_paren_subsasgn_impl", matrix, matrix, index, + scalar); + resize_paren_subsasgn.add_mapping (engine, &octave_jit_paren_subsasgn_impl); + fn = create_function (jit_convention::internal, "octave_jit_paren_subsasgn", + matrix, matrix, scalar, scalar); + fn.mark_can_error (); + body = fn.new_block (); + builder.SetInsertPoint (body); + { + llvm::Value *one = llvm::ConstantInt::get (index_t, 1); + + llvm::Value *mat = fn.argument (builder, 0); + llvm::Value *idx = fn.argument (builder, 1); + llvm::Value *value = fn.argument (builder, 2); + + llvm::Value *int_idx = builder.CreateFPToSI (idx, index_t); + llvm::Value *check_idx = builder.CreateSIToFP (int_idx, scalar_t); + llvm::Value *cond0 = builder.CreateFCmpUNE (idx, check_idx); + llvm::Value *cond1 = builder.CreateICmpSLT (int_idx, one); + llvm::Value *cond = builder.CreateOr (cond0, cond1); + + llvm::BasicBlock *done = fn.new_block ("done"); + + llvm::BasicBlock *conv_error = fn.new_block ("conv_error", done); + llvm::BasicBlock *normal = fn.new_block ("normal", done); + builder.CreateCondBr (cond, conv_error, normal); + builder.SetInsertPoint (conv_error); + ginvalid_index.call (builder); + builder.CreateBr (done); + + builder.SetInsertPoint (normal); + llvm::Value *len = builder.CreateExtractValue (mat, 2); + cond0 = builder.CreateICmpSGT (int_idx, len); + + llvm::Value *rcount = builder.CreateExtractValue (mat, 0); + rcount = builder.CreateLoad (rcount); + cond1 = builder.CreateICmpSGT (rcount, one); + cond = builder.CreateOr (cond0, cond1); + + llvm::BasicBlock *bounds_error = fn.new_block ("bounds_error", done); + llvm::BasicBlock *success = fn.new_block ("success", done); + builder.CreateCondBr (cond, bounds_error, success); + + // resize on out of bounds access + builder.SetInsertPoint (bounds_error); + llvm::Value *resize_result = resize_paren_subsasgn.call (builder, mat, + int_idx, value); + builder.CreateBr (done); + + builder.SetInsertPoint (success); + llvm::Value *data = builder.CreateExtractValue (mat, + llvm::ArrayRef (1)); + llvm::Value *gep = builder.CreateInBoundsGEP (data, int_idx); + builder.CreateStore (value, gep); + builder.CreateBr (done); + + builder.SetInsertPoint (done); + + llvm::PHINode *merge = llvm::PHINode::Create (matrix_t, 3); + builder.Insert (merge); + merge->addIncoming (mat, conv_error); + merge->addIncoming (resize_result, bounds_error); + merge->addIncoming (mat, success); + fn.do_return (builder, merge); + } + paren_subsasgn_fn.add_overload (fn); + + fn = create_function (jit_convention::external, + "octave_jit_paren_subsasgn_matrix_range", matrix, + matrix, range, scalar); + fn.add_mapping (engine, &octave_jit_paren_subsasgn_matrix_range); + fn.mark_can_error (); + paren_subsasgn_fn.add_overload (fn); + + end_fn.stash_name ("end"); + fn = create_function (jit_convention::internal, "octave_jit_end_matrix", + scalar, matrix); + body = fn.new_block (); + builder.SetInsertPoint (body); + { + llvm::Value *mat = fn.argument (builder, 0); + llvm::Value *ret = builder.CreateExtractValue (mat, 2); + fn.do_return (builder, builder.CreateSIToFP (ret, scalar_t)); + } + end_fn.add_overload (fn); + + casts[any->type_id ()].stash_name ("(any)"); + casts[scalar->type_id ()].stash_name ("(scalar)"); + casts[complex->type_id ()].stash_name ("(complex)"); + casts[matrix->type_id ()].stash_name ("(matrix)"); + casts[any->type_id ()].stash_name ("(range)"); + + // cast any <- matrix + fn = create_function (jit_convention::external, "octave_jit_cast_any_matrix", + any, matrix); + fn.add_mapping (engine, &octave_jit_cast_any_matrix); + casts[any->type_id ()].add_overload (fn); + + // cast matrix <- any + fn = create_function (jit_convention::external, "octave_jit_cast_matrix_any", + matrix, any); + fn.add_mapping (engine, &octave_jit_cast_matrix_any); + casts[matrix->type_id ()].add_overload (fn); + + // cast any <- range + fn = create_function (jit_convention::external, "octave_jit_cast_any_range", + any, range); + fn.add_mapping (engine, &octave_jit_cast_any_range); + casts[any->type_id ()].add_overload (fn); + + // cast range <- any + fn = create_function (jit_convention::external, "octave_jit_cast_range_any", + range, any); + fn.add_mapping (engine, &octave_jit_cast_range_any); + casts[range->type_id ()].add_overload (fn); + + // cast any <- scalar + fn = create_function (jit_convention::external, "octave_jit_cast_any_scalar", + any, scalar); + fn.add_mapping (engine, &octave_jit_cast_any_scalar); + casts[any->type_id ()].add_overload (fn); + + // cast scalar <- any + fn = create_function (jit_convention::external, "octave_jit_cast_scalar_any", + scalar, any); + fn.add_mapping (engine, &octave_jit_cast_scalar_any); + casts[scalar->type_id ()].add_overload (fn); + + // cast any <- complex + fn = create_function (jit_convention::external, "octave_jit_cast_any_complex", + any, complex); + fn.add_mapping (engine, &octave_jit_cast_any_complex); + casts[any->type_id ()].add_overload (fn); + + // cast complex <- any + fn = create_function (jit_convention::external, "octave_jit_cast_complex_any", + complex, any); + fn.add_mapping (engine, &octave_jit_cast_complex_any); + casts[complex->type_id ()].add_overload (fn); + + // cast complex <- scalar + fn = create_function (jit_convention::internal, + "octave_jit_cast_complex_scalar", complex, scalar); + body = fn.new_block (); + builder.SetInsertPoint (body); + { + llvm::Value *zero = llvm::ConstantFP::get (scalar_t, 0); + fn.do_return (builder, complex_new (fn.argument (builder, 0), zero)); + } + casts[complex->type_id ()].add_overload (fn); + + // cast scalar <- complex + fn = create_function (jit_convention::internal, + "octave_jit_cast_scalar_complex", scalar, complex); + body = fn.new_block (); + builder.SetInsertPoint (body); + fn.do_return (builder, complex_real (fn.argument (builder, 0))); + casts[scalar->type_id ()].add_overload (fn); + + // cast any <- any + fn = create_identity (any); + casts[any->type_id ()].add_overload (fn); + + // cast scalar <- scalar + fn = create_identity (scalar); + casts[scalar->type_id ()].add_overload (fn); + + // cast complex <- complex + fn = create_identity (complex); + casts[complex->type_id ()].add_overload (fn); + + // -------------------- builtin functions -------------------- + add_builtin ("#unknown_function"); + unknown_function = builtins["#unknown_function"]; + + add_builtin ("sin"); + register_intrinsic ("sin", llvm::Intrinsic::sin, scalar, scalar); + register_generic ("sin", matrix, matrix); + + add_builtin ("cos"); + register_intrinsic ("cos", llvm::Intrinsic::cos, scalar, scalar); + register_generic ("cos", matrix, matrix); + + add_builtin ("exp"); + register_intrinsic ("exp", llvm::Intrinsic::cos, scalar, scalar); + register_generic ("exp", matrix, matrix); + + casts.resize (next_id + 1); + jit_function any_id = create_identity (any); + jit_function release_any = get_release (any); + std::vector args; + args.resize (1); + + for (std::map::iterator iter = builtins.begin (); + iter != builtins.end (); ++iter) + { + jit_type *btype = iter->second; + args[0] = btype; + + release_fn.add_overload (jit_function (release_any, 0, args)); + casts[any->type_id ()].add_overload (jit_function (any_id, any, args)); + + args[0] = any; + casts[btype->type_id ()].add_overload (jit_function (any_id, btype, + args)); + } +} + +void +jit_typeinfo::add_print (jit_type *ty, void *fptr) +{ + std::stringstream name; + name << "octave_jit_print_" << ty->name (); + jit_function fn = create_function (jit_convention::external, name.str (), 0, + intN (8), ty); + fn.add_mapping (engine, fptr); + print_fn.add_overload (fn); +} + +// FIXME: cp between add_binary_op, add_binary_icmp, and add_binary_fcmp +void +jit_typeinfo::add_binary_op (jit_type *ty, int op, int llvm_op) +{ + std::stringstream fname; + octave_value::binary_op ov_op = static_cast(op); + fname << "octave_jit_" << octave_value::binary_op_as_string (ov_op) + << "_" << ty->name (); + + jit_function fn = create_function (jit_convention::internal, fname.str (), + ty, ty, ty); + llvm::BasicBlock *block = fn.new_block (); + builder.SetInsertPoint (block); + llvm::Instruction::BinaryOps temp + = static_cast(llvm_op); + + llvm::Value *ret = builder.CreateBinOp (temp, fn.argument (builder, 0), + fn.argument (builder, 1)); + fn.do_return (builder, ret); + binary_ops[op].add_overload (fn); +} + +void +jit_typeinfo::add_binary_icmp (jit_type *ty, int op, int llvm_op) +{ + std::stringstream fname; + octave_value::binary_op ov_op = static_cast(op); + fname << "octave_jit" << octave_value::binary_op_as_string (ov_op) + << "_" << ty->name (); + + jit_function fn = create_function (jit_convention::internal, fname.str (), + boolean, ty, ty); + llvm::BasicBlock *block = fn.new_block (); + builder.SetInsertPoint (block); + llvm::CmpInst::Predicate temp + = static_cast(llvm_op); + llvm::Value *ret = builder.CreateICmp (temp, fn.argument (builder, 0), + fn.argument (builder, 1)); + fn.do_return (builder, ret); + binary_ops[op].add_overload (fn); +} + +void +jit_typeinfo::add_binary_fcmp (jit_type *ty, int op, int llvm_op) +{ + std::stringstream fname; + octave_value::binary_op ov_op = static_cast(op); + fname << "octave_jit" << octave_value::binary_op_as_string (ov_op) + << "_" << ty->name (); + + jit_function fn = create_function (jit_convention::internal, fname.str (), + boolean, ty, ty); + llvm::BasicBlock *block = fn.new_block (); + builder.SetInsertPoint (block); + llvm::CmpInst::Predicate temp + = static_cast(llvm_op); + llvm::Value *ret = builder.CreateFCmp (temp, fn.argument (builder, 0), + fn.argument (builder, 1)); + fn.do_return (builder, ret); + binary_ops[op].add_overload (fn); +} + +jit_function +jit_typeinfo::create_function (jit_convention::type cc, const llvm::Twine& name, + jit_type *ret, + const std::vector& args) +{ + jit_function result (module, cc, name, ret, args); + return result; +} + +jit_function +jit_typeinfo::create_identity (jit_type *type) +{ + size_t id = type->type_id (); + if (id >= identities.size ()) + identities.resize (id + 1); + + if (! identities[id].valid ()) + { + jit_function fn = create_function (jit_convention::internal, "id", type, + type); + llvm::BasicBlock *body = fn.new_block (); + builder.SetInsertPoint (body); + fn.do_return (builder, fn.argument (builder, 0)); + return identities[id] = fn; + } + + return identities[id]; +} + +llvm::Value * +jit_typeinfo::do_insert_error_check (llvm::IRBuilderD& abuilder) +{ + return abuilder.CreateLoad (lerror_state); +} + +void +jit_typeinfo::add_builtin (const std::string& name) +{ + jit_type *btype = new_type (name, any, any->to_llvm ()); + builtins[name] = btype; + + octave_builtin *ov_builtin = find_builtin (name); + if (ov_builtin) + ov_builtin->stash_jit (*btype); +} + +void +jit_typeinfo::register_intrinsic (const std::string& name, size_t iid, + jit_type *result, + const std::vector& args) +{ + jit_type *builtin_type = builtins[name]; + size_t nargs = args.size (); + llvm::SmallVector llvm_args (nargs); + for (size_t i = 0; i < nargs; ++i) + llvm_args[i] = args[i]->to_llvm (); + + llvm::Intrinsic::ID id = static_cast (iid); + llvm::Function *ifun = llvm::Intrinsic::getDeclaration (module, id, + llvm_args); + std::stringstream fn_name; + fn_name << "octave_jit_" << name; + + std::vector args1 (nargs + 1); + args1[0] = builtin_type; + std::copy (args.begin (), args.end (), args1.begin () + 1); + + // The first argument will be the Octave function, but we already know that + // the function call is the equivalent of the intrinsic, so we ignore it and + // call the intrinsic with the remaining arguments. + jit_function fn = create_function (jit_convention::internal, fn_name.str (), + result, args1); + llvm::BasicBlock *body = fn.new_block (); + builder.SetInsertPoint (body); + + llvm::SmallVector fargs (nargs); + for (size_t i = 0; i < nargs; ++i) + fargs[i] = fn.argument (builder, i + 1); + + llvm::Value *ret = builder.CreateCall (ifun, fargs); + fn.do_return (builder, ret); + paren_subsref_fn.add_overload (fn); +} + +octave_builtin * +jit_typeinfo::find_builtin (const std::string& name) +{ + // FIXME: Finalize what we want to store in octave_builtin, then add functions + // to access these values in octave_value + octave_value ov_builtin = symbol_table::find (name); + return dynamic_cast (ov_builtin.internal_rep ()); +} + +void +jit_typeinfo::register_generic (const std::string&, jit_type *, + const std::vector&) +{ + // FIXME: Implement +} + +jit_function +jit_typeinfo::mirror_binary (const jit_function& fn) +{ + jit_function ret = create_function (jit_convention::internal, + fn.name () + "_reverse", + fn.result (), fn.argument_type (1), + fn.argument_type (0)); + if (fn.can_error ()) + ret.mark_can_error (); + + llvm::BasicBlock *body = ret.new_block (); + builder.SetInsertPoint (body); + llvm::Value *result = fn.call (builder, ret.argument (builder, 1), + ret.argument (builder, 0)); + if (ret.result ()) + ret.do_return (builder, result); + else + ret.do_return (builder); + + return ret; +} + +llvm::Value * +jit_typeinfo::pack_complex (llvm::IRBuilderD& bld, llvm::Value *cplx) +{ + llvm::Type *complex_ret = instance->complex_ret; + llvm::Value *real = bld.CreateExtractElement (cplx, bld.getInt32 (0)); + llvm::Value *imag = bld.CreateExtractElement (cplx, bld.getInt32 (1)); + llvm::Value *ret = llvm::UndefValue::get (complex_ret); + ret = bld.CreateInsertValue (ret, real, 0); + return bld.CreateInsertValue (ret, imag, 1); +} + +llvm::Value * +jit_typeinfo::unpack_complex (llvm::IRBuilderD& bld, llvm::Value *result) +{ + llvm::Type *complex_t = get_complex ()->to_llvm (); + llvm::Value *real = bld.CreateExtractValue (result, 0); + llvm::Value *imag = bld.CreateExtractValue (result, 1); + llvm::Value *ret = llvm::UndefValue::get (complex_t); + ret = bld.CreateInsertElement (ret, real, bld.getInt32 (0)); + return bld.CreateInsertElement (ret, imag, bld.getInt32 (1)); +} + +llvm::Value * +jit_typeinfo::complex_real (llvm::Value *cx) +{ + return builder.CreateExtractElement (cx, builder.getInt32 (0)); +} + +llvm::Value * +jit_typeinfo::complex_real (llvm::Value *cx, llvm::Value *real) +{ + return builder.CreateInsertElement (cx, real, builder.getInt32 (0)); +} + +llvm::Value * +jit_typeinfo::complex_imag (llvm::Value *cx) +{ + return builder.CreateExtractElement (cx, builder.getInt32 (1)); +} + +llvm::Value * +jit_typeinfo::complex_imag (llvm::Value *cx, llvm::Value *imag) +{ + return builder.CreateInsertElement (cx, imag, builder.getInt32 (1)); +} + +llvm::Value * +jit_typeinfo::complex_new (llvm::Value *real, llvm::Value *imag) +{ + llvm::Value *ret = llvm::UndefValue::get (complex->to_llvm ()); + ret = complex_real (ret, real); + return complex_imag (ret, imag); +} + +void +jit_typeinfo::create_int (size_t nbits) +{ + std::stringstream tname; + tname << "int" << nbits; + ints[nbits] = new_type (tname.str (), any, llvm::Type::getIntNTy (context, + nbits)); +} + +jit_type * +jit_typeinfo::intN (size_t nbits) const +{ + std::map::const_iterator iter = ints.find (nbits); + if (iter != ints.end ()) + return iter->second; + + throw jit_fail_exception ("No such integer type"); +} + +jit_type * +jit_typeinfo::do_type_of (const octave_value &ov) const +{ + if (ov.is_function ()) + { + // FIXME: This is ugly, we need to finalize how we want to to this, then + // have octave_value fully support the needed functionality + octave_builtin *builtin + = dynamic_cast (ov.internal_rep ()); + return builtin && builtin->to_jit () ? builtin->to_jit () + : unknown_function; + } + + if (ov.is_range ()) + return get_range (); + + if (ov.is_double_type ()) + { + if (ov.is_real_scalar ()) + return get_scalar (); + + if (ov.is_matrix_type ()) + return get_matrix (); + } + + if (ov.is_complex_scalar ()) + return get_complex (); + + return get_any (); +} + +jit_type* +jit_typeinfo::new_type (const std::string& name, jit_type *parent, + llvm::Type *llvm_type) +{ + jit_type *ret = new jit_type (name, parent, llvm_type, next_id++); + id_to_type.push_back (ret); + return ret; +} + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/jit-typeinfo.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/jit-typeinfo.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,753 @@ +/* + +Copyright (C) 2012 Max Brister + +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 (octave_jit_typeinfo_h) +#define octave_jit_typeinfo_h 1 + +#ifdef HAVE_LLVM + +#include +#include + +#include "Range.h" +#include "jit-util.h" + +// Defines the type system used by jit and a singleton class, jit_typeinfo, to +// manage the types. +// +// FIXME: +// Operations are defined and implemented in jit_typeinfo. Eventually they +// should be moved elsewhere. (just like with octave_typeinfo) + +// jit_range is compatable with the llvm range structure +struct +jit_range +{ + jit_range (const Range& from) : base (from.base ()), limit (from.limit ()), + inc (from.inc ()), nelem (from.nelem ()) + {} + + operator Range () const + { + return Range (base, limit, inc); + } + + bool all_elements_are_ints () const; + + double base; + double limit; + double inc; + octave_idx_type nelem; +}; + +std::ostream& operator<< (std::ostream& os, const jit_range& rng); + +// jit_array is compatable with the llvm array/matrix structures +template +struct +jit_array +{ + jit_array (T& from) : array (new T (from)) + { + update (); + } + + void update (void) + { + ref_count = array->jit_ref_count (); + slice_data = array->jit_slice_data () - 1; + slice_len = array->capacity (); + dimensions = array->jit_dimensions (); + } + + void update (T *aarray) + { + array = aarray; + update (); + } + + operator T () const + { + return *array; + } + + int *ref_count; + + U *slice_data; + octave_idx_type slice_len; + octave_idx_type *dimensions; + + T *array; +}; + +typedef jit_array jit_matrix; + +std::ostream& operator<< (std::ostream& os, const jit_matrix& mat); + +// calling convention +namespace +jit_convention +{ + enum + type + { + // internal to jit + internal, + + // an external C call + external, + + length + }; +} + +// Used to keep track of estimated (infered) types during JIT. This is a +// hierarchical type system which includes both concrete and abstract types. +// +// The types form a lattice. Currently we only allow for one parent type, but +// eventually we may allow for multiple predecessors. +class +jit_type +{ +public: + typedef llvm::Value *(*convert_fn) (llvm::IRBuilderD&, llvm::Value *); + + jit_type (const std::string& aname, jit_type *aparent, llvm::Type *allvm_type, + int aid); + + // a user readable type name + const std::string& name (void) const { return mname; } + + // a unique id for the type + int type_id (void) const { return mid; } + + // An abstract base type, may be null + jit_type *parent (void) const { return mparent; } + + // convert to an llvm type + llvm::Type *to_llvm (void) const { return llvm_type; } + + // how this type gets passed as a function argument + llvm::Type *to_llvm_arg (void) const; + + size_t depth (void) const { return mdepth; } + + // -------------------- Calling Convention information -------------------- + + // A function declared like: mytype foo (int arg0, int arg1); + // Will be converted to: void foo (mytype *retval, int arg0, int arg1) + // if mytype is sret. The caller is responsible for allocating space for + // retval. (on the stack) + bool sret (jit_convention::type cc) const { return msret[cc]; } + + void mark_sret (jit_convention::type cc = jit_convention::external) + { msret[cc] = true; } + + // A function like: void foo (mytype arg0) + // Will be converted to: void foo (mytype *arg0) + // Basically just pass by reference. + bool pointer_arg (jit_convention::type cc) const { return mpointer_arg[cc]; } + + void mark_pointer_arg (jit_convention::type cc = jit_convention::external) + { mpointer_arg[cc] = true; } + + // Convert into an equivalent form before calling. For example, complex is + // represented as two values llvm vector, but we need to pass it as a two + // valued llvm structure to C functions. + convert_fn pack (jit_convention::type cc) { return mpack[cc]; } + + void set_pack (jit_convention::type cc, convert_fn fn) { mpack[cc] = fn; } + + // The inverse operation of pack. + convert_fn unpack (jit_convention::type cc) { return munpack[cc]; } + + void set_unpack (jit_convention::type cc, convert_fn fn) + { munpack[cc] = fn; } + + // The resulting type after pack is called. + llvm::Type *packed_type (jit_convention::type cc) + { return mpacked_type[cc]; } + + void set_packed_type (jit_convention::type cc, llvm::Type *ty) + { mpacked_type[cc] = ty; } +private: + std::string mname; + jit_type *mparent; + llvm::Type *llvm_type; + int mid; + size_t mdepth; + + bool msret[jit_convention::length]; + bool mpointer_arg[jit_convention::length]; + + convert_fn mpack[jit_convention::length]; + convert_fn munpack[jit_convention::length]; + + llvm::Type *mpacked_type[jit_convention::length]; +}; + +// seperate print function to allow easy printing if type is null +std::ostream& jit_print (std::ostream& os, jit_type *atype); + +class jit_value; + +// An abstraction for calling llvm functions with jit_values. Deals with calling +// convention details. +class +jit_function +{ + friend std::ostream& operator<< (std::ostream& os, const jit_function& fn); +public: + // create a function in an invalid state + jit_function (); + + jit_function (llvm::Module *amodule, jit_convention::type acall_conv, + const llvm::Twine& aname, jit_type *aresult, + const std::vector& aargs); + + // Use an existing function, but change the argument types. The new argument + // types must behave the same for the current calling convention. + jit_function (const jit_function& fn, jit_type *aresult, + const std::vector& aargs); + + jit_function (const jit_function& fn); + + template + void add_mapping (llvm::ExecutionEngine *engine, T fn) + { + do_add_mapping (engine, reinterpret_cast (fn)); + } + + bool valid (void) const { return llvm_function; } + + std::string name (void) const; + + llvm::BasicBlock *new_block (const std::string& aname = "body", + llvm::BasicBlock *insert_before = 0); + + llvm::Value *call (llvm::IRBuilderD& builder, + const std::vector& in_args) const; + + llvm::Value *call (llvm::IRBuilderD& builder, + const std::vector& in_args + = std::vector ()) const; + +#define JIT_PARAM_ARGS llvm::IRBuilderD& builder, +#define JIT_PARAMS builder, +#define JIT_CALL(N) JIT_EXPAND (llvm::Value *, call, llvm::Value *, const, N) + + JIT_CALL (1) + JIT_CALL (2) + JIT_CALL (3) + JIT_CALL (4) + JIT_CALL (5) + +#undef JIT_CALL + +#define JIT_CALL(N) JIT_EXPAND (llvm::Value *, call, jit_value *, const, N) + + JIT_CALL (1); + JIT_CALL (2); + +#undef JIT_CALL +#undef JIT_PARAMS +#undef JIT_PARAM_ARGS + + llvm::Value *argument (llvm::IRBuilderD& builder, size_t idx) const; + + void do_return (llvm::IRBuilderD& builder, llvm::Value *rval = 0); + + llvm::Function *to_llvm (void) const { return llvm_function; } + + // If true, then the return value is passed as a pointer in the first argument + bool sret (void) const { return mresult && mresult->sret (call_conv); } + + bool can_error (void) const { return mcan_error; } + + void mark_can_error (void) { mcan_error = true; } + + jit_type *result (void) const { return mresult; } + + jit_type *argument_type (size_t idx) const + { + assert (idx < args.size ()); + return args[idx]; + } + + const std::vector& arguments (void) const { return args; } +private: + void do_add_mapping (llvm::ExecutionEngine *engine, void *fn); + + llvm::Module *module; + llvm::Function *llvm_function; + jit_type *mresult; + std::vector args; + jit_convention::type call_conv; + bool mcan_error; +}; + +std::ostream& operator<< (std::ostream& os, const jit_function& fn); + + +// Keeps track of information about how to implement operations (+, -, *, ect) +// and their resulting types. +class +jit_operation +{ +public: + // type signature vector + typedef std::vector signature_vec; + + virtual ~jit_operation (void); + + void add_overload (const jit_function& func) + { + add_overload (func, func.arguments ()); + } + + void add_overload (const jit_function& func, + const signature_vec& args); + + const jit_function& overload (const signature_vec& types) const; + + jit_type *result (const signature_vec& types) const + { + const jit_function& temp = overload (types); + return temp.result (); + } + +#define JIT_PARAMS +#define JIT_PARAM_ARGS +#define JIT_OVERLOAD(N) \ + JIT_EXPAND (const jit_function&, overload, jit_type *, const, N) \ + JIT_EXPAND (jit_type *, result, jit_type *, const, N) + + JIT_OVERLOAD (1); + JIT_OVERLOAD (2); + JIT_OVERLOAD (3); + +#undef JIT_PARAMS +#undef JIT_PARAM_ARGS + + const std::string& name (void) const { return mname; } + + void stash_name (const std::string& aname) { mname = aname; } +protected: + virtual jit_function *generate (const signature_vec& types) const; +private: + Array to_idx (const signature_vec& types) const; + + const jit_function& do_generate (const signature_vec& types) const; + + struct signature_cmp + { + bool operator() (const signature_vec *lhs, const signature_vec *rhs); + }; + + typedef std::map + generated_map; + + mutable generated_map generated; + + std::vector > overloads; + + std::string mname; +}; + +class +jit_index_operation : public jit_operation +{ +public: + jit_index_operation (void) : module (0), engine (0) {} + + void initialize (llvm::Module *amodule, llvm::ExecutionEngine *aengine) + { + module = amodule; + engine = aengine; + do_initialize (); + } +protected: + virtual jit_function *generate (const signature_vec& types) const; + + virtual jit_function *generate_matrix (const signature_vec& types) const = 0; + + virtual void do_initialize (void) = 0; + + // helper functions + // [start_idx, end_idx). + llvm::Value *create_arg_array (llvm::IRBuilderD& builder, + const jit_function &fn, size_t start_idx, + size_t end_idx) const; + + llvm::Module *module; + llvm::ExecutionEngine *engine; +}; + +class +jit_paren_subsref : public jit_index_operation +{ +protected: + virtual jit_function *generate_matrix (const signature_vec& types) const; + + virtual void do_initialize (void); +private: + jit_function paren_scalar; +}; + +class +jit_paren_subsasgn : public jit_index_operation +{ +protected: + jit_function *generate_matrix (const signature_vec& types) const; + + virtual void do_initialize (void); +private: + jit_function paren_scalar; +}; + +// A singleton class which handles the construction of jit_types and +// jit_operations. +class +jit_typeinfo +{ +public: + static void initialize (llvm::Module *m, llvm::ExecutionEngine *e); + + static jit_type *join (jit_type *lhs, jit_type *rhs) + { + return instance->do_join (lhs, rhs); + } + + static jit_type *get_any (void) { return instance->any; } + + static jit_type *get_matrix (void) { return instance->matrix; } + + static jit_type *get_scalar (void) { return instance->scalar; } + + static llvm::Type *get_scalar_llvm (void) + { return instance->scalar->to_llvm (); } + + static jit_type *get_scalar_ptr (void) { return instance->scalar_ptr; } + + static jit_type *get_range (void) { return instance->range; } + + static jit_type *get_string (void) { return instance->string; } + + static jit_type *get_bool (void) { return instance->boolean; } + + static jit_type *get_index (void) { return instance->index; } + + static llvm::Type *get_index_llvm (void) + { return instance->index->to_llvm (); } + + static jit_type *get_complex (void) { return instance->complex; } + + // Get the jit_type of an octave_value + static jit_type *type_of (const octave_value& ov) + { + return instance->do_type_of (ov); + } + + static const jit_operation& binary_op (int op) + { + return instance->do_binary_op (op); + } + + static const jit_operation& grab (void) { return instance->grab_fn; } + + static const jit_function& get_grab (jit_type *type) + { + return instance->grab_fn.overload (type); + } + + static const jit_operation& release (void) + { + return instance->release_fn; + } + + static const jit_function& get_release (jit_type *type) + { + return instance->release_fn.overload (type); + } + + static const jit_operation& print_value (void) + { + return instance->print_fn; + } + + static const jit_operation& for_init (void) + { + return instance->for_init_fn; + } + + static const jit_operation& for_check (void) + { + return instance->for_check_fn; + } + + static const jit_operation& for_index (void) + { + return instance->for_index_fn; + } + + static const jit_operation& make_range (void) + { + return instance->make_range_fn; + } + + static const jit_operation& paren_subsref (void) + { + return instance->paren_subsref_fn; + } + + static const jit_operation& paren_subsasgn (void) + { + return instance->paren_subsasgn_fn; + } + + static const jit_operation& logically_true (void) + { + return instance->logically_true_fn; + } + + static const jit_operation& cast (jit_type *result) + { + return instance->do_cast (result); + } + + static const jit_function& cast (jit_type *to, jit_type *from) + { + return instance->do_cast (to, from); + } + + static llvm::Value *insert_error_check (llvm::IRBuilderD& bld) + { + return instance->do_insert_error_check (bld); + } + + static const jit_operation& end (void) + { + return instance->end_fn; + } + + static const jit_function& end (jit_type *ty) + { + return instance->end_fn.overload (ty); + } +private: + jit_typeinfo (llvm::Module *m, llvm::ExecutionEngine *e); + + // FIXME: Do these methods really need to be in jit_typeinfo? + jit_type *do_join (jit_type *lhs, jit_type *rhs) + { + // empty case + if (! lhs) + return rhs; + + if (! rhs) + return lhs; + + // check for a shared parent + while (lhs != rhs) + { + if (lhs->depth () > rhs->depth ()) + lhs = lhs->parent (); + else if (lhs->depth () < rhs->depth ()) + rhs = rhs->parent (); + else + { + // we MUST have depth > 0 as any is the base type of everything + do + { + lhs = lhs->parent (); + rhs = rhs->parent (); + } + while (lhs != rhs); + } + } + + return lhs; + } + + jit_type *do_difference (jit_type *lhs, jit_type *) + { + // FIXME: Maybe we can do something smarter? + return lhs; + } + + jit_type *do_type_of (const octave_value &ov) const; + + const jit_operation& do_binary_op (int op) const + { + assert (static_cast(op) < binary_ops.size ()); + return binary_ops[op]; + } + + const jit_operation& do_cast (jit_type *to) + { + static jit_operation null_function; + if (! to) + return null_function; + + size_t id = to->type_id (); + if (id >= casts.size ()) + return null_function; + return casts[id]; + } + + const jit_function& do_cast (jit_type *to, jit_type *from) + { + return do_cast (to).overload (from); + } + + jit_type *new_type (const std::string& name, jit_type *parent, + llvm::Type *llvm_type); + + + void add_print (jit_type *ty, void *fptr); + + void add_binary_op (jit_type *ty, int op, int llvm_op); + + void add_binary_icmp (jit_type *ty, int op, int llvm_op); + + void add_binary_fcmp (jit_type *ty, int op, int llvm_op); + + jit_function create_function (jit_convention::type cc, + const llvm::Twine& name, jit_type *ret, + const std::vector& args + = std::vector ()); + +#define JIT_PARAM_ARGS jit_convention::type cc, const llvm::Twine& name, \ + jit_type *ret, +#define JIT_PARAMS cc, name, ret, +#define CREATE_FUNCTION(N) JIT_EXPAND(jit_function, create_function, \ + jit_type *, /* empty */, N) + + CREATE_FUNCTION(1); + CREATE_FUNCTION(2); + CREATE_FUNCTION(3); + CREATE_FUNCTION(4); + +#undef JIT_PARAM_ARGS +#undef JIT_PARAMS +#undef CREATE_FUNCTION + + jit_function create_identity (jit_type *type); + + llvm::Value *do_insert_error_check (llvm::IRBuilderD& bld); + + void add_builtin (const std::string& name); + + void register_intrinsic (const std::string& name, size_t id, + jit_type *result, jit_type *arg0) + { + std::vector args (1, arg0); + register_intrinsic (name, id, result, args); + } + + void register_intrinsic (const std::string& name, size_t id, jit_type *result, + const std::vector& args); + + void register_generic (const std::string& name, jit_type *result, + jit_type *arg0) + { + std::vector args (1, arg0); + register_generic (name, result, args); + } + + void register_generic (const std::string& name, jit_type *result, + const std::vector& args); + + octave_builtin *find_builtin (const std::string& name); + + jit_function mirror_binary (const jit_function& fn); + + llvm::Function *wrap_complex (llvm::Function *wrap); + + static llvm::Value *pack_complex (llvm::IRBuilderD& bld, + llvm::Value *cplx); + + static llvm::Value *unpack_complex (llvm::IRBuilderD& bld, + llvm::Value *result); + + llvm::Value *complex_real (llvm::Value *cx); + + llvm::Value *complex_real (llvm::Value *cx, llvm::Value *real); + + llvm::Value *complex_imag (llvm::Value *cx); + + llvm::Value *complex_imag (llvm::Value *cx, llvm::Value *imag); + + llvm::Value *complex_new (llvm::Value *real, llvm::Value *imag); + + void create_int (size_t nbits); + + jit_type *intN (size_t nbits) const; + + static jit_typeinfo *instance; + + llvm::Module *module; + llvm::ExecutionEngine *engine; + int next_id; + + llvm::GlobalVariable *lerror_state; + + std::vector id_to_type; + jit_type *any; + jit_type *matrix; + jit_type *scalar; + jit_type *scalar_ptr; // a fake type for interfacing with C++ + jit_type *range; + jit_type *string; + jit_type *boolean; + jit_type *index; + jit_type *complex; + jit_type *unknown_function; + std::map ints; + std::map builtins; + + llvm::StructType *complex_ret; + + std::vector binary_ops; + jit_operation grab_fn; + jit_operation release_fn; + jit_operation print_fn; + jit_operation for_init_fn; + jit_operation for_check_fn; + jit_operation for_index_fn; + jit_operation logically_true_fn; + jit_operation make_range_fn; + jit_paren_subsref paren_subsref_fn; + jit_paren_subsasgn paren_subsasgn_fn; + jit_operation end_fn; + + // type id -> cast function TO that type + std::vector casts; + + // type id -> identity function + std::vector identities; + + llvm::IRBuilderD& builder; +}; + +#endif +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/jit-util.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/jit-util.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,44 @@ +/* + +Copyright (C) 2012 Max Brister + +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 +. + +*/ + +// defines required by llvm +#define __STDC_LIMIT_MACROS +#define __STDC_CONSTANT_MACROS + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_LLVM + +#include +#include + +std::ostream& +operator<< (std::ostream& os, const llvm::Value& v) +{ + llvm::raw_os_ostream llvm_out (os); + v.print (llvm_out); + return os; +} + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/jit-util.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/jit-util.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,203 @@ +/* + +Copyright (C) 2012 Max Brister + +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 +. + +*/ + +// Some utility classes and functions used throughout jit + +#if !defined (octave_jit_util_h) +#define octave_jit_util_h 1 + +#ifdef HAVE_LLVM + +#include + +// we don't want to include llvm headers here, as they require +// __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS be defined in the entire +// compilation unit +namespace llvm +{ + class Value; + class Module; + class FunctionPassManager; + class PassManager; + class ExecutionEngine; + class Function; + class BasicBlock; + class LLVMContext; + class Type; + class StructType; + class Twine; + class GlobalVariable; + class TerminatorInst; + class PHINode; + + class ConstantFolder; + + template + class IRBuilderDefaultInserter; + + template + class IRBuilder; + +typedef IRBuilder > +IRBuilderD; +} + +class octave_base_value; +class octave_builtin; +class octave_value; +class tree; +class tree_expression; + +// thrown when we should give up on JIT and interpret +class jit_fail_exception : public std::runtime_error +{ +public: + jit_fail_exception (void) : std::runtime_error ("unknown"), mknown (false) {} + jit_fail_exception (const std::string& reason) : std::runtime_error (reason), + mknown (true) + {} + + bool known (void) const { return mknown; } +private: + bool mknown; +}; + +// llvm doesn't provide this, and it's really useful for debugging +std::ostream& operator<< (std::ostream& os, const llvm::Value& v); + +template +class jit_internal_node; + +// jit_internal_list and jit_internal_node implement generic embedded doubly +// linked lists. List items extend from jit_internal_list, and can be placed +// in nodes of type jit_internal_node. We use CRTP twice. +template +class +jit_internal_list +{ + friend class jit_internal_node; +public: + jit_internal_list (void) : use_head (0), use_tail (0), muse_count (0) {} + + virtual ~jit_internal_list (void) + { + while (use_head) + use_head->stash_value (0); + } + + NODE_T *first_use (void) const { return use_head; } + + size_t use_count (void) const { return muse_count; } +private: + NODE_T *use_head; + NODE_T *use_tail; + size_t muse_count; +}; + +// a node for internal linked lists +template +class +jit_internal_node +{ +public: + typedef jit_internal_list jit_ilist; + + jit_internal_node (void) : mvalue (0), mnext (0), mprev (0) {} + + ~jit_internal_node (void) { remove (); } + + LIST_T *value (void) const { return mvalue; } + + void stash_value (LIST_T *avalue) + { + remove (); + + mvalue = avalue; + + if (mvalue) + { + jit_ilist *ilist = mvalue; + NODE_T *sthis = static_cast (this); + if (ilist->use_head) + { + ilist->use_tail->mnext = sthis; + mprev = ilist->use_tail; + } + else + ilist->use_head = sthis; + + ilist->use_tail = sthis; + ++ilist->muse_count; + } + } + + NODE_T *next (void) const { return mnext; } + + NODE_T *prev (void) const { return mprev; } +private: + void remove () + { + if (mvalue) + { + jit_ilist *ilist = mvalue; + if (mprev) + mprev->mnext = mnext; + else + // we are the use_head + ilist->use_head = mnext; + + if (mnext) + mnext->mprev = mprev; + else + // we are the use tail + ilist->use_tail = mprev; + + mnext = mprev = 0; + --ilist->muse_count; + mvalue = 0; + } + } + + LIST_T *mvalue; + NODE_T *mnext; + NODE_T *mprev; +}; + +// Use like: isa (value) +// basically just a short cut type typing dyanmic_cast. +template +bool isa (U *value) +{ + return dynamic_cast (value); +} + +#define JIT_ASSIGN_ARG(i) the_args[i] = arg ## i; +#define JIT_EXPAND(ret, fname, type, isconst, N) \ + ret fname (JIT_PARAM_ARGS OCT_MAKE_DECL_LIST (type, arg, N)) isconst \ + { \ + std::vector the_args (N); \ + OCT_ITERATE_MACRO (JIT_ASSIGN_ARG, N); \ + return fname (JIT_PARAMS the_args); \ + } + +#endif +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/ls-ascii-helper.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/ls-ascii-helper.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,175 @@ +/* + +Copyright (C) 2009-2012 Benjamin Lindner + +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 +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "ls-ascii-helper.h" + +#include +#include + +// Helper functions when reading from ascii files. + +// These function take care of CR/LF issues when files are opened in +// text-mode for reading. + +// Skip characters from stream IS until a newline is reached. +// Depending on KEEP_NEWLINE, either eat newline from stream or +// keep it unread. + +void +skip_until_newline (std::istream& is, bool keep_newline) +{ + if (! is) + return; + + while (is) + { + char c = is.peek (); + + if (c == '\n' || c == '\r') + { + // Reached newline. + if (! keep_newline) + { + // Eat the CR or LF character. + char d; + is.get (d); + + // Make sure that for binary-mode opened ascii files + // containing CRLF line endings we skip the LF after CR. + if (c == '\r' && is.peek () == '\n') + { + // Yes, LF following CR, eat it. + is.get (d); + } + } + + // Newline was found, and read from stream if + // keep_newline == true, so exit loop. + break; + } + else + { + // No newline charater peeked, so read it and proceed to next + // character. + char d; + is.get (d); + } + } +} + + +// If stream IS currently points to a newline (a leftover from a +// previous read) then eat newline(s) until a non-newline character is +// found. + +void +skip_preceeding_newline (std::istream& is) +{ + if (! is) + return; + + // Check whether IS currently points to newline character. + char c = is.peek (); + + if (c == '\n' || c == '\r') + { + // Yes, at newline. + do + { + // Eat the CR or LF character. + char d; + is.get (d); + + // Make sure that for binary-mode opened ascii files + // containing CRLF line endings we skip the LF after CR. + if (c == '\r' && is.peek () == '\n') + { + // Yes, LF following CR, eat it. + is.get (d); + } + + // Peek into next character. + c = is.peek (); + + // Loop while still a newline ahead. + } + while (c == '\n' || c == '\r'); + } +} + +// Read charaters from stream IS until a newline is reached. +// Depending on KEEP_NEWLINE, either eat newline from stream or keep +// it unread. Characters read are stored and returned as +// std::string. + +std::string +read_until_newline (std::istream& is, bool keep_newline) +{ + if (! is) + return std::string (); + + std::ostringstream buf; + + while (is) + { + char c = is.peek (); + + if (c == '\n' || c == '\r') + { + // Reached newline. + if (! keep_newline) + { + // Eat the CR or LF character. + char d; + is.get (d); + + // Make sure that for binary-mode opened ascii files + // containing CRLF line endings we skip the LF after + // CR. + + if (c == '\r' && is.peek () == '\n') + { + // Yes, LF following CR, eat it. + is.get (d); + } + } + + // Newline was found, and read from stream if + // keep_newline == true, so exit loop. + break; + } + else + { + // No newline charater peeked, so read it, store it, and + // proceed to next. + char d; + is.get (d); + buf << d; + } + } + + return buf.str (); +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/ls-ascii-helper.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/ls-ascii-helper.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,38 @@ +/* + +Copyright (C) 2009-2012 Benjamin Lindner + +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 (octave_ls_ascii_helper_h) +#define octave_ls_ascii_helper_h 1 + +#include +#include + +extern OCTINTERP_API void +skip_until_newline (std::istream& is, bool keep_newline = false); + +extern OCTINTERP_API void +skip_preceeding_newline (std::istream& is); + +extern OCTINTERP_API std::string +read_until_newline (std::istream& is, bool keep_newline = false); + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/ls-hdf5.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/ls-hdf5.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,921 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +// Author: Steven G. Johnson + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined (HAVE_HDF5) + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "byte-swap.h" +#include "data-conv.h" +#include "file-ops.h" +#include "glob-match.h" +#include "lo-mappers.h" +#include "mach-info.h" +#include "oct-env.h" +#include "oct-time.h" +#include "quit.h" +#include "str-vec.h" +#include "oct-locbuf.h" + +#include "Cell.h" +#include "defun.h" +#include "error.h" +#include "gripes.h" +#include "load-save.h" +#include "oct-obj.h" +#include "oct-map.h" +#include "ov-cell.h" +#include "pager.h" +#include "pt-exp.h" +#include "sysdep.h" +#include "unwind-prot.h" +#include "utils.h" +#include "variables.h" +#include "version.h" +#include "dMatrix.h" +#include "ov-lazy-idx.h" + +#include "ls-utils.h" +#include "ls-hdf5.h" + +static std::string +make_valid_identifier (const std::string& nm) +{ + std::string retval; + + size_t nm_len = nm.length (); + + if (nm_len > 0) + { + if (! isalpha (nm[0])) + retval += '_'; + + for (size_t i = 0; i < nm_len; i++) + { + char c = nm[i]; + retval += (isalnum (c) || c == '_') ? c : '_'; + } + } + + return retval; +} + +// Define this to 1 if/when HDF5 supports automatic conversion between +// integer and floating-point binary data: +#define HAVE_HDF5_INT2FLOAT_CONVERSIONS 0 + +// Given two compound types t1 and t2, determine whether they +// are compatible for reading/writing. This function only +// works for non-nested types composed of simple elements (ints, floats...), +// which is all we need it for + +bool +hdf5_types_compatible (hid_t t1, hid_t t2) +{ + int n; + if ((n = H5Tget_nmembers (t1)) != H5Tget_nmembers (t2)) + return false; + + for (int i = 0; i < n; ++i) + { + hid_t mt1 = H5Tget_member_type (t1, i); + hid_t mt2 = H5Tget_member_type (t2, i); + + if (H5Tget_class (mt1) != H5Tget_class (mt2)) + return false; + + H5Tclose (mt2); + H5Tclose (mt1); + } + + return true; +} + +// Return true if loc_id has the attribute named attr_name, and false +// otherwise. + +bool +hdf5_check_attr (hid_t loc_id, const char *attr_name) +{ + bool retval = false; + + // we have to pull some shenanigans here to make sure + // HDF5 doesn't print out all sorts of error messages if we + // call H5Aopen for a non-existing attribute + + H5E_auto_t err_func; + void *err_func_data; + + // turn off error reporting temporarily, but save the error + // reporting function: + +#if HAVE_HDF5_18 + H5Eget_auto (H5E_DEFAULT, &err_func, &err_func_data); + H5Eset_auto (H5E_DEFAULT, 0, 0); +#else + H5Eget_auto (&err_func, &err_func_data); + H5Eset_auto (0, 0); +#endif + + hid_t attr_id = H5Aopen_name (loc_id, attr_name); + + if (attr_id >= 0) + { + // successful + retval = true; + H5Aclose (attr_id); + } + + // restore error reporting: +#if HAVE_HDF5_18 + H5Eset_auto (H5E_DEFAULT, err_func, err_func_data); +#else + H5Eset_auto (err_func, err_func_data); +#endif + return retval; +} + +bool +hdf5_get_scalar_attr (hid_t loc_id, hid_t type_id, + const char *attr_name, void *buf) +{ + bool retval = false; + + // we have to pull some shenanigans here to make sure + // HDF5 doesn't print out all sorts of error messages if we + // call H5Aopen for a non-existing attribute + + H5E_auto_t err_func; + void *err_func_data; + + // turn off error reporting temporarily, but save the error + // reporting function: + +#if HAVE_HDF5_18 + H5Eget_auto (H5E_DEFAULT, &err_func, &err_func_data); + H5Eset_auto (H5E_DEFAULT, 0, 0); +#else + H5Eget_auto (&err_func, &err_func_data); + H5Eset_auto (0, 0); +#endif + + hid_t attr_id = H5Aopen_name (loc_id, attr_name); + + if (attr_id >= 0) + { + hid_t space_id = H5Aget_space (attr_id); + + hsize_t rank = H5Sget_simple_extent_ndims (space_id); + + if (rank == 0) + retval = H5Aread (attr_id, type_id, buf) >= 0; + H5Aclose (attr_id); + } + + // restore error reporting: +#if HAVE_HDF5_18 + H5Eset_auto (H5E_DEFAULT, err_func, err_func_data); +#else + H5Eset_auto (err_func, err_func_data); +#endif + return retval; +} + + + + +// The following subroutines creates an HDF5 representations of the way +// we will store Octave complex types (pairs of floating-point numbers). +// NUM_TYPE is the HDF5 numeric type to use for storage (e.g. +// H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary +// conversions are handled automatically by HDF5. + +hid_t +hdf5_make_complex_type (hid_t num_type) +{ + hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 2); + + H5Tinsert (type_id, "real", 0 * sizeof (double), num_type); + H5Tinsert (type_id, "imag", 1 * sizeof (double), num_type); + + return type_id; +} + +// This function is designed to be passed to H5Giterate, which calls it +// on each data item in an HDF5 file. For the item whose name is NAME in +// the group GROUP_ID, this function sets dv->tc to an Octave representation +// of that item. (dv must be a pointer to hdf5_callback_data.) (It also +// sets the other fields of dv). +// +// It returns 1 on success (in which case H5Giterate stops and returns), +// -1 on error, and 0 to tell H5Giterate to continue on to the next item +// (e.g. if NAME was a data type we don't recognize). + +herr_t +hdf5_read_next_data (hid_t group_id, const char *name, void *dv) +{ + hdf5_callback_data *d = static_cast (dv); + hid_t type_id = -1, type_class_id = -1, data_id = -1, subgroup_id = -1, + space_id = -1; + + H5G_stat_t info; + herr_t retval = 0; + bool ident_valid = valid_identifier (name); + + std::string vname = name; + + // Allow identifiers as all digits so we can load lists saved by + // earlier versions of Octave. + + if (! ident_valid ) + { + // fix the identifier, replacing invalid chars with underscores + vname = make_valid_identifier (vname); + + // check again (in case vname was null, empty, or some such thing): + ident_valid = valid_identifier (vname); + } + + H5Gget_objinfo (group_id, name, 1, &info); + + if (info.type == H5G_GROUP && ident_valid) + { +#if HAVE_HDF5_18 + subgroup_id = H5Gopen (group_id, name, H5P_DEFAULT); +#else + subgroup_id = H5Gopen (group_id, name); +#endif + + if (subgroup_id < 0) + { + retval = subgroup_id; + goto done; + } + + if (hdf5_check_attr (subgroup_id, "OCTAVE_NEW_FORMAT")) + { +#if HAVE_HDF5_18 + data_id = H5Dopen (subgroup_id, "type", H5P_DEFAULT); +#else + data_id = H5Dopen (subgroup_id, "type"); +#endif + + if (data_id < 0) + { + retval = data_id; + goto done; + } + + type_id = H5Dget_type (data_id); + + type_class_id = H5Tget_class (type_id); + + if (type_class_id != H5T_STRING) + goto done; + + space_id = H5Dget_space (data_id); + hsize_t rank = H5Sget_simple_extent_ndims (space_id); + + if (rank != 0) + goto done; + + int slen = H5Tget_size (type_id); + if (slen < 0) + goto done; + + OCTAVE_LOCAL_BUFFER (char, typ, slen); + + // create datatype for (null-terminated) string to read into: + hid_t st_id = H5Tcopy (H5T_C_S1); + H5Tset_size (st_id, slen); + + if (H5Dread (data_id, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, + typ) < 0) + goto done; + + H5Tclose (st_id); + H5Dclose (data_id); + + d->tc = octave_value_typeinfo::lookup_type (typ); + + retval = (d->tc.load_hdf5 (subgroup_id, "value") ? 1 : -1); + + // check for OCTAVE_GLOBAL attribute: + d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL"); + + H5Gclose (subgroup_id); + } + else + { + // an HDF5 group is treated as an octave structure by + // default (since that preserves name information), and an + // octave list otherwise. + + if (hdf5_check_attr (subgroup_id, "OCTAVE_LIST")) + d->tc = octave_value_typeinfo::lookup_type ("list"); + else + d->tc = octave_value_typeinfo::lookup_type ("struct"); + + // check for OCTAVE_GLOBAL attribute: + d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL"); + + H5Gclose (subgroup_id); + + retval = (d->tc.load_hdf5 (group_id, name) ? 1 : -1); + } + + } + else if (info.type == H5G_DATASET && ident_valid) + { + // For backwards compatiability. +#if HAVE_HDF5_18 + data_id = H5Dopen (group_id, name, H5P_DEFAULT); +#else + data_id = H5Dopen (group_id, name); +#endif + + if (data_id < 0) + { + retval = data_id; + goto done; + } + + type_id = H5Dget_type (data_id); + + type_class_id = H5Tget_class (type_id); + + if (type_class_id == H5T_FLOAT) + { + space_id = H5Dget_space (data_id); + + hsize_t rank = H5Sget_simple_extent_ndims (space_id); + + if (rank == 0) + d->tc = octave_value_typeinfo::lookup_type ("scalar"); + else + d->tc = octave_value_typeinfo::lookup_type ("matrix"); + + H5Sclose (space_id); + } + else if (type_class_id == H5T_INTEGER) + { + // What integer type do we really have.. + std::string int_typ; +#ifdef HAVE_H5T_GET_NATIVE_TYPE + // FIXME test this code and activated with an autoconf + // test!! It is also incorrect for 64-bit indexing!! + + switch (H5Tget_native_type (type_id, H5T_DIR_ASCEND)) + { + case H5T_NATIVE_CHAR: + int_typ = "int8 "; + break; + + case H5T_NATIVE_SHORT: + int_typ = "int16 "; + break; + + case H5T_NATIVE_INT: + case H5T_NATIVE_LONG: + int_typ = "int32 "; + break; + + case H5T_NATIVE_LLONG: + int_typ = "int64 "; + break; + + case H5T_NATIVE_UCHAR: + int_typ = "uint8 "; + break; + + case H5T_NATIVE_USHORT: + int_typ = "uint16 "; + break; + + case H5T_NATIVE_UINT: + case H5T_NATIVE_ULONG: + int_typ = "uint32 "; + break; + + case H5T_NATIVE_ULLONG: + int_typ = "uint64 "; + break; + } +#else + hid_t int_sign = H5Tget_sign (type_id); + + if (int_sign == H5T_SGN_ERROR) + warning ("load: can't read `%s' (unknown datatype)", name); + else + { + if (int_sign == H5T_SGN_NONE) + int_typ.append ("u"); + int_typ.append ("int"); + + int slen = H5Tget_size (type_id); + if (slen < 0) + warning ("load: can't read `%s' (unknown datatype)", name); + else + { + switch (slen) + { + case 1: + int_typ.append ("8 "); + break; + + case 2: + int_typ.append ("16 "); + break; + + case 4: + int_typ.append ("32 "); + break; + + case 8: + int_typ.append ("64 "); + break; + + default: + warning ("load: can't read `%s' (unknown datatype)", + name); + int_typ = ""; + break; + } + } + } +#endif + if (int_typ == "") + warning ("load: can't read `%s' (unknown datatype)", name); + else + { + // Matrix or scalar? + space_id = H5Dget_space (data_id); + + hsize_t rank = H5Sget_simple_extent_ndims (space_id); + + if (rank == 0) + int_typ.append ("scalar"); + else + int_typ.append ("matrix"); + + d->tc = octave_value_typeinfo::lookup_type (int_typ); + H5Sclose (space_id); + } + } + else if (type_class_id == H5T_STRING) + d->tc = octave_value_typeinfo::lookup_type ("string"); + else if (type_class_id == H5T_COMPOUND) + { + hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE); + + if (hdf5_types_compatible (type_id, complex_type)) + { + // read complex matrix or scalar variable + space_id = H5Dget_space (data_id); + hsize_t rank = H5Sget_simple_extent_ndims (space_id); + + if (rank == 0) + d->tc = octave_value_typeinfo::lookup_type ("complex scalar"); + else + d->tc = octave_value_typeinfo::lookup_type ("complex matrix"); + + H5Sclose (space_id); + } + else + // Assume that if its not complex its a range. If its not + // it'll be rejected later in the range code + d->tc = octave_value_typeinfo::lookup_type ("range"); + + H5Tclose (complex_type); + } + else + { + warning ("load: can't read `%s' (unknown datatype)", name); + retval = 0; // unknown datatype; skip + } + + // check for OCTAVE_GLOBAL attribute: + d->global = hdf5_check_attr (data_id, "OCTAVE_GLOBAL"); + + H5Tclose (type_id); + H5Dclose (data_id); + + retval = (d->tc.load_hdf5 (group_id, name) ? 1 : -1); + } + + if (!ident_valid) + { + // should we attempt to handle invalid identifiers by converting + // bad characters to '_', say? + warning ("load: skipping invalid identifier `%s' in hdf5 file", + name); + } + + done: + if (retval < 0) + error ("load: error while reading hdf5 item %s", name); + + if (retval > 0) + { + // get documentation string, if any: + int comment_length = H5Gget_comment (group_id, name, 0, 0); + + if (comment_length > 1) + { + OCTAVE_LOCAL_BUFFER (char, tdoc, comment_length); + H5Gget_comment (group_id, name, comment_length, tdoc); + d->doc = tdoc; + } + else if (vname != name) + { + // the name was changed; store the original name + // as the documentation string: + d->doc = name; + } + + // copy name (actually, vname): + d->name = vname; + } + + return retval; +} + +// Read the next Octave variable from the stream IS, which must really be +// an hdf5_ifstream. Return the variable value in tc, its doc string +// in doc, and whether it is global in global. The return value is +// the name of the variable, or NULL if none were found or there was +// and error. +std::string +read_hdf5_data (std::istream& is, const std::string& /* filename */, + bool& global, octave_value& tc, std::string& doc) +{ + std::string retval; + + doc.resize (0); + + hdf5_ifstream& hs = dynamic_cast (is); + hdf5_callback_data d; + + herr_t H5Giterate_retval = -1; + + hsize_t num_obj = 0; +#if HAVE_HDF5_18 + hid_t group_id = H5Gopen (hs.file_id, "/", H5P_DEFAULT); +#else + hid_t group_id = H5Gopen (hs.file_id, "/"); +#endif + H5Gget_num_objs (group_id, &num_obj); + H5Gclose (group_id); + if (hs.current_item < static_cast (num_obj)) + H5Giterate_retval = H5Giterate (hs.file_id, "/", &hs.current_item, + hdf5_read_next_data, &d); + + if (H5Giterate_retval > 0) + { + global = d.global; + tc = d.tc; + doc = d.doc; + } + else + { + // an error occurred (H5Giterate_retval < 0) or there are no + // more datasets print an error message if retval < 0? + // hdf5_read_next_data already printed one, probably. + } + + if (! d.name.empty ()) + retval = d.name; + + return retval; +} + +// Add an attribute named attr_name to loc_id (a simple scalar +// attribute with value 1). Return value is >= 0 on success. +herr_t +hdf5_add_attr (hid_t loc_id, const char *attr_name) +{ + herr_t retval = 0; + + hid_t as_id = H5Screate (H5S_SCALAR); + + if (as_id >= 0) + { +#if HAVE_HDF5_18 + hid_t a_id = H5Acreate (loc_id, attr_name, H5T_NATIVE_UCHAR, + as_id, H5P_DEFAULT, H5P_DEFAULT); +#else + hid_t a_id = H5Acreate (loc_id, attr_name, + H5T_NATIVE_UCHAR, as_id, H5P_DEFAULT); +#endif + if (a_id >= 0) + { + unsigned char attr_val = 1; + + retval = H5Awrite (a_id, H5T_NATIVE_UCHAR, &attr_val); + + H5Aclose (a_id); + } + else + retval = a_id; + + H5Sclose (as_id); + } + else + retval = as_id; + + return retval; +} + +herr_t +hdf5_add_scalar_attr (hid_t loc_id, hid_t type_id, + const char *attr_name, void *buf) +{ + herr_t retval = 0; + + hid_t as_id = H5Screate (H5S_SCALAR); + + if (as_id >= 0) + { +#if HAVE_HDF5_18 + hid_t a_id = H5Acreate (loc_id, attr_name, type_id, + as_id, H5P_DEFAULT, H5P_DEFAULT); +#else + hid_t a_id = H5Acreate (loc_id, attr_name, + type_id, as_id, H5P_DEFAULT); +#endif + if (a_id >= 0) + { + retval = H5Awrite (a_id, type_id, buf); + + H5Aclose (a_id); + } + else + retval = a_id; + + H5Sclose (as_id); + } + else + retval = as_id; + + return retval; +} + +// Save an empty matrix, if needed. Returns +// > 0 Saved empty matrix +// = 0 Not an empty matrix; did nothing +// < 0 Error condition +int +save_hdf5_empty (hid_t loc_id, const char *name, const dim_vector d) +{ + hsize_t sz = d.length (); + OCTAVE_LOCAL_BUFFER (octave_idx_type, dims, sz); + bool empty = false; + hid_t space_hid = -1, data_hid = -1; + int retval; + for (hsize_t i = 0; i < sz; i++) + { + dims[i] = d(i); + if (dims[i] < 1) + empty = true; + } + + if (!empty) + return 0; + + space_hid = H5Screate_simple (1, &sz, 0); + if (space_hid < 0) return space_hid; +#if HAVE_HDF5_18 + data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_IDX, space_hid, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); +#else + data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_IDX, space_hid, + H5P_DEFAULT); +#endif + if (data_hid < 0) + { + H5Sclose (space_hid); + return data_hid; + } + + retval = H5Dwrite (data_hid, H5T_NATIVE_IDX, H5S_ALL, H5S_ALL, + H5P_DEFAULT, dims) >= 0; + + H5Dclose (data_hid); + H5Sclose (space_hid); + + if (retval >= 0) + retval = hdf5_add_attr (loc_id, "OCTAVE_EMPTY_MATRIX"); + + return (retval == 0 ? 1 : retval); +} + +// Load an empty matrix, if needed. Returns +// > 0 loaded empty matrix, dimensions returned +// = 0 Not an empty matrix; did nothing +// < 0 Error condition +int +load_hdf5_empty (hid_t loc_id, const char *name, dim_vector &d) +{ + if (! hdf5_check_attr (loc_id, "OCTAVE_EMPTY_MATRIX")) + return 0; + + hsize_t hdims, maxdims; +#if HAVE_HDF5_18 + hid_t data_hid = H5Dopen (loc_id, name, H5P_DEFAULT); +#else + hid_t data_hid = H5Dopen (loc_id, name); +#endif + hid_t space_id = H5Dget_space (data_hid); + H5Sget_simple_extent_dims (space_id, &hdims, &maxdims); + int retval; + + OCTAVE_LOCAL_BUFFER (octave_idx_type, dims, hdims); + + retval = H5Dread (data_hid, H5T_NATIVE_IDX, H5S_ALL, H5S_ALL, + H5P_DEFAULT, dims); + if (retval >= 0) + { + d.resize (hdims); + for (hsize_t i = 0; i < hdims; i++) + d(i) = dims[i]; + } + + H5Sclose (space_id); + H5Dclose (data_hid); + + return (retval == 0 ? hdims : retval); +} + +// save_type_to_hdf5 is not currently used, since hdf5 doesn't yet support +// automatic float<->integer conversions: + +#if HAVE_HDF5_INT2FLOAT_CONVERSIONS + +// return the HDF5 type id corresponding to the Octave save_type + +hid_t +save_type_to_hdf5 (save_type st) +{ + switch (st) + { + case LS_U_CHAR: + return H5T_NATIVE_UCHAR; + + case LS_U_SHORT: + return H5T_NATIVE_USHORT; + + case LS_U_INT: + return H5T_NATIVE_UINT; + + case LS_CHAR: + return H5T_NATIVE_CHAR; + + case LS_SHORT: + return H5T_NATIVE_SHORT; + + case LS_INT: + return H5T_NATIVE_INT; + + case LS_FLOAT: + return H5T_NATIVE_FLOAT; + + case LS_DOUBLE: + default: + return H5T_NATIVE_DOUBLE; + } +} +#endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */ + +// Add the data from TC to the HDF5 location loc_id, which could +// be either a file or a group within a file. Return true if +// successful. This function calls itself recursively for lists +// (stored as HDF5 groups). + +bool +add_hdf5_data (hid_t loc_id, const octave_value& tc, + const std::string& name, const std::string& doc, + bool mark_as_global, bool save_as_floats) +{ + hsize_t dims[3]; + hid_t type_id = -1, space_id = -1, data_id = -1, data_type_id = -1; + bool retval = false; + octave_value val = tc; + // FIXME: diagonal & permutation matrices currently don't know how to save + // themselves, so we convert them first to normal matrices using A = A(:,:). + // This is a temporary hack. + if (val.is_diag_matrix () || val.is_perm_matrix () + || val.type_id () == octave_lazy_index::static_type_id ()) + val = val.full_value (); + + std::string t = val.type_name (); +#if HAVE_HDF5_18 + data_id = H5Gcreate (loc_id, name.c_str (), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); +#else + data_id = H5Gcreate (loc_id, name.c_str (), 0); +#endif + if (data_id < 0) + goto error_cleanup; + + // attach the type of the variable + type_id = H5Tcopy (H5T_C_S1); H5Tset_size (type_id, t.length () + 1); + if (type_id < 0) + goto error_cleanup; + + dims[0] = 0; + space_id = H5Screate_simple (0 , dims, 0); + if (space_id < 0) + goto error_cleanup; +#if HAVE_HDF5_18 + data_type_id = H5Dcreate (data_id, "type", type_id, space_id, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); +#else + data_type_id = H5Dcreate (data_id, "type", type_id, space_id, H5P_DEFAULT); +#endif + if (data_type_id < 0 || H5Dwrite (data_type_id, type_id, H5S_ALL, H5S_ALL, + H5P_DEFAULT, t.c_str ()) < 0) + goto error_cleanup; + + // Now call the real function to save the variable + retval = val.save_hdf5 (data_id, "value", save_as_floats); + + // attach doc string as comment: + if (retval && doc.length () > 0 + && H5Gset_comment (loc_id, name.c_str (), doc.c_str ()) < 0) + retval = false; + + // if it's global, add an attribute "OCTAVE_GLOBAL" with value 1 + if (retval && mark_as_global) + retval = hdf5_add_attr (data_id, "OCTAVE_GLOBAL") >= 0; + + // We are saving in the new variable format, so mark it + if (retval) + retval = hdf5_add_attr (data_id, "OCTAVE_NEW_FORMAT") >= 0; + + error_cleanup: + + if (data_type_id >= 0) + H5Dclose (data_type_id); + + if (type_id >= 0) + H5Tclose (type_id); + + if (space_id >= 0) + H5Sclose (space_id); + + if (data_id >= 0) + H5Gclose (data_id); + + if (! retval) + error ("save: error while writing `%s' to hdf5 file", name.c_str ()); + + return retval; +} + +// Write data from TC in HDF5 (binary) format to the stream OS, +// which must be an hdf5_ofstream, returning true on success. + +bool +save_hdf5_data (std::ostream& os, const octave_value& tc, + const std::string& name, const std::string& doc, + bool mark_as_global, bool save_as_floats) +{ + hdf5_ofstream& hs = dynamic_cast (os); + + return add_hdf5_data (hs.file_id, tc, name, doc, + mark_as_global, save_as_floats); +} + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/ls-hdf5.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/ls-hdf5.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,213 @@ +/* + +Copyright (C) 2003-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_ls_hdf5_h) +#define octave_ls_hdf5_h 1 + +#if defined (HAVE_HDF5) + +#include "oct-hdf5.h" + +// first, we need to define our own dummy stream subclass, since +// HDF5 needs to do its own file i/o + +// hdf5_fstreambase is used for both input and output streams, modeled +// on the fstreambase class in + +class hdf5_fstreambase : virtual public std::ios +{ +public: + + // HDF5 uses an "id" to refer to an open file + hid_t file_id; + + // keep track of current item index in the file + int current_item; + + hdf5_fstreambase () : file_id (-1), current_item () { } + + ~hdf5_fstreambase () { close (); } + + hdf5_fstreambase (const char *name, int mode, int /* prot */ = 0) + : file_id (-1), current_item (-1) + { + if (mode & std::ios::in) + file_id = H5Fopen (name, H5F_ACC_RDONLY, H5P_DEFAULT); + else if (mode & std::ios::out) + { + if (mode & std::ios::app && H5Fis_hdf5 (name) > 0) + file_id = H5Fopen (name, H5F_ACC_RDWR, H5P_DEFAULT); + else + file_id = H5Fcreate (name, H5F_ACC_TRUNC, H5P_DEFAULT, + H5P_DEFAULT); + } + if (file_id < 0) + std::ios::setstate (std::ios::badbit); + + current_item = 0; + } + + void close () + { + if (file_id >= 0) + { + if (H5Fclose (file_id) < 0) + std::ios::setstate (std::ios::badbit); + file_id = -1; + } + } + + void open (const char *name, int mode, int) + { + clear (); + + if (mode & std::ios::in) + file_id = H5Fopen (name, H5F_ACC_RDONLY, H5P_DEFAULT); + else if (mode & std::ios::out) + { + if (mode & std::ios::app && H5Fis_hdf5 (name) > 0) + file_id = H5Fopen (name, H5F_ACC_RDWR, H5P_DEFAULT); + else + file_id = H5Fcreate (name, H5F_ACC_TRUNC, H5P_DEFAULT, + H5P_DEFAULT); + } + if (file_id < 0) + std::ios::setstate (std::ios::badbit); + + current_item = 0; + } +}; + +// input and output streams, subclassing istream and ostream +// so that we can pass them for stream parameters in the functions below. + +class hdf5_ifstream : public hdf5_fstreambase, public std::istream +{ +public: + + hdf5_ifstream () : hdf5_fstreambase (), std::istream (0) { } + + hdf5_ifstream (const char *name, int mode = std::ios::in|std::ios::binary, + int prot = 0) + : hdf5_fstreambase (name, mode, prot), std::istream (0) { } + + void open (const char *name, int mode = std::ios::in|std::ios::binary, + int prot = 0) + { hdf5_fstreambase::open (name, mode, prot); } +}; + +class hdf5_ofstream : public hdf5_fstreambase, public std::ostream +{ +public: + + hdf5_ofstream () : hdf5_fstreambase (), std::ostream (0) { } + + hdf5_ofstream (const char *name, int mode = std::ios::out|std::ios::binary, + int prot = 0) + : hdf5_fstreambase (name, mode, prot), std::ostream (0) { } + + void open (const char *name, int mode = std::ios::out|std::ios::binary, + int prot = 0) + { hdf5_fstreambase::open (name, mode, prot); } +}; + +// Callback data structure for passing data to hdf5_read_next_data, below. + +struct +hdf5_callback_data +{ + hdf5_callback_data (void) + : name (), global (false), tc (), doc () { } + + // the following fields are set by hdf5_read_data on successful return: + + // the name of the variable + std::string name; + + // whether it is global + bool global; + + // the value of the variable, in Octave form + octave_value tc; + + // a documentation string (NULL if none) + std::string doc; +}; + +#if HAVE_HDF5_INT2FLOAT_CONVERSIONS +extern OCTINTERP_API hid_t +save_type_to_hdf5 (save_type st) +#endif + +extern OCTINTERP_API hid_t +hdf5_make_complex_type (hid_t num_type); + +extern OCTINTERP_API bool +hdf5_types_compatible (hid_t t1, hid_t t2); + +extern OCTINTERP_API herr_t +hdf5_read_next_data (hid_t group_id, const char *name, void *dv); + +extern OCTINTERP_API bool +add_hdf5_data (hid_t loc_id, const octave_value& tc, + const std::string& name, const std::string& doc, + bool mark_as_global, bool save_as_floats); + +extern OCTINTERP_API int +save_hdf5_empty (hid_t loc_id, const char *name, const dim_vector d); + +extern OCTINTERP_API int +load_hdf5_empty (hid_t loc_id, const char *name, dim_vector &d); + +extern OCTINTERP_API std::string +read_hdf5_data (std::istream& is, const std::string& filename, bool& global, + octave_value& tc, std::string& doc); + +extern OCTINTERP_API bool +save_hdf5_data (std::ostream& os, const octave_value& tc, + const std::string& name, const std::string& doc, + bool mark_as_global, bool save_as_floats); + +extern OCTINTERP_API bool +hdf5_check_attr (hid_t loc_id, const char *attr_name); + +extern OCTINTERP_API bool +hdf5_get_scalar_attr (hid_t loc_id, hid_t type_id, const char *attr_name, + void *buf); + +extern OCTINTERP_API herr_t +hdf5_add_attr (hid_t loc_id, const char *attr_name); + + +extern OCTINTERP_API herr_t +hdf5_add_scalar_attr (hid_t loc_id, hid_t type_id, + const char *attr_name, void *buf); + +#ifdef IDX_TYPE_LONG +#define H5T_NATIVE_IDX H5T_NATIVE_LONG +#else +#define H5T_NATIVE_IDX H5T_NATIVE_INT +#endif + +#endif + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/ls-mat-ascii.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/ls-mat-ascii.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,378 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "byte-swap.h" +#include "data-conv.h" +#include "file-ops.h" +#include "glob-match.h" +#include "lo-mappers.h" +#include "mach-info.h" +#include "oct-env.h" +#include "oct-time.h" +#include "quit.h" +#include "str-vec.h" + +#include "Cell.h" +#include "defun.h" +#include "error.h" +#include "gripes.h" +#include "lex.h" +#include "load-save.h" +#include "ls-ascii-helper.h" +#include "ls-mat-ascii.h" +#include "oct-obj.h" +#include "oct-map.h" +#include "ov-cell.h" +#include "pager.h" +#include "pt-exp.h" +#include "sysdep.h" +#include "unwind-prot.h" +#include "utils.h" +#include "variables.h" +#include "version.h" +#include "dMatrix.h" + +static std::string +get_mat_data_input_line (std::istream& is) +{ + std::string retval; + + bool have_data = false; + + do + { + retval = ""; + + char c; + while (is.get (c)) + { + if (c == '\n' || c == '\r') + { + is.putback (c); + skip_preceeding_newline (is); + break; + } + + if (c == '%' || c == '#') + { + skip_until_newline (is, false); + break; + } + + if (! is.eof ()) + { + if (! have_data && c != ' ' && c != '\t') + have_data = true; + + retval += c; + } + } + } + while (! (have_data || is.eof ())); + + return retval; +} + +static void +get_lines_and_columns (std::istream& is, const std::string& filename, octave_idx_type& nr, octave_idx_type& nc) +{ + std::streampos pos = is.tellg (); + + int file_line_number = 0; + + nr = 0; + nc = 0; + + while (is && ! error_state) + { + octave_quit (); + + std::string buf = get_mat_data_input_line (is); + + file_line_number++; + + size_t beg = buf.find_first_not_of (", \t"); + + // If we see a CR as the last character in the buffer, we had a + // CRLF pair as the line separator. Any other CR in the text + // will not be considered as whitespace. + + if (beg != std::string::npos && buf[beg] == '\r' && beg == buf.length () - 1) + { + // We had a blank line ending with a CRLF. Handle it the + // same as an empty line. + beg = std::string::npos; + } + + octave_idx_type tmp_nc = 0; + + while (beg != std::string::npos) + { + tmp_nc++; + + size_t end = buf.find_first_of (", \t", beg); + + if (end != std::string::npos) + { + beg = buf.find_first_not_of (", \t", end); + + if (beg == std::string::npos || (buf[beg] == '\r' && + beg == buf.length () - 1)) + { + // We had a line with trailing spaces and + // ending with a CRLF, so this should look like EOL, + // not a new colum. + break; + } + } + else + break; + } + + if (tmp_nc > 0) + { + if (nc == 0) + { + nc = tmp_nc; + nr++; + } + else if (nc == tmp_nc) + nr++; + else + error ("load: %s: inconsistent number of columns near line %d", + filename.c_str (), file_line_number); + } + } + + if (nr == 0 || nc == 0) + error ("load: file `%s' seems to be empty!", filename.c_str ()); + + is.clear (); + is.seekg (pos); +} + +// Extract a matrix from a file of numbers only. +// +// Comments are not allowed. The file should only have numeric values. +// +// Reads the file twice. Once to find the number of rows and columns, +// and once to extract the matrix. +// +// FILENAME is used for error messages. +// +// This format provides no way to tag the data as global. + +std::string +read_mat_ascii_data (std::istream& is, const std::string& filename, + octave_value& tc) +{ + std::string retval; + + std::string varname; + + size_t pos = filename.rfind ('/'); + + if (pos != std::string::npos) + varname = filename.substr (pos+1); + else + varname = filename; + + pos = varname.rfind ('.'); + + if (pos != std::string::npos) + varname = varname.substr (0, pos); + + size_t len = varname.length (); + for (size_t i = 0; i < len; i++) + { + char c = varname[i]; + if (! (isalnum (c) || c == '_')) + varname[i] = '_'; + } + + if (is_keyword (varname) || ! isalpha (varname[0])) + varname.insert (0, "X"); + + if (valid_identifier (varname)) + { + octave_idx_type nr = 0; + octave_idx_type nc = 0; + + int total_count = 0; + + get_lines_and_columns (is, filename, nr, nc); + + octave_quit (); + + if (! error_state && nr > 0 && nc > 0) + { + Matrix tmp (nr, nc); + + if (nr < 1 || nc < 1) + is.clear (std::ios::badbit); + else + { + double d; + for (octave_idx_type i = 0; i < nr; i++) + { + std::string buf = get_mat_data_input_line (is); + + std::istringstream tmp_stream (buf); + + for (octave_idx_type j = 0; j < nc; j++) + { + octave_quit (); + + d = octave_read_value (tmp_stream); + + if (tmp_stream || tmp_stream.eof ()) + { + tmp.elem (i, j) = d; + total_count++; + + // Skip whitespace and commas. + char c; + while (1) + { + tmp_stream >> c; + + if (! tmp_stream) + break; + + if (! (c == ' ' || c == '\t' || c == ',')) + { + tmp_stream.putback (c); + break; + } + } + + if (tmp_stream.eof ()) + break; + } + else + { + error ("load: failed to read matrix from file `%s'", + filename.c_str ()); + + return retval; + } + + } + } + } + + if (is || is.eof ()) + { + // FIXME -- not sure this is best, but it works. + + if (is.eof ()) + is.clear (); + + octave_idx_type expected = nr * nc; + + if (expected == total_count) + { + tc = tmp; + retval = varname; + } + else + error ("load: expected %d elements, found %d", + expected, total_count); + } + else + error ("load: failed to read matrix from file `%s'", + filename.c_str ()); + } + else + error ("load: unable to extract matrix size from file `%s'", + filename.c_str ()); + } + else + error ("load: unable to convert filename `%s' to valid identifier", + filename.c_str ()); + + return retval; +} + +bool +save_mat_ascii_data (std::ostream& os, const octave_value& val, + int precision, bool tabs) +{ + bool success = true; + + if (val.is_complex_type ()) + warning ("save: omitting imaginary part for ASCII file"); + + Matrix m = val.matrix_value (true); + + if (error_state) + { + success = false; + + error_state = 0; + } + else + { + long old_precision = os.precision (); + + os.precision (precision); + + std::ios::fmtflags oflags + = os.flags (static_cast (std::ios::scientific)); + + if (tabs) + { + for (octave_idx_type i = 0; i < m.rows (); i++) + { + for (octave_idx_type j = 0; j < m.cols (); j++) + { + // Omit leading tabs. + if (j != 0) os << '\t'; + octave_write_double (os, m (i, j)); + } + os << "\n"; + } + } + else + os << m; + + os.flags (oflags); + + os.precision (old_precision); + } + + return (os && success); +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/ls-mat-ascii.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/ls-mat-ascii.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,34 @@ +/* + +Copyright (C) 2003-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_ls_mat_ascii_h) +#define octave_ls_mat_ascii_h 1 + +extern std::string +read_mat_ascii_data (std::istream& is, const std::string& filename, + octave_value& tc); + +extern bool +save_mat_ascii_data (std::ostream& os, const octave_value& val_arg, + int precision, bool tabs = false); + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/ls-mat4.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/ls-mat4.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,609 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "byte-swap.h" +#include "data-conv.h" +#include "file-ops.h" +#include "glob-match.h" +#include "lo-mappers.h" +#include "mach-info.h" +#include "oct-env.h" +#include "oct-time.h" +#include "quit.h" +#include "str-vec.h" +#include "oct-locbuf.h" + +#include "Cell.h" +#include "defun.h" +#include "error.h" +#include "gripes.h" +#include "load-save.h" +#include "oct-obj.h" +#include "oct-map.h" +#include "ov-cell.h" +#include "pager.h" +#include "pt-exp.h" +#include "sysdep.h" +#include "unwind-prot.h" +#include "utils.h" +#include "variables.h" +#include "version.h" +#include "dMatrix.h" +#include "dSparse.h" + +#include "ls-mat4.h" + +// Read LEN elements of data from IS in the format specified by +// PRECISION, placing the result in DATA. If SWAP is TRUE, swap +// the bytes of each element before copying to DATA. FLT_FMT +// specifies the format of the data if we are reading floating point +// numbers. + +static void +read_mat_binary_data (std::istream& is, double *data, int precision, + int len, bool swap, + oct_mach_info::float_format flt_fmt) +{ + switch (precision) + { + case 0: + read_doubles (is, data, LS_DOUBLE, len, swap, flt_fmt); + break; + + case 1: + read_doubles (is, data, LS_FLOAT, len, swap, flt_fmt); + break; + + case 2: + read_doubles (is, data, LS_INT, len, swap, flt_fmt); + break; + + case 3: + read_doubles (is, data, LS_SHORT, len, swap, flt_fmt); + break; + + case 4: + read_doubles (is, data, LS_U_SHORT, len, swap, flt_fmt); + break; + + case 5: + read_doubles (is, data, LS_U_CHAR, len, swap, flt_fmt); + break; + + default: + break; + } +} + +int +read_mat_file_header (std::istream& is, bool& swap, int32_t& mopt, + int32_t& nr, int32_t& nc, + int32_t& imag, int32_t& len, + int quiet) +{ + swap = false; + + // We expect to fail here, at the beginning of a record, so not + // being able to read another mopt value should not result in an + // error. + + is.read (reinterpret_cast (&mopt), 4); + if (! is) + return 1; + + if (! is.read (reinterpret_cast (&nr), 4)) + goto data_read_error; + + if (! is.read (reinterpret_cast (&nc), 4)) + goto data_read_error; + + if (! is.read (reinterpret_cast (&imag), 4)) + goto data_read_error; + + if (! is.read (reinterpret_cast (&len), 4)) + goto data_read_error; + +// If mopt is nonzero and the byte order is swapped, mopt will be +// bigger than we expect, so we swap bytes. +// +// If mopt is zero, it means the file was written on a little endian +// machine, and we only need to swap if we are running on a big endian +// machine. +// +// Gag me. + + if (oct_mach_info::words_big_endian () && mopt == 0) + swap = true; + + // mopt is signed, therefore byte swap may result in negative value. + + if (mopt > 9999 || mopt < 0) + swap = true; + + if (swap) + { + swap_bytes<4> (&mopt); + swap_bytes<4> (&nr); + swap_bytes<4> (&nc); + swap_bytes<4> (&imag); + swap_bytes<4> (&len); + } + + if (mopt > 9999 || mopt < 0 || imag > 1 || imag < 0) + { + if (! quiet) + error ("load: can't read binary file"); + return -1; + } + + return 0; + + data_read_error: + return -1; +} + +// We don't just use a cast here, because we need to be able to detect +// possible errors. + +oct_mach_info::float_format +mopt_digit_to_float_format (int mach) +{ + oct_mach_info::float_format flt_fmt = oct_mach_info::flt_fmt_unknown; + + switch (mach) + { + case 0: + flt_fmt = oct_mach_info::flt_fmt_ieee_little_endian; + break; + + case 1: + flt_fmt = oct_mach_info::flt_fmt_ieee_big_endian; + break; + + case 2: + flt_fmt = oct_mach_info::flt_fmt_vax_d; + break; + + case 3: + flt_fmt = oct_mach_info::flt_fmt_vax_g; + break; + + case 4: + flt_fmt = oct_mach_info::flt_fmt_cray; + break; + + default: + flt_fmt = oct_mach_info::flt_fmt_unknown; + break; + } + + return flt_fmt; +} + +int +float_format_to_mopt_digit (oct_mach_info::float_format flt_fmt) +{ + int retval = -1; + + switch (flt_fmt) + { + case oct_mach_info::flt_fmt_ieee_little_endian: + retval = 0; + break; + + case oct_mach_info::flt_fmt_ieee_big_endian: + retval = 1; + break; + + case oct_mach_info::flt_fmt_vax_d: + retval = 2; + break; + + case oct_mach_info::flt_fmt_vax_g: + retval = 3; + break; + + case oct_mach_info::flt_fmt_cray: + retval = 4; + break; + + default: + break; + } + + return retval; +} + +// Extract one value (scalar, matrix, string, etc.) from stream IS and +// place it in TC, returning the name of the variable. +// +// The data is expected to be in Matlab version 4 .mat format, though +// not all the features of that format are supported. +// +// FILENAME is used for error messages. +// +// This format provides no way to tag the data as global. + +std::string +read_mat_binary_data (std::istream& is, const std::string& filename, + octave_value& tc) +{ + std::string retval; + + // These are initialized here instead of closer to where they are + // first used to avoid errors from gcc about goto crossing + // initialization of variable. + + Matrix re; + oct_mach_info::float_format flt_fmt = oct_mach_info::flt_fmt_unknown; + bool swap = false; + int type = 0; + int prec = 0; + int order = 0; + int mach = 0; + int dlen = 0; + + int32_t mopt, nr, nc, imag, len; + + int err = read_mat_file_header (is, swap, mopt, nr, nc, imag, len); + if (err) + { + if (err < 0) + goto data_read_error; + else + return retval; + } + + type = mopt % 10; // Full, sparse, etc. + mopt /= 10; // Eliminate first digit. + prec = mopt % 10; // double, float, int, etc. + mopt /= 10; // Eliminate second digit. + order = mopt % 10; // Row or column major ordering. + mopt /= 10; // Eliminate third digit. + mach = mopt % 10; // IEEE, VAX, etc. + + flt_fmt = mopt_digit_to_float_format (mach); + + if (flt_fmt == oct_mach_info::flt_fmt_unknown) + { + error ("load: unrecognized binary format!"); + return retval; + } + + if (imag && type == 1) + { + error ("load: encountered complex matrix with string flag set!"); + return retval; + } + + // LEN includes the terminating character, and the file is also + // supposed to include it, but apparently not all files do. Either + // way, I think this should work. + + { + OCTAVE_LOCAL_BUFFER (char, name, len+1); + name[len] = '\0'; + if (! is.read (name, len)) + goto data_read_error; + retval = name; + + dlen = nr * nc; + if (dlen < 0) + goto data_read_error; + + if (order) + { + octave_idx_type tmp = nr; + nr = nc; + nc = tmp; + } + + if (type == 2) + { + if (nc == 4) + { + octave_idx_type nr_new, nc_new; + Array data (dim_vector (1, nr - 1)); + Array c (dim_vector (1, nr - 1)); + Array r (dim_vector (1, nr - 1)); + OCTAVE_LOCAL_BUFFER (double, dtmp, nr); + OCTAVE_LOCAL_BUFFER (double, ctmp, nr); + + read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt); + for (octave_idx_type i = 0; i < nr - 1; i++) + r.xelem (i) = dtmp[i] - 1; + nr_new = dtmp[nr - 1]; + read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt); + for (octave_idx_type i = 0; i < nr - 1; i++) + c.xelem (i) = dtmp[i] - 1; + nc_new = dtmp[nr - 1]; + read_mat_binary_data (is, dtmp, prec, nr - 1, swap, flt_fmt); + read_mat_binary_data (is, ctmp, prec, 1, swap, flt_fmt); + read_mat_binary_data (is, ctmp, prec, nr - 1, swap, flt_fmt); + + for (octave_idx_type i = 0; i < nr - 1; i++) + data.xelem (i) = Complex (dtmp[i], ctmp[i]); + read_mat_binary_data (is, ctmp, prec, 1, swap, flt_fmt); + + SparseComplexMatrix smc = SparseComplexMatrix (data, r, c, + nr_new, nc_new); + + tc = order ? smc.transpose () : smc; + } + else + { + octave_idx_type nr_new, nc_new; + Array data (dim_vector (1, nr - 1)); + Array c (dim_vector (1, nr - 1)); + Array r (dim_vector (1, nr - 1)); + OCTAVE_LOCAL_BUFFER (double, dtmp, nr); + + read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt); + for (octave_idx_type i = 0; i < nr - 1; i++) + r.xelem (i) = dtmp[i] - 1; + nr_new = dtmp[nr - 1]; + read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt); + for (octave_idx_type i = 0; i < nr - 1; i++) + c.xelem (i) = dtmp[i] - 1; + nc_new = dtmp[nr - 1]; + read_mat_binary_data (is, data.fortran_vec (), prec, nr - 1, swap, flt_fmt); + read_mat_binary_data (is, dtmp, prec, 1, swap, flt_fmt); + + SparseMatrix sm = SparseMatrix (data, r, c, nr_new, nc_new); + + tc = order ? sm.transpose () : sm; + } + } + else + { + re.resize (nr, nc); + + read_mat_binary_data (is, re.fortran_vec (), prec, dlen, swap, flt_fmt); + + if (! is || error_state) + { + error ("load: reading matrix data for `%s'", name); + goto data_read_error; + } + + if (imag) + { + Matrix im (nr, nc); + + read_mat_binary_data (is, im.fortran_vec (), prec, dlen, swap, + flt_fmt); + + if (! is || error_state) + { + error ("load: reading imaginary matrix data for `%s'", name); + goto data_read_error; + } + + ComplexMatrix ctmp (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + ctmp (i, j) = Complex (re (i, j), im (i, j)); + + tc = order ? ctmp.transpose () : ctmp; + } + else + tc = order ? re.transpose () : re; + + if (type == 1) + tc = tc.convert_to_str (false, true, '\''); + } + + return retval; + } + + data_read_error: + error ("load: trouble reading binary file `%s'", filename.c_str ()); + return retval; +} + +// Save the data from TC along with the corresponding NAME on stream OS +// in the MatLab version 4 binary format. + +bool +save_mat_binary_data (std::ostream& os, const octave_value& tc, + const std::string& name) +{ + int32_t mopt = 0; + + mopt += tc.is_sparse_type () ? 2 : tc.is_string () ? 1 : 0; + + oct_mach_info::float_format flt_fmt = + oct_mach_info::native_float_format ();; + + mopt += 1000 * float_format_to_mopt_digit (flt_fmt); + + os.write (reinterpret_cast (&mopt), 4); + + octave_idx_type len; + int32_t nr = tc.rows (); + + int32_t nc = tc.columns (); + + if (tc.is_sparse_type ()) + { + len = tc.nnz (); + uint32_t nnz = len + 1; + os.write (reinterpret_cast (&nnz), 4); + + uint32_t iscmplx = tc.is_complex_type () ? 4 : 3; + os.write (reinterpret_cast (&iscmplx), 4); + + uint32_t tmp = 0; + os.write (reinterpret_cast (&tmp), 4); + } + else + { + os.write (reinterpret_cast (&nr), 4); + os.write (reinterpret_cast (&nc), 4); + + int32_t imag = tc.is_complex_type () ? 1 : 0; + os.write (reinterpret_cast (&imag), 4); + + len = nr * nc; + } + + + // LEN includes the terminating character, and the file is also + // supposed to include it. + + int32_t name_len = name.length () + 1; + + os.write (reinterpret_cast (&name_len), 4); + os << name << '\0'; + + if (tc.is_string ()) + { + unwind_protect frame; + + charMatrix chm = tc.char_matrix_value (); + + octave_idx_type nrow = chm.rows (); + octave_idx_type ncol = chm.cols (); + + OCTAVE_LOCAL_BUFFER (double, buf, ncol*nrow); + + for (octave_idx_type i = 0; i < nrow; i++) + { + std::string tstr = chm.row_as_string (i); + const char *s = tstr.data (); + + for (octave_idx_type j = 0; j < ncol; j++) + buf[j*nrow+i] = static_cast (*s++ & 0x00FF); + } + os.write (reinterpret_cast (buf), nrow*ncol*sizeof (double)); + } + else if (tc.is_range ()) + { + Range r = tc.range_value (); + double base = r.base (); + double inc = r.inc (); + octave_idx_type nel = r.nelem (); + for (octave_idx_type i = 0; i < nel; i++) + { + double x = base + i * inc; + os.write (reinterpret_cast (&x), 8); + } + } + else if (tc.is_real_scalar ()) + { + double tmp = tc.double_value (); + os.write (reinterpret_cast (&tmp), 8); + } + else if (tc.is_sparse_type ()) + { + double ds; + OCTAVE_LOCAL_BUFFER (double, dtmp, len); + if (tc.is_complex_matrix ()) + { + SparseComplexMatrix m = tc.sparse_complex_matrix_value (); + + for (octave_idx_type i = 0; i < len; i++) + dtmp[i] = m.ridx (i) + 1; + os.write (reinterpret_cast (dtmp), 8 * len); + ds = nr; + os.write (reinterpret_cast (&ds), 8); + + octave_idx_type ii = 0; + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) + dtmp[ii++] = j + 1; + os.write (reinterpret_cast (dtmp), 8 * len); + ds = nc; + os.write (reinterpret_cast (&ds), 8); + + for (octave_idx_type i = 0; i < len; i++) + dtmp[i] = std::real (m.data (i)); + os.write (reinterpret_cast (dtmp), 8 * len); + ds = 0.; + os.write (reinterpret_cast (&ds), 8); + + for (octave_idx_type i = 0; i < len; i++) + dtmp[i] = std::imag (m.data (i)); + os.write (reinterpret_cast (dtmp), 8 * len); + os.write (reinterpret_cast (&ds), 8); + } + else + { + SparseMatrix m = tc.sparse_matrix_value (); + + for (octave_idx_type i = 0; i < len; i++) + dtmp[i] = m.ridx (i) + 1; + os.write (reinterpret_cast (dtmp), 8 * len); + ds = nr; + os.write (reinterpret_cast (&ds), 8); + + octave_idx_type ii = 0; + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) + dtmp[ii++] = j + 1; + os.write (reinterpret_cast (dtmp), 8 * len); + ds = nc; + os.write (reinterpret_cast (&ds), 8); + + os.write (reinterpret_cast (m.data ()), 8 * len); + ds = 0.; + os.write (reinterpret_cast (&ds), 8); + } + } + else if (tc.is_real_matrix ()) + { + Matrix m = tc.matrix_value (); + os.write (reinterpret_cast (m.data ()), 8 * len); + } + else if (tc.is_complex_scalar ()) + { + Complex tmp = tc.complex_value (); + os.write (reinterpret_cast (&tmp), 16); + } + else if (tc.is_complex_matrix ()) + { + ComplexMatrix m_cmplx = tc.complex_matrix_value (); + Matrix m = ::real (m_cmplx); + os.write (reinterpret_cast (m.data ()), 8 * len); + m = ::imag (m_cmplx); + os.write (reinterpret_cast (m.data ()), 8 * len); + } + else + gripe_wrong_type_arg ("save", tc, false); + + return os; +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/ls-mat4.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/ls-mat4.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,45 @@ +/* + +Copyright (C) 2003-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_ls_mat4_h) +#define octave_ls_mat4_h 1 + +extern oct_mach_info::float_format +mopt_digit_to_float_format (int mach); + +extern int +float_format_to_mopt_digit (oct_mach_info::float_format flt_fmt); + +extern int +read_mat_file_header (std::istream& is, bool& swap, int32_t& mopt, + int32_t& nr, int32_t& nc, int32_t& imag, + int32_t& len, int quiet = 0); + +extern std::string +read_mat_binary_data (std::istream& is, const std::string& filename, + octave_value& tc); + +extern bool +save_mat_binary_data (std::ostream& os, const octave_value& tc, + const std::string& name) ; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/ls-mat5.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/ls-mat5.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,2719 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +// Author: James R. Van Zandt + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "byte-swap.h" +#include "data-conv.h" +#include "file-ops.h" +#include "glob-match.h" +#include "lo-mappers.h" +#include "mach-info.h" +#include "oct-env.h" +#include "oct-time.h" +#include "quit.h" +#include "str-vec.h" +#include "file-stat.h" +#include "oct-locbuf.h" + +#include "Cell.h" +#include "defun.h" +#include "error.h" +#include "gripes.h" +#include "load-save.h" +#include "load-path.h" +#include "oct-obj.h" +#include "oct-map.h" +#include "ov-cell.h" +#include "ov-class.h" +#include "ov-fcn-inline.h" +#include "pager.h" +#include "pt-exp.h" +#include "sysdep.h" +#include "toplev.h" +#include "unwind-prot.h" +#include "utils.h" +#include "variables.h" +#include "version.h" +#include "dMatrix.h" + +#include "ls-utils.h" +#include "ls-mat5.h" + +#include "parse.h" +#include "defaults.h" + +#ifdef HAVE_ZLIB +#include +#endif + +#define PAD(l) (((l) > 0 && (l) <= 4) ? 4 : (((l)+7)/8)*8) + + +// The subsystem data block +static octave_value subsys_ov; + +// FIXME -- the following enum values should be the same as the +// mxClassID values in mexproto.h, but it seems they have also changed +// over time. What is the correct way to handle this and maintain +// backward compatibility with old MAT files? For now, use +// "MAT_FILE_" instead of "mx" as the prefix for these names to avoid +// conflict with the mxClassID enum in mexproto.h. + +enum arrayclasstype + { + MAT_FILE_CELL_CLASS=1, // cell array + MAT_FILE_STRUCT_CLASS, // structure + MAT_FILE_OBJECT_CLASS, // object + MAT_FILE_CHAR_CLASS, // character array + MAT_FILE_SPARSE_CLASS, // sparse array + MAT_FILE_DOUBLE_CLASS, // double precision array + MAT_FILE_SINGLE_CLASS, // single precision floating point + MAT_FILE_INT8_CLASS, // 8 bit signed integer + MAT_FILE_UINT8_CLASS, // 8 bit unsigned integer + MAT_FILE_INT16_CLASS, // 16 bit signed integer + MAT_FILE_UINT16_CLASS, // 16 bit unsigned integer + MAT_FILE_INT32_CLASS, // 32 bit signed integer + MAT_FILE_UINT32_CLASS, // 32 bit unsigned integer + MAT_FILE_INT64_CLASS, // 64 bit signed integer + MAT_FILE_UINT64_CLASS, // 64 bit unsigned integer + MAT_FILE_FUNCTION_CLASS, // Function handle + MAT_FILE_WORKSPACE_CLASS // Workspace (undocumented) + }; + +// Read COUNT elements of data from IS in the format specified by TYPE, +// placing the result in DATA. If SWAP is TRUE, swap the bytes of +// each element before copying to DATA. FLT_FMT specifies the format +// of the data if we are reading floating point numbers. + +static void +read_mat5_binary_data (std::istream& is, double *data, + octave_idx_type count, bool swap, mat5_data_type type, + oct_mach_info::float_format flt_fmt) +{ + + switch (type) + { + case miINT8: + read_doubles (is, data, LS_CHAR, count, swap, flt_fmt); + break; + + case miUTF8: + case miUINT8: + read_doubles (is, data, LS_U_CHAR, count, swap, flt_fmt); + break; + + case miINT16: + read_doubles (is, data, LS_SHORT, count, swap, flt_fmt); + break; + + case miUTF16: + case miUINT16: + read_doubles (is, data, LS_U_SHORT, count, swap, flt_fmt); + break; + + case miINT32: + read_doubles (is, data, LS_INT, count, swap, flt_fmt); + break; + + case miUTF32: + case miUINT32: + read_doubles (is, data, LS_U_INT, count, swap, flt_fmt); + break; + + case miSINGLE: + read_doubles (is, data, LS_FLOAT, count, swap, flt_fmt); + break; + + case miRESERVE1: + break; + + case miDOUBLE: + read_doubles (is, data, LS_DOUBLE, count, swap, flt_fmt); + break; + + case miRESERVE2: + case miRESERVE3: + break; + + // FIXME -- how are the 64-bit cases supposed to work here? + case miINT64: + read_doubles (is, data, LS_LONG, count, swap, flt_fmt); + break; + + case miUINT64: + read_doubles (is, data, LS_U_LONG, count, swap, flt_fmt); + break; + + case miMATRIX: + default: + break; + } +} + +static void +read_mat5_binary_data (std::istream& is, float *data, + octave_idx_type count, bool swap, mat5_data_type type, + oct_mach_info::float_format flt_fmt) +{ + + switch (type) + { + case miINT8: + read_floats (is, data, LS_CHAR, count, swap, flt_fmt); + break; + + case miUTF8: + case miUINT8: + read_floats (is, data, LS_U_CHAR, count, swap, flt_fmt); + break; + + case miINT16: + read_floats (is, data, LS_SHORT, count, swap, flt_fmt); + break; + + case miUTF16: + case miUINT16: + read_floats (is, data, LS_U_SHORT, count, swap, flt_fmt); + break; + + case miINT32: + read_floats (is, data, LS_INT, count, swap, flt_fmt); + break; + + case miUTF32: + case miUINT32: + read_floats (is, data, LS_U_INT, count, swap, flt_fmt); + break; + + case miSINGLE: + read_floats (is, data, LS_FLOAT, count, swap, flt_fmt); + break; + + case miRESERVE1: + break; + + case miDOUBLE: + read_floats (is, data, LS_DOUBLE, count, swap, flt_fmt); + break; + + case miRESERVE2: + case miRESERVE3: + break; + + // FIXME -- how are the 64-bit cases supposed to work here? + case miINT64: + read_floats (is, data, LS_LONG, count, swap, flt_fmt); + break; + + case miUINT64: + read_floats (is, data, LS_U_LONG, count, swap, flt_fmt); + break; + + case miMATRIX: + default: + break; + } +} + +template +void +read_mat5_integer_data (std::istream& is, T *m, octave_idx_type count, + bool swap, mat5_data_type type) +{ + +#define READ_INTEGER_DATA(TYPE, swap, data, size, len, stream) \ + do \ + { \ + if (len > 0) \ + { \ + OCTAVE_LOCAL_BUFFER (TYPE, ptr, len); \ + stream.read (reinterpret_cast (ptr), size * len); \ + if (swap) \ + swap_bytes< size > (ptr, len); \ + for (octave_idx_type i = 0; i < len; i++) \ + data[i] = ptr[i]; \ + } \ + } \ + while (0) + + switch (type) + { + case miINT8: + READ_INTEGER_DATA (int8_t, swap, m, 1, count, is); + break; + + case miUINT8: + READ_INTEGER_DATA (uint8_t, swap, m, 1, count, is); + break; + + case miINT16: + READ_INTEGER_DATA (int16_t, swap, m, 2, count, is); + break; + + case miUINT16: + READ_INTEGER_DATA (uint16_t, swap, m, 2, count, is); + break; + + case miINT32: + READ_INTEGER_DATA (int32_t, swap, m, 4, count, is); + break; + + case miUINT32: + READ_INTEGER_DATA (uint32_t, swap, m, 4, count, is); + break; + + case miSINGLE: + case miRESERVE1: + case miDOUBLE: + case miRESERVE2: + case miRESERVE3: + break; + + case miINT64: + READ_INTEGER_DATA (int64_t, swap, m, 8, count, is); + break; + + case miUINT64: + READ_INTEGER_DATA (uint64_t, swap, m, 8, count, is); + break; + + case miMATRIX: + default: + break; + } + +#undef READ_INTEGER_DATA + +} + +template void +read_mat5_integer_data (std::istream& is, octave_int8 *m, + octave_idx_type count, bool swap, + mat5_data_type type); + +template void +read_mat5_integer_data (std::istream& is, octave_int16 *m, + octave_idx_type count, bool swap, + mat5_data_type type); + +template void +read_mat5_integer_data (std::istream& is, octave_int32 *m, + octave_idx_type count, bool swap, + mat5_data_type type); + +template void +read_mat5_integer_data (std::istream& is, octave_int64 *m, + octave_idx_type count, bool swap, + mat5_data_type type); + +template void +read_mat5_integer_data (std::istream& is, octave_uint8 *m, + octave_idx_type count, bool swap, + mat5_data_type type); + +template void +read_mat5_integer_data (std::istream& is, octave_uint16 *m, + octave_idx_type count, bool swap, + mat5_data_type type); + +template void +read_mat5_integer_data (std::istream& is, octave_uint32 *m, + octave_idx_type count, bool swap, + mat5_data_type type); + +template void +read_mat5_integer_data (std::istream& is, octave_uint64 *m, + octave_idx_type count, bool swap, + mat5_data_type type); + +template void +read_mat5_integer_data (std::istream& is, int *m, + octave_idx_type count, bool swap, + mat5_data_type type); + +#define OCTAVE_MAT5_INTEGER_READ(TYP) \ + { \ + TYP re (dims); \ + \ + std::streampos tmp_pos; \ + \ + if (read_mat5_tag (is, swap, type, len)) \ + { \ + error ("load: reading matrix data for `%s'", retval.c_str ()); \ + goto data_read_error; \ + } \ + \ + octave_idx_type n = re.numel (); \ + tmp_pos = is.tellg (); \ + read_mat5_integer_data (is, re.fortran_vec (), n, swap, \ + static_cast (type)); \ + \ + if (! is || error_state) \ + { \ + error ("load: reading matrix data for `%s'", retval.c_str ()); \ + goto data_read_error; \ + } \ + \ + is.seekg (tmp_pos + static_cast (PAD (len))); \ + \ + if (imag) \ + { \ + /* We don't handle imag integer types, convert to an array */ \ + NDArray im (dims); \ + \ + if (read_mat5_tag (is, swap, type, len)) \ + { \ + error ("load: reading matrix data for `%s'", \ + retval.c_str ()); \ + goto data_read_error; \ + } \ + \ + n = im.numel (); \ + read_mat5_binary_data (is, im.fortran_vec (), n, swap, \ + static_cast (type), flt_fmt); \ + \ + if (! is || error_state) \ + { \ + error ("load: reading imaginary matrix data for `%s'", \ + retval.c_str ()); \ + goto data_read_error; \ + } \ + \ + ComplexNDArray ctmp (dims); \ + \ + for (octave_idx_type i = 0; i < n; i++) \ + ctmp(i) = Complex (re(i).double_value (), im(i)); \ + \ + tc = ctmp; \ + } \ + else \ + tc = re; \ + } + +// Read one element tag from stream IS, +// place the type code in TYPE and the byte count in BYTES +// return nonzero on error +static int +read_mat5_tag (std::istream& is, bool swap, int32_t& type, int32_t& bytes) +{ + unsigned int upper; + int32_t temp; + + if (! is.read (reinterpret_cast (&temp), 4 )) + goto data_read_error; + + if (swap) + swap_bytes<4> (&temp); + + upper = (temp >> 16) & 0xffff; + type = temp & 0xffff; + + if (upper) + { + // "compressed" format + bytes = upper; + } + else + { + if (! is.read (reinterpret_cast (&temp), 4 )) + goto data_read_error; + if (swap) + swap_bytes<4> (&temp); + bytes = temp; + } + + return 0; + + data_read_error: + return 1; +} + +static void +read_int (std::istream& is, bool swap, int32_t& val) +{ + is.read (reinterpret_cast (&val), 4); + + if (swap) + swap_bytes<4> (&val); +} + +// Extract one data element (scalar, matrix, string, etc.) from stream +// IS and place it in TC, returning the name of the variable. +// +// The data is expected to be in Matlab's "Version 5" .mat format, +// though not all the features of that format are supported. +// +// FILENAME is used for error messages. + +std::string +read_mat5_binary_element (std::istream& is, const std::string& filename, + bool swap, bool& global, octave_value& tc) +{ + std::string retval; + + global = false; + + // NOTE: these are initialized here instead of closer to where they + // are first used to avoid errors from gcc about goto crossing + // initialization of variable. + + bool imag; + bool isclass = false; + bool logicalvar; + dim_vector dims; + enum arrayclasstype arrayclass; + int16_t number = *(reinterpret_cast("\x00\x01")); + octave_idx_type nzmax; + std::string classname; + + // MAT files always use IEEE floating point + oct_mach_info::float_format flt_fmt = oct_mach_info::flt_fmt_unknown; + if ((number == 1) ^ swap) + flt_fmt = oct_mach_info::flt_fmt_ieee_big_endian; + else + flt_fmt = oct_mach_info::flt_fmt_ieee_little_endian; + + // element type and length + int32_t type = 0; + int32_t element_length; + if (read_mat5_tag (is, swap, type, element_length)) + return retval; // EOF + +#ifdef HAVE_ZLIB + if (type == miCOMPRESSED) + { + // If C++ allowed us direct access to the file descriptor of an + // ifstream in a uniform way, the code below could be vastly + // simplified, and additional copies of the data in memory + // wouldn't be needed. + + OCTAVE_LOCAL_BUFFER (char, inbuf, element_length); + is.read (inbuf, element_length); + + // We uncompress the first 8 bytes of the header to get the buffer length + // This will fail with an error Z_MEM_ERROR + uLongf destLen = 8; + OCTAVE_LOCAL_BUFFER (unsigned int, tmp, 2); + if (uncompress (reinterpret_cast (tmp), &destLen, + reinterpret_cast (inbuf), element_length) + != Z_MEM_ERROR) + { + // Why should I have to initialize outbuf as I'll just overwrite!! + if (swap) + swap_bytes<4> (tmp, 2); + + destLen = tmp[1] + 8; + std::string outbuf (destLen, ' '); + + // FIXME -- find a way to avoid casting away const here! + + int err = uncompress (reinterpret_cast (const_cast (outbuf.c_str ())), + &destLen, reinterpret_cast (inbuf), + element_length); + + if (err != Z_OK) + { + std::string msg; + switch (err) + { + case Z_STREAM_END: + msg = "stream end"; + break; + + case Z_NEED_DICT: + msg = "need dict"; + break; + + case Z_ERRNO: + msg = "errno case"; + break; + + case Z_STREAM_ERROR: + msg = "stream error"; + break; + + case Z_DATA_ERROR: + msg = "data error"; + break; + + case Z_MEM_ERROR: + msg = "mem error"; + break; + + case Z_BUF_ERROR: + msg = "buf error"; + break; + + case Z_VERSION_ERROR: + msg = "version error"; + break; + } + + error ("load: error uncompressing data element (%s from zlib)", + msg.c_str ()); + } + else + { + std::istringstream gz_is (outbuf); + retval = read_mat5_binary_element (gz_is, filename, + swap, global, tc); + } + } + else + error ("load: error probing size of compressed data element"); + + return retval; + } +#endif + + std::streampos pos; + + if (type != miMATRIX) + { + pos = is.tellg (); + error ("load: invalid element type = %d", type); + goto early_read_error; + } + + if (element_length == 0) + { + tc = Matrix (); + return retval; + } + + pos = is.tellg (); + + // array flags subelement + int32_t len; + if (read_mat5_tag (is, swap, type, len) || type != miUINT32 || len != 8) + { + error ("load: invalid array flags subelement"); + goto early_read_error; + } + + int32_t flags; + read_int (is, swap, flags); + + imag = (flags & 0x0800) != 0; // has an imaginary part? + + global = (flags & 0x0400) != 0; // global variable? + + logicalvar = (flags & 0x0200) != 0; // boolean ? + + arrayclass = static_cast (flags & 0xff); + + int32_t tmp_nzmax; + read_int (is, swap, tmp_nzmax); // max number of non-zero in sparse + nzmax = tmp_nzmax; + + // dimensions array subelement + if (arrayclass != MAT_FILE_WORKSPACE_CLASS) + { + int32_t dim_len; + + if (read_mat5_tag (is, swap, type, dim_len) || type != miINT32) + { + error ("load: invalid dimensions array subelement"); + goto early_read_error; + } + + int ndims = dim_len / 4; + dims.resize (ndims); + for (int i = 0; i < ndims; i++) + { + int32_t n; + read_int (is, swap, n); + dims(i) = n; + } + + std::streampos tmp_pos = is.tellg (); + is.seekg (tmp_pos + static_cast (PAD (dim_len) - dim_len)); + } + else + { + // Why did mathworks decide to not have dims for a workspace!!! + dims.resize (2); + dims(0) = 1; + dims(1) = 1; + } + + if (read_mat5_tag (is, swap, type, len) || type != miINT8) + { + error ("load: invalid array name subelement"); + goto early_read_error; + } + + { + OCTAVE_LOCAL_BUFFER (char, name, len+1); + + // Structure field subelements have zero-length array name subelements. + + std::streampos tmp_pos = is.tellg (); + + if (len) + { + if (! is.read (name, len )) + goto data_read_error; + + is.seekg (tmp_pos + static_cast (PAD (len))); + } + + name[len] = '\0'; + retval = name; + } + + switch (arrayclass) + { + case MAT_FILE_CELL_CLASS: + { + Cell cell_array (dims); + + octave_idx_type n = cell_array.numel (); + + for (octave_idx_type i = 0; i < n; i++) + { + octave_value tc2; + + std::string nm + = read_mat5_binary_element (is, filename, swap, global, tc2); + + if (! is || error_state) + { + error ("load: reading cell data for `%s'", nm.c_str ()); + goto data_read_error; + } + + cell_array(i) = tc2; + } + + tc = cell_array; + } + break; + + case MAT_FILE_SPARSE_CLASS: + { + octave_idx_type nr = dims(0); + octave_idx_type nc = dims(1); + SparseMatrix sm; + SparseComplexMatrix scm; + octave_idx_type *ridx; + octave_idx_type *cidx; + double *data; + + // Setup return value + if (imag) + { + scm = SparseComplexMatrix (nr, nc, nzmax); + ridx = scm.ridx (); + cidx = scm.cidx (); + data = 0; + } + else + { + sm = SparseMatrix (nr, nc, nzmax); + ridx = sm.ridx (); + cidx = sm.cidx (); + data = sm.data (); + } + + // row indices + std::streampos tmp_pos; + + if (read_mat5_tag (is, swap, type, len)) + { + error ("load: reading sparse row data for `%s'", retval.c_str ()); + goto data_read_error; + } + + tmp_pos = is.tellg (); + + read_mat5_integer_data (is, ridx, nzmax, swap, + static_cast (type)); + + if (! is || error_state) + { + error ("load: reading sparse row data for `%s'", retval.c_str ()); + goto data_read_error; + } + + is.seekg (tmp_pos + static_cast (PAD (len))); + + // col indices + if (read_mat5_tag (is, swap, type, len)) + { + error ("load: reading sparse column data for `%s'", retval.c_str ()); + goto data_read_error; + } + + tmp_pos = is.tellg (); + + read_mat5_integer_data (is, cidx, nc + 1, swap, + static_cast (type)); + + if (! is || error_state) + { + error ("load: reading sparse column data for `%s'", retval.c_str ()); + goto data_read_error; + } + + is.seekg (tmp_pos + static_cast (PAD (len))); + + // real data subelement + if (read_mat5_tag (is, swap, type, len)) + { + error ("load: reading sparse matrix data for `%s'", retval.c_str ()); + goto data_read_error; + } + + octave_idx_type nnz = cidx[nc]; + NDArray re; + if (imag) + { + re = NDArray (dim_vector (nnz, 1)); + data = re.fortran_vec (); + } + + tmp_pos = is.tellg (); + read_mat5_binary_data (is, data, nnz, swap, + static_cast (type), flt_fmt); + + if (! is || error_state) + { + error ("load: reading sparse matrix data for `%s'", retval.c_str ()); + goto data_read_error; + } + + is.seekg (tmp_pos + static_cast (PAD (len))); + + // imaginary data subelement + if (imag) + { + NDArray im (dim_vector (static_cast (nnz), 1)); + + if (read_mat5_tag (is, swap, type, len)) + { + error ("load: reading sparse matrix data for `%s'", retval.c_str ()); + goto data_read_error; + } + + read_mat5_binary_data (is, im.fortran_vec (), nnz, swap, + static_cast (type), flt_fmt); + + if (! is || error_state) + { + error ("load: reading imaginary sparse matrix data for `%s'", + retval.c_str ()); + goto data_read_error; + } + + for (octave_idx_type i = 0; i < nnz; i++) + scm.xdata (i) = Complex (re (i), im (i)); + + tc = scm; + } + else + tc = sm; + } + break; + + case MAT_FILE_FUNCTION_CLASS: + { + octave_value tc2; + std::string nm + = read_mat5_binary_element (is, filename, swap, global, tc2); + + if (! is || error_state) + goto data_read_error; + + // Octave can handle both "/" and "\" as a directry seperator + // and so can ignore the seperator field of m0. I think the + // sentinel field is also save to ignore. + Octave_map m0 = tc2.map_value (); + Octave_map m1 = m0.contents ("function_handle")(0).map_value (); + std::string ftype = m1.contents ("type")(0).string_value (); + std::string fname = m1.contents ("function")(0).string_value (); + std::string fpath = m1.contents ("file")(0).string_value (); + + if (ftype == "simple" || ftype == "scopedfunction") + { + if (fpath.length () == 0) + // We have a builtin function + tc = make_fcn_handle (fname); + else + { + std::string mroot = + m0.contents ("matlabroot")(0).string_value (); + + if ((fpath.length () >= mroot.length ()) && + fpath.substr (0, mroot.length ()) == mroot && + OCTAVE_EXEC_PREFIX != mroot) + { + // If fpath starts with matlabroot, and matlabroot + // doesn't equal octave_config_info ("exec_prefix") + // then the function points to a version of Octave + // or Matlab other than the running version. In that + // case we replace with the same function in the + // running version of Octave? + + // First check if just replacing matlabroot is enough + std::string str = OCTAVE_EXEC_PREFIX + + fpath.substr (mroot.length ()); + file_stat fs (str); + + if (fs.exists ()) + { + size_t xpos + = str.find_last_of (file_ops::dir_sep_chars ()); + + std::string dir_name = str.substr (0, xpos); + + octave_function *fcn + = load_fcn_from_file (str, dir_name, "", fname); + + if (fcn) + { + octave_value tmp (fcn); + + tc = octave_value (new octave_fcn_handle (tmp, fname)); + } + } + else + { + // Next just search for it anywhere in the + // system path + string_vector names(3); + names(0) = fname + ".oct"; + names(1) = fname + ".mex"; + names(2) = fname + ".m"; + + dir_path p (load_path::system_path ()); + + str = octave_env::make_absolute (p.find_first_of (names)); + + size_t xpos + = str.find_last_of (file_ops::dir_sep_chars ()); + + std::string dir_name = str.substr (0, xpos); + + octave_function *fcn + = load_fcn_from_file (str, dir_name, "", fname); + + if (fcn) + { + octave_value tmp (fcn); + + tc = octave_value (new octave_fcn_handle (tmp, fname)); + } + else + { + warning ("load: can't find the file %s", + fpath.c_str ()); + goto skip_ahead; + } + } + } + else + { + size_t xpos + = fpath.find_last_of (file_ops::dir_sep_chars ()); + + std::string dir_name = fpath.substr (0, xpos); + + octave_function *fcn + = load_fcn_from_file (fpath, dir_name, "", fname); + + if (fcn) + { + octave_value tmp (fcn); + + tc = octave_value (new octave_fcn_handle (tmp, fname)); + } + else + { + warning ("load: can't find the file %s", + fpath.c_str ()); + goto skip_ahead; + } + } + } + } + else if (ftype == "nested") + { + warning ("load: can't load nested function"); + goto skip_ahead; + } + else if (ftype == "anonymous") + { + Octave_map m2 = m1.contents ("workspace")(0).map_value (); + uint32NDArray MCOS = m2.contents ("MCOS")(0).uint32_array_value (); + octave_idx_type off = static_cast(MCOS(4).double_value ()); + m2 = subsys_ov.map_value (); + m2 = m2.contents ("MCOS")(0).map_value (); + tc2 = m2.contents ("MCOS")(0).cell_value ()(1 + off).cell_value ()(1); + m2 = tc2.map_value (); + + unwind_protect_safe frame; + + // Set up temporary scope to use for evaluating the text + // that defines the anonymous function. + + symbol_table::scope_id local_scope = symbol_table::alloc_scope (); + frame.add_fcn (symbol_table::erase_scope, local_scope); + + symbol_table::set_scope (local_scope); + + octave_call_stack::push (local_scope, 0); + frame.add_fcn (octave_call_stack::pop); + + if (m2.nfields () > 0) + { + octave_value tmp; + + for (Octave_map::iterator p0 = m2.begin () ; + p0 != m2.end (); p0++) + { + std::string key = m2.key (p0); + octave_value val = m2.contents (p0)(0); + + symbol_table::varref (key, local_scope, 0) = val; + } + } + + int parse_status; + octave_value anon_fcn_handle = + eval_string (fname.substr (4), true, parse_status); + + if (parse_status == 0) + { + octave_fcn_handle *fh = + anon_fcn_handle.fcn_handle_value (); + + if (fh) + tc = new octave_fcn_handle (fh->fcn_val (), "@"); + else + { + error ("load: failed to load anonymous function handle"); + goto skip_ahead; + } + } + else + { + error ("load: failed to load anonymous function handle"); + goto skip_ahead; + } + + frame.run (); + } + else + { + error ("load: invalid function handle type"); + goto skip_ahead; + } + } + break; + + case MAT_FILE_WORKSPACE_CLASS: + { + Octave_map m (dim_vector (1, 1)); + int n_fields = 2; + string_vector field (n_fields); + + for (int i = 0; i < n_fields; i++) + { + int32_t fn_type; + int32_t fn_len; + if (read_mat5_tag (is, swap, fn_type, fn_len) || fn_type != miINT8) + { + error ("load: invalid field name subelement"); + goto data_read_error; + } + + OCTAVE_LOCAL_BUFFER (char, elname, fn_len + 1); + + std::streampos tmp_pos = is.tellg (); + + if (fn_len) + { + if (! is.read (elname, fn_len)) + goto data_read_error; + + is.seekg (tmp_pos + + static_cast (PAD (fn_len))); + } + + elname[fn_len] = '\0'; + + field(i) = elname; + } + + std::vector elt (n_fields); + + for (octave_idx_type i = 0; i < n_fields; i++) + elt[i] = Cell (dims); + + octave_idx_type n = dims.numel (); + + // fields subelements + for (octave_idx_type j = 0; j < n; j++) + { + for (octave_idx_type i = 0; i < n_fields; i++) + { + if (field(i) == "MCOS") + { + octave_value fieldtc; + read_mat5_binary_element (is, filename, swap, global, + fieldtc); + if (! is || error_state) + goto data_read_error; + + elt[i](j) = fieldtc; + } + else + elt[i](j) = octave_value (); + } + } + + for (octave_idx_type i = 0; i < n_fields; i++) + m.assign (field (i), elt[i]); + tc = m; + } + break; + + case MAT_FILE_OBJECT_CLASS: + { + isclass = true; + + if (read_mat5_tag (is, swap, type, len) || type != miINT8) + { + error ("load: invalid class name"); + goto skip_ahead; + } + + { + OCTAVE_LOCAL_BUFFER (char, name, len+1); + + std::streampos tmp_pos = is.tellg (); + + if (len) + { + if (! is.read (name, len )) + goto data_read_error; + + is.seekg (tmp_pos + static_cast (PAD (len))); + } + + name[len] = '\0'; + classname = name; + } + } + // Fall-through + case MAT_FILE_STRUCT_CLASS: + { + Octave_map m (dim_vector (1, 1)); + int32_t fn_type; + int32_t fn_len; + int32_t field_name_length; + + // field name length subelement -- actually the maximum length + // of a field name. The Matlab docs promise this will always + // be 32. We read and use the actual value, on the theory + // that eventually someone will recognize that's a waste of + // space. + if (read_mat5_tag (is, swap, fn_type, fn_len) || fn_type != miINT32) + { + error ("load: invalid field name length subelement"); + goto data_read_error; + } + + if (! is.read (reinterpret_cast (&field_name_length), fn_len )) + goto data_read_error; + + if (swap) + swap_bytes<4> (&field_name_length); + + // field name subelement. The length of this subelement tells + // us how many fields there are. + if (read_mat5_tag (is, swap, fn_type, fn_len) || fn_type != miINT8) + { + error ("load: invalid field name subelement"); + goto data_read_error; + } + + octave_idx_type n_fields = fn_len/field_name_length; + + if (n_fields > 0) + { + fn_len = PAD (fn_len); + + OCTAVE_LOCAL_BUFFER (char, elname, fn_len); + + if (! is.read (elname, fn_len)) + goto data_read_error; + + std::vector elt (n_fields); + + for (octave_idx_type i = 0; i < n_fields; i++) + elt[i] = Cell (dims); + + octave_idx_type n = dims.numel (); + + // fields subelements + for (octave_idx_type j = 0; j < n; j++) + { + for (octave_idx_type i = 0; i < n_fields; i++) + { + octave_value fieldtc; + read_mat5_binary_element (is, filename, swap, global, + fieldtc); + elt[i](j) = fieldtc; + } + } + + for (octave_idx_type i = 0; i < n_fields; i++) + { + const char *key = elname + i*field_name_length; + + m.assign (key, elt[i]); + } + } + + if (isclass) + { + if (classname == "inline") + { + // inline is not an object in Octave but rather an + // overload of a function handle. Special case. + tc = + new octave_fcn_inline (m.contents ("expr")(0).string_value (), + m.contents ("args")(0).string_value ()); + } + else + { + octave_class* cls + = new octave_class (m, classname, + std::list ()); + + if (cls->reconstruct_exemplar ()) + { + + if (! cls->reconstruct_parents ()) + warning ("load: unable to reconstruct object inheritance"); + + tc = cls; + if (load_path::find_method (classname, "loadobj") != + std::string ()) + { + octave_value_list tmp = feval ("loadobj", tc, 1); + + if (! error_state) + tc = tmp(0); + else + goto data_read_error; + } + } + else + { + tc = m; + warning ("load: element has been converted to a structure"); + } + } + } + else + tc = m; + } + break; + + case MAT_FILE_INT8_CLASS: + OCTAVE_MAT5_INTEGER_READ (int8NDArray); + break; + + case MAT_FILE_UINT8_CLASS: + { + OCTAVE_MAT5_INTEGER_READ (uint8NDArray); + + // Logical variables can either be MAT_FILE_UINT8_CLASS or + // MAT_FILE_DOUBLE_CLASS, so check if we have a logical + // variable and convert it. + + if (logicalvar) + { + uint8NDArray in = tc.uint8_array_value (); + octave_idx_type nel = in.numel (); + boolNDArray out (dims); + + for (octave_idx_type i = 0; i < nel; i++) + out(i) = in(i).bool_value (); + + tc = out; + } + } + break; + + case MAT_FILE_INT16_CLASS: + OCTAVE_MAT5_INTEGER_READ (int16NDArray); + break; + + case MAT_FILE_UINT16_CLASS: + OCTAVE_MAT5_INTEGER_READ (uint16NDArray); + break; + + case MAT_FILE_INT32_CLASS: + OCTAVE_MAT5_INTEGER_READ (int32NDArray); + break; + + case MAT_FILE_UINT32_CLASS: + OCTAVE_MAT5_INTEGER_READ (uint32NDArray); + break; + + case MAT_FILE_INT64_CLASS: + OCTAVE_MAT5_INTEGER_READ (int64NDArray); + break; + + case MAT_FILE_UINT64_CLASS: + OCTAVE_MAT5_INTEGER_READ (uint64NDArray); + break; + + + case MAT_FILE_SINGLE_CLASS: + { + FloatNDArray re (dims); + + // real data subelement + + std::streampos tmp_pos; + + if (read_mat5_tag (is, swap, type, len)) + { + error ("load: reading matrix data for `%s'", retval.c_str ()); + goto data_read_error; + } + + octave_idx_type n = re.numel (); + tmp_pos = is.tellg (); + read_mat5_binary_data (is, re.fortran_vec (), n, swap, + static_cast (type), flt_fmt); + + if (! is || error_state) + { + error ("load: reading matrix data for `%s'", retval.c_str ()); + goto data_read_error; + } + + is.seekg (tmp_pos + static_cast (PAD (len))); + + if (imag) + { + // imaginary data subelement + + FloatNDArray im (dims); + + if (read_mat5_tag (is, swap, type, len)) + { + error ("load: reading matrix data for `%s'", retval.c_str ()); + goto data_read_error; + } + + n = im.numel (); + read_mat5_binary_data (is, im.fortran_vec (), n, swap, + static_cast (type), flt_fmt); + + if (! is || error_state) + { + error ("load: reading imaginary matrix data for `%s'", + retval.c_str ()); + goto data_read_error; + } + + FloatComplexNDArray ctmp (dims); + + for (octave_idx_type i = 0; i < n; i++) + ctmp(i) = FloatComplex (re(i), im(i)); + + tc = ctmp; + } + else + tc = re; + } + break; + + case MAT_FILE_CHAR_CLASS: + // handle as a numerical array to start with + + case MAT_FILE_DOUBLE_CLASS: + default: + { + NDArray re (dims); + + // real data subelement + + std::streampos tmp_pos; + + if (read_mat5_tag (is, swap, type, len)) + { + error ("load: reading matrix data for `%s'", retval.c_str ()); + goto data_read_error; + } + + octave_idx_type n = re.numel (); + tmp_pos = is.tellg (); + read_mat5_binary_data (is, re.fortran_vec (), n, swap, + static_cast (type), flt_fmt); + + if (! is || error_state) + { + error ("load: reading matrix data for `%s'", retval.c_str ()); + goto data_read_error; + } + + is.seekg (tmp_pos + static_cast (PAD (len))); + + if (logicalvar) + { + // Logical variables can either be MAT_FILE_UINT8_CLASS or + // MAT_FILE_DOUBLE_CLASS, so check if we have a logical + // variable and convert it. + + boolNDArray out (dims); + + for (octave_idx_type i = 0; i < n; i++) + out (i) = static_cast (re (i)); + + tc = out; + } + else if (imag) + { + // imaginary data subelement + + NDArray im (dims); + + if (read_mat5_tag (is, swap, type, len)) + { + error ("load: reading matrix data for `%s'", retval.c_str ()); + goto data_read_error; + } + + n = im.numel (); + read_mat5_binary_data (is, im.fortran_vec (), n, swap, + static_cast (type), flt_fmt); + + if (! is || error_state) + { + error ("load: reading imaginary matrix data for `%s'", + retval.c_str ()); + goto data_read_error; + } + + ComplexNDArray ctmp (dims); + + for (octave_idx_type i = 0; i < n; i++) + ctmp(i) = Complex (re(i), im(i)); + + tc = ctmp; + } + else + { + if (arrayclass == MAT_FILE_CHAR_CLASS) + { + if (type == miUTF16 || type == miUTF32) + { + bool found_big_char = false; + for (octave_idx_type i = 0; i < n; i++) + { + if (re(i) > 127) { + re(i) = '?'; + found_big_char = true; + } + } + + if (found_big_char) + warning ("load: can not read non-ASCII portions of UTF characters; replacing unreadable characters with '?'"); + } + else if (type == miUTF8) + { + // Search for multi-byte encoded UTF8 characters and + // replace with 0x3F for '?'... Give the user a warning + + bool utf8_multi_byte = false; + for (octave_idx_type i = 0; i < n; i++) + { + unsigned char a = static_cast (re(i)); + if (a > 0x7f) + utf8_multi_byte = true; + } + + if (utf8_multi_byte) + { + warning ("load: can not read multi-byte encoded UTF8 characters; replacing unreadable characters with '?'"); + for (octave_idx_type i = 0; i < n; i++) + { + unsigned char a = static_cast (re(i)); + if (a > 0x7f) + re(i) = '?'; + } + } + } + tc = re; + tc = tc.convert_to_str (false, true, '\''); + } + else + tc = re; + } + } + } + + is.seekg (pos + static_cast (element_length)); + + if (is.eof ()) + is.clear (); + + return retval; + + data_read_error: + early_read_error: + error ("load: trouble reading binary file `%s'", filename.c_str ()); + return std::string (); + + skip_ahead: + warning ("skipping over `%s'", retval.c_str ()); + is.seekg (pos + static_cast (element_length)); + return read_mat5_binary_element (is, filename, swap, global, tc); +} + +int +read_mat5_binary_file_header (std::istream& is, bool& swap, bool quiet, + const std::string& filename) +{ + int16_t version=0, magic=0; + uint64_t subsys_offset; + + is.seekg (116, std::ios::beg); + is.read (reinterpret_cast (&subsys_offset), 8); + + is.seekg (124, std::ios::beg); + is.read (reinterpret_cast (&version), 2); + is.read (reinterpret_cast (&magic), 2); + + if (magic == 0x4d49) + swap = 0; + else if (magic == 0x494d) + swap = 1; + else + { + if (! quiet) + error ("load: can't read binary file"); + return -1; + } + + if (! swap) // version number is inverse swapped! + version = ((version >> 8) & 0xff) + ((version & 0xff) << 8); + + if (version != 1 && !quiet) + warning ("load: found version %d binary MAT file, " + "but only prepared for version 1", version); + + if (swap) + swap_bytes<8> (&subsys_offset, 1); + + if (subsys_offset != 0x2020202020202020ULL && subsys_offset != 0ULL) + { + // Read the subsystem data block + is.seekg (subsys_offset, std::ios::beg); + + octave_value tc; + bool global; + read_mat5_binary_element (is, filename, swap, global, tc); + + if (!is || error_state) + return -1; + + if (tc.is_uint8_type ()) + { + const uint8NDArray itmp = tc.uint8_array_value (); + octave_idx_type ilen = itmp.numel (); + + // Why should I have to initialize outbuf as just overwrite + std::string outbuf (ilen - 7, ' '); + + // FIXME -- find a way to avoid casting away const here + char *ctmp = const_cast (outbuf.c_str ()); + for (octave_idx_type j = 8; j < ilen; j++) + ctmp[j-8] = itmp(j).char_value (); + + std::istringstream fh_ws (outbuf); + + read_mat5_binary_element (fh_ws, filename, swap, global, subsys_ov); + + if (error_state) + return -1; + } + else + return -1; + + // Reposition to just after the header + is.seekg (128, std::ios::beg); + } + + return 0; +} + +static int +write_mat5_tag (std::ostream& is, int type, octave_idx_type bytes) +{ + int32_t temp; + + if (bytes > 0 && bytes <= 4) + temp = (bytes << 16) + type; + else + { + temp = type; + if (! is.write (reinterpret_cast (&temp), 4)) + goto data_write_error; + temp = bytes; + } + + if (! is.write (reinterpret_cast (&temp), 4)) + goto data_write_error; + + return 0; + + data_write_error: + return 1; +} + +// Have to use copy here to avoid writing over data accessed via +// Matrix::data(). + +#define MAT5_DO_WRITE(TYPE, data, count, stream) \ + do \ + { \ + OCTAVE_LOCAL_BUFFER (TYPE, ptr, count); \ + for (octave_idx_type i = 0; i < count; i++) \ + ptr[i] = static_cast (data[i]); \ + stream.write (reinterpret_cast (ptr), count * sizeof (TYPE)); \ + } \ + while (0) + +// write out the numeric values in M to OS, +// preceded by the appropriate tag. +static void +write_mat5_array (std::ostream& os, const NDArray& m, bool save_as_floats) +{ + save_type st = LS_DOUBLE; + const double *data = m.data (); + + if (save_as_floats) + { + if (m.too_large_for_float ()) + { + warning ("save: some values too large to save as floats --"); + warning ("save: saving as doubles instead"); + } + else + st = LS_FLOAT; + } + + double max_val, min_val; + if (m.all_integers (max_val, min_val)) + st = get_save_type (max_val, min_val); + + mat5_data_type mst; + int size; + switch (st) + { + default: + case LS_DOUBLE: mst = miDOUBLE; size = 8; break; + case LS_FLOAT: mst = miSINGLE; size = 4; break; + case LS_U_CHAR: mst = miUINT8; size = 1; break; + case LS_U_SHORT: mst = miUINT16; size = 2; break; + case LS_U_INT: mst = miUINT32; size = 4; break; + case LS_CHAR: mst = miINT8; size = 1; break; + case LS_SHORT: mst = miINT16; size = 2; break; + case LS_INT: mst = miINT32; size = 4; break; + } + + octave_idx_type nel = m.numel (); + octave_idx_type len = nel*size; + + write_mat5_tag (os, mst, len); + + { + switch (st) + { + case LS_U_CHAR: + MAT5_DO_WRITE (uint8_t, data, nel, os); + break; + + case LS_U_SHORT: + MAT5_DO_WRITE (uint16_t, data, nel, os); + break; + + case LS_U_INT: + MAT5_DO_WRITE (uint32_t, data, nel, os); + break; + + case LS_U_LONG: + MAT5_DO_WRITE (uint64_t, data, nel, os); + break; + + case LS_CHAR: + MAT5_DO_WRITE (int8_t, data, nel, os); + break; + + case LS_SHORT: + MAT5_DO_WRITE (int16_t, data, nel, os); + break; + + case LS_INT: + MAT5_DO_WRITE (int32_t, data, nel, os); + break; + + case LS_LONG: + MAT5_DO_WRITE (int64_t, data, nel, os); + break; + + case LS_FLOAT: + MAT5_DO_WRITE (float, data, nel, os); + break; + + case LS_DOUBLE: // No conversion necessary. + os.write (reinterpret_cast (data), len); + break; + + default: + (*current_liboctave_error_handler) + ("unrecognized data format requested"); + break; + } + } + if (PAD (len) > len) + { + static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00"; + os.write (buf, PAD (len) - len); + } +} + +static void +write_mat5_array (std::ostream& os, const FloatNDArray& m, bool) +{ + save_type st = LS_FLOAT; + const float *data = m.data (); + + float max_val, min_val; + if (m.all_integers (max_val, min_val)) + st = get_save_type (max_val, min_val); + + mat5_data_type mst; + int size; + switch (st) + { + default: + case LS_DOUBLE: mst = miDOUBLE; size = 8; break; + case LS_FLOAT: mst = miSINGLE; size = 4; break; + case LS_U_CHAR: mst = miUINT8; size = 1; break; + case LS_U_SHORT: mst = miUINT16; size = 2; break; + case LS_U_INT: mst = miUINT32; size = 4; break; + case LS_CHAR: mst = miINT8; size = 1; break; + case LS_SHORT: mst = miINT16; size = 2; break; + case LS_INT: mst = miINT32; size = 4; break; + } + + octave_idx_type nel = m.numel (); + octave_idx_type len = nel*size; + + write_mat5_tag (os, mst, len); + + { + switch (st) + { + case LS_U_CHAR: + MAT5_DO_WRITE (uint8_t, data, nel, os); + break; + + case LS_U_SHORT: + MAT5_DO_WRITE (uint16_t, data, nel, os); + break; + + case LS_U_INT: + MAT5_DO_WRITE (uint32_t, data, nel, os); + break; + + case LS_U_LONG: + MAT5_DO_WRITE (uint64_t, data, nel, os); + break; + + case LS_CHAR: + MAT5_DO_WRITE (int8_t, data, nel, os); + break; + + case LS_SHORT: + MAT5_DO_WRITE (int16_t, data, nel, os); + break; + + case LS_INT: + MAT5_DO_WRITE (int32_t, data, nel, os); + break; + + case LS_LONG: + MAT5_DO_WRITE (int64_t, data, nel, os); + break; + + case LS_FLOAT: // No conversion necessary. + os.write (reinterpret_cast (data), len); + break; + + case LS_DOUBLE: + MAT5_DO_WRITE (double, data, nel, os); + break; + + default: + (*current_liboctave_error_handler) + ("unrecognized data format requested"); + break; + } + } + if (PAD (len) > len) + { + static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00"; + os.write (buf, PAD (len) - len); + } +} + +template +void +write_mat5_integer_data (std::ostream& os, const T *m, int size, + octave_idx_type nel) +{ + mat5_data_type mst; + unsigned len; + + switch (size) + { + case 1: + mst = miUINT8; + break; + case 2: + mst = miUINT16; + break; + case 4: + mst = miUINT32; + break; + case 8: + mst = miUINT64; + break; + case -1: + mst = miINT8; + size = - size; + break; + case -2: + mst = miINT16; + size = - size; + break; + case -4: + mst = miINT32; + size = - size; + break; + case -8: + default: + mst = miINT64; + size = - size; + break; + } + + len = nel*size; + write_mat5_tag (os, mst, len); + + os.write (reinterpret_cast (m), len); + + if (PAD (len) > len) + { + static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00"; + os.write (buf, PAD (len) - len); + } +} + +template void +write_mat5_integer_data (std::ostream& os, const octave_int8 *m, + int size, octave_idx_type nel); + +template void +write_mat5_integer_data (std::ostream& os, const octave_int16 *m, + int size, octave_idx_type nel); + +template void +write_mat5_integer_data (std::ostream& os, const octave_int32 *m, + int size, octave_idx_type nel); + +template void +write_mat5_integer_data (std::ostream& os, const octave_int64 *m, + int size, octave_idx_type nel); + +template void +write_mat5_integer_data (std::ostream& os, const octave_uint8 *m, + int size, octave_idx_type nel); + +template void +write_mat5_integer_data (std::ostream& os, const octave_uint16 *m, + int size, octave_idx_type nel); + +template void +write_mat5_integer_data (std::ostream& os, const octave_uint32 *m, + int size, octave_idx_type nel); + +template void +write_mat5_integer_data (std::ostream& os, const octave_uint64 *m, + int size, octave_idx_type nel); + +template void +write_mat5_integer_data (std::ostream& os, const int *m, + int size, octave_idx_type nel); + +// Write out cell element values in the cell array to OS, preceded by +// the appropriate tag. + +static bool +write_mat5_cell_array (std::ostream& os, const Cell& cell, + bool mark_as_global, bool save_as_floats) +{ + octave_idx_type nel = cell.numel (); + + for (octave_idx_type i = 0; i < nel; i++) + { + octave_value ov = cell(i); + + if (! save_mat5_binary_element (os, ov, "", mark_as_global, + false, save_as_floats)) + return false; + } + + return true; +} + +int +save_mat5_array_length (const double* val, octave_idx_type nel, + bool save_as_floats) +{ + if (nel > 0) + { + int size = 8; + + if (save_as_floats) + { + bool too_large_for_float = false; + for (octave_idx_type i = 0; i < nel; i++) + { + double tmp = val[i]; + + if (! (xisnan (tmp) || xisinf (tmp)) + && fabs (tmp) > FLT_MAX) + { + too_large_for_float = true; + break; + } + } + + if (!too_large_for_float) + size = 4; + } + + // The code below is disabled since get_save_type currently doesn't + // deal with integer types. This will need to be activated if get_save_type + // is changed. + + // double max_val = val[0]; + // double min_val = val[0]; + // bool all_integers = true; + // + // for (int i = 0; i < nel; i++) + // { + // double val = val[i]; + // + // if (val > max_val) + // max_val = val; + // + // if (val < min_val) + // min_val = val; + // + // if (D_NINT (val) != val) + // { + // all_integers = false; + // break; + // } + // } + // + // if (all_integers) + // { + // if (max_val < 256 && min_val > -1) + // size = 1; + // else if (max_val < 65536 && min_val > -1) + // size = 2; + // else if (max_val < 4294967295UL && min_val > -1) + // size = 4; + // else if (max_val < 128 && min_val >= -128) + // size = 1; + // else if (max_val < 32768 && min_val >= -32768) + // size = 2; + // else if (max_val <= 2147483647L && min_val >= -2147483647L) + // size = 4; + // } + + return 8 + nel * size; + } + else + return 8; +} + +int +save_mat5_array_length (const float* /* val */, octave_idx_type nel, bool) +{ + if (nel > 0) + { + int size = 4; + + + // The code below is disabled since get_save_type currently doesn't + // deal with integer types. This will need to be activated if get_save_type + // is changed. + + // float max_val = val[0]; + // float min_val = val[0]; + // bool all_integers = true; + // + // for (int i = 0; i < nel; i++) + // { + // float val = val[i]; + // + // if (val > max_val) + // max_val = val; + // + // if (val < min_val) + // min_val = val; + // + // if (D_NINT (val) != val) + // { + // all_integers = false; + // break; + // } + // } + // + // if (all_integers) + // { + // if (max_val < 256 && min_val > -1) + // size = 1; + // else if (max_val < 65536 && min_val > -1) + // size = 2; + // else if (max_val < 4294967295UL && min_val > -1) + // size = 4; + // else if (max_val < 128 && min_val >= -128) + // size = 1; + // else if (max_val < 32768 && min_val >= -32768) + // size = 2; + // else if (max_val <= 2147483647L && min_val >= -2147483647L) + // size = 4; + // } + + // Round nel up to nearest even number of elements. Take into account + // Short tags for 4 byte elements. + return PAD ((nel > 0 && nel * size <= 4 ? 4 : 8) + nel * size); + } + else + return 8; +} + +int +save_mat5_array_length (const Complex* val, octave_idx_type nel, + bool save_as_floats) +{ + int ret; + + OCTAVE_LOCAL_BUFFER (double, tmp, nel); + + for (octave_idx_type i = 1; i < nel; i++) + tmp[i] = std::real (val[i]); + + ret = save_mat5_array_length (tmp, nel, save_as_floats); + + for (octave_idx_type i = 1; i < nel; i++) + tmp[i] = std::imag (val[i]); + + ret += save_mat5_array_length (tmp, nel, save_as_floats); + + return ret; +} + +int +save_mat5_array_length (const FloatComplex* val, octave_idx_type nel, + bool save_as_floats) +{ + int ret; + + OCTAVE_LOCAL_BUFFER (float, tmp, nel); + + for (octave_idx_type i = 1; i < nel; i++) + tmp[i] = std::real (val[i]); + + ret = save_mat5_array_length (tmp, nel, save_as_floats); + + for (octave_idx_type i = 1; i < nel; i++) + tmp[i] = std::imag (val[i]); + + ret += save_mat5_array_length (tmp, nel, save_as_floats); + + return ret; +} + +int +save_mat5_element_length (const octave_value& tc, const std::string& name, + bool save_as_floats, bool mat7_format) +{ + size_t max_namelen = (mat7_format ? 63 : 31); + size_t len = name.length (); + std::string cname = tc.class_name (); + int ret = 32; + + if (len > 4) + ret += PAD (len > max_namelen ? max_namelen : len); + + ret += PAD (4 * tc.ndims ()); + + if (tc.is_string ()) + { + charNDArray chm = tc.char_array_value (); + ret += 8; + if (chm.numel () > 2) + ret += PAD (2 * chm.numel ()); + } + else if (tc.is_sparse_type ()) + { + if (tc.is_complex_type ()) + { + const SparseComplexMatrix m = tc.sparse_complex_matrix_value (); + octave_idx_type nc = m.cols (); + octave_idx_type nnz = m.nnz (); + + ret += 16 + save_mat5_array_length (m.data (), nnz, save_as_floats); + if (nnz > 1) + ret += PAD (nnz * sizeof (int32_t)); + if (nc > 0) + ret += PAD ((nc + 1) * sizeof (int32_t)); + } + else + { + const SparseMatrix m = tc.sparse_matrix_value (); + octave_idx_type nc = m.cols (); + octave_idx_type nnz = m.nnz (); + + ret += 16 + save_mat5_array_length (m.data (), nnz, save_as_floats); + if (nnz > 1) + ret += PAD (nnz * sizeof (int32_t)); + if (nc > 0) + ret += PAD ((nc + 1) * sizeof (int32_t)); + } + } + +#define INT_LEN(nel, size) \ + { \ + ret += 8; \ + octave_idx_type sz = nel * size; \ + if (sz > 4) \ + ret += PAD (sz); \ + } + + else if (cname == "int8") + INT_LEN (tc.int8_array_value ().numel (), 1) + else if (cname == "int16") + INT_LEN (tc.int16_array_value ().numel (), 2) + else if (cname == "int32") + INT_LEN (tc.int32_array_value ().numel (), 4) + else if (cname == "int64") + INT_LEN (tc.int64_array_value ().numel (), 8) + else if (cname == "uint8") + INT_LEN (tc.uint8_array_value ().numel (), 1) + else if (cname == "uint16") + INT_LEN (tc.uint16_array_value ().numel (), 2) + else if (cname == "uint32") + INT_LEN (tc.uint32_array_value ().numel (), 4) + else if (cname == "uint64") + INT_LEN (tc.uint64_array_value ().numel (), 8) + else if (tc.is_bool_type ()) + INT_LEN (tc.bool_array_value ().numel (), 1) + else if (tc.is_real_scalar () || tc.is_real_matrix () || tc.is_range ()) + { + if (tc.is_single_type ()) + { + const FloatNDArray m = tc.float_array_value (); + ret += save_mat5_array_length (m.fortran_vec (), m.numel (), + save_as_floats); + } + else + { + const NDArray m = tc.array_value (); + ret += save_mat5_array_length (m.fortran_vec (), m.numel (), + save_as_floats); + } + } + else if (tc.is_cell ()) + { + Cell cell = tc.cell_value (); + octave_idx_type nel = cell.numel (); + + for (int i = 0; i < nel; i++) + ret += 8 + + save_mat5_element_length (cell (i), "", save_as_floats, mat7_format); + } + else if (tc.is_complex_scalar () || tc.is_complex_matrix ()) + { + if (tc.is_single_type ()) + { + const FloatComplexNDArray m = tc.float_complex_array_value (); + ret += save_mat5_array_length (m.fortran_vec (), m.numel (), + save_as_floats); + } + else + { + const ComplexNDArray m = tc.complex_array_value (); + ret += save_mat5_array_length (m.fortran_vec (), m.numel (), + save_as_floats); + } + } + else if (tc.is_map () || tc.is_inline_function () || tc.is_object ()) + { + int fieldcnt = 0; + const Octave_map m = tc.map_value (); + octave_idx_type nel = m.numel (); + + if (tc.is_inline_function ()) + // length of "inline" is 6 + ret += 8 + PAD (6 > max_namelen ? max_namelen : 6); + else if (tc.is_object ()) + { + size_t classlen = tc.class_name (). length (); + + ret += 8 + PAD (classlen > max_namelen ? max_namelen : classlen); + } + + for (Octave_map::const_iterator i = m.begin (); i != m.end (); i++) + fieldcnt++; + + ret += 16 + fieldcnt * (max_namelen + 1); + + + for (octave_idx_type j = 0; j < nel; j++) + { + + for (Octave_map::const_iterator i = m.begin (); i != m.end (); i++) + { + const Cell elts = m.contents (i); + + ret += 8 + save_mat5_element_length (elts(j), "", + save_as_floats, mat7_format); + } + } + } + else + ret = -1; + + return ret; +} + +static void +write_mat5_sparse_index_vector (std::ostream& os, + const octave_idx_type *idx, + octave_idx_type nel) +{ + int tmp = sizeof (int32_t); + + OCTAVE_LOCAL_BUFFER (int32_t, tmp_idx, nel); + + for (octave_idx_type i = 0; i < nel; i++) + tmp_idx[i] = idx[i]; + + write_mat5_integer_data (os, tmp_idx, -tmp, nel); +} + +static void +gripe_dim_too_large (const std::string& name) +{ + warning ("save: skipping %s: dimension too large for MAT format", + name.c_str ()); +} + +// save the data from TC along with the corresponding NAME on stream +// OS in the MatLab version 5 binary format. Return true on success. + +bool +save_mat5_binary_element (std::ostream& os, + const octave_value& tc, const std::string& name, + bool mark_as_global, bool mat7_format, + bool save_as_floats, bool compressing) +{ + int32_t flags = 0; + int32_t nnz_32 = 0; + std::string cname = tc.class_name (); + size_t max_namelen = (mat7_format ? 63 : 31); + + dim_vector dv = tc.dims (); + int nd = tc.ndims (); + int dim_len = 4*nd; + + static octave_idx_type max_dim_val = std::numeric_limits::max (); + + for (int i = 0; i < nd; i++) + { + if (dv(i) > max_dim_val) + { + gripe_dim_too_large (name); + goto skip_to_next; + } + } + + if (tc.is_sparse_type ()) + { + octave_idx_type nnz; + octave_idx_type nc; + + if (tc.is_complex_type ()) + { + SparseComplexMatrix scm = tc.sparse_complex_matrix_value (); + nnz = scm.nzmax (); + nc = scm.cols (); + } + else + { + SparseMatrix sm = tc.sparse_matrix_value (); + nnz = sm.nzmax (); + nc = sm.cols (); + } + + if (nnz > max_dim_val || nc + 1 > max_dim_val) + { + gripe_dim_too_large (name); + goto skip_to_next; + } + + nnz_32 = nnz; + } + else if (dv.numel () > max_dim_val) + { + gripe_dim_too_large (name); + goto skip_to_next; + } + +#ifdef HAVE_ZLIB + if (mat7_format && !compressing) + { + bool ret = false; + + std::ostringstream buf; + + // The code seeks backwards in the stream to fix the header. Can't + // do this with zlib, so use a stringstream. + ret = save_mat5_binary_element (buf, tc, name, mark_as_global, true, + save_as_floats, true); + + if (ret) + { + // destLen must be at least 0.1% larger than source buffer + // + 12 bytes. Reality is it must be larger again than that. + std::string buf_str = buf.str (); + uLongf srcLen = buf_str.length (); + uLongf destLen = srcLen * 101 / 100 + 12; + OCTAVE_LOCAL_BUFFER (char, out_buf, destLen); + + if (compress (reinterpret_cast (out_buf), &destLen, + reinterpret_cast (buf_str.c_str ()), srcLen) == Z_OK) + { + write_mat5_tag (os, miCOMPRESSED, + static_cast (destLen)); + + os.write (out_buf, destLen); + } + else + { + error ("save: error compressing data element"); + ret = false; + } + } + + return ret; + } +#endif + + write_mat5_tag (os, miMATRIX, save_mat5_element_length + (tc, name, save_as_floats, mat7_format)); + + // array flags subelement + write_mat5_tag (os, miUINT32, 8); + + if (tc.is_bool_type ()) + flags |= 0x0200; + + if (mark_as_global) + flags |= 0x0400; + + if (tc.is_complex_scalar () || tc.is_complex_matrix ()) + flags |= 0x0800; + + if (tc.is_string ()) + flags |= MAT_FILE_CHAR_CLASS; + else if (cname == "int8") + flags |= MAT_FILE_INT8_CLASS; + else if (cname == "int16") + flags |= MAT_FILE_INT16_CLASS; + else if (cname == "int32") + flags |= MAT_FILE_INT32_CLASS; + else if (cname == "int64") + flags |= MAT_FILE_INT64_CLASS; + else if (cname == "uint8" || tc.is_bool_type ()) + flags |= MAT_FILE_UINT8_CLASS; + else if (cname == "uint16") + flags |= MAT_FILE_UINT16_CLASS; + else if (cname == "uint32") + flags |= MAT_FILE_UINT32_CLASS; + else if (cname == "uint64") + flags |= MAT_FILE_UINT64_CLASS; + else if (tc.is_sparse_type ()) + flags |= MAT_FILE_SPARSE_CLASS; + else if (tc.is_real_scalar () || tc.is_real_matrix () || tc.is_range () + || tc.is_complex_scalar () || tc.is_complex_matrix ()) + { + if (tc.is_single_type ()) + flags |= MAT_FILE_SINGLE_CLASS; + else + flags |= MAT_FILE_DOUBLE_CLASS; + } + else if (tc.is_map ()) + flags |= MAT_FILE_STRUCT_CLASS; + else if (tc.is_cell ()) + flags |= MAT_FILE_CELL_CLASS; + else if (tc.is_inline_function () || tc.is_object ()) + flags |= MAT_FILE_OBJECT_CLASS; + else + { + gripe_wrong_type_arg ("save", tc, false); + goto error_cleanup; + } + + os.write (reinterpret_cast (&flags), 4); + os.write (reinterpret_cast (&nnz_32), 4); + + write_mat5_tag (os, miINT32, dim_len); + + for (int i = 0; i < nd; i++) + { + int32_t n = dv(i); + os.write (reinterpret_cast (&n), 4); + } + + if (PAD (dim_len) > dim_len) + { + static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00"; + os.write (buf, PAD (dim_len) - dim_len); + } + + // array name subelement + { + size_t namelen = name.length (); + + if (namelen > max_namelen) + namelen = max_namelen; // only 31 or 63 char names permitted in mat file + + int paddedlength = PAD (namelen); + + write_mat5_tag (os, miINT8, namelen); + OCTAVE_LOCAL_BUFFER (char, paddedname, paddedlength); + memset (paddedname, 0, paddedlength); + strncpy (paddedname, name.c_str (), namelen); + os.write (paddedname, paddedlength); + } + + // data element + if (tc.is_string ()) + { + charNDArray chm = tc.char_array_value (); + octave_idx_type nel = chm.numel (); + octave_idx_type len = nel*2; + octave_idx_type paddedlength = PAD (len); + + OCTAVE_LOCAL_BUFFER (int16_t, buf, nel+3); + write_mat5_tag (os, miUINT16, len); + + const char *s = chm.data (); + + for (octave_idx_type i = 0; i < nel; i++) + buf[i] = *s++ & 0x00FF; + + os.write (reinterpret_cast (buf), len); + + if (paddedlength > len) + { + static char padbuf[9]="\x00\x00\x00\x00\x00\x00\x00\x00"; + os.write (padbuf, paddedlength - len); + } + } + else if (tc.is_sparse_type ()) + { + if (tc.is_complex_type ()) + { + const SparseComplexMatrix m = tc.sparse_complex_matrix_value (); + octave_idx_type nnz = m.nnz (); + octave_idx_type nc = m.cols (); + + write_mat5_sparse_index_vector (os, m.ridx (), nnz); + write_mat5_sparse_index_vector (os, m.cidx (), nc + 1); + + NDArray buf (dim_vector (nnz, 1)); + + for (octave_idx_type i = 0; i < nnz; i++) + buf (i) = std::real (m.data (i)); + + write_mat5_array (os, buf, save_as_floats); + + for (octave_idx_type i = 0; i < nnz; i++) + buf (i) = std::imag (m.data (i)); + + write_mat5_array (os, buf, save_as_floats); + } + else + { + const SparseMatrix m = tc.sparse_matrix_value (); + octave_idx_type nnz = m.nnz (); + octave_idx_type nc = m.cols (); + + write_mat5_sparse_index_vector (os, m.ridx (), nnz); + write_mat5_sparse_index_vector (os, m.cidx (), nc + 1); + + // FIXME + // Is there a way to easily do without this buffer + NDArray buf (dim_vector (nnz, 1)); + + for (int i = 0; i < nnz; i++) + buf (i) = m.data (i); + + write_mat5_array (os, buf, save_as_floats); + } + } + else if (cname == "int8") + { + int8NDArray m = tc.int8_array_value (); + + write_mat5_integer_data (os, m.fortran_vec (), -1, m.numel ()); + } + else if (cname == "int16") + { + int16NDArray m = tc.int16_array_value (); + + write_mat5_integer_data (os, m.fortran_vec (), -2, m.numel ()); + } + else if (cname == "int32") + { + int32NDArray m = tc.int32_array_value (); + + write_mat5_integer_data (os, m.fortran_vec (), -4, m.numel ()); + } + else if (cname == "int64") + { + int64NDArray m = tc.int64_array_value (); + + write_mat5_integer_data (os, m.fortran_vec (), -8, m.numel ()); + } + else if (cname == "uint8") + { + uint8NDArray m = tc.uint8_array_value (); + + write_mat5_integer_data (os, m.fortran_vec (), 1, m.numel ()); + } + else if (cname == "uint16") + { + uint16NDArray m = tc.uint16_array_value (); + + write_mat5_integer_data (os, m.fortran_vec (), 2, m.numel ()); + } + else if (cname == "uint32") + { + uint32NDArray m = tc.uint32_array_value (); + + write_mat5_integer_data (os, m.fortran_vec (), 4, m.numel ()); + } + else if (cname == "uint64") + { + uint64NDArray m = tc.uint64_array_value (); + + write_mat5_integer_data (os, m.fortran_vec (), 8, m.numel ()); + } + else if (tc.is_bool_type ()) + { + uint8NDArray m (tc.bool_array_value ()); + + write_mat5_integer_data (os, m.fortran_vec (), 1, m.numel ()); + } + else if (tc.is_real_scalar () || tc.is_real_matrix () || tc.is_range ()) + { + if (tc.is_single_type ()) + { + FloatNDArray m = tc.float_array_value (); + + write_mat5_array (os, m, save_as_floats); + } + else + { + NDArray m = tc.array_value (); + + write_mat5_array (os, m, save_as_floats); + } + } + else if (tc.is_cell ()) + { + Cell cell = tc.cell_value (); + + if (! write_mat5_cell_array (os, cell, mark_as_global, save_as_floats)) + goto error_cleanup; + } + else if (tc.is_complex_scalar () || tc.is_complex_matrix ()) + { + if (tc.is_single_type ()) + { + FloatComplexNDArray m_cmplx = tc.float_complex_array_value (); + + write_mat5_array (os, ::real (m_cmplx), save_as_floats); + write_mat5_array (os, ::imag (m_cmplx), save_as_floats); + } + else + { + ComplexNDArray m_cmplx = tc.complex_array_value (); + + write_mat5_array (os, ::real (m_cmplx), save_as_floats); + write_mat5_array (os, ::imag (m_cmplx), save_as_floats); + } + } + else if (tc.is_map () || tc.is_inline_function () || tc.is_object ()) + { + if (tc.is_inline_function () || tc.is_object ()) + { + std::string classname = tc.is_object () ? tc.class_name () : "inline"; + size_t namelen = classname.length (); + + if (namelen > max_namelen) + namelen = max_namelen; // only 31 or 63 char names permitted + + int paddedlength = PAD (namelen); + + write_mat5_tag (os, miINT8, namelen); + OCTAVE_LOCAL_BUFFER (char, paddedname, paddedlength); + memset (paddedname, 0, paddedlength); + strncpy (paddedname, classname.c_str (), namelen); + os.write (paddedname, paddedlength); + } + + Octave_map m; + + if (tc.is_object () && + load_path::find_method (tc.class_name (), "saveobj") != std::string ()) + { + octave_value_list tmp = feval ("saveobj", tc, 1); + if (! error_state) + m = tmp(0).map_value (); + else + goto error_cleanup; + } + else + m = tc.map_value (); + + // an Octave structure */ + // recursively write each element of the structure + { + char buf[64]; + int32_t maxfieldnamelength = max_namelen + 1; + + octave_idx_type nf = m.nfields (); + + write_mat5_tag (os, miINT32, 4); + os.write (reinterpret_cast (&maxfieldnamelength), 4); + write_mat5_tag (os, miINT8, nf*maxfieldnamelength); + + // Iterating over the list of keys will preserve the order of + // the fields. + string_vector keys = m.keys (); + + for (octave_idx_type i = 0; i < nf; i++) + { + std::string key = keys(i); + + // write the name of each element + memset (buf, 0, max_namelen + 1); + // only 31 or 63 char names permitted + strncpy (buf, key.c_str (), max_namelen); + os.write (buf, max_namelen + 1); + } + + octave_idx_type len = m.numel (); + + // Create temporary copy of structure contents to avoid + // multiple calls of the contents method. + std::vector elts (nf); + for (octave_idx_type i = 0; i < nf; i++) + elts[i] = m.contents (keys(i)).data (); + + for (octave_idx_type j = 0; j < len; j++) + { + // write the data of each element + + // Iterating over the list of keys will preserve the order + // of the fields. + for (octave_idx_type i = 0; i < nf; i++) + { + bool retval2 = save_mat5_binary_element (os, elts[i][j], "", + mark_as_global, + false, + save_as_floats); + if (! retval2) + goto error_cleanup; + } + } + } + } + else + gripe_wrong_type_arg ("save", tc, false); + + skip_to_next: + return true; + + error_cleanup: + error ("save: error while writing `%s' to MAT file", name.c_str ()); + + return false; +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/ls-mat5.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/ls-mat5.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,61 @@ +/* + +Copyright (C) 2003-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_ls_mat5_h) +#define octave_ls_mat5_h 1 + +enum mat5_data_type + { + miINT8 = 1, // 8 bit signed + miUINT8, // 8 bit unsigned + miINT16, // 16 bit signed + miUINT16, // 16 bit unsigned + miINT32, // 32 bit signed + miUINT32, // 32 bit unsigned + miSINGLE, // IEEE 754 single precision float + miRESERVE1, + miDOUBLE, // IEEE 754 double precision float + miRESERVE2, + miRESERVE3, + miINT64, // 64 bit signed + miUINT64, // 64 bit unsigned + miMATRIX, // MATLAB array + miCOMPRESSED, // Compressed data + miUTF8, // Unicode UTF-8 Encoded Character Data + miUTF16, // Unicode UTF-16 Encoded Character Data + miUTF32 // Unicode UTF-32 Encoded Character Data + }; + +extern int +read_mat5_binary_file_header (std::istream& is, bool& swap, + bool quiet = false, + const std::string& filename = std::string ()); +extern std::string +read_mat5_binary_element (std::istream& is, const std::string& filename, + bool swap, bool& global, octave_value& tc); +extern bool +save_mat5_binary_element (std::ostream& os, + const octave_value& tc, const std::string& name, + bool mark_as_global, bool mat7_format, + bool save_as_floats, bool compressing = false); + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/ls-oct-binary.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/ls-oct-binary.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,307 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "byte-swap.h" +#include "data-conv.h" +#include "file-ops.h" +#include "glob-match.h" +#include "lo-mappers.h" +#include "mach-info.h" +#include "oct-env.h" +#include "oct-time.h" +#include "quit.h" +#include "str-vec.h" +#include "oct-locbuf.h" + +#include "Cell.h" +#include "defun.h" +#include "error.h" +#include "gripes.h" +#include "load-save.h" +#include "oct-obj.h" +#include "oct-map.h" +#include "ov-cell.h" +#include "pager.h" +#include "pt-exp.h" +#include "sysdep.h" +#include "unwind-prot.h" +#include "utils.h" +#include "variables.h" +#include "version.h" +#include "dMatrix.h" + +#include "ls-utils.h" +#include "ls-oct-binary.h" + +// Extract one value (scalar, matrix, string, etc.) from stream IS and +// place it in TC, returning the name of the variable. If the value +// is tagged as global in the file, return TRUE in GLOBAL. If SWAP +// is TRUE, swap bytes after reading. +// +// The data is expected to be in the following format: +// +// Header (one per file): +// ===================== +// +// object type bytes +// ------ ---- ----- +// magic number string 10 +// +// float format integer 1 +// +// +// Data (one set for each item): +// ============================ +// +// object type bytes +// ------ ---- ----- +// name_length integer 4 +// +// name string name_length +// +// doc_length integer 4 +// +// doc string doc_length +// +// global flag integer 1 +// +// data type char 1 +// +// In general "data type" is 255, and in that case the next arguments +// in the data set are +// +// object type bytes +// ------ ---- ----- +// type_length integer 4 +// +// type string type_length +// +// The string "type" is then used with octave_value_typeinfo::lookup_type +// to create an octave_value of the correct type. The specific load/save +// function is then called. +// +// For backward compatiablity "data type" can also be a value between 1 +// and 7, where this defines a hardcoded octave_value of the type +// +// data type octave_value +// --------- ------------ +// 1 scalar +// 2 matrix +// 3 complex scalar +// 4 complex matrix +// 5 string (old style storage) +// 6 range +// 7 string +// +// Except for "data type" equal 5 that requires special treatment, these +// old style "data type" value also cause the specific load/save functions +// to be called. FILENAME is used for error messages. + +std::string +read_binary_data (std::istream& is, bool swap, + oct_mach_info::float_format fmt, + const std::string& filename, bool& global, + octave_value& tc, std::string& doc) +{ + std::string retval; + + unsigned char tmp = 0; + + int32_t name_len = 0; + int32_t doc_len = 0; + + doc.resize (0); + + // We expect to fail here, at the beginning of a record, so not + // being able to read another name should not result in an error. + + is.read (reinterpret_cast (&name_len), 4); + if (! is) + return retval; + if (swap) + swap_bytes<4> (&name_len); + + { + OCTAVE_LOCAL_BUFFER (char, name, name_len+1); + name[name_len] = '\0'; + if (! is.read (reinterpret_cast (name), name_len)) + goto data_read_error; + retval = name; + } + + is.read (reinterpret_cast (&doc_len), 4); + if (! is) + goto data_read_error; + if (swap) + swap_bytes<4> (&doc_len); + + { + OCTAVE_LOCAL_BUFFER (char, tdoc, doc_len+1); + tdoc[doc_len] = '\0'; + if (! is.read (reinterpret_cast (tdoc), doc_len)) + goto data_read_error; + doc = tdoc; + } + + if (! is.read (reinterpret_cast (&tmp), 1)) + goto data_read_error; + global = tmp ? 1 : 0; + + tmp = 0; + if (! is.read (reinterpret_cast (&tmp), 1)) + goto data_read_error; + + // All cases except 255 kept for backwards compatibility + switch (tmp) + { + case 1: + tc = octave_value_typeinfo::lookup_type ("scalar"); + break; + + case 2: + tc = octave_value_typeinfo::lookup_type ("matrix"); + break; + + case 3: + tc = octave_value_typeinfo::lookup_type ("complex scalar"); + break; + + case 4: + tc = octave_value_typeinfo::lookup_type ("complex matrix"); + break; + + case 5: + { + // FIXMEX + // This is cruft, since its for a save type that is old. Maybe + // this is taking backward compatability too far!! + int32_t len; + if (! is.read (reinterpret_cast (&len), 4)) + goto data_read_error; + if (swap) + swap_bytes<4> (&len); + OCTAVE_LOCAL_BUFFER (char, s, len+1); + if (! is.read (reinterpret_cast (s), len)) + goto data_read_error; + s[len] = '\0'; + tc = s; + + // Early return, since don't want rest of this function + return retval; + } + break; + + case 6: + tc = octave_value_typeinfo::lookup_type ("range"); + break; + + case 7: + tc = octave_value_typeinfo::lookup_type ("string"); + break; + + case 255: + { + // Read the saved variable type + int32_t len; + if (! is.read (reinterpret_cast (&len), 4)) + goto data_read_error; + if (swap) + swap_bytes<4> (&len); + OCTAVE_LOCAL_BUFFER (char, s, len+1); + if (! is.read (s, len)) + goto data_read_error; + s[len] = '\0'; + std::string typ = s; + tc = octave_value_typeinfo::lookup_type (typ); + } + break; + default: + goto data_read_error; + break; + } + + if (!tc.load_binary (is, swap, fmt)) + { + data_read_error: + error ("load: trouble reading binary file `%s'", filename.c_str ()); + } + + return retval; +} + +// Save the data from TC along with the corresponding NAME, help +// string DOC, and global flag MARK_AS_GLOBAL on stream OS in the +// binary format described above for read_binary_data. + +bool +save_binary_data (std::ostream& os, const octave_value& tc, + const std::string& name, const std::string& doc, + bool mark_as_global, bool save_as_floats) +{ + int32_t name_len = name.length (); + + os.write (reinterpret_cast (&name_len), 4); + os << name; + + int32_t doc_len = doc.length (); + + os.write (reinterpret_cast (&doc_len), 4); + os << doc; + + unsigned char tmp; + + tmp = mark_as_global; + os.write (reinterpret_cast (&tmp), 1); + + // 255 flags the new binary format + tmp = 255; + os.write (reinterpret_cast (&tmp), 1); + + // Write the string corresponding to the octave_value type + std::string typ = tc.type_name (); + int32_t len = typ.length (); + os.write (reinterpret_cast (&len), 4); + const char *btmp = typ.data (); + os.write (btmp, len); + + // The octave_value of tc is const. Make a copy... + octave_value val = tc; + + // Call specific save function + bool success = val.save_binary (os, save_as_floats); + + return (os && success); +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/ls-oct-binary.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/ls-oct-binary.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,37 @@ +/* + +Copyright (C) 2003-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_ls_oct_binary_h) +#define octave_ls_oct_binary_h 1 + +extern OCTINTERP_API bool +save_binary_data (std::ostream& os, const octave_value& tc, + const std::string& name, const std::string& doc, + bool mark_as_global, bool save_as_floats); + +extern OCTINTERP_API std::string +read_binary_data (std::istream& is, bool swap, + oct_mach_info::float_format fmt, + const std::string& filename, bool& global, + octave_value& tc, std::string& doc); + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/ls-utils.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/ls-utils.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,88 @@ +/* + +Copyright (C) 2003-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "data-conv.h" + +#include "ls-utils.h" + +// MAX_VAL and MIN_VAL are assumed to have integral values even though +// they are stored in doubles. + +save_type +get_save_type (double /* max_val */, double /* min_val */) +{ + save_type st = LS_DOUBLE; + + // Matlab doesn't seem to load the UINT32 type correctly, so let's + // avoid it (and the other unsigned types, even though they may not + // have the same problem. And apparently, there are problems with + // other smaller types as well. If we avoid them all, then maybe we + // will avoid problems. Unfortunately, we won't be able to save + // space... + + // if (max_val < 256 && min_val > -1) + // st = LS_U_CHAR; + // else if (max_val < 65536 && min_val > -1) + // st = LS_U_SHORT; + // else if (max_val < 4294967295UL && min_val > -1) + // st = LS_U_INT; + // else if (max_val < 128 && min_val >= -128) + // st = LS_CHAR; + // else if (max_val < 32768 && min_val >= -32768) + // st = LS_SHORT; + // else if (max_val <= 2147483647L && min_val >= -2147483647L) + // st = LS_INT; + + return st; +} + +save_type +get_save_type (float /* max_val */, float /* min_val */) +{ + save_type st = LS_FLOAT; + + // Matlab doesn't seem to load the UINT32 type correctly, so let's + // avoid it (and the other unsigned types, even though they may not + // have the same problem. And apparently, there are problems with + // other smaller types as well. If we avoid them all, then maybe we + // will avoid problems. Unfortunately, we won't be able to save + // space... + + // if (max_val < 256 && min_val > -1) + // st = LS_U_CHAR; + // else if (max_val < 65536 && min_val > -1) + // st = LS_U_SHORT; + // else if (max_val < 4294967295UL && min_val > -1) + // st = LS_U_INT; + // else if (max_val < 128 && min_val >= -128) + // st = LS_CHAR; + // else if (max_val < 32768 && min_val >= -32768) + // st = LS_SHORT; + // else if (max_val <= 2147483647L && min_val >= -2147483647L) + // st = LS_INT; + + return st; +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/ls-utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/ls-utils.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,32 @@ +/* + +Copyright (C) 2003-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_ls_utils_h) +#define octave_ls_utils 1 + +extern save_type +get_save_type (double max_val, double min_val); + +extern save_type +get_save_type (float max_val, float min_val); + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/matherr.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/matherr.c Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,53 @@ +/* + +Copyright (C) 1997-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined (EXCEPTION_IN_MATH) + +#include "lo-math.h" + +int +matherr (struct exception *x) +{ + /* Possibly print our own message someday. Should probably be + user-switchable. */ + + switch (x->type) + { + case DOMAIN: + case SING: + case OVERFLOW: + case UNDERFLOW: + case TLOSS: + case PLOSS: + default: + break; + } + + /* But don't print the system message. */ + + return 1; +} +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/mex.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/mex.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,3540 @@ +/* + +Copyright (C) 2006-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include "f77-fcn.h" +#include "lo-ieee.h" +#include "oct-locbuf.h" + +// mxArray must be declared as a class before including mexproto.h. +class mxArray; +#include "Cell.h" +#include "mexproto.h" +#include "oct-map.h" +#include "oct-obj.h" +#include "ov.h" +#include "ov-mex-fcn.h" +#include "ov-usr-fcn.h" +#include "pager.h" +#include "parse.h" +#include "toplev.h" +#include "unwind-prot.h" +#include "utils.h" +#include "variables.h" +#include "graphics.h" + +// #define DEBUG 1 + +static void +xfree (void *ptr) +{ + ::free (ptr); +} + +static mwSize +max_str_len (mwSize m, const char **str) +{ + int max_len = 0; + + for (mwSize i = 0; i < m; i++) + { + mwSize tmp = strlen (str[i]); + + if (tmp > max_len) + max_len = tmp; + } + + return max_len; +} + +static int +valid_key (const char *key) +{ + int retval = 0; + + int nel = strlen (key); + + if (nel > 0) + { + if (isalpha (key[0])) + { + for (int i = 1; i < nel; i++) + { + if (! (isalnum (key[i]) || key[i] == '_')) + goto done; + } + + retval = 1; + } + } + + done: + + return retval; +} + +// ------------------------------------------------------------------ + +// A class to provide the default implemenation of some of the virtual +// functions declared in the mxArray class. + +class mxArray_base : public mxArray +{ +protected: + + mxArray_base (void) : mxArray (xmxArray ()) { } + +public: + + mxArray *dup (void) const = 0; + + ~mxArray_base (void) { } + + bool is_octave_value (void) const { return false; } + + int is_cell (void) const = 0; + + int is_char (void) const = 0; + + int is_class (const char *name_arg) const + { + int retval = 0; + + const char *cname = get_class_name (); + + if (cname && name_arg) + retval = ! strcmp (cname, name_arg); + + return retval; + } + + int is_complex (void) const = 0; + + int is_double (void) const = 0; + + int is_function_handle (void) const = 0; + + int is_int16 (void) const = 0; + + int is_int32 (void) const = 0; + + int is_int64 (void) const = 0; + + int is_int8 (void) const = 0; + + int is_logical (void) const = 0; + + int is_numeric (void) const = 0; + + int is_single (void) const = 0; + + int is_sparse (void) const = 0; + + int is_struct (void) const = 0; + + int is_uint16 (void) const = 0; + + int is_uint32 (void) const = 0; + + int is_uint64 (void) const = 0; + + int is_uint8 (void) const = 0; + + int is_logical_scalar (void) const + { + return is_logical () && get_number_of_elements () == 1; + } + + int is_logical_scalar_true (void) const = 0; + + mwSize get_m (void) const = 0; + + mwSize get_n (void) const = 0; + + mwSize *get_dimensions (void) const = 0; + + mwSize get_number_of_dimensions (void) const = 0; + + void set_m (mwSize m) = 0; + + void set_n (mwSize n) = 0; + + void set_dimensions (mwSize *dims_arg, mwSize ndims_arg) = 0; + + mwSize get_number_of_elements (void) const = 0; + + int is_empty (void) const = 0; + + mxClassID get_class_id (void) const = 0; + + const char *get_class_name (void) const = 0; + + void set_class_name (const char *name_arg) = 0; + + mxArray *get_cell (mwIndex /*idx*/) const + { + invalid_type_error (); + return 0; + } + + void set_cell (mwIndex idx, mxArray *val) = 0; + + double get_scalar (void) const = 0; + + void *get_data (void) const = 0; + + void *get_imag_data (void) const = 0; + + void set_data (void *pr) = 0; + + void set_imag_data (void *pi) = 0; + + mwIndex *get_ir (void) const = 0; + + mwIndex *get_jc (void) const = 0; + + mwSize get_nzmax (void) const = 0; + + void set_ir (mwIndex *ir) = 0; + + void set_jc (mwIndex *jc) = 0; + + void set_nzmax (mwSize nzmax) = 0; + + int add_field (const char *key) = 0; + + void remove_field (int key_num) = 0; + + mxArray *get_field_by_number (mwIndex index, int key_num) const = 0; + + void set_field_by_number (mwIndex index, int key_num, mxArray *val) = 0; + + int get_number_of_fields (void) const = 0; + + const char *get_field_name_by_number (int key_num) const = 0; + + int get_field_number (const char *key) const = 0; + + int get_string (char *buf, mwSize buflen) const = 0; + + char *array_to_string (void) const = 0; + + mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const = 0; + + size_t get_element_size (void) const = 0; + + bool mutation_needed (void) const { return false; } + + mxArray *mutate (void) const { return 0; } + +protected: + + octave_value as_octave_value (void) const = 0; + + mxArray_base (const mxArray_base&) : mxArray (xmxArray ()) { } + + void invalid_type_error (void) const + { + error ("invalid type for operation"); + } + + void error (const char *msg) const + { + // FIXME + ::error ("%s", msg); + } +}; + +static mwIndex +calc_single_subscript_internal (mwSize ndims, const mwSize *dims, + mwSize nsubs, const mwIndex *subs) +{ + mwIndex retval = 0; + + switch (nsubs) + { + case 0: + break; + + case 1: + retval = subs[0]; + break; + + default: + { + // Both nsubs and ndims should be at least 2 here. + + mwSize n = nsubs <= ndims ? nsubs : ndims; + + retval = subs[--n]; + + while (--n >= 0) + retval = dims[n] * retval + subs[n]; + } + break; + } + + return retval; +} + +// The object that handles values pass to MEX files from Octave. Some +// methods in this class may set mutate_flag to TRUE to tell the +// mxArray class to convert to the Matlab-style representation and +// then invoke the method on that object instead (for example, getting +// a pointer to real or imaginary data from a complex object requires +// a mutation but getting a pointer to real data from a real object +// does not). Changing the representation causes a copy so we try to +// avoid it unless it is really necessary. Once the conversion +// happens, we delete this representation, so the conversion can only +// happen once per call to a MEX file. + +static inline void *maybe_mark_foreign (void *ptr); + +class mxArray_octave_value : public mxArray_base +{ +public: + + mxArray_octave_value (const octave_value& ov) + : mxArray_base (), val (ov), mutate_flag (false), + id (mxUNKNOWN_CLASS), class_name (0), ndims (-1), dims (0) { } + + mxArray *dup (void) const + { + mxArray *retval = val.as_mxArray (); + + if (! retval) + retval = new mxArray_octave_value (*this); + + return retval; + } + + ~mxArray_octave_value (void) + { + mxFree (class_name); + mxFree (dims); + } + + bool is_octave_value (void) const { return true; } + + int is_cell (void) const { return val.is_cell (); } + + int is_char (void) const { return val.is_string (); } + + int is_complex (void) const { return val.is_complex_type (); } + + int is_double (void) const { return val.is_double_type (); } + + int is_function_handle (void) const { return val.is_function_handle (); } + + int is_int16 (void) const { return val.is_int16_type (); } + + int is_int32 (void) const { return val.is_int32_type (); } + + int is_int64 (void) const { return val.is_int64_type (); } + + int is_int8 (void) const { return val.is_int8_type (); } + + int is_logical (void) const { return val.is_bool_type (); } + + int is_numeric (void) const { return val.is_numeric_type (); } + + int is_single (void) const { return val.is_single_type (); } + + int is_sparse (void) const { return val.is_sparse_type (); } + + int is_struct (void) const { return val.is_map (); } + + int is_uint16 (void) const { return val.is_uint16_type (); } + + int is_uint32 (void) const { return val.is_uint32_type (); } + + int is_uint64 (void) const { return val.is_uint64_type (); } + + int is_uint8 (void) const { return val.is_uint8_type (); } + + int is_range (void) const { return val.is_range (); } + + int is_real_type (void) const { return val.is_real_type (); } + + int is_logical_scalar_true (void) const + { + return (is_logical_scalar () && val.is_true ()); + } + + mwSize get_m (void) const { return val.rows (); } + + mwSize get_n (void) const + { + mwSize n = 1; + + // Force dims and ndims to be cached. + get_dimensions (); + + for (mwIndex i = ndims - 1; i > 0; i--) + n *= dims[i]; + + return n; + } + + mwSize *get_dimensions (void) const + { + if (! dims) + { + ndims = val.ndims (); + + dims = static_cast (malloc (ndims * sizeof (mwSize))); + + dim_vector dv = val.dims (); + + for (mwIndex i = 0; i < ndims; i++) + dims[i] = dv(i); + } + + return dims; + } + + mwSize get_number_of_dimensions (void) const + { + // Force dims and ndims to be cached. + get_dimensions (); + + return ndims; + } + + void set_m (mwSize /*m*/) { request_mutation (); } + + void set_n (mwSize /*n*/) { request_mutation (); } + + void set_dimensions (mwSize */*dims_arg*/, mwSize /*ndims_arg*/) + { + request_mutation (); + } + + mwSize get_number_of_elements (void) const { return val.numel (); } + + int is_empty (void) const { return val.is_empty (); } + + mxClassID get_class_id (void) const + { + id = mxUNKNOWN_CLASS; + + std::string cn = val.class_name (); + + if (cn == "cell") + id = mxCELL_CLASS; + else if (cn == "struct") + id = mxSTRUCT_CLASS; + else if (cn == "logical") + id = mxLOGICAL_CLASS; + else if (cn == "char") + id = mxCHAR_CLASS; + else if (cn == "double") + id = mxDOUBLE_CLASS; + else if (cn == "single") + id = mxSINGLE_CLASS; + else if (cn == "int8") + id = mxINT8_CLASS; + else if (cn == "uint8") + id = mxUINT8_CLASS; + else if (cn == "int16") + id = mxINT16_CLASS; + else if (cn == "uint16") + id = mxUINT16_CLASS; + else if (cn == "int32") + id = mxINT32_CLASS; + else if (cn == "uint32") + id = mxUINT32_CLASS; + else if (cn == "int64") + id = mxINT64_CLASS; + else if (cn == "uint64") + id = mxUINT64_CLASS; + else if (cn == "function_handle") + id = mxFUNCTION_CLASS; + + return id; + } + + const char *get_class_name (void) const + { + if (! class_name) + { + std::string s = val.class_name (); + class_name = strsave (s.c_str ()); + } + + return class_name; + } + + // Not allowed. + void set_class_name (const char */*name_arg*/) { request_mutation (); } + + mxArray *get_cell (mwIndex /*idx*/) const + { + request_mutation (); + return 0; + } + + // Not allowed. + void set_cell (mwIndex /*idx*/, mxArray */*val*/) { request_mutation (); } + + double get_scalar (void) const { return val.scalar_value (true); } + + void *get_data (void) const + { + void *retval = val.mex_get_data (); + + if (retval) + maybe_mark_foreign (retval); + else + request_mutation (); + + return retval; + } + + void *get_imag_data (void) const + { + void *retval = 0; + + if (is_numeric () && is_real_type ()) + retval = 0; + else + request_mutation (); + + return retval; + } + + // Not allowed. + void set_data (void */*pr*/) { request_mutation (); } + + // Not allowed. + void set_imag_data (void */*pi*/) { request_mutation (); } + + mwIndex *get_ir (void) const + { + return static_cast (maybe_mark_foreign (val.mex_get_ir ())); + } + + mwIndex *get_jc (void) const + { + return static_cast (maybe_mark_foreign (val.mex_get_jc ())); + } + + mwSize get_nzmax (void) const { return val.nzmax (); } + + // Not allowed. + void set_ir (mwIndex */*ir*/) { request_mutation (); } + + // Not allowed. + void set_jc (mwIndex */*jc*/) { request_mutation (); } + + // Not allowed. + void set_nzmax (mwSize /*nzmax*/) { request_mutation (); } + + // Not allowed. + int add_field (const char */*key*/) + { + request_mutation (); + return 0; + } + + // Not allowed. + void remove_field (int /*key_num*/) { request_mutation (); } + + mxArray *get_field_by_number (mwIndex /*index*/, int /*key_num*/) const + { + request_mutation (); + return 0; + } + + // Not allowed. + void set_field_by_number (mwIndex /*index*/, int /*key_num*/, mxArray */*val*/) + { + request_mutation (); + } + + int get_number_of_fields (void) const { return val.nfields (); } + + const char *get_field_name_by_number (int /*key_num*/) const + { + request_mutation (); + return 0; + } + + int get_field_number (const char */*key*/) const + { + request_mutation (); + return 0; + } + + int get_string (char *buf, mwSize buflen) const + { + int retval = 1; + + mwSize nel = get_number_of_elements (); + + if (val.is_string () && nel < buflen) + { + charNDArray tmp = val.char_array_value (); + + const char *p = tmp.data (); + + for (mwIndex i = 0; i < nel; i++) + buf[i] = p[i]; + + buf[nel] = 0; + + retval = 0; + } + + return retval; + } + + char *array_to_string (void) const + { + // FIXME -- this is suposed to handle multi-byte character + // strings. + + char *buf = 0; + + if (val.is_string ()) + { + mwSize nel = get_number_of_elements (); + + buf = static_cast (malloc (nel + 1)); + + if (buf) + { + charNDArray tmp = val.char_array_value (); + + const char *p = tmp.data (); + + for (mwIndex i = 0; i < nel; i++) + buf[i] = p[i]; + + buf[nel] = '\0'; + } + } + + return buf; + } + + mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const + { + // Force ndims, dims to be cached. + get_dimensions (); + + return calc_single_subscript_internal (ndims, dims, nsubs, subs); + } + + size_t get_element_size (void) const + { + // Force id to be cached. + get_class_id (); + + switch (id) + { + case mxCELL_CLASS: return sizeof (mxArray *); + case mxSTRUCT_CLASS: return sizeof (mxArray *); + case mxLOGICAL_CLASS: return sizeof (mxLogical); + case mxCHAR_CLASS: return sizeof (mxChar); + case mxDOUBLE_CLASS: return sizeof (double); + case mxSINGLE_CLASS: return sizeof (float); + case mxINT8_CLASS: return 1; + case mxUINT8_CLASS: return 1; + case mxINT16_CLASS: return 2; + case mxUINT16_CLASS: return 2; + case mxINT32_CLASS: return 4; + case mxUINT32_CLASS: return 4; + case mxINT64_CLASS: return 8; + case mxUINT64_CLASS: return 8; + case mxFUNCTION_CLASS: return 0; + default: return 0; + } + } + + bool mutation_needed (void) const { return mutate_flag; } + + void request_mutation (void) const + { + if (mutate_flag) + panic_impossible (); + + mutate_flag = true; + } + + mxArray *mutate (void) const { return val.as_mxArray (); } + +protected: + + octave_value as_octave_value (void) const { return val; } + + mxArray_octave_value (const mxArray_octave_value& arg) + : mxArray_base (arg), val (arg.val), mutate_flag (arg.mutate_flag), + id (arg.id), class_name (strsave (arg.class_name)), ndims (arg.ndims), + dims (ndims > 0 ? static_cast (malloc (ndims * sizeof (mwSize))) : 0) + { + if (dims) + { + for (mwIndex i = 0; i < ndims; i++) + dims[i] = arg.dims[i]; + } + } + +private: + + octave_value val; + + mutable bool mutate_flag; + + // Caching these does not cost much or lead to much duplicated + // code. For other things, we just request mutation to a + // Matlab-style mxArray object. + + mutable mxClassID id; + mutable char *class_name; + mutable mwSize ndims; + mutable mwSize *dims; + + // No assignment! FIXME -- should this be implemented? Note that we + // do have a copy constructor. + + mxArray_octave_value& operator = (const mxArray_octave_value&); +}; + +// The base class for the Matlab-style representation, used to handle +// things that are common to all Matlab-style objects. + +class mxArray_matlab : public mxArray_base +{ +protected: + + mxArray_matlab (mxClassID id_arg = mxUNKNOWN_CLASS) + : mxArray_base (), class_name (0), id (id_arg), ndims (0), dims (0) { } + + mxArray_matlab (mxClassID id_arg, mwSize ndims_arg, const mwSize *dims_arg) + : mxArray_base (), class_name (0), id (id_arg), + ndims (ndims_arg < 2 ? 2 : ndims_arg), + dims (static_cast (malloc (ndims * sizeof (mwSize)))) + { + if (ndims_arg < 2) + { + dims[0] = 1; + dims[1] = 1; + } + + for (mwIndex i = 0; i < ndims_arg; i++) + dims[i] = dims_arg[i]; + + for (mwIndex i = ndims - 1; i > 1; i--) + { + if (dims[i] == 1) + ndims--; + else + break; + } + } + + mxArray_matlab (mxClassID id_arg, const dim_vector& dv) + : mxArray_base (), class_name (0), id (id_arg), + ndims (dv.length ()), + dims (static_cast (malloc (ndims * sizeof (mwSize)))) + { + for (mwIndex i = 0; i < ndims; i++) + dims[i] = dv(i); + + for (mwIndex i = ndims - 1; i > 1; i--) + { + if (dims[i] == 1) + ndims--; + else + break; + } + } + + mxArray_matlab (mxClassID id_arg, mwSize m, mwSize n) + : mxArray_base (), class_name (0), id (id_arg), ndims (2), + dims (static_cast (malloc (ndims * sizeof (mwSize)))) + { + dims[0] = m; + dims[1] = n; + } + +public: + + ~mxArray_matlab (void) + { + mxFree (class_name); + mxFree (dims); + } + + int is_cell (void) const { return id == mxCELL_CLASS; } + + int is_char (void) const { return id == mxCHAR_CLASS; } + + int is_complex (void) const { return 0; } + + int is_double (void) const { return id == mxDOUBLE_CLASS; } + + int is_function_handle (void) const { return id == mxFUNCTION_CLASS; } + + int is_int16 (void) const { return id == mxINT16_CLASS; } + + int is_int32 (void) const { return id == mxINT32_CLASS; } + + int is_int64 (void) const { return id == mxINT64_CLASS; } + + int is_int8 (void) const { return id == mxINT8_CLASS; } + + int is_logical (void) const { return id == mxLOGICAL_CLASS; } + + int is_numeric (void) const + { + return (id == mxDOUBLE_CLASS || id == mxSINGLE_CLASS + || id == mxINT8_CLASS || id == mxUINT8_CLASS + || id == mxINT16_CLASS || id == mxUINT16_CLASS + || id == mxINT32_CLASS || id == mxUINT32_CLASS + || id == mxINT64_CLASS || id == mxUINT64_CLASS); + } + + int is_single (void) const { return id == mxSINGLE_CLASS; } + + int is_sparse (void) const { return 0; } + + int is_struct (void) const { return id == mxSTRUCT_CLASS; } + + int is_uint16 (void) const { return id == mxUINT16_CLASS; } + + int is_uint32 (void) const { return id == mxUINT32_CLASS; } + + int is_uint64 (void) const { return id == mxUINT64_CLASS; } + + int is_uint8 (void) const { return id == mxUINT8_CLASS; } + + int is_logical_scalar_true (void) const + { + return (is_logical_scalar () + && static_cast (get_data ())[0] != 0); + } + + mwSize get_m (void) const { return dims[0]; } + + mwSize get_n (void) const + { + mwSize n = 1; + + for (mwSize i = ndims - 1 ; i > 0 ; i--) + n *= dims[i]; + + return n; + } + + mwSize *get_dimensions (void) const { return dims; } + + mwSize get_number_of_dimensions (void) const { return ndims; } + + void set_m (mwSize m) { dims[0] = m; } + + void set_n (mwSize n) { dims[1] = n; } + + void set_dimensions (mwSize *dims_arg, mwSize ndims_arg) + { + dims = dims_arg; + ndims = ndims_arg; + } + + mwSize get_number_of_elements (void) const + { + mwSize retval = dims[0]; + + for (mwIndex i = 1; i < ndims; i++) + retval *= dims[i]; + + return retval; + } + + int is_empty (void) const { return get_number_of_elements () == 0; } + + mxClassID get_class_id (void) const { return id; } + + const char *get_class_name (void) const + { + switch (id) + { + case mxCELL_CLASS: return "cell"; + case mxSTRUCT_CLASS: return "struct"; + case mxLOGICAL_CLASS: return "logical"; + case mxCHAR_CLASS: return "char"; + case mxDOUBLE_CLASS: return "double"; + case mxSINGLE_CLASS: return "single"; + case mxINT8_CLASS: return "int8"; + case mxUINT8_CLASS: return "uint8"; + case mxINT16_CLASS: return "int16"; + case mxUINT16_CLASS: return "uint16"; + case mxINT32_CLASS: return "int32"; + case mxUINT32_CLASS: return "uint32"; + case mxINT64_CLASS: return "int64"; + case mxUINT64_CLASS: return "uint64"; + case mxFUNCTION_CLASS: return "function_handle"; + default: return "unknown"; + } + } + + void set_class_name (const char *name_arg) + { + mxFree (class_name); + class_name = static_cast (malloc (strlen (name_arg) + 1)); + strcpy (class_name, name_arg); + } + + mxArray *get_cell (mwIndex /*idx*/) const + { + invalid_type_error (); + return 0; + } + + void set_cell (mwIndex /*idx*/, mxArray */*val*/) + { + invalid_type_error (); + } + + double get_scalar (void) const + { + invalid_type_error (); + return 0; + } + + void *get_data (void) const + { + invalid_type_error (); + return 0; + } + + void *get_imag_data (void) const + { + invalid_type_error (); + return 0; + } + + void set_data (void */*pr*/) + { + invalid_type_error (); + } + + void set_imag_data (void */*pi*/) + { + invalid_type_error (); + } + + mwIndex *get_ir (void) const + { + invalid_type_error (); + return 0; + } + + mwIndex *get_jc (void) const + { + invalid_type_error (); + return 0; + } + + mwSize get_nzmax (void) const + { + invalid_type_error (); + return 0; + } + + void set_ir (mwIndex */*ir*/) + { + invalid_type_error (); + } + + void set_jc (mwIndex */*jc*/) + { + invalid_type_error (); + } + + void set_nzmax (mwSize /*nzmax*/) + { + invalid_type_error (); + } + + int add_field (const char */*key*/) + { + invalid_type_error (); + return -1; + } + + void remove_field (int /*key_num*/) + { + invalid_type_error (); + } + + mxArray *get_field_by_number (mwIndex /*index*/, int /*key_num*/) const + { + invalid_type_error (); + return 0; + } + + void set_field_by_number (mwIndex /*index*/, int /*key_num*/, mxArray */*val*/) + { + invalid_type_error (); + } + + int get_number_of_fields (void) const + { + invalid_type_error (); + return 0; + } + + const char *get_field_name_by_number (int /*key_num*/) const + { + invalid_type_error (); + return 0; + } + + int get_field_number (const char */*key*/) const + { + return -1; + } + + int get_string (char */*buf*/, mwSize /*buflen*/) const + { + invalid_type_error (); + return 0; + } + + char *array_to_string (void) const + { + invalid_type_error (); + return 0; + } + + mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const + { + return calc_single_subscript_internal (ndims, dims, nsubs, subs); + } + + size_t get_element_size (void) const + { + switch (id) + { + case mxCELL_CLASS: return sizeof (mxArray *); + case mxSTRUCT_CLASS: return sizeof (mxArray *); + case mxLOGICAL_CLASS: return sizeof (mxLogical); + case mxCHAR_CLASS: return sizeof (mxChar); + case mxDOUBLE_CLASS: return sizeof (double); + case mxSINGLE_CLASS: return sizeof (float); + case mxINT8_CLASS: return 1; + case mxUINT8_CLASS: return 1; + case mxINT16_CLASS: return 2; + case mxUINT16_CLASS: return 2; + case mxINT32_CLASS: return 4; + case mxUINT32_CLASS: return 4; + case mxINT64_CLASS: return 8; + case mxUINT64_CLASS: return 8; + case mxFUNCTION_CLASS: return 0; + default: return 0; + } + } + +protected: + + mxArray_matlab (const mxArray_matlab& val) + : mxArray_base (val), class_name (strsave (val.class_name)), + id (val.id), ndims (val.ndims), + dims (static_cast (malloc (ndims * sizeof (mwSize)))) + { + for (mwIndex i = 0; i < ndims; i++) + dims[i] = val.dims[i]; + } + + dim_vector + dims_to_dim_vector (void) const + { + mwSize nd = get_number_of_dimensions (); + + mwSize *d = get_dimensions (); + + dim_vector dv; + dv.resize (nd); + + for (mwIndex i = 0; i < nd; i++) + dv(i) = d[i]; + + return dv; + } + +private: + + char *class_name; + + mxClassID id; + + mwSize ndims; + mwSize *dims; + + void invalid_type_error (void) const + { + error ("invalid type for operation"); + } + + // No assignment! FIXME -- should this be implemented? Note that we + // do have a copy constructor. + + mxArray_matlab& operator = (const mxArray_matlab&); +}; + +// Matlab-style numeric, character, and logical data. + +class mxArray_number : public mxArray_matlab +{ +public: + + mxArray_number (mxClassID id_arg, mwSize ndims_arg, const mwSize *dims_arg, + mxComplexity flag = mxREAL) + : mxArray_matlab (id_arg, ndims_arg, dims_arg), + pr (calloc (get_number_of_elements (), get_element_size ())), + pi (flag == mxCOMPLEX ? calloc (get_number_of_elements (), get_element_size ()) : 0) { } + + mxArray_number (mxClassID id_arg, const dim_vector& dv, + mxComplexity flag = mxREAL) + : mxArray_matlab (id_arg, dv), + pr (calloc (get_number_of_elements (), get_element_size ())), + pi (flag == mxCOMPLEX ? calloc (get_number_of_elements (), get_element_size ()) : 0) { } + + mxArray_number (mxClassID id_arg, mwSize m, mwSize n, mxComplexity flag = mxREAL) + : mxArray_matlab (id_arg, m, n), + pr (calloc (get_number_of_elements (), get_element_size ())), + pi (flag == mxCOMPLEX ? calloc (get_number_of_elements (), get_element_size ()) : 0) { } + + mxArray_number (mxClassID id_arg, double val) + : mxArray_matlab (id_arg, 1, 1), + pr (calloc (get_number_of_elements (), get_element_size ())), + pi (0) + { + double *dpr = static_cast (pr); + dpr[0] = val; + } + + mxArray_number (mxClassID id_arg, mxLogical val) + : mxArray_matlab (id_arg, 1, 1), + pr (calloc (get_number_of_elements (), get_element_size ())), + pi (0) + { + mxLogical *lpr = static_cast (pr); + lpr[0] = val; + } + + mxArray_number (const char *str) + : mxArray_matlab (mxCHAR_CLASS, + str ? (strlen (str) ? 1 : 0) : 0, + str ? strlen (str) : 0), + pr (calloc (get_number_of_elements (), get_element_size ())), + pi (0) + { + mxChar *cpr = static_cast (pr); + mwSize nel = get_number_of_elements (); + for (mwIndex i = 0; i < nel; i++) + cpr[i] = str[i]; + } + + // FIXME?? + mxArray_number (mwSize m, const char **str) + : mxArray_matlab (mxCHAR_CLASS, m, max_str_len (m, str)), + pr (calloc (get_number_of_elements (), get_element_size ())), + pi (0) + { + mxChar *cpr = static_cast (pr); + + mwSize *dv = get_dimensions (); + + mwSize nc = dv[1]; + + for (mwIndex j = 0; j < m; j++) + { + const char *ptr = str[j]; + + size_t tmp_len = strlen (ptr); + + for (size_t i = 0; i < tmp_len; i++) + cpr[m*i+j] = static_cast (ptr[i]); + + for (size_t i = tmp_len; i < static_cast(nc); i++) + cpr[m*i+j] = static_cast (' '); + } + } + + mxArray_number *dup (void) const { return new mxArray_number (*this); } + + ~mxArray_number (void) + { + mxFree (pr); + mxFree (pi); + } + + int is_complex (void) const { return pi != 0; } + + double get_scalar (void) const + { + double retval = 0; + + switch (get_class_id ()) + { + case mxLOGICAL_CLASS: + retval = *(static_cast (pr)); + break; + + case mxCHAR_CLASS: + retval = *(static_cast (pr)); + break; + + case mxSINGLE_CLASS: + retval = *(static_cast (pr)); + break; + + case mxDOUBLE_CLASS: + retval = *(static_cast (pr)); + break; + + case mxINT8_CLASS: + retval = *(static_cast (pr)); + break; + + case mxUINT8_CLASS: + retval = *(static_cast (pr)); + break; + + case mxINT16_CLASS: + retval = *(static_cast (pr)); + break; + + case mxUINT16_CLASS: + retval = *(static_cast (pr)); + break; + + case mxINT32_CLASS: + retval = *(static_cast (pr)); + break; + + case mxUINT32_CLASS: + retval = *(static_cast (pr)); + break; + + case mxINT64_CLASS: + retval = *(static_cast (pr)); + break; + + case mxUINT64_CLASS: + retval = *(static_cast (pr)); + break; + + default: + panic_impossible (); + } + + return retval; + } + + void *get_data (void) const { return pr; } + + void *get_imag_data (void) const { return pi; } + + void set_data (void *pr_arg) { pr = pr_arg; } + + void set_imag_data (void *pi_arg) { pi = pi_arg; } + + int get_string (char *buf, mwSize buflen) const + { + int retval = 0; + + mwSize nel = get_number_of_elements (); + + if (! (nel < buflen)) + { + retval = 1; + if (buflen > 0) + nel = buflen-1; + } + + if (nel < buflen) + { + mxChar *ptr = static_cast (pr); + + for (mwIndex i = 0; i < nel; i++) + buf[i] = static_cast (ptr[i]); + + buf[nel] = 0; + } + + return retval; + } + + char *array_to_string (void) const + { + // FIXME -- this is suposed to handle multi-byte character + // strings. + + mwSize nel = get_number_of_elements (); + + char *buf = static_cast (malloc (nel + 1)); + + if (buf) + { + mxChar *ptr = static_cast (pr); + + for (mwIndex i = 0; i < nel; i++) + buf[i] = static_cast (ptr[i]); + + buf[nel] = '\0'; + } + + return buf; + } + +protected: + + template + octave_value + int_to_ov (const dim_vector& dv) const + { + octave_value retval; + + mwSize nel = get_number_of_elements (); + + ELT_T *ppr = static_cast (pr); + + if (pi) + error ("complex integer types are not supported"); + else + { + ARRAY_T val (dv); + + ARRAY_ELT_T *ptr = val.fortran_vec (); + + for (mwIndex i = 0; i < nel; i++) + ptr[i] = ppr[i]; + + retval = val; + } + + return retval; + } + + octave_value as_octave_value (void) const + { + octave_value retval; + + dim_vector dv = dims_to_dim_vector (); + + switch (get_class_id ()) + { + case mxLOGICAL_CLASS: + retval = int_to_ov (dv); + break; + + case mxCHAR_CLASS: + { + mwSize nel = get_number_of_elements (); + + mxChar *ppr = static_cast (pr); + + charNDArray val (dv); + + char *ptr = val.fortran_vec (); + + for (mwIndex i = 0; i < nel; i++) + ptr[i] = static_cast (ppr[i]); + + retval = val; + } + break; + + case mxSINGLE_CLASS: + { + mwSize nel = get_number_of_elements (); + + float *ppr = static_cast (pr); + + if (pi) + { + FloatComplexNDArray val (dv); + + FloatComplex *ptr = val.fortran_vec (); + + float *ppi = static_cast (pi); + + for (mwIndex i = 0; i < nel; i++) + ptr[i] = FloatComplex (ppr[i], ppi[i]); + + retval = val; + } + else + { + FloatNDArray val (dv); + + float *ptr = val.fortran_vec (); + + for (mwIndex i = 0; i < nel; i++) + ptr[i] = ppr[i]; + + retval = val; + } + } + break; + + case mxDOUBLE_CLASS: + { + mwSize nel = get_number_of_elements (); + + double *ppr = static_cast (pr); + + if (pi) + { + ComplexNDArray val (dv); + + Complex *ptr = val.fortran_vec (); + + double *ppi = static_cast (pi); + + for (mwIndex i = 0; i < nel; i++) + ptr[i] = Complex (ppr[i], ppi[i]); + + retval = val; + } + else + { + NDArray val (dv); + + double *ptr = val.fortran_vec (); + + for (mwIndex i = 0; i < nel; i++) + ptr[i] = ppr[i]; + + retval = val; + } + } + break; + + case mxINT8_CLASS: + retval = int_to_ov (dv); + break; + + case mxUINT8_CLASS: + retval = int_to_ov (dv); + break; + + case mxINT16_CLASS: + retval = int_to_ov (dv); + break; + + case mxUINT16_CLASS: + retval = int_to_ov (dv); + break; + + case mxINT32_CLASS: + retval = int_to_ov (dv); + break; + + case mxUINT32_CLASS: + retval = int_to_ov (dv); + break; + + case mxINT64_CLASS: + retval = int_to_ov (dv); + break; + + case mxUINT64_CLASS: + retval = int_to_ov (dv); + break; + + default: + panic_impossible (); + } + + return retval; + } + + mxArray_number (const mxArray_number& val) + : mxArray_matlab (val), + pr (malloc (get_number_of_elements () * get_element_size ())), + pi (val.pi ? malloc (get_number_of_elements () * get_element_size ()) : 0) + { + size_t nbytes = get_number_of_elements () * get_element_size (); + + if (pr) + memcpy (pr, val.pr, nbytes); + + if (pi) + memcpy (pi, val.pi, nbytes); + } + +private: + + void *pr; + void *pi; + + // No assignment! FIXME -- should this be implemented? Note that we + // do have a copy constructor. + + mxArray_number& operator = (const mxArray_number&); +}; + +// Matlab-style sparse arrays. + +class mxArray_sparse : public mxArray_matlab +{ +public: + + mxArray_sparse (mxClassID id_arg, mwSize m, mwSize n, mwSize nzmax_arg, + mxComplexity flag = mxREAL) + : mxArray_matlab (id_arg, m, n), nzmax (nzmax_arg), + pr (calloc (nzmax, get_element_size ())), + pi (flag == mxCOMPLEX ? calloc (nzmax, get_element_size ()) : 0), + ir (static_cast (calloc (nzmax, sizeof (mwIndex)))), + jc (static_cast (calloc (n + 1, sizeof (mwIndex)))) + { } + + mxArray_sparse *dup (void) const { return new mxArray_sparse (*this); } + + ~mxArray_sparse (void) + { + mxFree (pr); + mxFree (pi); + mxFree (ir); + mxFree (jc); + } + + int is_complex (void) const { return pi != 0; } + + int is_sparse (void) const { return 1; } + + void *get_data (void) const { return pr; } + + void *get_imag_data (void) const { return pi; } + + void set_data (void *pr_arg) { pr = pr_arg; } + + void set_imag_data (void *pi_arg) { pi = pi_arg; } + + mwIndex *get_ir (void) const { return ir; } + + mwIndex *get_jc (void) const { return jc; } + + mwSize get_nzmax (void) const { return nzmax; } + + void set_ir (mwIndex *ir_arg) { ir = ir_arg; } + + void set_jc (mwIndex *jc_arg) { jc = jc_arg; } + + void set_nzmax (mwSize nzmax_arg) { nzmax = nzmax_arg; } + +protected: + + octave_value as_octave_value (void) const + { + octave_value retval; + + dim_vector dv = dims_to_dim_vector (); + + switch (get_class_id ()) + { + case mxLOGICAL_CLASS: + { + bool *ppr = static_cast (pr); + + SparseBoolMatrix val (get_m (), get_n (), + static_cast (nzmax)); + + for (mwIndex i = 0; i < nzmax; i++) + { + val.xdata (i) = ppr[i]; + val.xridx (i) = ir[i]; + } + + for (mwIndex i = 0; i < get_n () + 1; i++) + val.xcidx (i) = jc[i]; + + retval = val; + } + break; + + case mxSINGLE_CLASS: + error ("single precision sparse data type not supported"); + break; + + case mxDOUBLE_CLASS: + { + if (pi) + { + double *ppr = static_cast (pr); + double *ppi = static_cast (pi); + + SparseComplexMatrix val (get_m (), get_n (), + static_cast (nzmax)); + + for (mwIndex i = 0; i < nzmax; i++) + { + val.xdata (i) = Complex (ppr[i], ppi[i]); + val.xridx (i) = ir[i]; + } + + for (mwIndex i = 0; i < get_n () + 1; i++) + val.xcidx (i) = jc[i]; + + retval = val; + } + else + { + double *ppr = static_cast (pr); + + SparseMatrix val (get_m (), get_n (), + static_cast (nzmax)); + + for (mwIndex i = 0; i < nzmax; i++) + { + val.xdata (i) = ppr[i]; + val.xridx (i) = ir[i]; + } + + for (mwIndex i = 0; i < get_n () + 1; i++) + val.xcidx (i) = jc[i]; + + retval = val; + } + } + break; + + default: + panic_impossible (); + } + + return retval; + } + +private: + + mwSize nzmax; + + void *pr; + void *pi; + mwIndex *ir; + mwIndex *jc; + + mxArray_sparse (const mxArray_sparse& val) + : mxArray_matlab (val), nzmax (val.nzmax), + pr (malloc (nzmax * get_element_size ())), + pi (val.pi ? malloc (nzmax * get_element_size ()) : 0), + ir (static_cast (malloc (nzmax * sizeof (mwIndex)))), + jc (static_cast (malloc (nzmax * sizeof (mwIndex)))) + { + size_t nbytes = nzmax * get_element_size (); + + if (pr) + memcpy (pr, val.pr, nbytes); + + if (pi) + memcpy (pi, val.pi, nbytes); + + if (ir) + memcpy (ir, val.ir, nzmax * sizeof (mwIndex)); + + if (jc) + memcpy (jc, val.jc, (val.get_n () + 1) * sizeof (mwIndex)); + } + + // No assignment! FIXME -- should this be implemented? Note that we + // do have a copy constructor. + + mxArray_sparse& operator = (const mxArray_sparse&); +}; + +// Matlab-style struct arrays. + +class mxArray_struct : public mxArray_matlab +{ +public: + + mxArray_struct (mwSize ndims_arg, const mwSize *dims_arg, int num_keys_arg, + const char **keys) + : mxArray_matlab (mxSTRUCT_CLASS, ndims_arg, dims_arg), nfields (num_keys_arg), + fields (static_cast (calloc (nfields, sizeof (char *)))), + data (static_cast (calloc (nfields * get_number_of_elements (), sizeof (mxArray *)))) + { + init (keys); + } + + mxArray_struct (const dim_vector& dv, int num_keys_arg, const char **keys) + : mxArray_matlab (mxSTRUCT_CLASS, dv), nfields (num_keys_arg), + fields (static_cast (calloc (nfields, sizeof (char *)))), + data (static_cast (calloc (nfields * get_number_of_elements (), sizeof (mxArray *)))) + { + init (keys); + } + + mxArray_struct (mwSize m, mwSize n, int num_keys_arg, const char **keys) + : mxArray_matlab (mxSTRUCT_CLASS, m, n), nfields (num_keys_arg), + fields (static_cast (calloc (nfields, sizeof (char *)))), + data (static_cast (calloc (nfields * get_number_of_elements (), sizeof (mxArray *)))) + { + init (keys); + } + + void init (const char **keys) + { + for (int i = 0; i < nfields; i++) + fields[i] = strsave (keys[i]); + } + + mxArray_struct *dup (void) const { return new mxArray_struct (*this); } + + ~mxArray_struct (void) + { + for (int i = 0; i < nfields; i++) + mxFree (fields[i]); + + mxFree (fields); + + mwSize ntot = nfields * get_number_of_elements (); + + for (mwIndex i = 0; i < ntot; i++) + delete data[i]; + + mxFree (data); + } + + int add_field (const char *key) + { + int retval = -1; + + if (valid_key (key)) + { + nfields++; + + fields = static_cast (mxRealloc (fields, nfields * sizeof (char *))); + + if (fields) + { + fields[nfields-1] = strsave (key); + + mwSize nel = get_number_of_elements (); + + mwSize ntot = nfields * nel; + + mxArray **new_data = static_cast (malloc (ntot * sizeof (mxArray *))); + + if (new_data) + { + mwIndex j = 0; + mwIndex k = 0; + mwIndex n = 0; + + for (mwIndex i = 0; i < ntot; i++) + { + if (++n == nfields) + { + new_data[j++] = 0; + n = 0; + } + else + new_data[j++] = data[k++]; + } + + mxFree (data); + + data = new_data; + + retval = nfields - 1; + } + } + } + + return retval; + } + + void remove_field (int key_num) + { + if (key_num >= 0 && key_num < nfields) + { + mwSize nel = get_number_of_elements (); + + mwSize ntot = nfields * nel; + + int new_nfields = nfields - 1; + + char **new_fields = static_cast (malloc (new_nfields * sizeof (char *))); + + mxArray **new_data = static_cast (malloc (new_nfields * nel * sizeof (mxArray *))); + + for (int i = 0; i < key_num; i++) + new_fields[i] = fields[i]; + + for (int i = key_num + 1; i < nfields; i++) + new_fields[i-1] = fields[i]; + + if (new_nfields > 0) + { + mwIndex j = 0; + mwIndex k = 0; + mwIndex n = 0; + + for (mwIndex i = 0; i < ntot; i++) + { + if (n == key_num) + k++; + else + new_data[j++] = data[k++]; + + if (++n == nfields) + n = 0; + } + } + + nfields = new_nfields; + + mxFree (fields); + mxFree (data); + + fields = new_fields; + data = new_data; + } + } + + mxArray *get_field_by_number (mwIndex index, int key_num) const + { + return key_num >= 0 && key_num < nfields + ? data[nfields * index + key_num] : 0; + } + + void set_field_by_number (mwIndex index, int key_num, mxArray *val); + + int get_number_of_fields (void) const { return nfields; } + + const char *get_field_name_by_number (int key_num) const + { + return key_num >= 0 && key_num < nfields ? fields[key_num] : 0; + } + + int get_field_number (const char *key) const + { + int retval = -1; + + for (int i = 0; i < nfields; i++) + { + if (! strcmp (key, fields[i])) + { + retval = i; + break; + } + } + + return retval; + } + + void *get_data (void) const { return data; } + + void set_data (void *data_arg) { data = static_cast (data_arg); } + +protected: + + octave_value as_octave_value (void) const + { + dim_vector dv = dims_to_dim_vector (); + + string_vector keys (fields, nfields); + + octave_map m; + + mwSize ntot = nfields * get_number_of_elements (); + + for (int i = 0; i < nfields; i++) + { + Cell c (dv); + + octave_value *p = c.fortran_vec (); + + mwIndex k = 0; + for (mwIndex j = i; j < ntot; j += nfields) + p[k++] = mxArray::as_octave_value (data[j]); + + m.assign (keys[i], c); + } + + return m; + } + +private: + + int nfields; + + char **fields; + + mxArray **data; + + mxArray_struct (const mxArray_struct& val) + : mxArray_matlab (val), nfields (val.nfields), + fields (static_cast (malloc (nfields * sizeof (char *)))), + data (static_cast (malloc (nfields * get_number_of_elements () * sizeof (mxArray *)))) + { + for (int i = 0; i < nfields; i++) + fields[i] = strsave (val.fields[i]); + + mwSize nel = get_number_of_elements (); + + for (mwIndex i = 0; i < nel * nfields; i++) + { + mxArray *ptr = val.data[i]; + data[i] = ptr ? ptr->dup () : 0; + } + } + + // No assignment! FIXME -- should this be implemented? Note that we + // do have a copy constructor. + + mxArray_struct& operator = (const mxArray_struct& val); +}; + +// Matlab-style cell arrays. + +class mxArray_cell : public mxArray_matlab +{ +public: + + mxArray_cell (mwSize ndims_arg, const mwSize *dims_arg) + : mxArray_matlab (mxCELL_CLASS, ndims_arg, dims_arg), + data (static_cast (calloc (get_number_of_elements (), sizeof (mxArray *)))) { } + + mxArray_cell (const dim_vector& dv) + : mxArray_matlab (mxCELL_CLASS, dv), + data (static_cast (calloc (get_number_of_elements (), sizeof (mxArray *)))) { } + + mxArray_cell (mwSize m, mwSize n) + : mxArray_matlab (mxCELL_CLASS, m, n), + data (static_cast (calloc (get_number_of_elements (), sizeof (mxArray *)))) { } + + mxArray_cell *dup (void) const { return new mxArray_cell (*this); } + + ~mxArray_cell (void) + { + mwSize nel = get_number_of_elements (); + + for (mwIndex i = 0; i < nel; i++) + delete data[i]; + + mxFree (data); + } + + mxArray *get_cell (mwIndex idx) const + { + return idx >= 0 && idx < get_number_of_elements () ? data[idx] : 0; + } + + void set_cell (mwIndex idx, mxArray *val); + + void *get_data (void) const { return data; } + + void set_data (void *data_arg) { data = static_cast (data_arg); } + +protected: + + octave_value as_octave_value (void) const + { + dim_vector dv = dims_to_dim_vector (); + + Cell c (dv); + + mwSize nel = get_number_of_elements (); + + octave_value *p = c.fortran_vec (); + + for (mwIndex i = 0; i < nel; i++) + p[i] = mxArray::as_octave_value (data[i]); + + return c; + } + +private: + + mxArray **data; + + mxArray_cell (const mxArray_cell& val) + : mxArray_matlab (val), + data (static_cast (malloc (get_number_of_elements () * sizeof (mxArray *)))) + { + mwSize nel = get_number_of_elements (); + + for (mwIndex i = 0; i < nel; i++) + { + mxArray *ptr = val.data[i]; + data[i] = ptr ? ptr->dup () : 0; + } + } + + // No assignment! FIXME -- should this be implemented? Note that we + // do have a copy constructor. + + mxArray_cell& operator = (const mxArray_cell&); +}; + +// ------------------------------------------------------------------ + +mxArray::mxArray (const octave_value& ov) + : rep (new mxArray_octave_value (ov)), name (0) { } + +mxArray::mxArray (mxClassID id, mwSize ndims, const mwSize *dims, mxComplexity flag) + : rep (new mxArray_number (id, ndims, dims, flag)), name (0) { } + +mxArray::mxArray (mxClassID id, const dim_vector& dv, mxComplexity flag) + : rep (new mxArray_number (id, dv, flag)), name (0) { } + +mxArray::mxArray (mxClassID id, mwSize m, mwSize n, mxComplexity flag) + : rep (new mxArray_number (id, m, n, flag)), name (0) { } + +mxArray::mxArray (mxClassID id, double val) + : rep (new mxArray_number (id, val)), name (0) { } + +mxArray::mxArray (mxClassID id, mxLogical val) + : rep (new mxArray_number (id, val)), name (0) { } + +mxArray::mxArray (const char *str) + : rep (new mxArray_number (str)), name (0) { } + +mxArray::mxArray (mwSize m, const char **str) + : rep (new mxArray_number (m, str)), name (0) { } + +mxArray::mxArray (mxClassID id, mwSize m, mwSize n, mwSize nzmax, mxComplexity flag) + : rep (new mxArray_sparse (id, m, n, nzmax, flag)), name (0) { } + +mxArray::mxArray (mwSize ndims, const mwSize *dims, int num_keys, const char **keys) + : rep (new mxArray_struct (ndims, dims, num_keys, keys)), name (0) { } + +mxArray::mxArray (const dim_vector& dv, int num_keys, const char **keys) + : rep (new mxArray_struct (dv, num_keys, keys)), name (0) { } + +mxArray::mxArray (mwSize m, mwSize n, int num_keys, const char **keys) + : rep (new mxArray_struct (m, n, num_keys, keys)), name (0) { } + +mxArray::mxArray (mwSize ndims, const mwSize *dims) + : rep (new mxArray_cell (ndims, dims)), name (0) { } + +mxArray::mxArray (const dim_vector& dv) + : rep (new mxArray_cell (dv)), name (0) { } + +mxArray::mxArray (mwSize m, mwSize n) + : rep (new mxArray_cell (m, n)), name (0) { } + +mxArray::~mxArray (void) +{ + mxFree (name); + + delete rep; +} + +void +mxArray::set_name (const char *name_arg) +{ + mxFree (name); + name = strsave (name_arg); +} + +octave_value +mxArray::as_octave_value (mxArray *ptr) +{ + return ptr ? ptr->as_octave_value () : octave_value (Matrix ()); +} + +octave_value +mxArray::as_octave_value (void) const +{ + return rep->as_octave_value (); +} + +void +mxArray::maybe_mutate (void) const +{ + if (rep->is_octave_value ()) + { + // The mutate function returns a pointer to a complete new + // mxArray object (or 0, if no mutation happened). We just want + // to replace the existing rep with the rep from the new object. + + mxArray *new_val = rep->mutate (); + + if (new_val) + { + delete rep; + rep = new_val->rep; + new_val->rep = 0; + delete new_val; + } + } +} + +// ------------------------------------------------------------------ + +// A class to manage calls to MEX functions. Mostly deals with memory +// management. + +class mex +{ +public: + + mex (octave_mex_function *f) + : curr_mex_fcn (f), memlist (), arraylist (), fname (0) { } + + ~mex (void) + { + if (! memlist.empty ()) + error ("mex: %s: cleanup failed", function_name ()); + + mxFree (fname); + } + + const char *function_name (void) const + { + if (! fname) + { + octave_function *fcn = octave_call_stack::current (); + + if (fcn) + { + std::string nm = fcn->name (); + fname = mxArray::strsave (nm.c_str ()); + } + else + fname = mxArray::strsave ("unknown"); + } + + return fname; + } + + // Free all unmarked pointers obtained from malloc and calloc. + static void cleanup (void *ptr) + { + mex *context = static_cast (ptr); + + // We can't use mex::free here because it modifies memlist. + for (std::set::iterator p = context->memlist.begin (); + p != context->memlist.end (); p++) + xfree (*p); + + context->memlist.clear (); + + // We can't use mex::free_value here because it modifies arraylist. + for (std::set::iterator p = context->arraylist.begin (); + p != context->arraylist.end (); p++) + delete *p; + + context->arraylist.clear (); + } + + // Allocate memory. + void *malloc_unmarked (size_t n) + { + void *ptr = gnulib::malloc (n); + + if (! ptr) + { + // FIXME -- could use "octave_new_handler();" instead + + error ("%s: failed to allocate %d bytes of memory", + function_name (), n); + + abort (); + } + + global_mark (ptr); + + return ptr; + } + + // Allocate memory to be freed on exit. + void *malloc (size_t n) + { + void *ptr = malloc_unmarked (n); + + mark (ptr); + + return ptr; + } + + // Allocate memory and initialize to 0. + void *calloc_unmarked (size_t n, size_t t) + { + void *ptr = malloc_unmarked (n*t); + + memset (ptr, 0, n*t); + + return ptr; + } + + // Allocate memory to be freed on exit and initialize to 0. + void *calloc (size_t n, size_t t) + { + void *ptr = calloc_unmarked (n, t); + + mark (ptr); + + return ptr; + } + + // Reallocate a pointer obtained from malloc or calloc. If the + // pointer is NULL, allocate using malloc. We don't need an + // "unmarked" version of this. + void *realloc (void *ptr, size_t n) + { + void *v; + + if (ptr) + { + v = gnulib::realloc (ptr, n); + + std::set::iterator p = memlist.find (ptr); + + if (v && p != memlist.end ()) + { + memlist.erase (p); + memlist.insert (v); + } + + p = global_memlist.find (ptr); + + if (v && p != global_memlist.end ()) + { + global_memlist.erase (p); + global_memlist.insert (v); + } + } + else + v = malloc (n); + + return v; + } + + // Free a pointer obtained from malloc or calloc. + void free (void *ptr) + { + if (ptr) + { + unmark (ptr); + + std::set::iterator p = global_memlist.find (ptr); + + if (p != global_memlist.end ()) + { + global_memlist.erase (p); + + xfree (ptr); + } + else + { + p = foreign_memlist.find (ptr); + + if (p != foreign_memlist.end ()) + foreign_memlist.erase (p); +#ifdef DEBUG + else + warning ("mxFree: skipping memory not allocated by mxMalloc, mxCalloc, or mxRealloc"); +#endif + } + } + } + + // Mark a pointer to be freed on exit. + void mark (void *ptr) + { +#ifdef DEBUG + if (memlist.find (ptr) != memlist.end ()) + warning ("%s: double registration ignored", function_name ()); +#endif + + memlist.insert (ptr); + } + + // Unmark a pointer to be freed on exit, either because it was + // made persistent, or because it was already freed. + void unmark (void *ptr) + { + std::set::iterator p = memlist.find (ptr); + + if (p != memlist.end ()) + memlist.erase (p); +#ifdef DEBUG + else + warning ("%s: value not marked", function_name ()); +#endif + } + + mxArray *mark_array (mxArray *ptr) + { + arraylist.insert (ptr); + return ptr; + } + + void unmark_array (mxArray *ptr) + { + std::set::iterator p = arraylist.find (ptr); + + if (p != arraylist.end ()) + arraylist.erase (p); + } + + // Mark a pointer as one we allocated. + void mark_foreign (void *ptr) + { +#ifdef DEBUG + if (foreign_memlist.find (ptr) != foreign_memlist.end ()) + warning ("%s: double registration ignored", function_name ()); +#endif + + foreign_memlist.insert (ptr); + } + + // Unmark a pointer as one we allocated. + void unmark_foreign (void *ptr) + { + std::set::iterator p = foreign_memlist.find (ptr); + + if (p != foreign_memlist.end ()) + foreign_memlist.erase (p); +#ifdef DEBUG + else + warning ("%s: value not marked", function_name ()); +#endif + + } + + // Make a new array value and initialize from an octave value; it will be + // freed on exit unless marked as persistent. + mxArray *make_value (const octave_value& ov) + { + return mark_array (new mxArray (ov)); + } + + // Free an array and its contents. + bool free_value (mxArray *ptr) + { + bool inlist = false; + + std::set::iterator p = arraylist.find (ptr); + + if (p != arraylist.end ()) + { + inlist = true; + arraylist.erase (p); + delete ptr; + } +#ifdef DEBUG + else + warning ("mex::free_value: skipping memory not allocated by mex::make_value"); +#endif + + return inlist; + } + + octave_mex_function *current_mex_function (void) const + { + return curr_mex_fcn; + } + + // 1 if error should be returned to MEX file, 0 if abort. + int trap_feval_error; + + // longjmp return point if mexErrMsgTxt or error. + jmp_buf jump; + + // Trigger a long jump back to the mex calling function. + void abort (void) { longjmp (jump, 1); } + +private: + + // Pointer to the mex function that corresponds to this mex context. + octave_mex_function *curr_mex_fcn; + + // List of memory resources that need to be freed upon exit. + std::set memlist; + + // List of mxArray objects that need to be freed upon exit. + std::set arraylist; + + // List of memory resources we know about, but that were allocated + // elsewhere. + std::set foreign_memlist; + + // The name of the currently executing function. + mutable char *fname; + + // List of memory resources we allocated. + static std::set global_memlist; + + // Mark a pointer as one we allocated. + void global_mark (void *ptr) + { +#ifdef DEBUG + if (global_memlist.find (ptr) != global_memlist.end ()) + warning ("%s: double registration ignored", function_name ()); +#endif + + global_memlist.insert (ptr); + } + + // Unmark a pointer as one we allocated. + void global_unmark (void *ptr) + { + std::set::iterator p = global_memlist.find (ptr); + + if (p != global_memlist.end ()) + global_memlist.erase (p); +#ifdef DEBUG + else + warning ("%s: value not marked", function_name ()); +#endif + + } + + // No copying! + + mex (const mex&); + + mex& operator = (const mex&); +}; + +// List of memory resources we allocated. +std::set mex::global_memlist; + +// Current context. +mex *mex_context = 0; + +void * +mxArray::malloc (size_t n) +{ + return mex_context ? mex_context->malloc_unmarked (n) : gnulib::malloc (n); +} + +void * +mxArray::calloc (size_t n, size_t t) +{ + return mex_context ? mex_context->calloc_unmarked (n, t) : ::calloc (n, t); +} + +static inline void * +maybe_mark_foreign (void *ptr) +{ + if (mex_context) + mex_context->mark_foreign (ptr); + + return ptr; +} + +static inline mxArray * +maybe_unmark_array (mxArray *ptr) +{ + if (mex_context) + mex_context->unmark_array (ptr); + + return ptr; +} + +static inline void * +maybe_unmark (void *ptr) +{ + if (mex_context) + mex_context->unmark (ptr); + + return ptr; +} + +void +mxArray_struct::set_field_by_number (mwIndex index, int key_num, mxArray *val) +{ + if (key_num >= 0 && key_num < nfields) + data[nfields * index + key_num] = maybe_unmark_array (val); +} + +void +mxArray_cell::set_cell (mwIndex idx, mxArray *val) +{ + if (idx >= 0 && idx < get_number_of_elements ()) + data[idx] = maybe_unmark_array (val); +} + +// ------------------------------------------------------------------ + +// C interface to mxArray objects: + +// Floating point predicates. + +int +mxIsFinite (const double v) +{ + return lo_ieee_finite (v) != 0; +} + +int +mxIsInf (const double v) +{ + return lo_ieee_isinf (v) != 0; +} + +int +mxIsNaN (const double v) +{ + return lo_ieee_isnan (v) != 0; +} + +double +mxGetEps (void) +{ + return DBL_EPSILON; +} + +double +mxGetInf (void) +{ + return lo_ieee_inf_value (); +} + +double +mxGetNaN (void) +{ + return lo_ieee_nan_value (); +} + +// Memory management. +void * +mxCalloc (size_t n, size_t size) +{ + return mex_context ? mex_context->calloc (n, size) : calloc (n, size); +} + +void * +mxMalloc (size_t n) +{ + return mex_context ? mex_context->malloc (n) : gnulib::malloc (n); +} + +void * +mxRealloc (void *ptr, size_t size) +{ + return mex_context ? mex_context->realloc (ptr, size) : gnulib::realloc (ptr, size); +} + +void +mxFree (void *ptr) +{ + if (mex_context) + mex_context->free (ptr); + else + xfree (ptr); +} + +static inline mxArray * +maybe_mark_array (mxArray *ptr) +{ + return mex_context ? mex_context->mark_array (ptr) : ptr; +} + +// Constructors. +mxArray * +mxCreateCellArray (mwSize ndims, const mwSize *dims) +{ + return maybe_mark_array (new mxArray (ndims, dims)); +} + +mxArray * +mxCreateCellMatrix (mwSize m, mwSize n) +{ + return maybe_mark_array (new mxArray (m, n)); +} + +mxArray * +mxCreateCharArray (mwSize ndims, const mwSize *dims) +{ + return maybe_mark_array (new mxArray (mxCHAR_CLASS, ndims, dims)); +} + +mxArray * +mxCreateCharMatrixFromStrings (mwSize m, const char **str) +{ + return maybe_mark_array (new mxArray (m, str)); +} + +mxArray * +mxCreateDoubleMatrix (mwSize m, mwSize n, mxComplexity flag) +{ + return maybe_mark_array (new mxArray (mxDOUBLE_CLASS, m, n, flag)); +} + +mxArray * +mxCreateDoubleScalar (double val) +{ + return maybe_mark_array (new mxArray (mxDOUBLE_CLASS, val)); +} + +mxArray * +mxCreateLogicalArray (mwSize ndims, const mwSize *dims) +{ + return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, ndims, dims)); +} + +mxArray * +mxCreateLogicalMatrix (mwSize m, mwSize n) +{ + return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, m, n)); +} + +mxArray * +mxCreateLogicalScalar (mxLogical val) +{ + return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, val)); +} + +mxArray * +mxCreateNumericArray (mwSize ndims, const mwSize *dims, mxClassID class_id, + mxComplexity flag) +{ + return maybe_mark_array (new mxArray (class_id, ndims, dims, flag)); +} + +mxArray * +mxCreateNumericMatrix (mwSize m, mwSize n, mxClassID class_id, mxComplexity flag) +{ + return maybe_mark_array (new mxArray (class_id, m, n, flag)); +} + +mxArray * +mxCreateSparse (mwSize m, mwSize n, mwSize nzmax, mxComplexity flag) +{ + return maybe_mark_array (new mxArray (mxDOUBLE_CLASS, m, n, nzmax, flag)); +} + +mxArray * +mxCreateSparseLogicalMatrix (mwSize m, mwSize n, mwSize nzmax) +{ + return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, m, n, nzmax)); +} + +mxArray * +mxCreateString (const char *str) +{ + return maybe_mark_array (new mxArray (str)); +} + +mxArray * +mxCreateStructArray (mwSize ndims, const mwSize *dims, int num_keys, const char **keys) +{ + return maybe_mark_array (new mxArray (ndims, dims, num_keys, keys)); +} + +mxArray * +mxCreateStructMatrix (mwSize m, mwSize n, int num_keys, const char **keys) +{ + return maybe_mark_array (new mxArray (m, n, num_keys, keys)); +} + +// Copy constructor. +mxArray * +mxDuplicateArray (const mxArray *ptr) +{ + return maybe_mark_array (ptr->dup ()); +} + +// Destructor. +void +mxDestroyArray (mxArray *ptr) +{ + if (! (mex_context && mex_context->free_value (ptr))) + delete ptr; +} + +// Type Predicates. +int +mxIsCell (const mxArray *ptr) +{ + return ptr->is_cell (); +} + +int +mxIsChar (const mxArray *ptr) +{ + return ptr->is_char (); +} + +int +mxIsClass (const mxArray *ptr, const char *name) +{ + return ptr->is_class (name); +} + +int +mxIsComplex (const mxArray *ptr) +{ + return ptr->is_complex (); +} + +int +mxIsDouble (const mxArray *ptr) +{ + return ptr->is_double (); +} + +int +mxIsFunctionHandle (const mxArray *ptr) +{ + return ptr->is_function_handle (); +} + +int +mxIsInt16 (const mxArray *ptr) +{ + return ptr->is_int16 (); +} + +int +mxIsInt32 (const mxArray *ptr) +{ + return ptr->is_int32 (); +} + +int +mxIsInt64 (const mxArray *ptr) +{ + return ptr->is_int64 (); +} + +int +mxIsInt8 (const mxArray *ptr) +{ + return ptr->is_int8 (); +} + +int +mxIsLogical (const mxArray *ptr) +{ + return ptr->is_logical (); +} + +int +mxIsNumeric (const mxArray *ptr) +{ + return ptr->is_numeric (); +} + +int +mxIsSingle (const mxArray *ptr) +{ + return ptr->is_single (); +} + +int +mxIsSparse (const mxArray *ptr) +{ + return ptr->is_sparse (); +} + +int +mxIsStruct (const mxArray *ptr) +{ + return ptr->is_struct (); +} + +int +mxIsUint16 (const mxArray *ptr) +{ + return ptr->is_uint16 (); +} + +int +mxIsUint32 (const mxArray *ptr) +{ + return ptr->is_uint32 (); +} + +int +mxIsUint64 (const mxArray *ptr) +{ + return ptr->is_uint64 (); +} + +int +mxIsUint8 (const mxArray *ptr) +{ + return ptr->is_uint8 (); +} + +// Odd type+size predicate. +int +mxIsLogicalScalar (const mxArray *ptr) +{ + return ptr->is_logical_scalar (); +} + +// Odd type+size+value predicate. +int +mxIsLogicalScalarTrue (const mxArray *ptr) +{ + return ptr->is_logical_scalar_true (); +} + +// Size predicate. +int +mxIsEmpty (const mxArray *ptr) +{ + return ptr->is_empty (); +} + +// Just plain odd thing to ask of a value. +int +mxIsFromGlobalWS (const mxArray */*ptr*/) +{ + // FIXME + abort (); + return 0; +} + +// Dimension extractors. +size_t +mxGetM (const mxArray *ptr) +{ + return ptr->get_m (); +} + +size_t +mxGetN (const mxArray *ptr) +{ + return ptr->get_n (); +} + +mwSize * +mxGetDimensions (const mxArray *ptr) +{ + return ptr->get_dimensions (); +} + +mwSize +mxGetNumberOfDimensions (const mxArray *ptr) +{ + return ptr->get_number_of_dimensions (); +} + +size_t +mxGetNumberOfElements (const mxArray *ptr) +{ + return ptr->get_number_of_elements (); +} + +// Dimension setters. +void +mxSetM (mxArray *ptr, mwSize m) +{ + ptr->set_m (m); +} + +void +mxSetN (mxArray *ptr, mwSize n) +{ + ptr->set_n (n); +} + +void +mxSetDimensions (mxArray *ptr, const mwSize *dims, mwSize ndims) +{ + ptr->set_dimensions (static_cast ( + maybe_unmark (const_cast (dims))), + ndims); +} + +// Data extractors. +double * +mxGetPr (const mxArray *ptr) +{ + return static_cast (ptr->get_data ()); +} + +double * +mxGetPi (const mxArray *ptr) +{ + return static_cast (ptr->get_imag_data ()); +} + +double +mxGetScalar (const mxArray *ptr) +{ + return ptr->get_scalar (); +} + +mxChar * +mxGetChars (const mxArray *ptr) +{ + return static_cast (ptr->get_data ()); +} + +mxLogical * +mxGetLogicals (const mxArray *ptr) +{ + return static_cast (ptr->get_data ()); +} + +void * +mxGetData (const mxArray *ptr) +{ + return ptr->get_data (); +} + +void * +mxGetImagData (const mxArray *ptr) +{ + return ptr->get_imag_data (); +} + +// Data setters. +void +mxSetPr (mxArray *ptr, double *pr) +{ + ptr->set_data (maybe_unmark (pr)); +} + +void +mxSetPi (mxArray *ptr, double *pi) +{ + ptr->set_imag_data (maybe_unmark (pi)); +} + +void +mxSetData (mxArray *ptr, void *pr) +{ + ptr->set_data (maybe_unmark (pr)); +} + +void +mxSetImagData (mxArray *ptr, void *pi) +{ + ptr->set_imag_data (maybe_unmark (pi)); +} + +// Classes. +mxClassID +mxGetClassID (const mxArray *ptr) +{ + return ptr->get_class_id (); +} + +const char * +mxGetClassName (const mxArray *ptr) +{ + return ptr->get_class_name (); +} + +void +mxSetClassName (mxArray *ptr, const char *name) +{ + ptr->set_class_name (name); +} + +// Cell support. +mxArray * +mxGetCell (const mxArray *ptr, mwIndex idx) +{ + return ptr->get_cell (idx); +} + +void +mxSetCell (mxArray *ptr, mwIndex idx, mxArray *val) +{ + ptr->set_cell (idx, val); +} + +// Sparse support. +mwIndex * +mxGetIr (const mxArray *ptr) +{ + return ptr->get_ir (); +} + +mwIndex * +mxGetJc (const mxArray *ptr) +{ + return ptr->get_jc (); +} + +mwSize +mxGetNzmax (const mxArray *ptr) +{ + return ptr->get_nzmax (); +} + +void +mxSetIr (mxArray *ptr, mwIndex *ir) +{ + ptr->set_ir (static_cast (maybe_unmark (ir))); +} + +void +mxSetJc (mxArray *ptr, mwIndex *jc) +{ + ptr->set_jc (static_cast (maybe_unmark (jc))); +} + +void +mxSetNzmax (mxArray *ptr, mwSize nzmax) +{ + ptr->set_nzmax (nzmax); +} + +// Structure support. +int +mxAddField (mxArray *ptr, const char *key) +{ + return ptr->add_field (key); +} + +void +mxRemoveField (mxArray *ptr, int key_num) +{ + ptr->remove_field (key_num); +} + +mxArray * +mxGetField (const mxArray *ptr, mwIndex index, const char *key) +{ + int key_num = mxGetFieldNumber (ptr, key); + return mxGetFieldByNumber (ptr, index, key_num); +} + +mxArray * +mxGetFieldByNumber (const mxArray *ptr, mwIndex index, int key_num) +{ + return ptr->get_field_by_number (index, key_num); +} + +void +mxSetField (mxArray *ptr, mwIndex index, const char *key, mxArray *val) +{ + int key_num = mxGetFieldNumber (ptr, key); + mxSetFieldByNumber (ptr, index, key_num, val); +} + +void +mxSetFieldByNumber (mxArray *ptr, mwIndex index, int key_num, mxArray *val) +{ + ptr->set_field_by_number (index, key_num, val); +} + +int +mxGetNumberOfFields (const mxArray *ptr) +{ + return ptr->get_number_of_fields (); +} + +const char * +mxGetFieldNameByNumber (const mxArray *ptr, int key_num) +{ + return ptr->get_field_name_by_number (key_num); +} + +int +mxGetFieldNumber (const mxArray *ptr, const char *key) +{ + return ptr->get_field_number (key); +} + +int +mxGetString (const mxArray *ptr, char *buf, mwSize buflen) +{ + return ptr->get_string (buf, buflen); +} + +char * +mxArrayToString (const mxArray *ptr) +{ + return ptr->array_to_string (); +} + +mwIndex +mxCalcSingleSubscript (const mxArray *ptr, mwSize nsubs, mwIndex *subs) +{ + return ptr->calc_single_subscript (nsubs, subs); +} + +size_t +mxGetElementSize (const mxArray *ptr) +{ + return ptr->get_element_size (); +} + +// ------------------------------------------------------------------ + +typedef void (*cmex_fptr) (int nlhs, mxArray **plhs, int nrhs, mxArray **prhs); +typedef F77_RET_T (*fmex_fptr) (int& nlhs, mxArray **plhs, int& nrhs, mxArray **prhs); + +octave_value_list +call_mex (bool have_fmex, void *f, const octave_value_list& args, + int nargout_arg, octave_mex_function *curr_mex_fcn) +{ + // Use at least 1 for nargout since even for zero specified args, + // still want to be able to return an ans. + + volatile int nargout = nargout_arg; + + int nargin = args.length (); + OCTAVE_LOCAL_BUFFER (mxArray *, argin, nargin); + for (int i = 0; i < nargin; i++) + argin[i] = 0; + + int nout = nargout == 0 ? 1 : nargout; + OCTAVE_LOCAL_BUFFER (mxArray *, argout, nout); + for (int i = 0; i < nout; i++) + argout[i] = 0; + + unwind_protect_safe frame; + + // Save old mex pointer. + frame.protect_var (mex_context); + + mex context (curr_mex_fcn); + + frame.add (mex::cleanup, static_cast (&context)); + + for (int i = 0; i < nargin; i++) + argin[i] = context.make_value (args(i)); + + if (setjmp (context.jump) == 0) + { + mex_context = &context; + + if (have_fmex) + { + fmex_fptr fcn = FCN_PTR_CAST (fmex_fptr, f); + + int tmp_nargout = nargout; + int tmp_nargin = nargin; + + fcn (tmp_nargout, argout, tmp_nargin, argin); + } + else + { + cmex_fptr fcn = FCN_PTR_CAST (cmex_fptr, f); + + fcn (nargout, argout, nargin, argin); + } + } + + // Convert returned array entries back into octave values. + + octave_value_list retval; + + if (! error_state) + { + if (nargout == 0 && argout[0]) + { + // We have something for ans. + nargout = 1; + } + + retval.resize (nargout); + + for (int i = 0; i < nargout; i++) + retval(i) = mxArray::as_octave_value (argout[i]); + } + + // Clean up mex resources. + frame.run (); + + return retval; +} + +// C interface to mex functions: + +const char * +mexFunctionName (void) +{ + return mex_context ? mex_context->function_name () : "unknown"; +} + +int +mexCallMATLAB (int nargout, mxArray *argout[], int nargin, mxArray *argin[], + const char *fname) +{ + octave_value_list args; + + // FIXME -- do we need unwind protect to clean up args? Off hand, I + // would say that this problem is endemic to Octave and we will + // continue to have memory leaks after Ctrl-C until proper exception + // handling is implemented. longjmp() only clears the stack, so any + // class which allocates data on the heap is going to leak. + + args.resize (nargin); + + for (int i = 0; i < nargin; i++) + args(i) = mxArray::as_octave_value (argin[i]); + + octave_value_list retval = feval (fname, args, nargout); + + if (error_state && mex_context->trap_feval_error == 0) + { + // FIXME -- is this the correct way to clean up? abort() is + // going to trigger a long jump, so the normal class destructors + // will not be called. Hopefully this will reduce things to a + // tiny leak. Maybe create a new octave memory tracer type + // which prints a friendly message every time it is + // created/copied/deleted to check this. + + args.resize (0); + retval.resize (0); + mex_context->abort (); + } + + int num_to_copy = retval.length (); + + if (nargout < retval.length ()) + num_to_copy = nargout; + + for (int i = 0; i < num_to_copy; i++) + { + // FIXME -- it would be nice to avoid copying the value here, + // but there is no way to steal memory from a matrix, never mind + // that matrix memory is allocated by new[] and mxArray memory + // is allocated by malloc(). + argout[i] = mex_context->make_value (retval (i)); + } + + while (num_to_copy < nargout) + argout[num_to_copy++] = 0; + + if (error_state) + { + error_state = 0; + return 1; + } + else + return 0; +} + +void +mexSetTrapFlag (int flag) +{ + if (mex_context) + mex_context->trap_feval_error = flag; +} + +int +mexEvalString (const char *s) +{ + int retval = 0; + + int parse_status; + + octave_value_list ret; + + ret = eval_string (s, false, parse_status, 0); + + if (parse_status || error_state) + { + error_state = 0; + + retval = 1; + } + + return retval; +} + +void +mexErrMsgTxt (const char *s) +{ + if (s && strlen (s) > 0) + error ("%s: %s", mexFunctionName (), s); + else + // Just set the error state; don't print msg. + error (""); + + mex_context->abort (); +} + +void +mexErrMsgIdAndTxt (const char *id, const char *fmt, ...) +{ + if (fmt && strlen (fmt) > 0) + { + const char *fname = mexFunctionName (); + size_t len = strlen (fname) + 2 + strlen (fmt) + 1; + OCTAVE_LOCAL_BUFFER (char, tmpfmt, len); + sprintf (tmpfmt, "%s: %s", fname, fmt); + va_list args; + va_start (args, fmt); + verror_with_id (id, tmpfmt, args); + va_end (args); + } + else + // Just set the error state; don't print msg. + error (""); + + mex_context->abort (); +} + +void +mexWarnMsgTxt (const char *s) +{ + warning ("%s", s); +} + +void +mexWarnMsgIdAndTxt (const char *id, const char *fmt, ...) +{ + // FIXME -- is this right? What does Matlab do if fmt is NULL or + // an empty string? + + if (fmt && strlen (fmt) > 0) + { + const char *fname = mexFunctionName (); + size_t len = strlen (fname) + 2 + strlen (fmt) + 1; + OCTAVE_LOCAL_BUFFER (char, tmpfmt, len); + sprintf (tmpfmt, "%s: %s", fname, fmt); + va_list args; + va_start (args, fmt); + vwarning_with_id (id, tmpfmt, args); + va_end (args); + } +} + +int +mexPrintf (const char *fmt, ...) +{ + int retval; + va_list args; + va_start (args, fmt); + retval = octave_vformat (octave_stdout, fmt, args); + va_end (args); + return retval; +} + +mxArray * +mexGetVariable (const char *space, const char *name) +{ + mxArray *retval = 0; + + octave_value val; + + if (! strcmp (space, "global")) + val = get_global_value (name); + else + { + // FIXME -- should this be in variables.cc? + + unwind_protect frame; + + bool caller = ! strcmp (space, "caller"); + bool base = ! strcmp (space, "base"); + + if (caller || base) + { + if (caller) + octave_call_stack::goto_caller_frame (); + else + octave_call_stack::goto_base_frame (); + + if (! error_state) + frame.add_fcn (octave_call_stack::pop); + + val = symbol_table::varval (name); + } + else + mexErrMsgTxt ("mexGetVariable: symbol table does not exist"); + } + + if (val.is_defined ()) + { + retval = mex_context->make_value (val); + + retval->set_name (name); + } + + return retval; +} + +const mxArray * +mexGetVariablePtr (const char *space, const char *name) +{ + return mexGetVariable (space, name); +} + +int +mexPutVariable (const char *space, const char *name, mxArray *ptr) +{ + if (! ptr) + return 1; + + if (! name) + return 1; + + if (name[0] == '\0') + name = ptr->get_name (); + + if (! name || name[0] == '\0') + return 1; + + if (! strcmp (space, "global")) + set_global_value (name, mxArray::as_octave_value (ptr)); + else + { + // FIXME -- should this be in variables.cc? + + unwind_protect frame; + + bool caller = ! strcmp (space, "caller"); + bool base = ! strcmp (space, "base"); + + if (caller || base) + { + if (caller) + octave_call_stack::goto_caller_frame (); + else + octave_call_stack::goto_base_frame (); + + if (! error_state) + frame.add_fcn (octave_call_stack::pop); + + symbol_table::varref (name) = mxArray::as_octave_value (ptr); + } + else + mexErrMsgTxt ("mexPutVariable: symbol table does not exist"); + } + + return 0; +} + +void +mexMakeArrayPersistent (mxArray *ptr) +{ + maybe_unmark_array (ptr); +} + +void +mexMakeMemoryPersistent (void *ptr) +{ + maybe_unmark (ptr); +} + +int +mexAtExit (void (*f) (void)) +{ + if (mex_context) + { + octave_mex_function *curr_mex_fcn = mex_context->current_mex_function (); + + assert (curr_mex_fcn); + + curr_mex_fcn->atexit (f); + } + + return 0; +} + +const mxArray * +mexGet (double handle, const char *property) +{ + mxArray *m = 0; + octave_value ret = get_property_from_handle (handle, property, "mexGet"); + + if (!error_state && ret.is_defined ()) + m = ret.as_mxArray (); + return m; +} + +int +mexIsGlobal (const mxArray *ptr) +{ + return mxIsFromGlobalWS (ptr); +} + +int +mexIsLocked (void) +{ + int retval = 0; + + if (mex_context) + { + const char *fname = mexFunctionName (); + + retval = mislocked (fname); + } + + return retval; +} + +std::map mex_lock_count; + +void +mexLock (void) +{ + if (mex_context) + { + const char *fname = mexFunctionName (); + + if (mex_lock_count.find (fname) == mex_lock_count.end ()) + mex_lock_count[fname] = 1; + else + mex_lock_count[fname]++; + + mlock (); + } +} + +int +mexSet (double handle, const char *property, mxArray *val) +{ + bool ret = + set_property_in_handle (handle, property, mxArray::as_octave_value (val), + "mexSet"); + return (ret ? 0 : 1); +} + +void +mexUnlock (void) +{ + if (mex_context) + { + const char *fname = mexFunctionName (); + + std::map::iterator p = mex_lock_count.find (fname); + + if (p != mex_lock_count.end ()) + { + int count = --mex_lock_count[fname]; + + if (count == 0) + { + munlock (fname); + + mex_lock_count.erase (p); + } + } + } +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/mex.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/mex.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,175 @@ +/* + +Copyright (C) 2001-2012 Paul Kienzle + +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 +. + +*/ + +/* + +This code was originally distributed as part of Octave Forge under +the following terms: + +Author: Paul Kienzle +I grant this code to the public domain. +2001-03-22 + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +*/ + +/* mex.h is for use in C-programs only; do NOT include it in mex.cc */ + +#if ! defined (MEX_H) +#define MEX_H + +#define HAVE_OCTAVE + +typedef void mxArray; + +#if ! defined (__cplusplus) +typedef int bool; +#endif + +/* -V4 stuff */ +#if defined (V4) +#define Matrix mxArray +#define REAL mxREAL +#endif + +#define mxMAXNAME 64 + +#if defined (__cplusplus) +extern "C" { +#endif + +#if defined (V4) +void mexFunction (int nlhs, mxArray* plhs[], int nrhs, mxArray *prhs[]); +#else +void mexFunction (int nlhs, mxArray* plhs[], int nrhs, const mxArray *prhs[]); +#endif + +#include "mexproto.h" + +/* V4 floating point routines renamed in V5. */ +#define mexIsNaN mxIsNaN +#define mexIsFinite mxIsFinite +#define mexIsInf mxIsInf +#define mexGetEps mxGetEps +#define mexGetInf mxGetInf +#define mexGetNaN mxGetNan + +#define mexGetGlobal(nm) mexGetArray (nm, "global") +#define mexGetMatrix(nm) mexGetArray (nm, "caller") +#define mexGetMatrixPtr(nm) mexGetArrayPtr (nm, "caller") + +#define mexGetArray(nm, space) mexGetVariable (space, nm) +#define mexGetArrayPtr(nm, space) mexGetVariablePtr (space, nm) + +#define mexPutMatrix(ptr) mexPutVariable ("caller", "", ptr) +#define mexPutArray(ptr, space) mexPutVariable (space, "", ptr) + +#define mxCreateFull mxCreateDoubleMatrix + +#define mxCreateScalarDouble mxCreateDoubleScalar + +#define mxFreeMatrix mxDestroyArray + +#define mxIsString mxIsChar + +/* Apparently these are also defined. */ + +#ifndef UINT64_T +#define UINT64_T uint64_t +#endif + +#ifndef uint64_T +#define uint64_T uint64_t +#endif + +#ifndef INT64_T +#define INT64_T int64_t +#endif + +#ifndef int64_T +#define int64_T int64_t +#endif + +#ifndef UINT32_T +#define UINT32_T uint32_t +#endif + +#ifndef uint32_T +#define uint32_T uint32_t +#endif + +#ifndef INT32_T +#define INT32_T int32_t +#endif + +#ifndef int32_T +#define int32_T int32_t +#endif + +#ifndef UINT16_T +#define UINT16_T uint16_t +#endif + +#ifndef uint16_T +#define uint16_T uint16_t +#endif + +#ifndef INT16_T +#define INT16_T int16_t +#endif + +#ifndef int16_T +#define int16_T int16_t +#endif + +#ifndef UINT8_T +#define UINT8_T uint8_t +#endif + +#ifndef uint8_T +#define uint8_T uint8_t +#endif + +#ifndef INT8_T +#define INT8_T int8_t +#endif + +#ifndef int8_T +#define int8_T int8_t +#endif + +#if defined (__cplusplus) +} +#endif + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/mexproto.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/mexproto.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,279 @@ +/* + +Copyright (C) 2006-2012 Paul Kienzle + +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 +. + +*/ + +/* + +This code was originally distributed as part of Octave Forge under +the following terms: + +Author: Paul Kienzle +I grant this code to the public domain. +2001-03-22 + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +*/ + +/* mex.h is for use in C-programs only; do NOT include it in mex.cc */ + +#if ! defined (MEXPROTO_H) +#define MEXPROTO_H + +#if defined (__cplusplus) +#include +extern "C" { +#else +#include +#endif + +/* The definition of OCTINTERP_API is normally provided by Octave's + config.h file. This is provided for the case of mex.h included by + user programs that don't use Octave's config.h. */ +#if ! defined (OCTINTERP_API) +#if defined (_MSC_VER) +#define OCTINTERP_API __declspec(dllimport) +#else +/* All other compilers, at least for now. */ +#define OCTINTERP_API +#endif +#endif + +#define MXARRAY_TYPEDEFS_ONLY +#include "mxarray.h" +#undef MXARRAY_TYPEDEFS_ONLY + +/* Interface to the interpreter. */ +extern OCTINTERP_API const char *mexFunctionName (void); + +extern OCTINTERP_API int mexCallMATLAB (int nargout, mxArray *argout[], int nargin, mxArray *argin[], const char *fname); + +extern OCTINTERP_API void mexSetTrapFlag (int flag); +extern OCTINTERP_API int mexEvalString (const char *s); +extern OCTINTERP_API void mexErrMsgTxt (const char *s); +extern OCTINTERP_API void mexErrMsgIdAndTxt (const char *id, const char *s, ...); +extern OCTINTERP_API void mexWarnMsgTxt (const char *s); +extern OCTINTERP_API void mexWarnMsgIdAndTxt (const char *id, const char *s, ...); +extern OCTINTERP_API int mexPrintf (const char *fmt, ...); + +extern OCTINTERP_API mxArray *mexGetVariable (const char *space, const char *name); +extern OCTINTERP_API const mxArray *mexGetVariablePtr (const char *space, const char *name); + +extern OCTINTERP_API int mexPutVariable (const char *space, const char *name, mxArray *ptr); + +extern OCTINTERP_API void mexMakeArrayPersistent (mxArray *ptr); +extern OCTINTERP_API void mexMakeMemoryPersistent (void *ptr); + +extern OCTINTERP_API int mexAtExit (void (*f) (void)); +extern OCTINTERP_API const mxArray *mexGet (double handle, const char *property); +extern OCTINTERP_API int mexIsGlobal (const mxArray *ptr); +extern OCTINTERP_API int mexIsLocked (void); +extern OCTINTERP_API void mexLock (void); +extern OCTINTERP_API int mexSet (double handle, const char *property, mxArray *val); +extern OCTINTERP_API void mexUnlock (void); + +/* Floating point predicates. */ +extern OCTINTERP_API int mxIsFinite (double v); +extern OCTINTERP_API int mxIsInf (double v); +extern OCTINTERP_API int mxIsNaN (double v); + +/* Floating point values. */ +extern OCTINTERP_API double mxGetEps (void); +extern OCTINTERP_API double mxGetInf (void); +extern OCTINTERP_API double mxGetNaN (void); + +/* Memory management. */ +extern OCTINTERP_API void *mxCalloc (size_t n, size_t size); +extern OCTINTERP_API void *mxMalloc (size_t n); +extern OCTINTERP_API void *mxRealloc (void *ptr, size_t size); +extern OCTINTERP_API void mxFree (void *ptr); + +/* Constructors. */ +extern OCTINTERP_API mxArray *mxCreateCellArray (mwSize ndims, const mwSize *dims); +extern OCTINTERP_API mxArray *mxCreateCellMatrix (mwSize m, mwSize n); +extern OCTINTERP_API mxArray *mxCreateCharArray (mwSize ndims, const mwSize *dims); +extern OCTINTERP_API mxArray *mxCreateCharMatrixFromStrings (mwSize m, const char **str); +extern OCTINTERP_API mxArray *mxCreateDoubleMatrix (mwSize nr, mwSize nc, mxComplexity flag); +extern OCTINTERP_API mxArray *mxCreateDoubleScalar (double val); +extern OCTINTERP_API mxArray *mxCreateLogicalArray (mwSize ndims, const mwSize *dims); +extern OCTINTERP_API mxArray *mxCreateLogicalMatrix (mwSize m, mwSize n); +extern OCTINTERP_API mxArray *mxCreateLogicalScalar (mxLogical val); +extern OCTINTERP_API mxArray *mxCreateNumericArray (mwSize ndims, const mwSize *dims, mxClassID class_id, mxComplexity flag); +extern OCTINTERP_API mxArray *mxCreateNumericMatrix (mwSize m, mwSize n, mxClassID class_id, mxComplexity flag); +extern OCTINTERP_API mxArray *mxCreateSparse (mwSize m, mwSize n, mwSize nzmax, mxComplexity flag); +extern OCTINTERP_API mxArray *mxCreateSparseLogicalMatrix (mwSize m, mwSize n, mwSize nzmax); +extern OCTINTERP_API mxArray *mxCreateString (const char *str); +extern OCTINTERP_API mxArray *mxCreateStructArray (mwSize ndims, const mwSize *dims, int num_keys, const char **keys); +extern OCTINTERP_API mxArray *mxCreateStructMatrix (mwSize rows, mwSize cols, int num_keys, const char **keys); + +/* Copy constructor. */ +extern OCTINTERP_API mxArray *mxDuplicateArray (const mxArray *v); + +/* Destructor. */ +extern OCTINTERP_API void mxDestroyArray (mxArray *v); + +/* Type Predicates. */ +extern OCTINTERP_API int mxIsCell (const mxArray *ptr); +extern OCTINTERP_API int mxIsChar (const mxArray *ptr); +extern OCTINTERP_API int mxIsClass (const mxArray *ptr, const char *name); +extern OCTINTERP_API int mxIsComplex (const mxArray *ptr); +extern OCTINTERP_API int mxIsDouble (const mxArray *ptr); +extern OCTINTERP_API int mxIsFunctionHandle (const mxArray *ptr); +extern OCTINTERP_API int mxIsInt16 (const mxArray *ptr); +extern OCTINTERP_API int mxIsInt32 (const mxArray *ptr); +extern OCTINTERP_API int mxIsInt64 (const mxArray *ptr); +extern OCTINTERP_API int mxIsInt8 (const mxArray *ptr); +extern OCTINTERP_API int mxIsLogical (const mxArray *ptr); +extern OCTINTERP_API int mxIsNumeric (const mxArray *ptr); +extern OCTINTERP_API int mxIsSingle (const mxArray *ptr); +extern OCTINTERP_API int mxIsSparse (const mxArray *ptr); +extern OCTINTERP_API int mxIsStruct (const mxArray *ptr); +extern OCTINTERP_API int mxIsUint16 (const mxArray *ptr); +extern OCTINTERP_API int mxIsUint32 (const mxArray *ptr); +extern OCTINTERP_API int mxIsUint64 (const mxArray *ptr); +extern OCTINTERP_API int mxIsUint8 (const mxArray *ptr); + +/* Odd type+size predicate. */ +extern OCTINTERP_API int mxIsLogicalScalar (const mxArray *ptr); + +/* Odd type+size+value predicate. */ +extern OCTINTERP_API int mxIsLogicalScalarTrue (const mxArray *ptr); + +/* Size predicate. */ +extern OCTINTERP_API int mxIsEmpty (const mxArray *ptr); + +/* Just plain odd thing to ask of a value. */ +extern OCTINTERP_API int mxIsFromGlobalWS (const mxArray *ptr); + +/* Dimension extractors. */ +extern OCTINTERP_API size_t mxGetM (const mxArray *ptr); +extern OCTINTERP_API size_t mxGetN (const mxArray *ptr); +extern OCTINTERP_API mwSize *mxGetDimensions (const mxArray *ptr); +extern OCTINTERP_API mwSize mxGetNumberOfDimensions (const mxArray *ptr); +extern OCTINTERP_API size_t mxGetNumberOfElements (const mxArray *ptr); + +/* Dimension setters. */ +extern OCTINTERP_API void mxSetM (mxArray *ptr, mwSize M); +extern OCTINTERP_API void mxSetN (mxArray *ptr, mwSize N); +extern OCTINTERP_API void mxSetDimensions (mxArray *ptr, const mwSize *dims, mwSize ndims); + +/* Data extractors. */ +extern OCTINTERP_API double *mxGetPi (const mxArray *ptr); +extern OCTINTERP_API double *mxGetPr (const mxArray *ptr); +extern OCTINTERP_API double mxGetScalar (const mxArray *ptr); +extern OCTINTERP_API mxChar *mxGetChars (const mxArray *ptr); +extern OCTINTERP_API mxLogical *mxGetLogicals (const mxArray *ptr); +extern OCTINTERP_API void *mxGetData (const mxArray *ptr); +extern OCTINTERP_API void *mxGetImagData (const mxArray *ptr); + +/* Data setters. */ +extern OCTINTERP_API void mxSetPr (mxArray *ptr, double *pr); +extern OCTINTERP_API void mxSetPi (mxArray *ptr, double *pi); +extern OCTINTERP_API void mxSetData (mxArray *ptr, void *data); +extern OCTINTERP_API void mxSetImagData (mxArray *ptr, void *pi); + +/* Classes. */ +extern OCTINTERP_API mxClassID mxGetClassID (const mxArray *ptr); +extern OCTINTERP_API const char *mxGetClassName (const mxArray *ptr); + +extern OCTINTERP_API void mxSetClassName (mxArray *ptr, const char *name); + +/* Cell support. */ +extern OCTINTERP_API mxArray *mxGetCell (const mxArray *ptr, mwIndex idx); + +extern OCTINTERP_API void mxSetCell (mxArray *ptr, mwIndex idx, mxArray *val); + +/* Sparse support. */ +extern OCTINTERP_API mwIndex *mxGetIr (const mxArray *ptr); +extern OCTINTERP_API mwIndex *mxGetJc (const mxArray *ptr); +extern OCTINTERP_API mwSize mxGetNzmax (const mxArray *ptr); + +extern OCTINTERP_API void mxSetIr (mxArray *ptr, mwIndex *ir); +extern OCTINTERP_API void mxSetJc (mxArray *ptr, mwIndex *jc); +extern OCTINTERP_API void mxSetNzmax (mxArray *ptr, mwSize nzmax); + +/* Structure support. */ +extern OCTINTERP_API int mxAddField (mxArray *ptr, const char *key); + +extern OCTINTERP_API void mxRemoveField (mxArray *ptr, int key_num); + +extern OCTINTERP_API mxArray *mxGetField (const mxArray *ptr, mwIndex index, const char *key); +extern OCTINTERP_API mxArray *mxGetFieldByNumber (const mxArray *ptr, mwIndex index, int key_num); + +extern OCTINTERP_API void mxSetField (mxArray *ptr, mwIndex index, const char *key, mxArray *val); +extern OCTINTERP_API void mxSetFieldByNumber (mxArray *ptr, mwIndex index, int key_num, mxArray *val); + +extern OCTINTERP_API int mxGetNumberOfFields (const mxArray *ptr); + +extern OCTINTERP_API const char *mxGetFieldNameByNumber (const mxArray *ptr, int key_num); +extern OCTINTERP_API int mxGetFieldNumber (const mxArray *ptr, const char *key); + +extern OCTINTERP_API int mxGetString (const mxArray *ptr, char *buf, mwSize buflen); +extern OCTINTERP_API char *mxArrayToString (const mxArray *ptr); + +/* Miscellaneous. */ +#ifdef NDEBUG +#define mxAssert(expr, msg) \ + do \ + { \ + if (! expr) \ + { \ + mexPrintf ("Assertion failed: %s, at line %d of file \"%s\".\n%s\n", \ + #expr, __LINE__, __FILE__, msg); \ + } \ + } \ + while (0) + +#define mxAssertS(expr, msg) \ + do \ + { \ + if (! expr) \ + { \ + mexPrintf ("Assertion failed at line %d of file \"%s\".\n%s\n", \ + __LINE__, __FILE__, msg); \ + abort (); \ + } \ + } \ + while (0) +#else +#define mxAssert(expr, msg) +#define mxAssertS(expr, msg) +#endif + +extern OCTINTERP_API mwIndex mxCalcSingleSubscript (const mxArray *ptr, mwSize nsubs, mwIndex *subs); + +extern OCTINTERP_API size_t mxGetElementSize (const mxArray *ptr); + +#if defined (__cplusplus) +} +#endif + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/module.mk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/module.mk Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,138 @@ +EXTRA_DIST += \ + interp-core/module.mk \ + interp-core/gl2ps.c \ + interp-core/mxarray.in.h \ + interp-core/oct-errno.in.cc + +JIT_INCLUDES = \ + interp-core/jit-util.h \ + interp-core/jit-typeinfo.h \ + interp-core/jit-ir.h \ + interp-core/pt-jit.h + +INTERP_CORE_INCLUDES = \ + interp-core/Cell.h \ + interp-core/c-file-ptr-stream.h \ + interp-core/comment-list.h \ + interp-core/cutils.h \ + interp-core/defun-dld.h \ + interp-core/defun-int.h \ + interp-core/display.h \ + interp-core/dynamic-ld.h \ + interp-core/gl-render.h \ + interp-core/gl2ps-renderer.h \ + interp-core/gl2ps.h \ + interp-core/gripes.h \ + interp-core/jit-ir.h \ + interp-core/jit-typeinfo.h \ + interp-core/jit-util.h \ + interp-core/ls-ascii-helper.h \ + interp-core/ls-hdf5.h \ + interp-core/ls-mat-ascii.h \ + interp-core/ls-mat4.h \ + interp-core/ls-mat5.h \ + interp-core/ls-oct-binary.h \ + interp-core/ls-utils.h \ + interp-core/mex.h \ + interp-core/mexproto.h \ + interp-core/mxarray.in.h \ + interp-core/oct-errno.h \ + interp-core/oct-fstrm.h \ + interp-core/oct-hdf5.h \ + interp-core/oct-iostrm.h \ + interp-core/oct-lvalue.h \ + interp-core/oct-map.h \ + interp-core/oct-obj.h \ + interp-core/oct-prcstrm.h \ + interp-core/oct-procbuf.h \ + interp-core/oct-stdstrm.h \ + interp-core/oct-stream.h \ + interp-core/oct-strstrm.h \ + interp-core/oct.h \ + interp-core/procstream.h \ + interp-core/pt-jit.h \ + interp-core/siglist.h \ + interp-core/sparse-xdiv.h \ + interp-core/sparse-xpow.h \ + interp-core/txt-eng-ft.h \ + interp-core/txt-eng.h \ + interp-core/unwind-prot.h \ + interp-core/xdiv.h \ + interp-core/xnorm.h \ + interp-core/xpow.h \ + interp-core/zfstream.h \ + $(JIT_INCLUDES) + +JIT_SRC = \ + interp-core/jit-util.cc \ + interp-core/jit-typeinfo.cc \ + interp-core/jit-ir.cc \ + interp-core/pt-jit.cc + +C_INTERP_CORE_SRC = \ + interp-core/cutils.c \ + interp-core/matherr.c \ + interp-core/siglist.c \ + interp-core/xgl2ps.c + +INTERP_CORE_SRC = \ + interp-core/Cell.cc \ + interp-core/c-file-ptr-stream.cc \ + interp-core/comment-list.cc \ + interp-core/display.cc \ + interp-core/dynamic-ld.cc \ + interp-core/gl-render.cc \ + interp-core/gl2ps-renderer.cc \ + interp-core/gripes.cc \ + interp-core/jit-ir.cc \ + interp-core/jit-typeinfo.cc \ + interp-core/jit-util.cc \ + interp-core/ls-ascii-helper.cc \ + interp-core/ls-hdf5.cc \ + interp-core/ls-mat-ascii.cc \ + interp-core/ls-mat4.cc \ + interp-core/ls-mat5.cc \ + interp-core/ls-oct-binary.cc \ + interp-core/ls-utils.cc \ + interp-core/mex.cc \ + interp-core/oct-fstrm.cc \ + interp-core/oct-iostrm.cc \ + interp-core/oct-lvalue.cc \ + interp-core/oct-map.cc \ + interp-core/oct-obj.cc \ + interp-core/oct-prcstrm.cc \ + interp-core/oct-procbuf.cc \ + interp-core/oct-stream.cc \ + interp-core/oct-strstrm.cc \ + interp-core/procstream.cc \ + interp-core/pt-jit.cc \ + interp-core/sparse-xdiv.cc \ + interp-core/sparse-xpow.cc \ + interp-core/txt-eng-ft.cc \ + interp-core/unwind-prot.cc \ + interp-core/xdiv.cc \ + interp-core/xnorm.cc \ + interp-core/xpow.cc \ + interp-core/zfstream.cc \ + $(JIT_SRC) \ + $(C_INTERP_CORE_SRC) + +## FIXME: I don't believe this rule actually fires +display.df display.lo: CPPFLAGS += $(X11_FLAGS) + +## Special rules for sources which must be built before rest of compilation. +interp-core/oct-errno.cc: interp-core/oct-errno.in.cc Makefile + if test -n "$(PERL)"; then \ + $(srcdir)/mk-errno-list --perl "$(PERL)" < $< > $@-t; \ + elif test -n "$(PYTHON)"; then \ + $(srcdir)/mk-errno-list --python "$(PYTHON)" < $< > $@-t; \ + else \ + $(SED) '/@SYSDEP_ERRNO_LIST@/D' $< > $@-t; \ + fi + mv $@-t $@ + +interp-core/mxarray.h: interp-core/mxarray.in.h Makefile + $(SED) < $< \ + -e "s|%OCTAVE_IDX_TYPE%|${OCTAVE_IDX_TYPE}|" > $@-t + mv $@-t $@ + diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/mxarray.in.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/mxarray.in.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,348 @@ +// DO NOT EDIT! Generated automatically from mxarray.in.h by configure +/* + +Copyright (C) 2001-2012 Paul Kienzle + +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 +. + +*/ + +/* + +Part of this code was originally distributed as part of Octave Forge under +the following terms: + +Author: Paul Kienzle +I grant this code to the public domain. +2001-03-22 + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +*/ + +#if ! defined (MXARRAY_H) +#define MXARRAY_H + +typedef enum + { + mxREAL = 0, + mxCOMPLEX = 1 + } + mxComplexity; + +typedef enum + { + mxUNKNOWN_CLASS = 0, + mxCELL_CLASS, + mxSTRUCT_CLASS, + mxLOGICAL_CLASS, + mxCHAR_CLASS, + mxUNUSED_CLASS, + mxDOUBLE_CLASS, + mxSINGLE_CLASS, + mxINT8_CLASS, + mxUINT8_CLASS, + mxINT16_CLASS, + mxUINT16_CLASS, + mxINT32_CLASS, + mxUINT32_CLASS, + mxINT64_CLASS, + mxUINT64_CLASS, + mxFUNCTION_CLASS + } + mxClassID; + +typedef unsigned char mxLogical; + +/* typedef Uint16 mxChar; */ +typedef char mxChar; + +/* + * FIXME? Mathworks says these should be size_t on 64-bit system and when + * mex is used with the -largearraydims flag, but why do that? Its better + * to conform to the same indexing as the rest of Octave + */ +typedef %OCTAVE_IDX_TYPE% mwSize; +typedef %OCTAVE_IDX_TYPE% mwIndex; + +#if ! defined (MXARRAY_TYPEDEFS_ONLY) + +#include + +class octave_value; + +#define DO_MUTABLE_METHOD(RET_T, METHOD_CALL) \ + RET_T retval = rep->METHOD_CALL; \ + \ + if (rep->mutation_needed ()) \ + { \ + maybe_mutate (); \ + retval = rep->METHOD_CALL; \ + } \ + \ + return retval + +#define DO_VOID_MUTABLE_METHOD(METHOD_CALL) \ + rep->METHOD_CALL; \ + \ + if (rep->mutation_needed ()) \ + { \ + maybe_mutate (); \ + rep->METHOD_CALL; \ + } + +// This just provides a way to avoid infinite recursion when building +// mxArray objects. + +struct +xmxArray +{ + xmxArray (void) { } +}; + +// The main interface class. The representation can be based on an +// octave_value object or a separate object that tries to reproduce +// the semantics of mxArray objects in Matlab more directly. + +class mxArray +{ +public: + + mxArray (const octave_value& ov); + + mxArray (mxClassID id, mwSize ndims, const mwSize *dims, + mxComplexity flag = mxREAL); + + mxArray (mxClassID id, const dim_vector& dv, mxComplexity flag = mxREAL); + + mxArray (mxClassID id, mwSize m, mwSize n, mxComplexity flag = mxREAL); + + mxArray (mxClassID id, double val); + + mxArray (mxClassID id, mxLogical val); + + mxArray (const char *str); + + mxArray (mwSize m, const char **str); + + mxArray (mxClassID id, mwSize m, mwSize n, mwSize nzmax, + mxComplexity flag = mxREAL); + + mxArray (mwSize ndims, const mwSize *dims, int num_keys, const char **keys); + + mxArray (const dim_vector& dv, int num_keys, const char **keys); + + mxArray (mwSize m, mwSize n, int num_keys, const char **keys); + + mxArray (mwSize ndims, const mwSize *dims); + + mxArray (const dim_vector& dv); + + mxArray (mwSize m, mwSize n); + + virtual mxArray *dup (void) const + { + mxArray *new_rep = rep->dup (); + + return new mxArray (new_rep, name); + } + + virtual ~mxArray (void); + + virtual bool is_octave_value (void) const { return rep->is_octave_value (); } + + virtual int is_cell (void) const { return rep->is_cell (); } + + virtual int is_char (void) const { return rep->is_char (); } + + virtual int is_class (const char *name_arg) const { return rep->is_class (name_arg); } + + virtual int is_complex (void) const { return rep->is_complex (); } + + virtual int is_double (void) const { return rep->is_double (); } + + virtual int is_function_handle (void) const { return rep->is_function_handle (); } + + virtual int is_int16 (void) const { return rep->is_int16 (); } + + virtual int is_int32 (void) const { return rep->is_int32 (); } + + virtual int is_int64 (void) const { return rep->is_int64 (); } + + virtual int is_int8 (void) const { return rep->is_int8 (); } + + virtual int is_logical (void) const { return rep->is_logical (); } + + virtual int is_numeric (void) const { return rep->is_numeric (); } + + virtual int is_single (void) const { return rep->is_single (); } + + virtual int is_sparse (void) const { return rep->is_sparse (); } + + virtual int is_struct (void) const { return rep->is_struct (); } + + virtual int is_uint16 (void) const { return rep->is_uint16 (); } + + virtual int is_uint32 (void) const { return rep->is_uint32 (); } + + virtual int is_uint64 (void) const { return rep->is_uint64 (); } + + virtual int is_uint8 (void) const { return rep->is_uint8 (); } + + virtual int is_logical_scalar (void) const { return rep->is_logical_scalar (); } + + virtual int is_logical_scalar_true (void) const { return rep->is_logical_scalar_true (); } + + virtual mwSize get_m (void) const { return rep->get_m (); } + + virtual mwSize get_n (void) const { return rep->get_n (); } + + virtual mwSize *get_dimensions (void) const { return rep->get_dimensions (); } + + virtual mwSize get_number_of_dimensions (void) const { return rep->get_number_of_dimensions (); } + + virtual void set_m (mwSize m) { DO_VOID_MUTABLE_METHOD (set_m (m)); } + + virtual void set_n (mwSize n) { DO_VOID_MUTABLE_METHOD (set_n (n)); } + + virtual void set_dimensions (mwSize *dims_arg, mwSize ndims_arg) { DO_VOID_MUTABLE_METHOD (set_dimensions (dims_arg, ndims_arg)); } + + virtual mwSize get_number_of_elements (void) const { return rep->get_number_of_elements (); } + + virtual int is_empty (void) const { return get_number_of_elements () == 0; } + + const char *get_name (void) const { return name; } + + void set_name (const char *name_arg); + + virtual mxClassID get_class_id (void) const { return rep->get_class_id (); } + + virtual const char *get_class_name (void) const { return rep->get_class_name (); } + + virtual void set_class_name (const char *name_arg) { DO_VOID_MUTABLE_METHOD (set_class_name (name_arg)); } + + virtual mxArray *get_cell (mwIndex idx) const { DO_MUTABLE_METHOD (mxArray *, get_cell (idx)); } + + virtual void set_cell (mwIndex idx, mxArray *val) { DO_VOID_MUTABLE_METHOD (set_cell (idx, val)); } + + virtual double get_scalar (void) const { return rep->get_scalar (); } + + virtual void *get_data (void) const { DO_MUTABLE_METHOD (void *, get_data ()); } + + virtual void *get_imag_data (void) const { DO_MUTABLE_METHOD (void *, get_imag_data ()); } + + virtual void set_data (void *pr) { DO_VOID_MUTABLE_METHOD (set_data (pr)); } + + virtual void set_imag_data (void *pi) { DO_VOID_MUTABLE_METHOD (set_imag_data (pi)); } + + virtual mwIndex *get_ir (void) const { DO_MUTABLE_METHOD (mwIndex *, get_ir ()); } + + virtual mwIndex *get_jc (void) const { DO_MUTABLE_METHOD (mwIndex *, get_jc ()); } + + virtual mwSize get_nzmax (void) const { return rep->get_nzmax (); } + + virtual void set_ir (mwIndex *ir) { DO_VOID_MUTABLE_METHOD (set_ir (ir)); } + + virtual void set_jc (mwIndex *jc) { DO_VOID_MUTABLE_METHOD (set_jc (jc)); } + + virtual void set_nzmax (mwSize nzmax) { DO_VOID_MUTABLE_METHOD (set_nzmax (nzmax)); } + + virtual int add_field (const char *key) { DO_MUTABLE_METHOD (int, add_field (key)); } + + virtual void remove_field (int key_num) { DO_VOID_MUTABLE_METHOD (remove_field (key_num)); } + + virtual mxArray *get_field_by_number (mwIndex index, int key_num) const { DO_MUTABLE_METHOD (mxArray *, get_field_by_number (index, key_num)); } + + virtual void set_field_by_number (mwIndex index, int key_num, mxArray *val) { DO_VOID_MUTABLE_METHOD (set_field_by_number (index, key_num, val)); } + + virtual int get_number_of_fields (void) const { return rep->get_number_of_fields (); } + + virtual const char *get_field_name_by_number (int key_num) const { DO_MUTABLE_METHOD (const char*, get_field_name_by_number (key_num)); } + + virtual int get_field_number (const char *key) const { DO_MUTABLE_METHOD (int, get_field_number (key)); } + + virtual int get_string (char *buf, mwSize buflen) const { return rep->get_string (buf, buflen); } + + virtual char *array_to_string (void) const { return rep->array_to_string (); } + + virtual mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const { return rep->calc_single_subscript (nsubs, subs); } + + virtual size_t get_element_size (void) const { return rep->get_element_size (); } + + virtual bool mutation_needed (void) const { return rep->mutation_needed (); } + + virtual mxArray *mutate (void) const { return rep->mutate (); } + + static void *malloc (size_t n); + + static void *calloc (size_t n, size_t t); + + static char *strsave (const char *str) + { + char *retval = 0; + + if (str) + { + mwSize sz = sizeof (mxChar) * (strlen (str) + 1); + retval = static_cast (mxArray::malloc (sz)); + strcpy (retval, str); + } + + return retval; + } + + static octave_value as_octave_value (mxArray *ptr); + +protected: + + virtual octave_value as_octave_value (void) const; + + mxArray (const xmxArray&) : rep (0), name (0) { } + +private: + + mutable mxArray *rep; + + char *name; + + mxArray (mxArray *r, const char *n) + : rep (r), name (strsave (n)) { } + + void maybe_mutate (void) const; + + // No copying! + + mxArray (const mxArray&); + + mxArray& operator = (const mxArray&); +}; + +#undef DO_MUTABLE_METHOD +#undef DO_VOID_MUTABLE_METHOD + +#endif +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-errno.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-errno.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,72 @@ +// oct-errno.h.in +/* + +Copyright (C) 2005-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_errno_h) +#define octave_errno_h 1 + +#include +#include +#include + +#include "oct-map.h" + +class +octave_errno +{ +protected: + + octave_errno (void); + +public: + + ~octave_errno (void) { } + + static bool instance_ok (void); + + static void cleanup_instance (void) { delete instance; instance = 0; } + + static int lookup (const std::string& name); + + static octave_scalar_map list (void); + + static int get (void) { return errno; } + + static int set (int val) + { + int retval = errno; + errno = val; + return retval; + } + +private: + + std::map errno_tbl; + + static octave_errno *instance; + + int do_lookup (const std::string& name); + + octave_scalar_map do_list (void); +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-errno.in.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-errno.in.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,345 @@ +// DO NOT EDIT! Generated automatically from oct-errno.in.cc by configure +/* + +Copyright (C) 2005-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "singleton-cleanup.h" + +#include "oct-errno.h" +#include "oct-map.h" +#include "error.h" + +octave_errno *octave_errno::instance = 0; + +octave_errno::octave_errno (void) +{ + struct errno_struct + { + const char *name; + int value; + }; + + static errno_struct errno_codes[] = + { + // POSIX. + +#if defined (E2BIG) + { "E2BIG", E2BIG, }, +#endif +#if defined (EACCES) + { "EACCES", EACCES, }, +#endif +#if defined (EADDRINUSE) + { "EADDRINUSE", EADDRINUSE, }, +#endif +#if defined (EADDRNOTAVAIL) + { "EADDRNOTAVAIL", EADDRNOTAVAIL, }, +#endif +#if defined (EAFNOSUPPORT) + { "EAFNOSUPPORT", EAFNOSUPPORT, }, +#endif +#if defined (EAGAIN) + { "EAGAIN", EAGAIN, }, +#endif +#if defined (EALREADY) + { "EALREADY", EALREADY, }, +#endif +#if defined (EBADF) + { "EBADF", EBADF, }, +#endif +#if defined (EBUSY) + { "EBUSY", EBUSY, }, +#endif +#if defined (ECHILD) + { "ECHILD", ECHILD, }, +#endif +#if defined (ECONNABORTED) + { "ECONNABORTED", ECONNABORTED, }, +#endif +#if defined (ECONNREFUSED) + { "ECONNREFUSED", ECONNREFUSED, }, +#endif +#if defined (ECONNRESET) + { "ECONNRESET", ECONNRESET, }, +#endif +#if defined (EDEADLK) + { "EDEADLK", EDEADLK, }, +#endif +#if defined (EDESTADDRREQ) + { "EDESTADDRREQ", EDESTADDRREQ, }, +#endif +#if defined (EDOM) + { "EDOM", EDOM, }, +#endif +#if defined (EDQUOT) + { "EDQUOT", EDQUOT, }, +#endif +#if defined (EEXIST) + { "EEXIST", EEXIST, }, +#endif +#if defined (EFAULT) + { "EFAULT", EFAULT, }, +#endif +#if defined (EFBIG) + { "EFBIG", EFBIG, }, +#endif +#if defined (EHOSTDOWN) + { "EHOSTDOWN", EHOSTDOWN, }, +#endif +#if defined (EHOSTUNREACH) + { "EHOSTUNREACH", EHOSTUNREACH, }, +#endif +#if defined (EINPROGRESS) + { "EINPROGRESS", EINPROGRESS, }, +#endif +#if defined (EINTR) + { "EINTR", EINTR, }, +#endif +#if defined (EINVAL) + { "EINVAL", EINVAL, }, +#endif +#if defined (EIO) + { "EIO", EIO, }, +#endif +#if defined (EISCONN) + { "EISCONN", EISCONN, }, +#endif +#if defined (EISDIR) + { "EISDIR", EISDIR, }, +#endif +#if defined (ELOOP) + { "ELOOP", ELOOP, }, +#endif +#if defined (EMFILE) + { "EMFILE", EMFILE, }, +#endif +#if defined (EMLINK) + { "EMLINK", EMLINK, }, +#endif +#if defined (EMSGSIZE) + { "EMSGSIZE", EMSGSIZE, }, +#endif +#if defined (ENAMETOOLONG) + { "ENAMETOOLONG", ENAMETOOLONG, }, +#endif +#if defined (ENETDOWN) + { "ENETDOWN", ENETDOWN, }, +#endif +#if defined (ENETRESET) + { "ENETRESET", ENETRESET, }, +#endif +#if defined (ENETUNREACH) + { "ENETUNREACH", ENETUNREACH, }, +#endif +#if defined (ENFILE) + { "ENFILE", ENFILE, }, +#endif +#if defined (ENOBUFS) + { "ENOBUFS", ENOBUFS, }, +#endif +#if defined (ENODEV) + { "ENODEV", ENODEV, }, +#endif +#if defined (ENOENT) + { "ENOENT", ENOENT, }, +#endif +#if defined (ENOEXEC) + { "ENOEXEC", ENOEXEC, }, +#endif +#if defined (ENOLCK) + { "ENOLCK", ENOLCK, }, +#endif +#if defined (ENOMEM) + { "ENOMEM", ENOMEM, }, +#endif +#if defined (ENOPROTOOPT) + { "ENOPROTOOPT", ENOPROTOOPT, }, +#endif +#if defined (ENOSPC) + { "ENOSPC", ENOSPC, }, +#endif +#if defined (ENOSYS) + { "ENOSYS", ENOSYS, }, +#endif +#if defined (ENOTBLK) + { "ENOTBLK", ENOTBLK, }, +#endif +#if defined (ENOTCONN) + { "ENOTCONN", ENOTCONN, }, +#endif +#if defined (ENOTDIR) + { "ENOTDIR", ENOTDIR, }, +#endif +#if defined (ENOTEMPTY) + { "ENOTEMPTY", ENOTEMPTY, }, +#endif +#if defined (ENOTSOCK) + { "ENOTSOCK", ENOTSOCK, }, +#endif +#if defined (ENOTTY) + { "ENOTTY", ENOTTY, }, +#endif +#if defined (ENXIO) + { "ENXIO", ENXIO, }, +#endif +#if defined (EOPNOTSUPP) + { "EOPNOTSUPP", EOPNOTSUPP, }, +#endif +#if defined (EPERM) + { "EPERM", EPERM, }, +#endif +#if defined (EPFNOSUPPORT) + { "EPFNOSUPPORT", EPFNOSUPPORT, }, +#endif +#if defined (EPIPE) + { "EPIPE", EPIPE, }, +#endif +#if defined (EPROTONOSUPPORT) + { "EPROTONOSUPPORT", EPROTONOSUPPORT, }, +#endif +#if defined (EPROTOTYPE) + { "EPROTOTYPE", EPROTOTYPE, }, +#endif +#if defined (ERANGE) + { "ERANGE", ERANGE, }, +#endif +#if defined (EREMOTE) + { "EREMOTE", EREMOTE, }, +#endif +#if defined (ERESTART) + { "ERESTART", ERESTART, }, +#endif +#if defined (EROFS) + { "EROFS", EROFS, }, +#endif +#if defined (ESHUTDOWN) + { "ESHUTDOWN", ESHUTDOWN, }, +#endif +#if defined (ESOCKTNOSUPPORT) + { "ESOCKTNOSUPPORT", ESOCKTNOSUPPORT, }, +#endif +#if defined (ESPIPE) + { "ESPIPE", ESPIPE, }, +#endif +#if defined (ESRCH) + { "ESRCH", ESRCH, }, +#endif +#if defined (ESTALE) + { "ESTALE", ESTALE, }, +#endif +#if defined (ETIMEDOUT) + { "ETIMEDOUT", ETIMEDOUT, }, +#endif +#if defined (ETOOMANYREFS) + { "ETOOMANYREFS", ETOOMANYREFS, }, +#endif +#if defined (ETXTBSY) + { "ETXTBSY", ETXTBSY, }, +#endif +#if defined (EUSERS) + { "EUSERS", EUSERS, }, +#endif +#if defined (EWOULDBLOCK) + { "EWOULDBLOCK", EWOULDBLOCK, }, +#endif +#if defined (EXDEV) + { "EXDEV", EXDEV, }, +#endif + + // Others (duplicates are OK). + +@SYSDEP_ERRNO_LIST@ + + { 0, 0, }, + }; + + // Stuff them all in a map for fast access. + + errno_struct *ptr = errno_codes; + + while (ptr->name) + { + errno_tbl[ptr->name] = ptr->value; + ptr++; + } +} + +bool +octave_errno::instance_ok (void) +{ + bool retval = true; + + if (! instance) + { + instance = new octave_errno (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } + + if (! instance) + { + ::error ("unable to create errno object!"); + + retval = false; + } + + return retval; +} + +int +octave_errno::lookup (const std::string& name) +{ + return (instance_ok ()) ? instance->do_lookup (name) : -1; +} + +octave_scalar_map +octave_errno::list (void) +{ + return (instance_ok ()) ? instance->do_list () : octave_scalar_map (); +} + +int +octave_errno::do_lookup (const std::string& name) +{ + return (errno_tbl.find (name) != errno_tbl.end ()) ? errno_tbl[name] : -1; +} + +octave_scalar_map +octave_errno::do_list (void) +{ + octave_scalar_map retval; + + for (std::map::const_iterator p = errno_tbl.begin (); + p != errno_tbl.end (); + p++) + { + retval.assign (p->first, p->second); + } + + return retval; +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-fstrm.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-fstrm.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,114 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "error.h" +#include "oct-fstrm.h" + +octave_stream +octave_fstream::create (const std::string& nm_arg, std::ios::openmode arg_md, + oct_mach_info::float_format ff) +{ + return octave_stream (new octave_fstream (nm_arg, arg_md, ff)); +} + +octave_fstream::octave_fstream (const std::string& nm_arg, + std::ios::openmode arg_md, + oct_mach_info::float_format ff) + : octave_base_stream (arg_md, ff), nm (nm_arg) +{ + +#if CXX_ISO_COMPLIANT_LIBRARY + + fs.open (nm.c_str (), arg_md); + +#else + // Override default protection of 0664 so that umask will appear to + // do the right thing. + + fs.open (nm.c_str (), arg_md, 0666); + +#endif + + if (! fs) + error (gnulib::strerror (errno)); +} + +// Position a stream at OFFSET relative to ORIGIN. + +int +octave_fstream::seek (long, int) +{ + error ("fseek: invalid_operation"); + return -1; +} + +// Return current stream position. + +long +octave_fstream::tell (void) +{ + error ("ftell: invalid_operation"); + return -1; +} + +// Return non-zero if EOF has been reached on this stream. + +bool +octave_fstream::eof (void) const +{ + return fs.eof (); +} + +void +octave_fstream::do_close (void) +{ + fs.close (); +} + +std::istream * +octave_fstream::input_stream (void) +{ + std::istream *retval = 0; + + if (mode () & std::ios::in) + retval = &fs; + + return retval; +} + +std::ostream * +octave_fstream::output_stream (void) +{ + std::ostream *retval = 0; + + if (mode () & std::ios::out) + retval = &fs; + + return retval; +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-fstrm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-fstrm.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,86 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_octave_fstream_h) +#define octave_octave_fstream_h 1 + +#include +#include + +#include "oct-stream.h" + +class +octave_fstream : public octave_base_stream +{ +public: + + octave_fstream (const std::string& nm_arg, + std::ios::openmode arg_md = std::ios::in|std::ios::out, + oct_mach_info::float_format flt_fmt + = oct_mach_info::native_float_format ()); + + static octave_stream + create (const std::string& nm_arg, + std::ios::openmode arg_md = std::ios::in|std::ios::out, + oct_mach_info::float_format flt_fmt + = oct_mach_info::native_float_format ()); + + // Position a stream at OFFSET relative to ORIGIN. + + int seek (long offset, int origin); + + // Return current stream position. + + long tell (void); + + // Return non-zero if EOF has been reached on this stream. + + bool eof (void) const; + + void do_close (void); + + // The name of the file. + + std::string name (void) const { return nm; } + + std::istream *input_stream (void); + + std::ostream *output_stream (void); + +protected: + + ~octave_fstream (void) { } + +private: + + std::string nm; + + std::fstream fs; + + // No copying! + + octave_fstream (const octave_fstream&); + + octave_fstream& operator = (const octave_fstream&); +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-hdf5.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-hdf5.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,30 @@ +/* + +Copyright (C) 2009-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave__hdf5_h) +#define octave_hdf5_h 1 + +#if defined (HAVE_HDF5) +#include +#endif + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-iostrm.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-iostrm.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,89 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "error.h" +#include "oct-iostrm.h" + +// Position a stream at OFFSET relative to ORIGIN. + +int +octave_base_iostream::seek (long, int) +{ + invalid_operation (); + return -1; +} + +// Return current stream position. + +long +octave_base_iostream::tell (void) +{ + invalid_operation (); + return -1; +} + +// Return non-zero if EOF has been reached on this stream. + +bool +octave_base_iostream::eof (void) const +{ + invalid_operation (); + return false; +} + +void +octave_base_iostream::invalid_operation (void) const +{ + ::error ("%s: invalid operation", stream_type ()); +} + +// Return non-zero if EOF has been reached on this stream. + +bool +octave_istream::eof (void) const +{ + return is && is->eof (); +} + +octave_stream +octave_istream::create (std::istream *arg, const std::string& n) +{ + return octave_stream (new octave_istream (arg, n)); +} + +// Return non-zero if EOF has been reached on this stream. + +bool +octave_ostream::eof (void) const +{ + return os && os->eof (); +} + +octave_stream +octave_ostream::create (std::ostream *arg, const std::string& n) +{ + return octave_stream (new octave_ostream (arg, n)); +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-iostrm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-iostrm.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,154 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_octave_iostream_h) +#define octave_octave_iostream_h 1 + +#include + +#include "oct-stream.h" + +class +octave_base_iostream : public octave_base_stream +{ +public: + + octave_base_iostream (const std::string& n = std::string (), + std::ios::openmode m = std::ios::in|std::ios::out, + oct_mach_info::float_format ff + = oct_mach_info::native_float_format ()) + : octave_base_stream (m, ff), nm (n) { } + + // Position a stream at OFFSET relative to ORIGIN. + + int seek (long offset, int origin); + + // Return current stream position. + + long tell (void); + + // Return non-zero if EOF has been reached on this stream. + + bool eof (void) const; + + // The name of the file. + + std::string name (void) const { return nm; } + +protected: + + ~octave_base_iostream (void) { } + + void invalid_operation (void) const; + +private: + + std::string nm; + + virtual const char *stream_type (void) const = 0; + + // No copying! + + octave_base_iostream (const octave_base_iostream&); + + octave_base_iostream& operator = (const octave_base_iostream&); +}; + +class +octave_istream : public octave_base_iostream +{ +public: + + octave_istream (std::istream *arg = 0, const std::string& n = std::string ()) + : octave_base_iostream (n, std::ios::in, + oct_mach_info::native_float_format ()), + is (arg) + { } + + static octave_stream + create (std::istream *arg = 0, const std::string& n = std::string ()); + + // Return non-zero if EOF has been reached on this stream. + + bool eof (void) const; + + std::istream *input_stream (void) { return is; } + + std::ostream *output_stream (void) { return 0; } + +protected: + + ~octave_istream (void) { } + +private: + + std::istream *is; + + const char *stream_type (void) const { return "octave_istream"; } + + // No copying! + + octave_istream (const octave_istream&); + + octave_istream& operator = (const octave_istream&); +}; + +class +octave_ostream : public octave_base_iostream +{ +public: + + octave_ostream (std::ostream *arg, const std::string& n = std::string ()) + : octave_base_iostream (n, std::ios::out, + oct_mach_info::native_float_format ()), + os (arg) + { } + + static octave_stream + create (std::ostream *arg, const std::string& n = std::string ()); + + // Return non-zero if EOF has been reached on this stream. + + bool eof (void) const; + + std::istream *input_stream (void) { return 0; } + + std::ostream *output_stream (void) { return os; } + +protected: + + ~octave_ostream (void) { } + +private: + + std::ostream *os; + + const char *stream_type (void) const { return "octave_ostream"; } + + // No copying! + + octave_ostream (const octave_ostream&); + + octave_ostream& operator = (const octave_ostream&); +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-lvalue.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-lvalue.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,94 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "error.h" +#include "oct-obj.h" +#include "oct-lvalue.h" +#include "ov.h" + +void +octave_lvalue::assign (octave_value::assign_op op, const octave_value& rhs) +{ + if (val) + { + if (idx.empty ()) + val->assign (op, rhs); + else + val->assign (op, type, idx, rhs); + } +} + +void +octave_lvalue::set_index (const std::string& t, + const std::list& i) +{ + if (idx.empty ()) + { + type = t; + idx = i; + } + else + error ("invalid index expression in assignment"); +} + +void +octave_lvalue::do_unary_op (octave_value::unary_op op) +{ + if (val) + { + if (idx.empty ()) + val->do_non_const_unary_op (op); + else + val->do_non_const_unary_op (op, type, idx); + } + else + error ("internal: invalid operation on ~"); +} + +octave_value +octave_lvalue::value (void) +{ + octave_value retval; + + if (val) + { + if (idx.empty ()) + retval = *val; + else + { + if (val->is_constant ()) + retval = val->subsref (type, idx); + else + { + octave_value_list t = val->subsref (type, idx, 1); + if (t.length () > 0) + retval = t(0); + } + } + } + + return retval; +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-lvalue.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-lvalue.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,104 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_lvalue_h) +#define octave_lvalue_h 1 + +class octave_value; +class octave_value_list; + +#include + +#include "oct-obj.h" +#include "pt-idx.h" + +class +octave_lvalue +{ +public: + + octave_lvalue (octave_value *v = 0) + : val (v), type (), idx (), nel (1) + { } + + octave_lvalue (const octave_lvalue& vr) + : val (vr.val), type (vr.type), idx (vr.idx), nel (vr.nel) + { + } + + octave_lvalue& operator = (const octave_lvalue& vr) + { + if (this != &vr) + { + val = vr.val; + type = vr.type; + idx = vr.idx; + nel = vr.nel; + } + + return *this; + } + + ~octave_lvalue (void) { } + + bool is_black_hole (void) const { return val == 0; } + + bool is_defined (void) const { return val && val->is_defined (); } + + bool is_undefined (void) const { return ! val || val->is_undefined (); } + + bool is_map (void) const { return val && val->is_map (); } + + void define (const octave_value& v) + { + if (val) + *val = v; + } + + void assign (octave_value::assign_op, const octave_value&); + + void numel (octave_idx_type n) { nel = n; } + + octave_idx_type numel (void) const { return nel; } + + void set_index (const std::string& t, const std::list& i); + + void clear_index (void) { type = std::string (); idx.clear (); } + + void do_unary_op (octave_value::unary_op op); + + octave_value value (void); + + const octave_value *object (void) const { return val; } + +private: + + octave_value *val; + + std::string type; + + std::list idx; + + octave_idx_type nel; +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-map.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-map.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,1779 @@ +/* + +Copyright (C) 1995-2012 John W. Eaton +Copyright (C) 2010 VZLU Prague + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "error.h" +#include "str-vec.h" + +#include "oct-map.h" +#include "utils.h" + +octave_fields::octave_fields (const string_vector& fields) + : rep (new fields_rep) +{ + octave_idx_type n = fields.numel (); + for (octave_idx_type i = 0; i < n; i++) + (*rep)[fields(i)] = i; +} + +octave_fields::octave_fields (const char * const *fields) + : rep (new fields_rep) +{ + octave_idx_type n = 0; + while (*fields) + (*rep)[std::string (*fields++)] = n++; +} + +bool +octave_fields::isfield (const std::string& field) const +{ + return rep->find (field) != rep->end (); +} + +octave_idx_type +octave_fields::getfield (const std::string& field) const +{ + fields_rep::iterator p = rep->find (field); + return (p != rep->end ()) ? p->second : -1; +} + +octave_idx_type +octave_fields::getfield (const std::string& field) +{ + fields_rep::iterator p = rep->find (field); + if (p != rep->end ()) + return p->second; + else + { + make_unique (); + octave_idx_type n = rep->size (); + return (*rep)[field] = n; + } +} + +octave_idx_type +octave_fields::rmfield (const std::string& field) +{ + fields_rep::iterator p = rep->find (field); + if (p == rep->end ()) + return -1; + else + { + octave_idx_type n = p->second; + make_unique (); + rep->erase (field); + for (fields_rep::iterator q = rep->begin (); q != rep->end (); q++) + { + if (q->second >= n) + q->second--; + } + + return n; + } +} + +void +octave_fields::orderfields (Array& perm) +{ + octave_idx_type n = rep->size (); + perm.clear (n, 1); + + make_unique (); + octave_idx_type i = 0; + for (fields_rep::iterator q = rep->begin (); q != rep->end (); q++) + { + octave_idx_type j = q->second; + q->second = i; + perm(i++) = j; + } +} + +bool +octave_fields::equal_up_to_order (const octave_fields& other, + octave_idx_type* perm) const +{ + bool retval = true; + + iterator p = begin (), q = other.begin (); + for (; p != end () && q != other.end (); p++, q++) + { + if (p->first == q->first) + perm[p->second] = q->second; + else + { + retval = false; + break; + } + } + + retval = (p == end () && q == other.end ()); + + return retval; +} + +bool +octave_fields::equal_up_to_order (const octave_fields& other, + Array& perm) const +{ + octave_idx_type n = nfields (); + if (perm.length () != n) + perm.clear (1, n); + + return equal_up_to_order (other, perm.fortran_vec ()); +} + +string_vector +octave_fields::fieldnames (void) const +{ + octave_idx_type n = nfields (); + string_vector retval(n); + + for (iterator p = begin (); p != end (); p++) + retval.xelem (p->second) = p->first; + + return retval; +} + +octave_value +octave_scalar_map::getfield (const std::string& k) const +{ + octave_idx_type idx = xkeys.getfield (k); + return (idx >= 0) ? xvals[idx] : octave_value (); +} + +void +octave_scalar_map::setfield (const std::string& k, const octave_value& val) +{ + octave_idx_type idx = xkeys.getfield (k); + if (idx < static_cast (xvals.size ())) + xvals[idx] = val; + else + xvals.push_back (val); +} + +void +octave_scalar_map::rmfield (const std::string& k) +{ + octave_idx_type idx = xkeys.rmfield (k); + if (idx >= 0) + xvals.erase (xvals.begin () + idx); +} + +octave_scalar_map +octave_scalar_map::orderfields (void) const +{ + Array perm; + return orderfields (perm); +} + +octave_scalar_map +octave_scalar_map::orderfields (Array& perm) const +{ + octave_scalar_map retval (xkeys); + retval.xkeys.orderfields (perm); + + octave_idx_type nf = nfields (); + for (octave_idx_type i = 0; i < nf; i++) + retval.xvals[i] = xvals[perm.xelem (i)]; + + return retval; +} + +octave_scalar_map +octave_scalar_map::orderfields (const octave_scalar_map& other, + Array& perm) const +{ + if (xkeys.is_same (other.xkeys)) + return *this; + else + { + octave_scalar_map retval (other.xkeys); + if (other.xkeys.equal_up_to_order (xkeys, perm)) + { + octave_idx_type nf = nfields (); + for (octave_idx_type i = 0; i < nf; i++) + retval.xvals[i] = xvals[perm.xelem (i)]; + } + else + error ("orderfields: structs must have same fields up to order"); + + return retval; + } +} + +octave_value +octave_scalar_map::contents (const std::string& k) const +{ + return getfield (k); +} + +octave_value& +octave_scalar_map::contents (const std::string& k) +{ + octave_idx_type idx = xkeys.getfield (k); + if (idx >= static_cast (xvals.size ())) + xvals.resize (idx+1); + return xvals[idx]; +} + +octave_map::octave_map (const octave_scalar_map& m) + : xkeys (m.xkeys), xvals (), dimensions (1, 1) +{ + octave_idx_type nf = m.nfields (); + xvals.reserve (nf); + for (octave_idx_type i = 0; i < nf; i++) + { + xvals.push_back (Cell (dimensions)); + xvals[i].xelem (0) = m.xvals[i]; + } +} + +octave_map::octave_map (const Octave_map& m) + : xkeys (m.keys ()), xvals (m.nfields ()), dimensions (m.dims ()) +{ + for (iterator p = begin (); p != end (); p++) + contents(p) = m.contents (key (p)); + + optimize_dimensions (); +} + +Cell +octave_map::getfield (const std::string& k) const +{ + octave_idx_type idx = xkeys.getfield (k); + return (idx >= 0) ? xvals[idx] : Cell (); +} + +void +octave_map::setfield (const std::string& k, const Cell& val) +{ + if (nfields () == 0) + dimensions = val.dims (); + + if (val.dims () == dimensions) + { + octave_idx_type idx = xkeys.getfield (k); + if (idx < static_cast (xvals.size ())) + xvals[idx] = val; + else + xvals.push_back (val); + } + else + error ("octave_map::setfield: internal error"); +} + +void +octave_map::rmfield (const std::string& k) +{ + octave_idx_type idx = xkeys.rmfield (k); + if (idx >= 0) + xvals.erase (xvals.begin () + idx); +} + +octave_map +octave_map::orderfields (void) const +{ + Array perm; + return orderfields (perm); +} + +octave_map +octave_map::orderfields (Array& perm) const +{ + octave_map retval (xkeys); + retval.xkeys.orderfields (perm); + + octave_idx_type nf = nfields (); + for (octave_idx_type i = 0; i < nf; i++) + retval.xvals[i] = xvals[perm.xelem (i)]; + + return retval; +} + +octave_map +octave_map::orderfields (const octave_map& other, + Array& perm) const +{ + if (xkeys.is_same (other.xkeys)) + return *this; + else + { + octave_map retval (other.xkeys); + if (other.xkeys.equal_up_to_order (xkeys, perm)) + { + octave_idx_type nf = nfields (); + for (octave_idx_type i = 0; i < nf; i++) + retval.xvals[i] = xvals[perm.xelem (i)]; + } + else + error ("orderfields: structs must have same fields up to order"); + + return retval; + } +} + +Cell +octave_map::contents (const std::string& k) const +{ + return getfield (k); +} + +Cell& +octave_map::contents (const std::string& k) +{ + octave_idx_type idx = xkeys.getfield (k); + if (idx >= static_cast (xvals.size ())) + xvals.push_back (Cell (dimensions)); // auto-set correct dims. + return xvals[idx]; +} + +void +octave_map::extract_scalar (octave_scalar_map& dest, + octave_idx_type idx) const +{ + octave_idx_type nf = nfields (); + for (octave_idx_type i = 0; i < nf; i++) + dest.xvals[i] = xvals[i](idx); +} + +octave_scalar_map +octave_map::checkelem (octave_idx_type n) const +{ + octave_scalar_map retval (xkeys); + + // Optimize this so that there is just one check. + extract_scalar (retval, compute_index (n, dimensions)); + + return retval; +} + +octave_scalar_map +octave_map::checkelem (octave_idx_type i, octave_idx_type j) const +{ + octave_scalar_map retval (xkeys); + + // Optimize this so that there is just one check. + extract_scalar (retval, compute_index (i, j, dimensions)); + + return retval; +} + +octave_scalar_map +octave_map::checkelem (const Array& ra_idx) const +{ + octave_scalar_map retval (xkeys); + + // Optimize this so that there is just one check. + extract_scalar (retval, compute_index (ra_idx, dimensions)); + + return retval; +} + +octave_scalar_map +octave_map::fast_elem_extract (octave_idx_type n) const +{ + octave_scalar_map retval (xkeys); + + extract_scalar (retval, n); + + return retval; +} + +bool +octave_map::fast_elem_insert (octave_idx_type n, + const octave_scalar_map& rhs) +{ + bool retval = false; + + octave_idx_type nf = nfields (); + if (rhs.xkeys.is_same (xkeys)) + { + for (octave_idx_type i = 0; i < nf; i++) + xvals[i](n) = rhs.xvals[i]; + + retval = true; + } + else + { + OCTAVE_LOCAL_BUFFER (octave_idx_type, perm, nf); + if (xkeys.equal_up_to_order (rhs.xkeys, perm)) + { + for (octave_idx_type i = 0; i < nf; i++) + xvals[i](n) = rhs.xvals[perm[i]]; + + retval = true; + } + } + + return retval; +} + +octave_map +octave_map::squeeze (void) const +{ + octave_map retval (*this); + octave_idx_type nf = nfields (); + + retval.dimensions = dimensions.squeeze (); + + for (octave_idx_type i = 0; i < nf; i++) + retval.xvals[i] = xvals[i].squeeze (); + + retval.optimize_dimensions (); + + return retval; +} + +/* +## test preservation of xkeys by squeeze +%!test +%! x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27; +%! assert (fieldnames (squeeze (x)), {"d"; "a"; "f"}); +*/ + +octave_map +octave_map::permute (const Array& vec, bool inv) const +{ + octave_map retval (xkeys); + octave_idx_type nf = nfields (); + + for (octave_idx_type i = 0; i < nf; i++) + retval.xvals[i] = xvals[i].permute (vec, inv); + + // FIXME: + // There is no dim_vector::permute for technical reasons. + // We pick the dim vector from results if possible, otherwise use a dummy + // array to get it. Need (?) a better solution to this problem. + if (nf > 0) + retval.dimensions = retval.xvals[0].dims (); + else + { + Array dummy (dimensions); + dummy = dummy.permute (vec, inv); + retval.dimensions = dummy.dims (); + } + + retval.optimize_dimensions (); + + return retval; +} + +/* +## test preservation of key order by permute +%!test +%! x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27; +%! assert (fieldnames (permute (x, [3, 4, 1, 2])), {"d"; "a"; "f"}); +*/ + +octave_map +octave_map::transpose (void) const +{ + assert (ndims () == 2); + + octave_map retval (xkeys); + + retval.dimensions = dim_vector (dimensions (1), dimensions (0)); + + octave_idx_type nf = nfields (); + for (octave_idx_type i = 0; i < nf; i++) + retval.xvals[i] = xvals[i].transpose (); + + retval.optimize_dimensions (); + + return retval; +} + +/* +## test preservation of key order by transpose +%!test +%! x(1,1).d = 10; x(3,5).a = "b"; x(2,4).f = 27; +%! assert (fieldnames (transpose (x)), {"d"; "a"; "f"}); +%! assert (fieldnames (x'), {"d"; "a"; "f"}); +%! assert (fieldnames (x.'), {"d"; "a"; "f"}); +*/ + +octave_map +octave_map::reshape (const dim_vector& dv) const +{ + octave_map retval (xkeys); + retval.dimensions = dv; + + octave_idx_type nf = nfields (); + if (nf > 0) + { + retval.xvals.reserve (nf); + for (octave_idx_type i = 0; i < nf; i++) + retval.xvals[i] = xvals[i].reshape (dv); + } + else + { + // FIXME: Do it with a dummy array, to reuse error message. + // Need (?) a better solution. + Array dummy (dimensions); + dummy.reshape (dv); + } + + retval.optimize_dimensions (); + + return retval; +} + +/* +## test preservation of key order by reshape +%!test +%! x(1,1).d = 10; x(4,6).a = "b"; x(2,4).f = 27; +%! assert (fieldnames (reshape (x, 3, 8)), {"d"; "a"; "f"}); +*/ + +void +octave_map::resize (const dim_vector& dv, bool fill) +{ + octave_idx_type nf = nfields (); + if (nf > 0) + { + for (octave_idx_type i = 0; i < nf; i++) + { + if (fill) + xvals[i].resize (dv, Matrix ()); + else + xvals[i].resize (dv); + } + } + else + { + // FIXME: Do it with a dummy array, to reuse error message. + // Need (?) a better solution. + Array dummy (dimensions); + dummy.resize (dv); + } + + dimensions = dv; + optimize_dimensions (); +} + +void +octave_map::do_cat (int dim, octave_idx_type n, const octave_scalar_map *map_list, + octave_map& retval) +{ + octave_idx_type nf = retval.nfields (); + retval.xvals.reserve (nf); + + dim_vector& rd = retval.dimensions; + rd.resize (dim+1, 1); + rd(0) = rd(1) = 1; + rd(dim) = n; + + for (octave_idx_type j = 0; j < nf; j++) + { + retval.xvals.push_back (Cell (rd)); + assert (retval.xvals[j].numel () == n); + for (octave_idx_type i = 0; i < n; i++) + retval.xvals[j].xelem (i) = map_list[i].xvals[j]; + } +} + +void +octave_map::do_cat (int dim, octave_idx_type n, const octave_map *map_list, + octave_map& retval) +{ + octave_idx_type nf = retval.nfields (); + retval.xvals.reserve (nf); + + OCTAVE_LOCAL_BUFFER (Array, field_list, n); + + for (octave_idx_type j = 0; j < nf; j++) + { + for (octave_idx_type i = 0; i < n; i++) + field_list[i] = map_list[i].xvals[j]; + + retval.xvals.push_back (Array::cat (dim, n, field_list)); + if (j == 0) + retval.dimensions = retval.xvals[j].dims (); + } +} + +// This is just a wrapper. +void permute_to_correct_order1 (const octave_scalar_map& ref, const octave_scalar_map& src, + octave_scalar_map& dest, Array& perm) +{ + dest = src.orderfields (ref, perm); +} + +// In non-scalar case, we also promote empty structs without fields. +void permute_to_correct_order1 (const octave_map& ref, const octave_map& src, + octave_map& dest, Array& perm) +{ + if (src.nfields () == 0 && src.is_empty ()) + dest = octave_map (src.dims (), ref.keys ()); + else + dest = src.orderfields (ref, perm); +} + +template +static void +permute_to_correct_order (octave_idx_type n, octave_idx_type nf, + octave_idx_type idx, const map *map_list, + map *new_map_list) +{ + new_map_list[idx] = map_list[idx]; + + Array perm (dim_vector (1, nf)); + + for (octave_idx_type i = 0; i < n; i++) + { + if (i == idx) + continue; + + permute_to_correct_order1 (map_list[idx], map_list[i], new_map_list[i], perm); + + if (error_state) + { + // Use liboctave exception to be consistent. + (*current_liboctave_error_handler) + ("cat: field names mismatch in concatenating structs"); + break; + } + } +} + + +octave_map +octave_map::cat (int dim, octave_idx_type n, const octave_scalar_map *map_list) +{ + octave_map retval; + + // Allow dim = -1, -2 for compatibility, though it makes no difference here. + if (dim == -1 || dim == -2) + dim = -dim - 1; + else if (dim < 0) + (*current_liboctave_error_handler) + ("cat: invalid dimension"); + + if (n == 1) + retval = map_list[0]; + else if (n > 1) + { + octave_idx_type idx, nf = 0; + for (idx = 0; idx < n; idx++) + { + nf = map_list[idx].nfields (); + if (nf > 0) + { + retval.xkeys = map_list[idx].xkeys; + break; + } + } + + if (nf > 0) + { + // Try the fast case. + bool all_same = true; + for (octave_idx_type i = 0; i < n; i++) + { + all_same = map_list[idx].xkeys.is_same (map_list[i].xkeys); + if (! all_same) + break; + } + + if (all_same) + do_cat (dim, n, map_list, retval); + else + { + // permute all structures to common order. + OCTAVE_LOCAL_BUFFER (octave_scalar_map, new_map_list, n); + + permute_to_correct_order (n, nf, idx, map_list, new_map_list); + + do_cat (dim, n, new_map_list, retval); + } + + } + else + { + dim_vector& rd = retval.dimensions; + rd.resize (dim+1, 1); + rd(0) = rd(1) = 1; + rd(dim) = n; + } + + retval.optimize_dimensions (); + } + + return retval; +} + +octave_map +octave_map::cat (int dim, octave_idx_type n, const octave_map *map_list) +{ + octave_map retval; + + // Allow dim = -1, -2 for compatibility, though it makes no difference here. + if (dim == -1 || dim == -2) + dim = -dim - 1; + else if (dim < 0) + (*current_liboctave_error_handler) + ("cat: invalid dimension"); + + if (n == 1) + retval = map_list[0]; + else if (n > 1) + { + octave_idx_type idx, nf = 0; + + for (idx = 0; idx < n; idx++) + { + nf = map_list[idx].nfields (); + if (nf > 0) + { + retval.xkeys = map_list[idx].xkeys; + break; + } + } + + // Try the fast case. + bool all_same = true; + + if (nf > 0) + { + for (octave_idx_type i = 0; i < n; i++) + { + all_same = map_list[idx].xkeys.is_same (map_list[i].xkeys); + + if (! all_same) + break; + } + } + + if (all_same && nf > 0) + do_cat (dim, n, map_list, retval); + else + { + if (nf > 0) + { + // permute all structures to correct order. + OCTAVE_LOCAL_BUFFER (octave_map, new_map_list, n); + + permute_to_correct_order (n, nf, idx, map_list, new_map_list); + + do_cat (dim, n, new_map_list, retval); + } + else + { + dim_vector dv = map_list[0].dimensions; + + for (octave_idx_type i = 1; i < n; i++) + { + if (! dv.concat (map_list[i].dimensions, dim)) + { + error ("dimension mismatch in struct concatenation"); + return retval; + } + } + + retval.dimensions = dv; + } + } + + retval.optimize_dimensions (); + } + + return retval; +} + +/* +## test preservation of key order by concatenation +%!test +%! x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27; +%! y(1, 6).f = 11; y(1, 6).a = "c"; y(1, 6).d = 33; +%! assert (fieldnames ([x; y]), {"d"; "a"; "f"}); + +%!test +%! s = struct (); +%! sr = [s,s]; +%! sc = [s;s]; +%! sm = [s,s;s,s]; +%! assert (nfields (sr), 0); +%! assert (nfields (sc), 0); +%! assert (nfields (sm), 0); +%! assert (size (sr), [1, 2]); +%! assert (size (sc), [2, 1]); +%! assert (size (sm), [2, 2]); +*/ + +octave_map +octave_map::index (const idx_vector& i, bool resize_ok) const +{ + octave_map retval (xkeys); + octave_idx_type nf = nfields (); + + for (octave_idx_type k = 0; k < nf; k++) + retval.xvals[k] = xvals[k].index (i, resize_ok); + + if (nf > 0) + retval.dimensions = retval.xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array dummy (dimensions); + dummy = dummy.index (i, resize_ok); + retval.dimensions = dummy.dims (); + } + + retval.optimize_dimensions (); + + return retval; +} + +octave_map +octave_map::index (const idx_vector& i, const idx_vector& j, + bool resize_ok) const +{ + octave_map retval (xkeys); + octave_idx_type nf = nfields (); + + for (octave_idx_type k = 0; k < nf; k++) + retval.xvals[k] = xvals[k].index (i, j, resize_ok); + + if (nf > 0) + retval.dimensions = retval.xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array dummy (dimensions); + dummy = dummy.index (i, j, resize_ok); + retval.dimensions = dummy.dims (); + } + + retval.optimize_dimensions (); + + return retval; +} + +octave_map +octave_map::index (const Array& ia, bool resize_ok) const +{ + octave_map retval (xkeys); + octave_idx_type nf = nfields (); + + for (octave_idx_type k = 0; k < nf; k++) + retval.xvals[k] = xvals[k].index (ia, resize_ok); + + if (nf > 0) + retval.dimensions = retval.xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array dummy (dimensions); + dummy = dummy.index (ia, resize_ok); + retval.dimensions = dummy.dims (); + } + + retval.optimize_dimensions (); + + return retval; +} + +octave_map +octave_map::index (const octave_value_list& idx, bool resize_ok) const +{ + octave_idx_type n_idx = idx.length (); + octave_map retval; + + switch (n_idx) + { + case 1: + { + idx_vector i = idx(0).index_vector (); + + if (! error_state) + retval = index (i, resize_ok); + } + break; + + case 2: + { + idx_vector i = idx(0).index_vector (); + + if (! error_state) + { + idx_vector j = idx(1).index_vector (); + + retval = index (i, j, resize_ok); + } + } + break; + + default: + { + Array ia (dim_vector (n_idx, 1)); + + for (octave_idx_type i = 0; i < n_idx; i++) + { + ia(i) = idx(i).index_vector (); + + if (error_state) + break; + } + + if (! error_state) + retval = index (ia, resize_ok); + } + break; + } + + return retval; +} + +// Perhaps one day these will be optimized. Right now, they just call index. +octave_map +octave_map::column (octave_idx_type k) const +{ + return index (idx_vector::colon, k); +} + +octave_map +octave_map::page (octave_idx_type k) const +{ + static Array ia (dim_vector (3, 1), idx_vector::colon); + + ia(2) = k; + return index (ia); +} + +void +octave_map::assign (const idx_vector& i, const octave_map& rhs) +{ + if (rhs.xkeys.is_same (xkeys)) + { + octave_idx_type nf = nfields (); + + for (octave_idx_type k = 0; k < nf; k++) + xvals[k].assign (i, rhs.xvals[k], Matrix ()); + + if (nf > 0) + dimensions = xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array dummy (dimensions), rhs_dummy (rhs.dimensions); + dummy.assign (i, rhs_dummy);; + dimensions = dummy.dims (); + } + + optimize_dimensions (); + } + else if (nfields () == 0) + { + octave_map tmp (dimensions, rhs.xkeys); + tmp.assign (i, rhs); + *this = tmp; + } + else + { + Array perm; + octave_map rhs1 = rhs.orderfields (*this, perm); + if (! error_state) + { + assert (rhs1.xkeys.is_same (xkeys)); + assign (i, rhs1); + } + else + error ("incompatible fields in struct assignment"); + } +} + +void +octave_map::assign (const idx_vector& i, const idx_vector& j, + const octave_map& rhs) +{ + if (rhs.xkeys.is_same (xkeys)) + { + octave_idx_type nf = nfields (); + + for (octave_idx_type k = 0; k < nf; k++) + xvals[k].assign (i, j, rhs.xvals[k], Matrix ()); + + if (nf > 0) + dimensions = xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array dummy (dimensions), rhs_dummy (rhs.dimensions); + dummy.assign (i, j, rhs_dummy);; + dimensions = dummy.dims (); + } + + optimize_dimensions (); + } + else if (nfields () == 0) + { + octave_map tmp (dimensions, rhs.xkeys); + tmp.assign (i, j, rhs); + *this = tmp; + } + else + { + Array perm; + octave_map rhs1 = rhs.orderfields (*this, perm); + if (! error_state) + { + assert (rhs1.xkeys.is_same (xkeys)); + assign (i, j, rhs1); + } + else + error ("incompatible fields in struct assignment"); + } +} + +void +octave_map::assign (const Array& ia, + const octave_map& rhs) +{ + if (rhs.xkeys.is_same (xkeys)) + { + octave_idx_type nf = nfields (); + + for (octave_idx_type k = 0; k < nf; k++) + xvals[k].assign (ia, rhs.xvals[k], Matrix ()); + + if (nf > 0) + dimensions = xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array dummy (dimensions), rhs_dummy (rhs.dimensions); + dummy.assign (ia, rhs_dummy);; + dimensions = dummy.dims (); + } + + optimize_dimensions (); + } + else if (nfields () == 0) + { + octave_map tmp (dimensions, rhs.xkeys); + tmp.assign (ia, rhs); + *this = tmp; + } + else + { + Array perm; + octave_map rhs1 = rhs.orderfields (*this, perm); + if (! error_state) + { + assert (rhs1.xkeys.is_same (xkeys)); + assign (ia, rhs1); + } + else + error ("incompatible fields in struct assignment"); + } +} + +void +octave_map::assign (const octave_value_list& idx, const octave_map& rhs) +{ + octave_idx_type n_idx = idx.length (); + + switch (n_idx) + { + case 1: + { + idx_vector i = idx(0).index_vector (); + + if (! error_state) + assign (i, rhs); + } + break; + + case 2: + { + idx_vector i = idx(0).index_vector (); + + if (! error_state) + { + idx_vector j = idx(1).index_vector (); + + assign (i, j, rhs); + } + } + break; + + default: + { + Array ia (dim_vector (n_idx, 1)); + + for (octave_idx_type i = 0; i < n_idx; i++) + { + ia(i) = idx(i).index_vector (); + + if (error_state) + break; + } + + if (! error_state) + assign (ia, rhs); + } + break; + } +} + +void +octave_map::assign (const octave_value_list& idx, const std::string& k, + const Cell& rhs) +{ + Cell tmp; + iterator p = seek (k); + Cell& ref = p != end () ? contents (p) : tmp; + + if (&ref == &tmp) + ref = Cell (dimensions); + + ref.assign (idx, rhs); + + if (! error_state && ref.dims () != dimensions) + { + dimensions = ref.dims (); + + octave_idx_type nf = nfields (); + for (octave_idx_type i = 0; i < nf; i++) + { + if (&xvals[i] != &ref) + xvals[i].resize (dimensions, Matrix ()); + } + + optimize_dimensions (); + } + + if (! error_state && &ref == &tmp) + setfield (k, tmp); +} + +/* +%!test +%! rhs.b = 1; +%! a(3) = rhs; +%! assert ({a.b}, {[], [], 1}) +*/ + +void +octave_map::delete_elements (const idx_vector& i) +{ + octave_idx_type nf = nfields (); + for (octave_idx_type k = 0; k < nf; k++) + xvals[k].delete_elements (i); + + if (nf > 0) + dimensions = xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array dummy (dimensions); + dummy.delete_elements (i); + dimensions = dummy.dims (); + } + + optimize_dimensions (); +} + +void +octave_map::delete_elements (int dim, const idx_vector& i) +{ + octave_idx_type nf = nfields (); + for (octave_idx_type k = 0; k < nf; k++) + xvals[k].delete_elements (dim, i); + + if (nf > 0) + dimensions = xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array dummy (dimensions); + dummy.delete_elements (dim, i); + dimensions = dummy.dims (); + } + + optimize_dimensions (); +} + +void +octave_map::delete_elements (const Array& ia) +{ + octave_idx_type nf = nfields (); + for (octave_idx_type k = 0; k < nf; k++) + xvals[k].delete_elements (ia); + + if (nf > 0) + dimensions = xvals[0].dims (); + else + { + // Use dummy array. FIXME: Need(?) a better solution. + Array dummy (dimensions); + dummy.delete_elements (ia); + dimensions = dummy.dims (); + } + + optimize_dimensions (); +} + +void +octave_map::delete_elements (const octave_value_list& idx) +{ + octave_idx_type n_idx = idx.length (); + + Array ia (dim_vector (n_idx, 1)); + + for (octave_idx_type i = 0; i < n_idx; i++) + { + ia(i) = idx(i).index_vector (); + + if (error_state) + break; + } + + if (! error_state) + delete_elements (ia); +} + +/* +## test preservation of key order by indexing +%!test +%! x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27; +%! assert (fieldnames (x([1, 2], [2:5])), {"d"; "a"; "f"}); +*/ + +octave_map +octave_map::concat (const octave_map& rb, const Array& ra_idx) +{ + if (nfields () == rb.nfields ()) + { + for (const_iterator pa = begin (); pa != end (); pa++) + { + const_iterator pb = rb.seek (key(pa)); + + if (pb == rb.end ()) + { + error ("field name mismatch in structure concatenation"); + break; + } + + contents(pa).insert (rb.contents (pb), ra_idx); + } + } + else + { + dim_vector dv = dims (); + + if (dv.all_zero ()) + *this = rb; + else if (! rb.dims ().all_zero ()) + error ("invalid structure concatenation"); + } + + return *this; +} + +void +octave_map::optimize_dimensions (void) +{ + octave_idx_type nf = nfields (); + + for (octave_idx_type i = 0; i < nf; i++) + { + if (! xvals[i].optimize_dimensions (dimensions)) + { + error ("internal error: dimension mismatch across fields in struct"); + break; + } + } + +} + +Octave_map::Octave_map (const dim_vector& dv, const Cell& key_vals) + : map (), key_list (), dimensions (dv) +{ + Cell c (dv); + + if (key_vals.is_cellstr ()) + { + for (octave_idx_type i = 0; i < key_vals.numel (); i++) + { + std::string k = key_vals(i).string_value (); + map[k] = c; + key_list.push_back (k); + } + } + else + error ("Octave_map: expecting keys to be cellstr"); +} + +Octave_map::Octave_map (const octave_map& m) + : map (), key_list (), dimensions (m.dims ()) +{ + for (octave_map::const_iterator p = m.begin (); p != m.end (); p++) + map[m.key (p)] = m.contents (p); + const string_vector mkeys = m.fieldnames (); + for (octave_idx_type i = 0; i < mkeys.numel (); i++) + key_list.push_back (mkeys(i)); +} + +Octave_map +Octave_map::squeeze (void) const +{ + Octave_map retval (dims ().squeeze ()); + + for (const_iterator pa = begin (); pa != end (); pa++) + { + Cell tmp = contents (pa).squeeze (); + + if (error_state) + break; + + retval.assign (key (pa), tmp); + } + + // Preserve order of keys. + retval.key_list = key_list; + + return retval; +} + +Octave_map +Octave_map::permute (const Array& vec, bool inv) const +{ + Octave_map retval (dims ()); + + for (const_iterator pa = begin (); pa != end (); pa++) + { + Cell tmp = contents (pa).permute (vec, inv); + + if (error_state) + break; + + retval.assign (key (pa), tmp); + } + + // Preserve order of keys. + retval.key_list = key_list; + + return retval; +} + +Cell& +Octave_map::contents (const std::string& k) +{ + maybe_add_to_key_list (k); + + return map[k]; +} + +Cell +Octave_map::contents (const std::string& k) const +{ + const_iterator p = seek (k); + + return p != end () ? p->second : Cell (); +} + +int +Octave_map::intfield (const std::string& k, int def_val) const +{ + int retval = def_val; + + Cell c = contents (k); + + if (! c.is_empty ()) + retval = c(0).int_value (); + + return retval; +} + +std::string +Octave_map::stringfield (const std::string& k, + const std::string& def_val) const +{ + std::string retval = def_val; + + Cell c = contents (k); + + if (! c.is_empty ()) + retval = c(0).string_value (); + + return retval; +} + +string_vector +Octave_map::keys (void) const +{ + assert (static_cast(nfields ()) == key_list.size ()); + + return string_vector (key_list); +} + +Octave_map +Octave_map::transpose (void) const +{ + assert (ndims () == 2); + + dim_vector dv = dims (); + + octave_idx_type nr = dv(0); + octave_idx_type nc = dv(1); + + dim_vector new_dims (nc, nr); + + Octave_map retval (new_dims); + + for (const_iterator p = begin (); p != end (); p++) + retval.assign (key(p), Cell (contents(p).transpose ())); + + // Preserve order of keys. + retval.key_list = key_list; + + return retval; +} + +Octave_map +Octave_map::reshape (const dim_vector& new_dims) const +{ + Octave_map retval; + + if (new_dims != dims ()) + { + for (const_iterator p = begin (); p != end (); p++) + retval.assign (key(p), contents(p).reshape (new_dims)); + + retval.dimensions = new_dims; + + // Preserve order of keys. + retval.key_list = key_list; + } + else + retval = *this; + + return retval; +} + +void +Octave_map::resize (const dim_vector& dv, bool fill) +{ + if (dv != dims ()) + { + if (nfields () == 0) + dimensions = dv; + else + { + for (const_iterator p = begin (); p != end (); p++) + { + Cell tmp = contents(p); + + if (fill) + tmp.resize (dv, Matrix ()); + else + tmp.resize (dv); + + dimensions = dv; + + assign (key(p), tmp); + } + } + } +} + +Octave_map +Octave_map::concat (const Octave_map& rb, const Array& ra_idx) +{ + Octave_map retval; + + if (nfields () == rb.nfields ()) + { + for (const_iterator pa = begin (); pa != end (); pa++) + { + const_iterator pb = rb.seek (key(pa)); + + if (pb == rb.end ()) + { + error ("field name mismatch in structure concatenation"); + break; + } + + retval.assign (key(pa), + contents(pa).insert (rb.contents(pb), ra_idx)); + } + + // Preserve order of keys. + retval.key_list = key_list; + } + else + { + dim_vector dv = dims (); + + if (dv.all_zero ()) + retval = rb; + else + { + dv = rb.dims (); + + if (dv.all_zero ()) + retval = *this; + else + error ("invalid structure concatenation"); + } + } + + return retval; +} + +static bool +keys_ok (const Octave_map& a, const Octave_map& b, string_vector& keys) +{ + bool retval = false; + + keys = string_vector (); + + if (a.nfields () == 0) + { + keys = b.keys (); + retval = true; + } + else + { + string_vector a_keys = a.keys ().sort (); + string_vector b_keys = b.keys ().sort (); + + octave_idx_type a_len = a_keys.length (); + octave_idx_type b_len = b_keys.length (); + + if (a_len == b_len) + { + for (octave_idx_type i = 0; i < a_len; i++) + { + if (a_keys[i] != b_keys[i]) + goto done; + } + + keys = a_keys; + retval = true; + } + } + + done: + return retval; +} + +Octave_map& +Octave_map::maybe_delete_elements (const octave_value_list& idx) +{ + string_vector t_keys = keys (); + octave_idx_type len = t_keys.length (); + + if (len > 0) + { + for (octave_idx_type i = 0; i < len; i++) + { + std::string k = t_keys[i]; + + contents(k).delete_elements (idx); + + if (error_state) + break; + } + + if (!error_state) + dimensions = contents(t_keys[0]).dims (); + } + + return *this; +} + +Octave_map& +Octave_map::assign (const octave_value_list& idx, const Octave_map& rhs) +{ + string_vector t_keys; + + if (keys_ok (*this, rhs, t_keys)) + { + octave_idx_type len = t_keys.length (); + + if (len == 0) + { + Cell tmp_lhs (dims ()); + Cell tmp_rhs (rhs.dims ()); + + tmp_lhs.assign (idx, tmp_rhs, Matrix ()); + + if (! error_state) + resize (tmp_lhs.dims ()); + else + error ("size mismatch in structure assignment"); + } + else + { + for (octave_idx_type i = 0; i < len; i++) + { + std::string k = t_keys[i]; + + Cell t_rhs = rhs.contents (k); + + assign (idx, k, t_rhs); + + if (error_state) + break; + } + } + } + else + error ("field name mismatch in structure assignment"); + + return *this; +} + +Octave_map& +Octave_map::assign (const octave_value_list& idx, const std::string& k, + const Cell& rhs) +{ + Cell tmp; + + if (contains (k)) + tmp = map[k]; + else + tmp = Cell (dimensions); + + tmp.assign (idx, rhs); + + if (! error_state) + { + dim_vector tmp_dims = tmp.dims (); + + if (tmp_dims != dimensions) + { + for (iterator p = begin (); p != end (); p++) + contents(p).resize (tmp_dims, Matrix ()); + + dimensions = tmp_dims; + } + + maybe_add_to_key_list (k); + + map[k] = tmp; + } + + return *this; +} + +Octave_map& +Octave_map::assign (const std::string& k, const octave_value& rhs) +{ + if (nfields () == 0) + { + maybe_add_to_key_list (k); + + map[k] = Cell (rhs); + + dimensions = dim_vector (1, 1); + } + else + { + dim_vector dv = dims (); + + if (dv.all_ones ()) + { + maybe_add_to_key_list (k); + + map[k] = Cell (rhs); + } + else + error ("invalid structure assignment"); + } + + return *this; +} + +Octave_map& +Octave_map::assign (const std::string& k, const Cell& rhs) +{ + if (nfields () == 0) + { + maybe_add_to_key_list (k); + + map[k] = rhs; + + dimensions = rhs.dims (); + } + else + { + if (dims () == rhs.dims ()) + { + maybe_add_to_key_list (k); + + map[k] = rhs; + } + else + error ("invalid structure assignment"); + } + + return *this; +} + +Octave_map +Octave_map::index (const octave_value_list& idx, bool resize_ok) const +{ + Octave_map retval; + + octave_idx_type n_idx = idx.length (); + + if (n_idx > 0) + { + Array ra_idx (dim_vector (n_idx, 1)); + + for (octave_idx_type i = 0; i < n_idx; i++) + { + ra_idx(i) = idx(i).index_vector (); + if (error_state) + break; + } + + if (! error_state) + { + for (const_iterator p = begin (); p != end (); p++) + { + Cell tmp = contents (p); + + tmp = tmp.Array::index (ra_idx, resize_ok); + + if (error_state) + break; + + retval.assign (key(p), tmp); + } + + // Preserve order of keys. + retval.key_list = key_list; + } + } + else + retval = *this; + + return retval; +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-map.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-map.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,659 @@ +/* + +Copyright (C) 1994-2012 John W. Eaton +Copyright (C) 2010 VZLU Prague + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_oct_map_h) +#define octave_oct_map_h 1 + +#include +#include + +#include "Cell.h" +#include "oct-obj.h" + +class string_vector; + +// A class holding a map field->index. Supports reference-counting. +class OCTINTERP_API +octave_fields +{ + class fields_rep : public std::map + { + public: + fields_rep (void) : std::map (), count (1) { } + fields_rep (const fields_rep& other) + : std::map (other), count (1) { } + + octave_refcount count; + + private: + fields_rep& operator = (const fields_rep&); // no assignment! + }; + + fields_rep *rep; + + static fields_rep *nil_rep (void) + { + static fields_rep nr; + return &nr; + } + +public: + + octave_fields (void) : rep (nil_rep ()) { rep->count++; } + octave_fields (const string_vector&); + octave_fields (const char * const *); + + ~octave_fields (void) + { + if (--rep->count == 0) + delete rep; + } + + void make_unique (void) + { + if (rep->count > 1) + { + fields_rep *r = new fields_rep (*rep); + + if (--rep->count == 0) + delete rep; + + rep = r; + } + } + + octave_fields (const octave_fields& o) : rep (o.rep) { rep->count++; } + + octave_fields& + operator = (const octave_fields& o) + { + o.rep->count++; + if (--rep->count == 0) + delete rep; + rep = o.rep; + + return *this; + } + + // constant iteration support. non-const iteration intentionally unsupported. + + typedef std::map::const_iterator const_iterator; + typedef const_iterator iterator; + + const_iterator begin (void) const { return rep->begin (); } + const_iterator end (void) const { return rep->end (); } + + std::string key (const_iterator p) const { return p->first; } + octave_idx_type index (const_iterator p) const { return p->second; } + + const_iterator seek (const std::string& k) const + { return rep->find (k); } + + // high-level methods. + + // number of fields. + octave_idx_type nfields (void) const { return rep->size (); } + + // check whether a field exists. + bool isfield (const std::string& name) const; + + // get index of field. return -1 if not exist + octave_idx_type getfield (const std::string& name) const; + // get index of field. add if not exist + octave_idx_type getfield (const std::string& name); + // remove field and return the index. -1 if didn't exist. + octave_idx_type rmfield (const std::string& name); + + // order the fields of this map. creates a permutation + // used to order the fields. + void orderfields (Array& perm); + + // compares two instances for equality up to order of fields. + // returns a permutation needed to bring the fields of *other* + // into the order of *this*. + bool equal_up_to_order (const octave_fields& other, + octave_idx_type* perm) const; + + bool equal_up_to_order (const octave_fields& other, + Array& perm) const; + + bool is_same (const octave_fields& other) const + { return rep == other.rep; } + + // Returns the fields as a vector of strings. + string_vector fieldnames (void) const; + + void clear (void) + { + *this = octave_fields (); + } +}; + + +class OCTINTERP_API +octave_scalar_map +{ +public: + + octave_scalar_map (const octave_fields& k) + : xkeys (k), xvals (k.nfields ()) { } + + octave_scalar_map (void) : xkeys (), xvals () { } + + octave_scalar_map (const string_vector& k) + : xkeys (k), xvals (k.length ()) { } + + octave_scalar_map (const octave_scalar_map& m) + : xkeys (m.xkeys), xvals(m.xvals) { } + + octave_scalar_map& operator = (const octave_scalar_map& m) + { + xkeys = m.xkeys; + xvals = m.xvals; + + return *this; + } + + // iteration support. note that both const and non-const iterators are the + // same. The const/non-const distinction is made by the key & contents method. + typedef octave_fields::const_iterator const_iterator; + typedef const_iterator iterator; + + const_iterator begin (void) const { return xkeys.begin (); } + const_iterator end (void) const { return xkeys.end (); } + + const_iterator seek (const std::string& k) const { return xkeys.seek (k); } + + std::string key (const_iterator p) const + { return xkeys.key (p); } + octave_idx_type index (const_iterator p) const + { return xkeys.index (p); } + + const octave_value& contents (const_iterator p) const + { return xvals[xkeys.index (p)]; } + + octave_value& contents (iterator p) + { return xvals[xkeys.index (p)]; } + + const octave_value& contents (octave_idx_type i) const + { return xvals[i]; } + + octave_value& contents (octave_idx_type i) + { return xvals[i]; } + + // number of fields. + octave_idx_type nfields (void) const { return xkeys.nfields (); } + + // check whether a field exists. + bool isfield (const std::string& name) const + { return xkeys.isfield (name); } + + bool contains (const std::string& name) const + { return isfield (name); } + + string_vector fieldnames (void) const + { return xkeys.fieldnames (); } + + string_vector keys (void) const + { return fieldnames (); } + + // get contents of a given field. empty value if not exist. + octave_value getfield (const std::string& key) const; + + // set contents of a given field. add if not exist. + void setfield (const std::string& key, const octave_value& val); + void assign (const std::string& k, const octave_value& val) + { setfield (k, val); } + + // remove a given field. do nothing if not exist. + void rmfield (const std::string& key); + void del (const std::string& k) { rmfield (k); } + + // return a copy with fields ordered, optionally along with permutation. + octave_scalar_map orderfields (void) const; + octave_scalar_map orderfields (Array& perm) const; + octave_scalar_map orderfields (const octave_scalar_map& other, + Array& perm) const; + + // aka getfield/setfield, but the latter returns a reference. + octave_value contents (const std::string& k) const; + octave_value& contents (const std::string& k); + + void clear (void) + { + xkeys.clear (); + xvals.clear (); + } + + friend class octave_map; + +private: + + octave_fields xkeys; + std::vector xvals; + +}; + +template<> +inline octave_scalar_map octave_value_extract (const octave_value& v) + { return v.scalar_map_value (); } + +class OCTINTERP_API +octave_map +{ +public: + + octave_map (const octave_fields& k) + : xkeys (k), xvals (k.nfields ()), dimensions () { } + + octave_map (const dim_vector& dv, const octave_fields& k) + : xkeys (k), xvals (k.nfields (), Cell (dv)), dimensions (dv) { } + + typedef octave_scalar_map element_type; + + octave_map (void) : xkeys (), xvals (), dimensions () { } + + octave_map (const dim_vector& dv) : xkeys (), xvals (), dimensions (dv) { } + + octave_map (const string_vector& k) + : xkeys (k), xvals (k.length (), Cell (1, 1)), dimensions (1, 1) { } + + octave_map (const dim_vector& dv, const string_vector& k) + : xkeys (k), xvals (k.length (), Cell (dv)), dimensions (dv) { } + + octave_map (const octave_map& m) + : xkeys (m.xkeys), xvals (m.xvals), dimensions (m.dimensions) { } + + octave_map (const octave_scalar_map& m); + + octave_map (const Octave_map& m); + + octave_map& operator = (const octave_map& m) + { + xkeys = m.xkeys; + xvals = m.xvals; + dimensions = m.dimensions; + + return *this; + } + + // iteration support. note that both const and non-const iterators are the + // same. The const/non-const distinction is made by the key & contents method. + typedef octave_fields::const_iterator const_iterator; + typedef const_iterator iterator; + + const_iterator begin (void) const { return xkeys.begin (); } + const_iterator end (void) const { return xkeys.end (); } + + const_iterator seek (const std::string& k) const { return xkeys.seek (k); } + + std::string key (const_iterator p) const + { return xkeys.key (p); } + octave_idx_type index (const_iterator p) const + { return xkeys.index (p); } + + const Cell& contents (const_iterator p) const + { return xvals[xkeys.index (p)]; } + + Cell& contents (iterator p) + { return xvals[xkeys.index (p)]; } + + const Cell& contents (octave_idx_type i) const + { return xvals[i]; } + + Cell& contents (octave_idx_type i) + { return xvals[i]; } + + // number of fields. + octave_idx_type nfields (void) const { return xkeys.nfields (); } + + // check whether a field exists. + bool isfield (const std::string& name) const + { return xkeys.isfield (name); } + + bool contains (const std::string& name) const + { return isfield (name); } + + string_vector fieldnames (void) const + { return xkeys.fieldnames (); } + + string_vector keys (void) const + { return fieldnames (); } + + // get contents of a given field. empty value if not exist. + Cell getfield (const std::string& key) const; + + // set contents of a given field. add if not exist. checks for + // correct dimensions. + void setfield (const std::string& key, const Cell& val); + void assign (const std::string& k, const Cell& val) + { setfield (k, val); } + + // remove a given field. do nothing if not exist. + void rmfield (const std::string& key); + void del (const std::string& k) { rmfield (k); } + + // return a copy with fields ordered, optionally along with permutation. + octave_map orderfields (void) const; + octave_map orderfields (Array& perm) const; + octave_map orderfields (const octave_map& other, + Array& perm) const; + + // aka getfield/setfield, but the latter returns a reference. + Cell contents (const std::string& k) const; + Cell& contents (const std::string& k); + + void clear (void) + { + xkeys.clear (); + xvals.clear (); + } + + // The Array-like methods. + octave_idx_type numel (void) const { return dimensions.numel (); } + octave_idx_type length (void) const { return numel (); } + bool is_empty (void) const { return dimensions.any_zero (); } + + octave_idx_type rows (void) const { return dimensions(0); } + octave_idx_type cols (void) const { return dimensions(1); } + octave_idx_type columns (void) const { return dimensions(1); } + + // Extract a scalar substructure. + octave_scalar_map checkelem (octave_idx_type n) const; + octave_scalar_map checkelem (octave_idx_type i, octave_idx_type j) const; + + octave_scalar_map + checkelem (const Array& ra_idx) const; + + octave_scalar_map operator () (octave_idx_type n) const + { return checkelem (n); } + octave_scalar_map operator () (octave_idx_type i, octave_idx_type j) const + { return checkelem (i, j); } + + octave_scalar_map + operator () (const Array& ra_idx) const + { return checkelem (ra_idx); } + + octave_map squeeze (void) const; + + octave_map permute (const Array& vec, bool inv = false) const; + + dim_vector dims (void) const { return dimensions; } + + int ndims (void) const { return dimensions.length (); } + + octave_map transpose (void) const; + + octave_map reshape (const dim_vector& dv) const; + + void resize (const dim_vector& dv, bool fill = false); + + static octave_map + cat (int dim, octave_idx_type n, const octave_scalar_map *map_list); + + static octave_map + cat (int dim, octave_idx_type n, const octave_map *map_list); + + octave_map index (const idx_vector& i, bool resize_ok = false) const; + + octave_map index (const idx_vector& i, const idx_vector& j, + bool resize_ok = false) const; + + octave_map index (const Array& ia, + bool resize_ok = false) const; + + octave_map index (const octave_value_list&, bool resize_ok = false) const; + + octave_map column (octave_idx_type k) const; + octave_map page (octave_idx_type k) const; + + void assign (const idx_vector& i, const octave_map& rhs); + + void assign (const idx_vector& i, const idx_vector& j, const octave_map& rhs); + + void assign (const Array& ia, const octave_map& rhs); + + void assign (const octave_value_list&, const octave_map& rhs); + + void assign (const octave_value_list& idx, const std::string& k, + const Cell& rhs); + + void delete_elements (const idx_vector& i); + + void delete_elements (int dim, const idx_vector& i); + + void delete_elements (const Array& ia); + + void delete_elements (const octave_value_list&); + + octave_map concat (const octave_map& rb, const Array& ra_idx); + + // like checkelem, but no check. + octave_scalar_map fast_elem_extract (octave_idx_type n) const; + + // element assignment, no bounds check + bool fast_elem_insert (octave_idx_type n, const octave_scalar_map& rhs); + +private: + + octave_fields xkeys; + std::vector xvals; + dim_vector dimensions; + + void optimize_dimensions (void); + void extract_scalar (octave_scalar_map& dest, + octave_idx_type index) const; + static void do_cat (int dim, octave_idx_type n, + const octave_scalar_map *map_list, octave_map& retval); + static void do_cat (int dim, octave_idx_type n, + const octave_map *map_list, octave_map& retval); +}; + +template<> +inline octave_map octave_value_extract (const octave_value& v) + { return v.map_value (); } + +// The original Octave_map object. Octave_map and octave_map are convertible to +// each other. + +class +OCTINTERP_API +Octave_map +{ + public: + + typedef std::map::iterator iterator; + typedef std::map::const_iterator const_iterator; + + typedef std::list::iterator key_list_iterator; + typedef std::list::const_iterator const_key_list_iterator; + + // Warning! You should always use at least two dimensions. + + Octave_map (const dim_vector& dv = dim_vector (0, 0), + const Cell& key_vals = Cell ()); + + Octave_map (const std::string& k, const octave_value& value) + : map (), key_list (), dimensions (1, 1) + { + map[k] = value; + key_list.push_back (k); + } + + Octave_map (const string_vector& sv, + const dim_vector& dv = dim_vector (0, 0)) + : map (), key_list (), dimensions (dv) + { + for (octave_idx_type i = 0; i < sv.length (); i++) + { + std::string k = sv[i]; + map[k] = Cell (dv); + key_list.push_back (k); + } + } + + Octave_map (const std::string& k, const Cell& vals) + : map (), key_list (), dimensions (vals.dims ()) + { + map[k] = vals; + key_list.push_back (k); + } + + Octave_map (const std::string& k, const octave_value_list& val_list) + : map (), key_list (), dimensions (1, val_list.length ()) + { + map[k] = val_list; + key_list.push_back (k); + } + + Octave_map (const Octave_map& m) + : map (m.map), key_list (m.key_list), dimensions (m.dimensions) { } + + Octave_map (const octave_map& m); + + Octave_map& operator = (const Octave_map& m) + { + if (this != &m) + { + map = m.map; + key_list = m.key_list; + dimensions = m.dimensions; + } + + return *this; + } + + ~Octave_map (void) { } + + Octave_map squeeze (void) const; + + Octave_map permute (const Array& vec, bool inv = false) const; + + // This is the number of keys. + octave_idx_type nfields (void) const { return map.size (); } + + void del (const std::string& k) + { + iterator p = map.find (k); + + if (p != map.end ()) + { + map.erase (p); + + key_list_iterator q + = std::find (key_list.begin (), key_list.end (), k); + + assert (q != key_list.end ()); + + key_list.erase (q); + } + } + + iterator begin (void) { return iterator (map.begin ()); } + const_iterator begin (void) const { return const_iterator (map.begin ()); } + + iterator end (void) { return iterator (map.end ()); } + const_iterator end (void) const { return const_iterator (map.end ()); } + + std::string key (const_iterator p) const { return p->first; } + + Cell& contents (const std::string& k); + Cell contents (const std::string& k) const; + + Cell& contents (iterator p) + { return p->second; } + + Cell contents (const_iterator p) const + { return p->second; } + + int intfield (const std::string& k, int def_val = 0) const; + + std::string stringfield (const std::string& k, + const std::string& def_val = std::string ()) const; + + iterator seek (const std::string& k) { return map.find (k); } + const_iterator seek (const std::string& k) const { return map.find (k); } + + bool contains (const std::string& k) const + { return (seek (k) != map.end ()); } + + void clear (void) + { + map.clear (); + key_list.clear (); + } + + string_vector keys (void) const; + + octave_idx_type rows (void) const { return dimensions(0); } + + octave_idx_type columns (void) const { return dimensions(1); } + + dim_vector dims (void) const { return dimensions; } + + int ndims (void) const { return dimensions.length (); } + + Octave_map transpose (void) const; + + Octave_map reshape (const dim_vector& new_dims) const; + + void resize (const dim_vector& dv, bool fill = false); + + octave_idx_type numel (void) const { return dimensions.numel (); } + + Octave_map concat (const Octave_map& rb, const Array& ra_idx); + + Octave_map& maybe_delete_elements (const octave_value_list& idx); + + Octave_map& assign (const octave_value_list& idx, const Octave_map& rhs); + + Octave_map& assign (const octave_value_list& idx, const std::string& k, + const Cell& rhs); + + Octave_map& assign (const std::string& k, const octave_value& rhs); + + Octave_map& assign (const std::string& k, const Cell& rhs); + + Octave_map index (const octave_value_list& idx, + bool resize_ok = false) const; + +private: + + // The map of names to values. + std::map map; + + // An extra list of keys, so we can keep track of the order the keys + // are added for compatibility with you know what. + std::list key_list; + + // The current size. + mutable dim_vector dimensions; + + void maybe_add_to_key_list (const std::string& k) + { + if (! contains (k)) + key_list.push_back (k); + } +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-obj.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-obj.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,284 @@ +/* + +Copyright (C) 1994-2012 John W. Eaton +Copyright (C) 2009 VZLU Prague + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "error.h" +#include "oct-obj.h" +#include "Cell.h" + +// We are likely to have a lot of octave_value_list objects to allocate, +// so make the grow_size large. +DEFINE_OCTAVE_ALLOCATOR2(octave_value_list, 1024); + +octave_value_list::octave_value_list (const std::list& lst) +{ + octave_idx_type n = 0, nel = 0; + + // Determine number. + for (std::list::const_iterator p = lst.begin (); + p != lst.end (); p++) + { + n++; + nel += p->length (); + } + + // Optimize single-element case + if (n == 1) + data = lst.front ().data; + else if (nel > 0) + { + data.resize (dim_vector (1, nel)); + octave_idx_type k = 0; + for (std::list::const_iterator p = lst.begin (); + p != lst.end (); p++) + { + data.assign (idx_vector (k, k + p->length ()), p->data); + k += p->length (); + } + assert (k == nel); + } + +} + +octave_value_list& +octave_value_list::prepend (const octave_value& val) +{ + octave_idx_type n = length (); + + resize (n + 1); + + while (n > 0) + { + elem (n) = elem (n - 1); + n--; + } + + elem (0) = val; + + return *this; +} + +octave_value_list& +octave_value_list::append (const octave_value& val) +{ + octave_idx_type n = length (); + + resize (n + 1); + + elem (n) = val; + + return *this; +} + +octave_value_list& +octave_value_list::append (const octave_value_list& lst) +{ + octave_idx_type len = length (); + octave_idx_type lst_len = lst.length (); + + resize (len + lst_len); + + for (octave_idx_type i = 0; i < lst_len; i++) + elem (len + i) = lst (i); + + return *this; +} + +octave_value_list& +octave_value_list::reverse (void) +{ + octave_idx_type n = length (); + + for (octave_idx_type i = 0; i < n / 2; i++) + { + octave_value tmp = elem (i); + elem (i) = elem (n - i - 1); + elem (n - i - 1) = tmp; + } + + return *this; +} + +octave_value_list +octave_value_list::splice (octave_idx_type offset, octave_idx_type rep_length, + const octave_value_list& lst) const +{ + octave_value_list retval; + + octave_idx_type len = length (); + + if (offset < 0 || offset >= len) + { + if (! (rep_length == 0 && offset == len)) + { + error ("octave_value_list::splice: invalid OFFSET"); + return retval; + } + } + + if (rep_length < 0 || rep_length + offset > len) + { + error ("octave_value_list::splice: invalid LENGTH"); + return retval; + } + + octave_idx_type lst_len = lst.length (); + + octave_idx_type new_len = len - rep_length + lst_len; + + retval.resize (new_len); + + octave_idx_type k = 0; + + for (octave_idx_type i = 0; i < offset; i++) + retval(k++) = elem (i); + + for (octave_idx_type i = 0; i < lst_len; i++) + retval(k++) = lst (i); + + for (octave_idx_type i = offset + rep_length; i < len; i++) + retval(k++) = elem (i); + + return retval; +} + +bool +octave_value_list::all_strings_p (void) const +{ + octave_idx_type n = length (); + + for (octave_idx_type i = 0; i < n; i++) + if (! elem(i).is_string ()) + return false; + + return true; +} + +bool +octave_value_list::all_scalars (void) const +{ + octave_idx_type n = length (); + + for (octave_idx_type i = 0; i < n; i++) + { + dim_vector dv = elem(i).dims (); + if (! dv.all_ones ()) + return false; + } + + return true; +} + +bool +octave_value_list::any_cell (void) const +{ + octave_idx_type n = length (); + + for (octave_idx_type i = 0; i < n; i++) + if (elem (i).is_cell ()) + return true; + + return false; +} + +bool +octave_value_list::has_magic_colon (void) const +{ + octave_idx_type n = length (); + + for (octave_idx_type i = 0; i < n; i++) + if (elem(i).is_magic_colon ()) + return true; + + return false; +} + +string_vector +octave_value_list::make_argv (const std::string& fcn_name) const +{ + string_vector argv; + + if (all_strings_p ()) + { + octave_idx_type len = length (); + + octave_idx_type total_nr = 0; + + for (octave_idx_type i = 0; i < len; i++) + { + // An empty std::string ("") has zero columns and zero rows (a + // change that was made for Matlab contemptibility. + + octave_idx_type n = elem(i).rows (); + + total_nr += n ? n : 1; + } + + octave_idx_type k = 0; + if (! fcn_name.empty ()) + { + argv.resize (total_nr+1); + argv[0] = fcn_name; + k = 1; + } + else + argv.resize (total_nr); + + for (octave_idx_type i = 0; i < len; i++) + { + octave_idx_type nr = elem(i).rows (); + + if (nr < 2) + argv[k++] = elem(i).string_value (); + else + { + string_vector tmp = elem(i).all_strings (); + + for (octave_idx_type j = 0; j < nr; j++) + argv[k++] = tmp[j]; + } + } + } + else + error ("%s: expecting all arguments to be strings", fcn_name.c_str ()); + + return argv; +} + +void +octave_value_list::make_storable_values (void) +{ + octave_idx_type len = length (); + const Array& cdata = data; + + for (octave_idx_type i = 0; i < len; i++) + { + // This is optimized so that we don't force a copy unless necessary. + octave_value tmp = cdata(i).storable_value (); + if (! tmp.is_copy_of (cdata (i))) + data(i) = tmp; + } +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-obj.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-obj.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,169 @@ +/* + +Copyright (C) 1994-2012 John W. Eaton +Copyright (C) 2009 VZLU Prague + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_oct_obj_h) +#define octave_oct_obj_h 1 + +#include +#include + +#include "oct-alloc.h" +#include "str-vec.h" +#include "Array.h" + +#include "ov.h" +#include "Cell.h" + +class +OCTINTERP_API +octave_value_list +{ +public: + + octave_value_list (void) + : data (), names () { } + + explicit octave_value_list (octave_idx_type n) + : data (dim_vector (1, n)), names () { } + + octave_value_list (octave_idx_type n, const octave_value& val) + : data (dim_vector (1, n), val), names () { } + + octave_value_list (const octave_value& tc) + : data (dim_vector (1, 1), tc), names () { } + + octave_value_list (const Array& d) + : data (d.as_row ()), names () { } + + octave_value_list (const Cell& tc) + : data (tc.as_row ()), names () { } + + octave_value_list (const octave_value_list& obj) + : data (obj.data), names (obj.names) { } + + // Concatenation constructor. + octave_value_list (const std::list&); + + ~octave_value_list (void) { } + + octave_value_list& operator = (const octave_value_list& obj) + { + if (this != &obj) + { + data = obj.data; + names = obj.names; + } + + return *this; + } + + Array array_value (void) const { return data; } + + Cell cell_value (void) const { return array_value (); } + + // Assignment will resize on range errors. + + octave_value& operator () (octave_idx_type n) { return elem (n); } + + const octave_value& operator () (octave_idx_type n) const { return elem (n); } + + octave_idx_type length (void) const { return data.length (); } + + bool empty (void) const { return length () == 0; } + + void resize (octave_idx_type n, const octave_value& rfv = octave_value ()) + { + data.resize (dim_vector (1, n), rfv); + } + + octave_value_list& prepend (const octave_value& val); + + octave_value_list& append (const octave_value& val); + + octave_value_list& append (const octave_value_list& lst); + + octave_value_list& reverse (void); + + octave_value_list + slice (octave_idx_type offset, octave_idx_type len, bool tags = false) const + { + octave_value_list retval (data.linear_slice (offset, offset + len)); + if (tags && len > 0 && names.length () > 0) + retval.names = names.linear_slice (offset, std::min (len, names.length ())); + + return retval; + } + + octave_value_list + splice (octave_idx_type offset, octave_idx_type len, + const octave_value_list& lst = octave_value_list ()) const; + + bool all_strings_p (void) const; + + bool all_scalars (void) const; + + bool any_cell (void) const; + + bool has_magic_colon (void) const; + + string_vector make_argv (const std::string& = std::string ()) const; + + void stash_name_tags (const string_vector& nm) { names = nm; } + + string_vector name_tags (void) const { return names; } + + void make_storable_values (void); + + octave_value& xelem (octave_idx_type i) + { + return data.xelem (i); + } + + void clear (void) + { + data.clear (); + } + +private: + + Array data; + + // This list of strings can be used to tag each element of data with + // a name. By default, it is empty. + string_vector names; + + octave_value& elem (octave_idx_type n) + { + if (n >= length ()) + resize (n + 1); + + return data(n); + } + + const octave_value& elem (octave_idx_type n) const + { return data(n); } + + DECLARE_OCTAVE_ALLOCATOR +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-prcstrm.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-prcstrm.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,70 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "oct-prcstrm.h" +#include "sysdep.h" + +octave_stream +octave_iprocstream::create (const std::string& n, std::ios::openmode arg_md, + oct_mach_info::float_format ff) +{ + return octave_stream (new octave_iprocstream (n, arg_md, ff)); +} + +octave_iprocstream::octave_iprocstream (const std::string& n, + std::ios::openmode arg_md, + oct_mach_info::float_format ff) + : octave_stdiostream (n, octave_popen (n.c_str (), "r"), + arg_md, ff, octave_pclose) +{ +} + +octave_iprocstream::~octave_iprocstream (void) +{ + do_close (); +} + +octave_stream +octave_oprocstream::create (const std::string& n, std::ios::openmode arg_md, + oct_mach_info::float_format ff) +{ + return octave_stream (new octave_oprocstream (n, arg_md, ff)); +} + +octave_oprocstream::octave_oprocstream (const std::string& n, + std::ios::openmode arg_md, + oct_mach_info::float_format ff) + : octave_stdiostream (n, octave_popen (n.c_str (), "w"), + arg_md, ff, octave_pclose) +{ +} + +octave_oprocstream::~octave_oprocstream (void) +{ + do_close (); +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-prcstrm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-prcstrm.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,87 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_octave_procstream_h) +#define octave_octave_procstream_h 1 + +#include "oct-stdstrm.h" + +// FIXME -- why don't these classes use iprocstream and +// oprocstream, which in turn use the octave_procbuf class? + +class +octave_iprocstream : public octave_stdiostream +{ +public: + + octave_iprocstream (const std::string& n, + std::ios::openmode arg_md = std::ios::in, + oct_mach_info::float_format flt_fmt + = oct_mach_info::native_float_format ()); + + static octave_stream + create (const std::string& n, std::ios::openmode arg_md = std::ios::in, + oct_mach_info::float_format flt_fmt + = oct_mach_info::native_float_format ()); + +protected: + + ~octave_iprocstream (void); + +private: + + // No copying! + + octave_iprocstream (const octave_iprocstream&); + + octave_iprocstream& operator = (const octave_iprocstream&); +}; + +class +octave_oprocstream : public octave_stdiostream +{ +public: + + octave_oprocstream (const std::string& n, + std::ios::openmode arg_md = std::ios::out, + oct_mach_info::float_format flt_fmt + = oct_mach_info::native_float_format ()); + + static octave_stream + create (const std::string& n, std::ios::openmode arg_md = std::ios::out, + oct_mach_info::float_format flt_fmt + = oct_mach_info::native_float_format ()); + +protected: + + ~octave_oprocstream (void); + +private: + + // No copying! + + octave_oprocstream (const octave_oprocstream&); + + octave_oprocstream& operator = (const octave_oprocstream&); +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-procbuf.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-procbuf.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,218 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include +#include + +#include "lo-mappers.h" +#include "lo-utils.h" +#include "oct-procbuf.h" +#include "oct-syscalls.h" +#include "sysdep.h" +#include "variables.h" + +#include "defun.h" +#include "gripes.h" +#include "utils.h" + +// This class is based on the procbuf class from libg++, written by +// Per Bothner, Copyright (C) 1993 Free Software Foundation. + +static octave_procbuf *octave_procbuf_list = 0; + +#ifndef BUFSIZ +#define BUFSIZ 1024 +#endif + +octave_procbuf * +octave_procbuf::open (const char *command, int mode) +{ +#if defined (__CYGWIN__) || defined (__MINGW32__) || defined (_MSC_VER) + + if (is_open ()) + return 0; + + f = octave_popen (command, (mode & std::ios::in) ? "r" : "w"); + + if (! f) + return 0; + + // Oops... popen doesn't return the associated pid, so fake it for now + + proc_pid = 1; + + open_p = true; + + if (mode & std::ios::out) + ::setvbuf (f, 0, _IOLBF, BUFSIZ); + + return this; + +#elif defined (HAVE_SYS_WAIT_H) + + int pipe_fds[2]; + + volatile int child_std_end = (mode & std::ios::in) ? 1 : 0; + + volatile int parent_end, child_end; + + if (is_open ()) + return 0; + + if (pipe (pipe_fds) < 0) + return 0; + + if (mode & std::ios::in) + { + parent_end = pipe_fds[0]; + child_end = pipe_fds[1]; + } + else + { + parent_end = pipe_fds[1]; + child_end = pipe_fds[0]; + } + + proc_pid = ::fork (); + + if (proc_pid == 0) + { + gnulib::close (parent_end); + + if (child_end != child_std_end) + { + gnulib::dup2 (child_end, child_std_end); + gnulib::close (child_end); + } + + while (octave_procbuf_list) + { + FILE *fp = octave_procbuf_list->f; + + if (fp) + { + gnulib::fclose (fp); + fp = 0; + } + + octave_procbuf_list = octave_procbuf_list->next; + } + + execl ("/bin/sh", "sh", "-c", command, static_cast (0)); + + exit (127); + } + + gnulib::close (child_end); + + if (proc_pid < 0) + { + gnulib::close (parent_end); + return 0; + } + + f = ::fdopen (parent_end, (mode & std::ios::in) ? "r" : "w"); + + if (mode & std::ios::out) + ::setvbuf (f, 0, _IOLBF, BUFSIZ); + + open_p = true; + + next = octave_procbuf_list; + octave_procbuf_list = this; + + return this; + +#else + + return 0; + +#endif +} + +octave_procbuf * +octave_procbuf::close (void) +{ +#if defined (__CYGWIN__) || defined (__MINGW32__) || defined (_MSC_VER) + + if (f) + { + wstatus = octave_pclose (f); + f = 0; + } + + open_p = false; + + return this; + +#elif defined (HAVE_SYS_WAIT_H) + + if (f) + { + pid_t wait_pid; + + int status = -1; + + for (octave_procbuf **ptr = &octave_procbuf_list; + *ptr != 0; + ptr = &(*ptr)->next) + { + if (*ptr == this) + { + *ptr = (*ptr)->next; + status = 0; + break; + } + } + + if (status == 0 && gnulib::fclose (f) == 0) + { + using namespace std; + + do + { + wait_pid = octave_syscalls::waitpid (proc_pid, &wstatus, 0); + } + while (wait_pid == -1 && errno == EINTR); + } + + f = 0; + } + + open_p = false; + + return this; + +#else + + return 0; + +#endif +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-procbuf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-procbuf.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,79 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +// This class is based on the procbuf class from libg++, written by +// Per Bothner, Copyright (C) 1993 Free Software Foundation. + +#if !defined (octave_octave_procbuf_h) +#define octave_octave_procbuf_h 1 + +#include + +#include "c-file-ptr-stream.h" + +class +octave_procbuf : public c_file_ptr_buf +{ +public: + + octave_procbuf (void) + : c_file_ptr_buf (0), wstatus (-1), open_p (false), proc_pid (-1), + next (0) { } + + octave_procbuf (const char *command, int mode) + : c_file_ptr_buf (0), wstatus (-1), open_p (false), proc_pid (-1), + next (0) { open (command, mode); } + + ~octave_procbuf (void) { close (); } + + octave_procbuf *open (const char *command, int mode); + + octave_procbuf *close (void); + + int wait_status (void) const { return wstatus; } + + bool is_open (void) const { return open_p; } + + pid_t pid (void) const { return proc_pid; } + +protected: + + int wstatus; + + bool open_p; + + pid_t proc_pid; + + octave_procbuf *next; + +private: + + // No copying! + + octave_procbuf (const octave_procbuf&); + + octave_procbuf& operator = (const octave_procbuf&); +}; + +extern void symbols_of_oct_procbuf (void); + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-stdstrm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-stdstrm.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,175 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_octave_stdiostream_h) +#define octave_octave_stdiostream_h 1 + +#include "oct-stream.h" +#include "c-file-ptr-stream.h" + +template +class +octave_tstdiostream : public octave_base_stream +{ +public: + + octave_tstdiostream (const std::string& n, FILE_T f = 0, int fid = 0, + std::ios::openmode m = std::ios::in|std::ios::out, + oct_mach_info::float_format ff + = oct_mach_info::native_float_format (), + typename BUF_T::close_fcn cf = BUF_T::file_close) + : octave_base_stream (m, ff), nm (n), md (m), + s (f ? new STREAM_T (f, cf) : 0), fnum (fid) + { } + + // Position a stream at OFFSET relative to ORIGIN. + + int seek (long offset, int origin) + { return s ? s->seek (offset, origin) : -1; } + + // Return current stream position. + + long tell (void) { return s ? s->tell () : -1; } + + // Return non-zero if EOF has been reached on this stream. + + bool eof (void) const { return s ? s->eof () : true; } + + // The name of the file. + + std::string name (void) const { return nm; } + + std::istream *input_stream (void) { return (md & std::ios::in) ? s : 0; } + + std::ostream *output_stream (void) { return (md & std::ios::out) ? s : 0; } + + // FIXME -- should not have to cast away const here. + BUF_T *rdbuf (void) const + { return s ? (const_cast (s))->rdbuf () : 0; } + + int file_number (void) const { return fnum; } + + bool bad (void) const { return s ? s->bad () : true; } + + void clear (void) { if (s) s->clear (); } + + void do_close (void) { if (s) s->stream_close (); } + +protected: + + std::string nm; + + std::ios::openmode md; + + STREAM_T *s; + + // The file number associated with this file. + int fnum; + + ~octave_tstdiostream (void) { delete s; } + +private: + + // No copying! + + octave_tstdiostream (const octave_tstdiostream&); + + octave_tstdiostream& operator = (const octave_tstdiostream&); +}; + +class +octave_stdiostream + : public octave_tstdiostream +{ +public: + + octave_stdiostream (const std::string& n, FILE *f = 0, + std::ios::openmode m = std::ios::in|std::ios::out, + oct_mach_info::float_format ff + = oct_mach_info::native_float_format (), + c_file_ptr_buf::close_fcn cf = c_file_ptr_buf::file_close) + : octave_tstdiostream (n, f, f ? fileno (f) : -1, m, ff, cf) { } + + static octave_stream + create (const std::string& n, FILE *f = 0, + std::ios::openmode m = std::ios::in|std::ios::out, + oct_mach_info::float_format ff + = oct_mach_info::native_float_format (), + c_file_ptr_buf::close_fcn cf = c_file_ptr_buf::file_close) + { + return octave_stream (new octave_stdiostream (n, f, m, ff, cf)); + } + +protected: + + ~octave_stdiostream (void) { } + +private: + + // No copying! + + octave_stdiostream (const octave_stdiostream&); + + octave_stdiostream& operator = (const octave_stdiostream&); +}; + +#ifdef HAVE_ZLIB + +class +octave_zstdiostream + : public octave_tstdiostream +{ +public: + + octave_zstdiostream (const std::string& n, gzFile f = 0, int fid = 0, + std::ios::openmode m = std::ios::in|std::ios::out, + oct_mach_info::float_format ff + = oct_mach_info::native_float_format (), + c_zfile_ptr_buf::close_fcn cf = c_zfile_ptr_buf::file_close) + : octave_tstdiostream (n, f, fid, m, ff, cf) { } + + static octave_stream + create (const std::string& n, gzFile f = 0, int fid = 0, + std::ios::openmode m = std::ios::in|std::ios::out, + oct_mach_info::float_format ff + = oct_mach_info::native_float_format (), + c_zfile_ptr_buf::close_fcn cf = c_zfile_ptr_buf::file_close) + { + return octave_stream (new octave_zstdiostream (n, f, fid, m, ff, cf)); + } + +protected: + + ~octave_zstdiostream (void) { } + +private: + + // No copying! + + octave_zstdiostream (const octave_zstdiostream&); + + octave_zstdiostream& operator = (const octave_zstdiostream&); +}; + +#endif + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-stream.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-stream.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,4308 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include "byte-swap.h" +#include "lo-ieee.h" +#include "lo-mappers.h" +#include "lo-utils.h" +#include "quit.h" +#include "singleton-cleanup.h" +#include "str-vec.h" + +#include "error.h" +#include "gripes.h" +#include "input.h" +#include "oct-stdstrm.h" +#include "oct-stream.h" +#include "oct-obj.h" +#include "utils.h" + +// Possible values for conv_err: +// +// 1 : not a real scalar +// 2 : value is NaN +// 3 : value is not an integer + +static int +convert_to_valid_int (const octave_value& tc, int& conv_err) +{ + int retval = 0; + + conv_err = 0; + + double dval = tc.double_value (); + + if (! error_state) + { + if (! lo_ieee_isnan (dval)) + { + int ival = NINT (dval); + + if (ival == dval) + retval = ival; + else + conv_err = 3; + } + else + conv_err = 2; + } + else + conv_err = 1; + + return retval; +} + +static int +get_size (double d, const std::string& who) +{ + int retval = -1; + + if (! lo_ieee_isnan (d)) + { + if (! xisinf (d)) + { + if (d >= 0.0) + retval = NINT (d); + else + ::error ("%s: negative value invalid as size specification", + who.c_str ()); + } + else + retval = -1; + } + else + ::error ("%s: NaN is invalid as size specification", who.c_str ()); + + return retval; +} + +static void +get_size (const Array& size, octave_idx_type& nr, octave_idx_type& nc, bool& one_elt_size_spec, + const std::string& who) +{ + nr = -1; + nc = -1; + + one_elt_size_spec = false; + + double dnr = -1.0; + double dnc = -1.0; + + octave_idx_type sz_len = size.length (); + + if (sz_len == 1) + { + one_elt_size_spec = true; + + dnr = size (0); + + dnc = (dnr == 0.0) ? 0.0 : 1.0; + } + else if (sz_len == 2) + { + dnr = size (0); + + if (! xisinf (dnr)) + dnc = size (1); + else + ::error ("%s: invalid size specification", who.c_str ()); + } + else + ::error ("%s: invalid size specification", who.c_str ()); + + if (! error_state) + { + nr = get_size (dnr, who); + + if (! error_state && dnc >= 0.0) + nc = get_size (dnc, who); + } +} + +scanf_format_list::scanf_format_list (const std::string& s) + : nconv (0), curr_idx (0), list (dim_vector (16, 1)), buf (0) +{ + octave_idx_type num_elts = 0; + + size_t n = s.length (); + + size_t i = 0; + + int width = 0; + bool discard = false; + char modifier = '\0'; + char type = '\0'; + + bool have_more = true; + + while (i < n) + { + have_more = true; + + if (! buf) + buf = new std::ostringstream (); + + if (s[i] == '%') + { + // Process percent-escape conversion type. + + process_conversion (s, i, n, width, discard, type, modifier, + num_elts); + + have_more = (buf != 0); + } + else if (isspace (s[i])) + { + type = scanf_format_elt::whitespace_conversion; + + width = 0; + discard = false; + modifier = '\0'; + *buf << " "; + + while (++i < n && isspace (s[i])) + /* skip whitespace */; + + add_elt_to_list (width, discard, type, modifier, num_elts); + + have_more = false; + } + else + { + type = scanf_format_elt::literal_conversion; + + width = 0; + discard = false; + modifier = '\0'; + + while (i < n && ! isspace (s[i]) && s[i] != '%') + *buf << s[i++]; + + add_elt_to_list (width, discard, type, modifier, num_elts); + + have_more = false; + } + + if (nconv < 0) + { + have_more = false; + break; + } + } + + if (have_more) + add_elt_to_list (width, discard, type, modifier, num_elts); + + list.resize (dim_vector (num_elts, 1)); + + delete buf; +} + +scanf_format_list::~scanf_format_list (void) +{ + octave_idx_type n = list.length (); + + for (octave_idx_type i = 0; i < n; i++) + { + scanf_format_elt *elt = list(i); + delete elt; + } +} + +void +scanf_format_list::add_elt_to_list (int width, bool discard, char type, + char modifier, octave_idx_type& num_elts, + const std::string& char_class) +{ + if (buf) + { + std::string text = buf->str (); + + if (! text.empty ()) + { + scanf_format_elt *elt + = new scanf_format_elt (text.c_str (), width, discard, type, + modifier, char_class); + + if (num_elts == list.length ()) + list.resize (dim_vector (2 * num_elts, 1)); + + list(num_elts++) = elt; + } + + delete buf; + buf = 0; + } +} + +static std::string +expand_char_class (const std::string& s) +{ + std::string retval; + + size_t len = s.length (); + + size_t i = 0; + + while (i < len) + { + unsigned char c = s[i++]; + + if (c == '-' && i > 1 && i < len + && static_cast (s[i-2]) <= static_cast (s[i])) + { + // Add all characters from the range except the first (we + // already added it below). + + for (c = s[i-2]+1; c < s[i]; c++) + retval += c; + } + else + { + // Add the character to the class. Only add '-' if it is + // the last character in the class. + + if (c != '-' || i == len) + retval += c; + } + } + + return retval; +} + +void +scanf_format_list::process_conversion (const std::string& s, size_t& i, + size_t n, int& width, bool& discard, + char& type, char& modifier, + octave_idx_type& num_elts) +{ + width = 0; + discard = false; + modifier = '\0'; + type = '\0'; + + *buf << s[i++]; + + bool have_width = false; + + while (i < n) + { + switch (s[i]) + { + case '*': + if (discard) + nconv = -1; + else + { + discard = true; + *buf << s[i++]; + } + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + if (have_width) + nconv = -1; + else + { + char c = s[i++]; + width = width * 10 + c - '0'; + have_width = true; + *buf << c; + while (i < n && isdigit (s[i])) + { + c = s[i++]; + width = width * 10 + c - '0'; + *buf << c; + } + } + break; + + case 'h': case 'l': case 'L': + if (modifier != '\0') + nconv = -1; + else + modifier = s[i++]; + break; + + case 'd': case 'i': case 'o': case 'u': case 'x': + if (modifier == 'L') + { + nconv = -1; + break; + } + goto fini; + + case 'e': case 'f': case 'g': + if (modifier == 'h') + { + nconv = -1; + break; + } + + // No float or long double conversions, thanks. + *buf << 'l'; + + goto fini; + + case 'c': case 's': case 'p': case '%': case '[': + if (modifier != '\0') + { + nconv = -1; + break; + } + goto fini; + + fini: + { + if (finish_conversion (s, i, n, width, discard, type, + modifier, num_elts) == 0) + return; + } + break; + + default: + nconv = -1; + break; + } + + if (nconv < 0) + break; + } + + nconv = -1; +} + +int +scanf_format_list::finish_conversion (const std::string& s, size_t& i, + size_t n, int& width, bool discard, + char& type, char modifier, + octave_idx_type& num_elts) +{ + int retval = 0; + + std::string char_class; + + size_t beg_idx = std::string::npos; + size_t end_idx = std::string::npos; + + if (s[i] == '%') + { + type = '%'; + *buf << s[i++]; + } + else + { + type = s[i]; + + if (s[i] == '[') + { + *buf << s[i++]; + + if (i < n) + { + beg_idx = i; + + if (s[i] == '^') + { + type = '^'; + *buf << s[i++]; + + if (i < n) + { + beg_idx = i; + + if (s[i] == ']') + *buf << s[i++]; + } + } + else if (s[i] == ']') + *buf << s[i++]; + } + + while (i < n && s[i] != ']') + *buf << s[i++]; + + if (i < n && s[i] == ']') + { + end_idx = i-1; + *buf << s[i++]; + } + + if (s[i-1] != ']') + retval = nconv = -1; + } + else + *buf << s[i++]; + + nconv++; + } + + if (nconv >= 0) + { + if (beg_idx != std::string::npos && end_idx != std::string::npos) + char_class = expand_char_class (s.substr (beg_idx, + end_idx - beg_idx + 1)); + + add_elt_to_list (width, discard, type, modifier, num_elts, char_class); + } + + return retval; +} + +void +scanf_format_list::printme (void) const +{ + octave_idx_type n = list.length (); + + for (octave_idx_type i = 0; i < n; i++) + { + scanf_format_elt *elt = list(i); + + std::cerr + << "width: " << elt->width << "\n" + << "discard: " << elt->discard << "\n" + << "type: "; + + if (elt->type == scanf_format_elt::literal_conversion) + std::cerr << "literal text\n"; + else if (elt->type == scanf_format_elt::whitespace_conversion) + std::cerr << "whitespace\n"; + else + std::cerr << elt->type << "\n"; + + std::cerr + << "modifier: " << elt->modifier << "\n" + << "char_class: `" << undo_string_escapes (elt->char_class) << "'\n" + << "text: `" << undo_string_escapes (elt->text) << "'\n\n"; + } +} + +bool +scanf_format_list::all_character_conversions (void) +{ + octave_idx_type n = list.length (); + + if (n > 0) + { + for (octave_idx_type i = 0; i < n; i++) + { + scanf_format_elt *elt = list(i); + + switch (elt->type) + { + case 'c': case 's': case '%': case '[': case '^': + case scanf_format_elt::literal_conversion: + case scanf_format_elt::whitespace_conversion: + break; + + default: + return false; + break; + } + } + + return true; + } + else + return false; +} + +bool +scanf_format_list::all_numeric_conversions (void) +{ + octave_idx_type n = list.length (); + + if (n > 0) + { + for (octave_idx_type i = 0; i < n; i++) + { + scanf_format_elt *elt = list(i); + + switch (elt->type) + { + case 'd': case 'i': case 'o': case 'u': case 'x': + case 'e': case 'f': case 'g': + break; + + default: + return false; + break; + } + } + + return true; + } + else + return false; +} + +// Ugh again. + +printf_format_list::printf_format_list (const std::string& s) + : nconv (0), curr_idx (0), list (dim_vector (16, 1)), buf (0) +{ + octave_idx_type num_elts = 0; + + size_t n = s.length (); + + size_t i = 0; + + int args = 0; + std::string flags; + int fw = 0; + int prec = 0; + char modifier = '\0'; + char type = '\0'; + + bool have_more = true; + bool empty_buf = true; + + if (n == 0) + { + printf_format_elt *elt + = new printf_format_elt ("", args, fw, prec, flags, type, modifier); + + list(num_elts++) = elt; + + list.resize (dim_vector (num_elts, 1)); + } + else + { + while (i < n) + { + have_more = true; + + if (! buf) + { + buf = new std::ostringstream (); + empty_buf = true; + } + + switch (s[i]) + { + case '%': + { + if (empty_buf) + { + process_conversion (s, i, n, args, flags, fw, prec, + type, modifier, num_elts); + + have_more = (buf != 0); + } + else + add_elt_to_list (args, flags, fw, prec, type, modifier, + num_elts); + } + break; + + default: + { + args = 0; + flags = ""; + fw = 0; + prec = 0; + modifier = '\0'; + type = '\0'; + *buf << s[i++]; + empty_buf = false; + } + break; + } + + if (nconv < 0) + { + have_more = false; + break; + } + } + + if (have_more) + add_elt_to_list (args, flags, fw, prec, type, modifier, num_elts); + + list.resize (dim_vector (num_elts, 1)); + + delete buf; + } +} + +printf_format_list::~printf_format_list (void) +{ + octave_idx_type n = list.length (); + + for (octave_idx_type i = 0; i < n; i++) + { + printf_format_elt *elt = list(i); + delete elt; + } +} + +void +printf_format_list::add_elt_to_list (int args, const std::string& flags, + int fw, int prec, char type, + char modifier, octave_idx_type& num_elts) +{ + if (buf) + { + std::string text = buf->str (); + + if (! text.empty ()) + { + printf_format_elt *elt + = new printf_format_elt (text.c_str (), args, fw, prec, flags, + type, modifier); + + if (num_elts == list.length ()) + list.resize (dim_vector (2 * num_elts, 1)); + + list(num_elts++) = elt; + } + + delete buf; + buf = 0; + } +} + +void +printf_format_list::process_conversion + (const std::string& s, size_t& i, size_t n, int& args, std::string& flags, + int& fw, int& prec, char& modifier, char& type, octave_idx_type& num_elts) +{ + args = 0; + flags = ""; + fw = 0; + prec = 0; + modifier = '\0'; + type = '\0'; + + *buf << s[i++]; + + bool nxt = false; + + while (i < n) + { + switch (s[i]) + { + case '-': case '+': case ' ': case '0': case '#': + flags += s[i]; + *buf << s[i++]; + break; + + default: + nxt = true; + break; + } + + if (nxt) + break; + } + + if (i < n) + { + if (s[i] == '*') + { + fw = -1; + args++; + *buf << s[i++]; + } + else + { + if (isdigit (s[i])) + { + int nn = 0; + std::string tmp = s.substr (i); + sscanf (tmp.c_str (), "%d%n", &fw, &nn); + } + + while (i < n && isdigit (s[i])) + *buf << s[i++]; + } + } + + if (i < n && s[i] == '.') + { + *buf << s[i++]; + + if (i < n) + { + if (s[i] == '*') + { + prec = -1; + args++; + *buf << s[i++]; + } + else + { + if (isdigit (s[i])) + { + int nn = 0; + std::string tmp = s.substr (i); + sscanf (tmp.c_str (), "%d%n", &prec, &nn); + } + + while (i < n && isdigit (s[i])) + *buf << s[i++]; + } + } + } + + if (i < n) + { + switch (s[i]) + { + case 'h': case 'l': case 'L': + modifier = s[i]; + *buf << s[i++]; + break; + + default: + break; + } + } + + if (i < n) + finish_conversion (s, i, args, flags, fw, prec, modifier, type, num_elts); + else + nconv = -1; +} + +void +printf_format_list::finish_conversion + (const std::string& s, size_t& i, int args, const std::string& flags, + int fw, int prec, char modifier, char& type, octave_idx_type& num_elts) + +{ + switch (s[i]) + { + case 'd': case 'i': case 'o': case 'x': case 'X': + case 'u': case 'c': + if (modifier == 'L') + { + nconv = -1; + break; + } + goto fini; + + case 'f': case 'e': case 'E': case 'g': case 'G': + if (modifier == 'h' || modifier == 'l') + { + nconv = -1; + break; + } + goto fini; + + case 's': case 'p': case '%': + if (modifier != '\0') + { + nconv = -1; + break; + } + goto fini; + + fini: + + type = s[i]; + + *buf << s[i++]; + + if (type != '%' || args != 0) + nconv++; + + if (type != '%') + args++; + + add_elt_to_list (args, flags, fw, prec, type, modifier, num_elts); + + break; + + default: + nconv = -1; + break; + } +} + +void +printf_format_list::printme (void) const +{ + int n = list.length (); + + for (int i = 0; i < n; i++) + { + printf_format_elt *elt = list(i); + + std::cerr + << "args: " << elt->args << "\n" + << "flags: `" << elt->flags << "'\n" + << "width: " << elt->fw << "\n" + << "prec: " << elt->prec << "\n" + << "type: `" << elt->type << "'\n" + << "modifier: `" << elt->modifier << "'\n" + << "text: `" << undo_string_escapes (elt->text) << "'\n\n"; + } +} + +void +octave_base_stream::error (const std::string& msg) +{ + fail = true; + errmsg = msg; +} + +void +octave_base_stream::error (const std::string& who, const std::string& msg) +{ + fail = true; + errmsg = who + ": " + msg; +} + +void +octave_base_stream::clear (void) +{ + fail = false; + errmsg = ""; +} + +void +octave_base_stream::clearerr (void) +{ + std::istream *is = input_stream (); + std::ostream *os = output_stream (); + + if (is) + is->clear (); + + if (os) + os->clear (); +} + +// Functions that are defined for all input streams (input streams +// are those that define is). + +std::string +octave_base_stream::do_gets (octave_idx_type max_len, bool& err, + bool strip_newline, const std::string& who) +{ + std::string retval; + + if ((interactive || forced_interactive) && file_number () == 0) + { + ::error ("%s: unable to read from stdin while running interactively", + who.c_str ()); + + return retval; + } + + err = false; + + std::istream *isp = input_stream (); + + if (isp) + { + std::istream& is = *isp; + + std::ostringstream buf; + + int c = 0; + int char_count = 0; + + if (max_len != 0) + { + while (is && (c = is.get ()) != EOF) + { + char_count++; + + // Handle CRLF, CR, or LF as line ending. + + if (c == '\r') + { + if (! strip_newline) + buf << static_cast (c); + + c = is.get (); + + if (c != EOF) + { + if (c == '\n') + { + char_count++; + + if (! strip_newline) + buf << static_cast (c); + } + else + is.putback (c); + } + + break; + } + else if (c == '\n') + { + if (! strip_newline) + buf << static_cast (c); + + break; + } + else + buf << static_cast (c); + + if (max_len > 0 && char_count == max_len) + break; + } + } + + if (! is.eof () && char_count > 0) + { + // GAGME. Matlab seems to check for EOF even if the last + // character in a file is a newline character. This is NOT + // what the corresponding C-library functions do. + int disgusting_compatibility_hack = is.get (); + if (! is.eof ()) + is.putback (disgusting_compatibility_hack); + } + + if (is.good () || (is.eof () && char_count > 0)) + retval = buf.str (); + else + { + err = true; + + if (is.eof () && char_count == 0) + error (who, "at end of file"); + else + error (who, "read error"); + } + } + else + { + err = true; + invalid_operation (who, "reading"); + } + + return retval; +} + +std::string +octave_base_stream::getl (octave_idx_type max_len, bool& err, const std::string& who) +{ + return do_gets (max_len, err, true, who); +} + +std::string +octave_base_stream::gets (octave_idx_type max_len, bool& err, const std::string& who) +{ + return do_gets (max_len, err, false, who); +} + +long +octave_base_stream::skipl (long num, bool& err, const std::string& who) +{ + long cnt = -1; + + if ((interactive || forced_interactive) && file_number () == 0) + { + ::error ("%s: unable to read from stdin while running interactively", + who.c_str ()); + + return count; + } + + err = false; + + std::istream *isp = input_stream (); + + if (isp) + { + std::istream& is = *isp; + + int c = 0, lastc = -1; + cnt = 0; + + while (is && (c = is.get ()) != EOF) + { + // Handle CRLF, CR, or LF as line ending. + + if (c == '\r' || (c == '\n' && lastc != '\r')) + { + if (++cnt == num) + break; + } + + lastc = c; + } + + // Maybe eat the following \n if \r was just met. + if (c == '\r' && is.peek () == '\n') + is.get (); + + if (is.bad ()) + { + err = true; + error (who, "read error"); + } + + if (err) + cnt = -1; + } + else + { + err = true; + invalid_operation (who, "reading"); + } + + return cnt; +} + +#define OCTAVE_SCAN(is, fmt, arg) octave_scan (is, fmt, arg) + +template +std::istream& +octave_scan_1 (std::istream& is, const scanf_format_elt& fmt, T* valptr) +{ + T& ref = *valptr; + + switch (fmt.type) + { + case 'o': + is >> std::oct >> ref >> std::dec; + break; + + case 'x': + is >> std::hex >> ref >> std::dec; + break; + + case 'i': + { + int c1 = EOF; + + while (is && (c1 = is.get ()) != EOF && isspace (c1)) + /* skip whitespace */; + + if (c1 != EOF) + { + if (c1 == '0') + { + int c2 = is.peek (); + + if (c2 == 'x' || c2 == 'X') + { + is.ignore (); + if (std::isxdigit (is.peek ())) + is >> std::hex >> ref >> std::dec; + else + ref = 0; + } + else + { + if (c2 == '0' || c2 == '1' || c2 == '2' + || c2 == '3' || c2 == '4' || c2 == '5' + || c2 == '6' || c2 == '7') + is >> std::oct >> ref >> std::dec; + else + ref = 0; + } + } + else + { + is.putback (c1); + + is >> ref; + } + } + } + break; + + default: + is >> ref; + break; + } + + return is; +} + +template +std::istream& +octave_scan (std::istream& is, const scanf_format_elt& fmt, T* valptr) +{ + if (fmt.width) + { + // Limit input to fmt.width characters by reading into a + // temporary stringstream buffer. + + std::string tmp; + + is.width (fmt.width); + is >> tmp; + + std::istringstream ss (tmp); + + octave_scan_1 (ss, fmt, valptr); + } + else + octave_scan_1 (is, fmt, valptr); + + return is; +} + +// Note that this specialization is only used for reading characters, not +// character strings. See BEGIN_S_CONVERSION for details. + +template<> +std::istream& +octave_scan<> (std::istream& is, const scanf_format_elt& /* fmt */, + char* valptr) +{ + return is >> valptr; +} + +template std::istream& +octave_scan (std::istream&, const scanf_format_elt&, int*); + +template std::istream& +octave_scan (std::istream&, const scanf_format_elt&, long int*); + +template std::istream& +octave_scan (std::istream&, const scanf_format_elt&, short int*); + +template std::istream& +octave_scan (std::istream&, const scanf_format_elt&, unsigned int*); + +template std::istream& +octave_scan (std::istream&, const scanf_format_elt&, unsigned long int*); + +template std::istream& +octave_scan (std::istream&, const scanf_format_elt&, unsigned short int*); + +#if 0 +template std::istream& +octave_scan (std::istream&, const scanf_format_elt&, float*); +#endif + +template<> +std::istream& +octave_scan<> (std::istream& is, const scanf_format_elt& fmt, double* valptr) +{ + double& ref = *valptr; + + switch (fmt.type) + { + case 'e': + case 'f': + case 'g': + { + int c1 = EOF; + + while (is && (c1 = is.get ()) != EOF && isspace (c1)) + /* skip whitespace */; + + if (c1 != EOF) + { + is.putback (c1); + + ref = octave_read_value (is); + } + } + break; + + default: + panic_impossible (); + break; + } + + return is; +} + +template +void +do_scanf_conv (std::istream& is, const scanf_format_elt& fmt, + T valptr, Matrix& mval, double *data, octave_idx_type& idx, + octave_idx_type& conversion_count, octave_idx_type nr, octave_idx_type max_size, + bool discard) +{ + OCTAVE_SCAN (is, fmt, valptr); + + if (is) + { + if (idx == max_size && ! discard) + { + max_size *= 2; + + if (nr > 0) + mval.resize (nr, max_size / nr, 0.0); + else + mval.resize (max_size, 1, 0.0); + + data = mval.fortran_vec (); + } + + if (! discard) + { + conversion_count++; + data[idx++] = *(valptr); + } + } +} + +template void +do_scanf_conv (std::istream&, const scanf_format_elt&, int*, + Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); + +template void +do_scanf_conv (std::istream&, const scanf_format_elt&, long int*, + Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); + +template void +do_scanf_conv (std::istream&, const scanf_format_elt&, short int*, + Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); + +template void +do_scanf_conv (std::istream&, const scanf_format_elt&, unsigned int*, + Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); + +template void +do_scanf_conv (std::istream&, const scanf_format_elt&, unsigned long int*, + Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); + +template void +do_scanf_conv (std::istream&, const scanf_format_elt&, unsigned short int*, + Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); + +#if 0 +template void +do_scanf_conv (std::istream&, const scanf_format_elt&, float*, + Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); +#endif + +template void +do_scanf_conv (std::istream&, const scanf_format_elt&, double*, + Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); + +#define DO_WHITESPACE_CONVERSION() \ + do \ + { \ + int c = EOF; \ + \ + while (is && (c = is.get ()) != EOF && isspace (c)) \ + /* skip whitespace */; \ + \ + if (c != EOF) \ + is.putback (c); \ + } \ + while (0) + +#define DO_LITERAL_CONVERSION() \ + do \ + { \ + int c = EOF; \ + \ + int n = strlen (fmt); \ + int i = 0; \ + \ + while (i < n && is && (c = is.get ()) != EOF) \ + { \ + if (c == static_cast (fmt[i])) \ + { \ + i++; \ + continue; \ + } \ + else \ + { \ + is.putback (c); \ + break; \ + } \ + } \ + \ + if (i != n) \ + is.setstate (std::ios::failbit); \ + } \ + while (0) + +#define DO_PCT_CONVERSION() \ + do \ + { \ + int c = is.get (); \ + \ + if (c != EOF) \ + { \ + if (c != '%') \ + { \ + is.putback (c); \ + is.setstate (std::ios::failbit); \ + } \ + } \ + else \ + is.setstate (std::ios::failbit); \ + } \ + while (0) + +#define BEGIN_C_CONVERSION() \ + is.unsetf (std::ios::skipws); \ + \ + int width = elt->width ? elt->width : 1; \ + \ + std::string tmp (width, '\0'); \ + \ + int c = EOF; \ + int n = 0; \ + \ + while (is && n < width && (c = is.get ()) != EOF) \ + tmp[n++] = static_cast (c); \ + \ + if (n > 0 && c == EOF) \ + 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. +#define BEGIN_S_CONVERSION() \ + int width = elt->width; \ + \ + std::string tmp; \ + \ + do \ + { \ + if (width) \ + { \ + tmp = std::string (width, '\0'); \ + \ + int c = EOF; \ + \ + int n = 0; \ + \ + while (is && (c = is.get ()) != EOF) \ + { \ + if (! isspace (c)) \ + { \ + tmp[n++] = static_cast (c); \ + break; \ + } \ + } \ + \ + while (is && n < width && (c = is.get ()) != EOF) \ + { \ + if (isspace (c)) \ + { \ + is.putback (c); \ + break; \ + } \ + else \ + tmp[n++] = static_cast (c); \ + } \ + \ + if (n > 0 && c == EOF) \ + is.clear (); \ + \ + tmp.resize (n); \ + } \ + else \ + { \ + is >> std::ws >> tmp; \ + } \ + } \ + while (0) + +// This format must match a nonempty sequence of characters. +#define BEGIN_CHAR_CLASS_CONVERSION() \ + int width = elt->width; \ + \ + std::string tmp; \ + \ + do \ + { \ + if (! width) \ + width = INT_MAX; \ + \ + std::ostringstream buf; \ + \ + std::string char_class = elt->char_class; \ + \ + int c = EOF; \ + \ + if (elt->type == '[') \ + { \ + int chars_read = 0; \ + while (is && chars_read++ < width && (c = is.get ()) != EOF \ + && char_class.find (c) != std::string::npos) \ + buf << static_cast (c); \ + } \ + else \ + { \ + int chars_read = 0; \ + while (is && chars_read++ < width && (c = is.get ()) != EOF \ + && char_class.find (c) == std::string::npos) \ + buf << static_cast (c); \ + } \ + \ + if (width == INT_MAX && c != EOF) \ + is.putback (c); \ + \ + tmp = buf.str (); \ + \ + if (tmp.empty ()) \ + is.setstate (std::ios::failbit); \ + else if (c == EOF) \ + is.clear (); \ + \ + } \ + while (0) + +#define FINISH_CHARACTER_CONVERSION() \ + do \ + { \ + width = tmp.length (); \ + \ + if (is) \ + { \ + int i = 0; \ + \ + if (! discard) \ + { \ + conversion_count++; \ + \ + while (i < width) \ + { \ + if (data_index == max_size) \ + { \ + max_size *= 2; \ + \ + if (all_char_conv) \ + { \ + if (one_elt_size_spec) \ + mval.resize (1, max_size, 0.0); \ + else if (nr > 0) \ + mval.resize (nr, max_size / nr, 0.0); \ + else \ + panic_impossible (); \ + } \ + else if (nr > 0) \ + mval.resize (nr, max_size / nr, 0.0); \ + else \ + mval.resize (max_size, 1, 0.0); \ + \ + data = mval.fortran_vec (); \ + } \ + \ + data[data_index++] = tmp[i++]; \ + } \ + } \ + } \ + } \ + while (0) + +octave_value +octave_base_stream::do_scanf (scanf_format_list& fmt_list, + octave_idx_type nr, octave_idx_type nc, bool one_elt_size_spec, + octave_idx_type& conversion_count, const std::string& who) +{ + octave_value retval = Matrix (); + + if ((interactive || forced_interactive) && file_number () == 0) + { + ::error ("%s: unable to read from stdin while running interactively", + who.c_str ()); + + return retval; + } + + conversion_count = 0; + + octave_idx_type nconv = fmt_list.num_conversions (); + + octave_idx_type data_index = 0; + + if (nr == 0 || nc == 0) + { + if (one_elt_size_spec) + nc = 0; + + return Matrix (nr, nc, 0.0); + } + + std::istream *isp = input_stream (); + + bool all_char_conv = fmt_list.all_character_conversions (); + + Matrix mval; + double *data = 0; + octave_idx_type max_size = 0; + octave_idx_type max_conv = 0; + + octave_idx_type final_nr = 0; + octave_idx_type final_nc = 0; + + if (all_char_conv) + { + // Any of these could be resized later (if we have %s + // conversions, we may read more than one element for each + // conversion). + + if (one_elt_size_spec) + { + max_size = 512; + mval.resize (1, max_size, 0.0); + + if (nr > 0) + max_conv = nr; + } + else if (nr > 0) + { + if (nc > 0) + { + mval.resize (nr, nc, 0.0); + max_size = max_conv = nr * nc; + } + else + { + mval.resize (nr, 32, 0.0); + max_size = nr * 32; + } + } + else + panic_impossible (); + } + else if (nr > 0) + { + if (nc > 0) + { + // Will not resize later. + mval.resize (nr, nc, 0.0); + max_size = nr * nc; + max_conv = max_size; + } + else + { + // Maybe resize later. + mval.resize (nr, 32, 0.0); + max_size = nr * 32; + } + } + else + { + // Maybe resize later. + mval.resize (32, 1, 0.0); + max_size = 32; + } + + data = mval.fortran_vec (); + + if (isp) + { + std::istream& is = *isp; + + const scanf_format_elt *elt = fmt_list.first (); + + std::ios::fmtflags flags = is.flags (); + + octave_idx_type trips = 0; + + octave_idx_type num_fmt_elts = fmt_list.length (); + + for (;;) + { + octave_quit (); + + if (elt) + { + if (! (elt->type == scanf_format_elt::whitespace_conversion + || elt->type == scanf_format_elt::literal_conversion + || elt->type == '%') + && max_conv > 0 && conversion_count == max_conv) + { + if (all_char_conv && one_elt_size_spec) + { + final_nr = 1; + final_nc = data_index; + } + else + { + final_nr = nr; + final_nc = (data_index - 1) / nr + 1; + } + + break; + } + else if (data_index == max_size) + { + max_size *= 2; + + if (all_char_conv) + { + if (one_elt_size_spec) + mval.resize (1, max_size, 0.0); + else if (nr > 0) + mval.resize (nr, max_size / nr, 0.0); + else + panic_impossible (); + } + else if (nr > 0) + mval.resize (nr, max_size / nr, 0.0); + else + mval.resize (max_size, 1, 0.0); + + data = mval.fortran_vec (); + } + + const char *fmt = elt->text; + + bool discard = elt->discard; + + switch (elt->type) + { + case scanf_format_elt::whitespace_conversion: + DO_WHITESPACE_CONVERSION (); + break; + + case scanf_format_elt::literal_conversion: + DO_LITERAL_CONVERSION (); + break; + + case '%': + DO_PCT_CONVERSION (); + break; + + case 'd': case 'i': + { + switch (elt->modifier) + { + case 'h': + { + short int tmp; + do_scanf_conv (is, *elt, &tmp, mval, data, + data_index, conversion_count, + nr, max_size, discard); + } + break; + + case 'l': + { + long int tmp; + do_scanf_conv (is, *elt, &tmp, mval, data, + data_index, conversion_count, + nr, max_size, discard); + } + break; + + default: + { + int tmp; + do_scanf_conv (is, *elt, &tmp, mval, data, + data_index, conversion_count, + nr, max_size, discard); + } + break; + } + } + break; + + case 'o': case 'u': case 'x': + { + switch (elt->modifier) + { + case 'h': + { + unsigned short int tmp; + do_scanf_conv (is, *elt, &tmp, mval, data, + data_index, conversion_count, + nr, max_size, discard); + } + break; + + case 'l': + { + unsigned long int tmp; + do_scanf_conv (is, *elt, &tmp, mval, data, + data_index, conversion_count, + nr, max_size, discard); + } + break; + + default: + { + unsigned int tmp; + do_scanf_conv (is, *elt, &tmp, mval, data, + data_index, conversion_count, + nr, max_size, discard); + } + break; + } + } + break; + + case 'e': case 'f': case 'g': + { + double tmp; + + do_scanf_conv (is, *elt, &tmp, mval, data, + data_index, conversion_count, + nr, max_size, discard); + } + break; + + case 'c': + { + BEGIN_C_CONVERSION (); + + FINISH_CHARACTER_CONVERSION (); + + is.setf (flags); + } + break; + + case 's': + { + BEGIN_S_CONVERSION (); + + FINISH_CHARACTER_CONVERSION (); + } + break; + + case '[': case '^': + { + BEGIN_CHAR_CLASS_CONVERSION (); + + FINISH_CHARACTER_CONVERSION (); + } + break; + + case 'p': + error ("%s: unsupported format specifier", who.c_str ()); + break; + + default: + error ("%s: internal format error", who.c_str ()); + break; + } + + if (! ok ()) + { + break; + } + else if (! is) + { + if (all_char_conv) + { + if (one_elt_size_spec) + { + final_nr = 1; + final_nc = data_index; + } + else if (data_index > nr) + { + final_nr = nr; + final_nc = (data_index - 1) / nr + 1; + } + else + { + final_nr = data_index; + final_nc = 1; + } + } + else if (nr > 0) + { + if (data_index > nr) + { + final_nr = nr; + final_nc = (data_index - 1) / nr + 1; + } + else + { + final_nr = data_index; + final_nc = 1; + } + } + else + { + final_nr = data_index; + final_nc = 1; + } + + // If it looks like we have a matching failure, then + // reset the failbit in the stream state. + + if (is.rdstate () & std::ios::failbit) + is.clear (is.rdstate () & (~std::ios::failbit)); + + // FIXME -- is this the right thing to do? + + if (interactive && name () == "stdin") + { + is.clear (); + + // Skip to end of line. + + bool err; + do_gets (-1, err, false, who); + } + + break; + } + } + else + { + error ("%s: internal format error", who.c_str ()); + break; + } + + if (nconv == 0 && ++trips == num_fmt_elts) + { + if (all_char_conv && one_elt_size_spec) + { + final_nr = 1; + final_nc = data_index; + } + else + { + final_nr = nr; + final_nc = (data_index - 1) / nr + 1; + } + + break; + } + else + elt = fmt_list.next (nconv > 0); + } + } + + if (ok ()) + { + mval.resize (final_nr, final_nc, 0.0); + + retval = mval; + + if (all_char_conv) + retval = retval.convert_to_str (false, true); + } + + return retval; +} + +octave_value +octave_base_stream::scanf (const std::string& fmt, const Array& size, + octave_idx_type& conversion_count, const std::string& who) +{ + octave_value retval = Matrix (); + + conversion_count = 0; + + std::istream *isp = input_stream (); + + if (isp) + { + scanf_format_list fmt_list (fmt); + + if (fmt_list.num_conversions () == -1) + ::error ("%s: invalid format specified", who.c_str ()); + else + { + octave_idx_type nr = -1; + octave_idx_type nc = -1; + + bool one_elt_size_spec; + + get_size (size, nr, nc, one_elt_size_spec, who); + + if (! error_state) + retval = do_scanf (fmt_list, nr, nc, one_elt_size_spec, + conversion_count, who); + } + } + else + invalid_operation (who, "reading"); + + return retval; +} + +bool +octave_base_stream::do_oscanf (const scanf_format_elt *elt, + octave_value& retval, const std::string& who) +{ + bool quit = false; + + std::istream *isp = input_stream (); + + if (isp) + { + std::istream& is = *isp; + + std::ios::fmtflags flags = is.flags (); + + if (elt) + { + const char *fmt = elt->text; + + bool discard = elt->discard; + + switch (elt->type) + { + case scanf_format_elt::whitespace_conversion: + DO_WHITESPACE_CONVERSION (); + break; + + case scanf_format_elt::literal_conversion: + DO_LITERAL_CONVERSION (); + break; + + case '%': + { + DO_PCT_CONVERSION (); + + if (! is) + quit = true; + + } + break; + + case 'd': case 'i': + { + int tmp; + + if (OCTAVE_SCAN (is, *elt, &tmp)) + { + if (! discard) + retval = tmp; + } + else + quit = true; + } + break; + + case 'o': case 'u': case 'x': + { + long int tmp; + + if (OCTAVE_SCAN (is, *elt, &tmp)) + { + if (! discard) + retval = tmp; + } + else + quit = true; + } + break; + + case 'e': case 'f': case 'g': + { + double tmp; + + if (OCTAVE_SCAN (is, *elt, &tmp)) + { + if (! discard) + retval = tmp; + } + else + quit = true; + } + break; + + case 'c': + { + BEGIN_C_CONVERSION (); + + if (! discard) + retval = tmp; + + if (! is) + quit = true; + + is.setf (flags); + } + break; + + case 's': + { + BEGIN_S_CONVERSION (); + + if (! discard) + retval = tmp; + + if (! is) + quit = true; + } + break; + + case '[': case '^': + { + BEGIN_CHAR_CLASS_CONVERSION (); + + if (! discard) + retval = tmp; + + if (! is) + quit = true; + } + break; + + case 'p': + error ("%s: unsupported format specifier", who.c_str ()); + break; + + default: + error ("%s: internal format error", who.c_str ()); + break; + } + } + + if (ok () && is.fail ()) + { + error ("%s: read error", who.c_str ()); + + // FIXME -- is this the right thing to do? + + if (interactive && name () == "stdin") + { + // Skip to end of line. + + bool err; + do_gets (-1, err, false, who); + } + } + } + + return quit; +} + +octave_value_list +octave_base_stream::oscanf (const std::string& fmt, const std::string& who) +{ + octave_value_list retval; + + std::istream *isp = input_stream (); + + if (isp) + { + std::istream& is = *isp; + + scanf_format_list fmt_list (fmt); + + octave_idx_type nconv = fmt_list.num_conversions (); + + if (nconv == -1) + ::error ("%s: invalid format specified", who.c_str ()); + else + { + is.clear (); + + octave_idx_type len = fmt_list.length (); + + retval.resize (nconv+2, Matrix ()); + + const scanf_format_elt *elt = fmt_list.first (); + + int num_values = 0; + + bool quit = false; + + for (octave_idx_type i = 0; i < len; i++) + { + octave_value tmp; + + quit = do_oscanf (elt, tmp, who); + + if (quit) + break; + else + { + if (tmp.is_defined ()) + retval(num_values++) = tmp; + + if (! ok ()) + break; + + elt = fmt_list.next (nconv > 0); + } + } + + retval(nconv) = num_values; + + int err_num; + retval(nconv+1) = error (false, err_num); + + if (! quit) + { + // Pick up any trailing stuff. + if (ok () && len > nconv) + { + octave_value tmp; + + elt = fmt_list.next (); + + do_oscanf (elt, tmp, who); + } + } + } + } + else + invalid_operation (who, "reading"); + + return retval; +} + +// Functions that are defined for all output streams (output streams +// are those that define os). + +int +octave_base_stream::flush (void) +{ + int retval = -1; + + std::ostream *os = output_stream (); + + if (os) + { + os->flush (); + + if (os->good ()) + retval = 0; + } + else + invalid_operation ("fflush", "writing"); + + return retval; +} + +class +printf_value_cache +{ +public: + + enum state { ok, conversion_error }; + + printf_value_cache (const octave_value_list& args, const std::string& who) + : values (args), val_idx (0), elt_idx (0), + n_vals (values.length ()), n_elts (0), data (0), + curr_state (ok) + { + for (octave_idx_type i = 0; i < values.length (); i++) + { + octave_value val = values(i); + + if (val.is_map () || val.is_cell () || val.is_object ()) + { + gripe_wrong_type_arg (who, val); + break; + } + } + } + + ~printf_value_cache (void) { } + + // Get the current value as a double and advance the internal pointer. + double double_value (void); + + // Get the current value as an int and advance the internal pointer. + int int_value (void); + + // Get the current value as a string and advance the internal pointer. + std::string string_value (void); + + operator bool () const { return (curr_state == ok); } + + bool exhausted (void) { return (val_idx >= n_vals); } + +private: + + const octave_value_list values; + int val_idx; + int elt_idx; + int n_vals; + int n_elts; + const double *data; + NDArray curr_val; + state curr_state; + + // Must create value cache with values! + + printf_value_cache (void); + + // No copying! + + printf_value_cache (const printf_value_cache&); + + printf_value_cache& operator = (const printf_value_cache&); +}; + +double +printf_value_cache::double_value (void) +{ + double retval = 0.0; + + if (exhausted ()) + curr_state = conversion_error; + + while (! exhausted ()) + { + if (! data) + { + octave_value tmp_val = values (val_idx); + + // Force string conversion here for compatibility. + + curr_val = tmp_val.array_value (true); + + if (! error_state) + { + elt_idx = 0; + n_elts = curr_val.length (); + data = curr_val.data (); + } + else + { + curr_state = conversion_error; + break; + } + } + + if (elt_idx < n_elts) + { + retval = data[elt_idx++]; + + if (elt_idx >= n_elts) + { + elt_idx = 0; + val_idx++; + data = 0; + } + + break; + } + else + { + val_idx++; + data = 0; + + if (n_elts == 0 && exhausted ()) + curr_state = conversion_error; + + continue; + } + } + + return retval; +} + +int +printf_value_cache::int_value (void) +{ + int retval = 0; + + double dval = double_value (); + + if (! error_state) + { + if (D_NINT (dval) == dval) + retval = NINT (dval); + else + curr_state = conversion_error; + } + + return retval; +} + +std::string +printf_value_cache::string_value (void) +{ + std::string retval; + + if (exhausted ()) + curr_state = conversion_error; + else + { + octave_value tval = values (val_idx++); + + if (tval.rows () == 1) + retval = tval.string_value (); + else + { + // In the name of Matlab compatibility. + + charMatrix chm = tval.char_matrix_value (); + + octave_idx_type nr = chm.rows (); + octave_idx_type nc = chm.columns (); + + int k = 0; + + retval.resize (nr * nc, '\0'); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + retval[k++] = chm(i,j); + } + + if (error_state) + curr_state = conversion_error; + } + + return retval; +} + +// Ugh again and again. + +template +int +do_printf_conv (std::ostream& os, const char *fmt, int nsa, int sa_1, + int sa_2, T arg, const std::string& who) +{ + int retval = 0; + + switch (nsa) + { + case 2: + retval = octave_format (os, fmt, sa_1, sa_2, arg); + break; + + case 1: + retval = octave_format (os, fmt, sa_1, arg); + break; + + case 0: + retval = octave_format (os, fmt, arg); + break; + + default: + ::error ("%s: internal error handling format", who.c_str ()); + break; + } + + return retval; +} + +template int +do_printf_conv (std::ostream&, const char*, int, int, int, int, + const std::string&); + +template int +do_printf_conv (std::ostream&, const char*, int, int, int, long, + const std::string&); + +template int +do_printf_conv (std::ostream&, const char*, int, int, int, unsigned int, + const std::string&); + +template int +do_printf_conv (std::ostream&, const char*, int, int, int, unsigned long, + const std::string&); + +template int +do_printf_conv (std::ostream&, const char*, int, int, int, double, + const std::string&); + +template int +do_printf_conv (std::ostream&, const char*, int, int, int, const char*, + const std::string&); + +#define DO_DOUBLE_CONV(TQUAL) \ + do \ + { \ + if (val > std::numeric_limits::max () \ + || val < std::numeric_limits::min ()) \ + { \ + std::string tfmt = fmt; \ + \ + tfmt.replace (tfmt.rfind (elt->type), 1, ".f"); \ + \ + if (elt->modifier == 'l') \ + tfmt.replace (tfmt.rfind (elt->modifier), 1, ""); \ + \ + retval += do_printf_conv (os, tfmt.c_str (), nsa, sa_1, sa_2, \ + val, who); \ + } \ + else \ + retval += do_printf_conv (os, fmt, nsa, sa_1, sa_2, \ + static_cast (val), who); \ + } \ + while (0) + +int +octave_base_stream::do_printf (printf_format_list& fmt_list, + const octave_value_list& args, + const std::string& who) +{ + int retval = 0; + + octave_idx_type nconv = fmt_list.num_conversions (); + + std::ostream *osp = output_stream (); + + if (osp) + { + std::ostream& os = *osp; + + const printf_format_elt *elt = fmt_list.first (); + + printf_value_cache val_cache (args, who); + + if (error_state) + return retval; + + for (;;) + { + octave_quit (); + + if (elt) + { + // NSA is the number of `star' args to convert. + + int nsa = (elt->fw < 0) + (elt->prec < 0); + + int sa_1 = 0; + int sa_2 = 0; + + if (nsa > 0) + { + sa_1 = val_cache.int_value (); + + if (! val_cache) + break; + else + { + if (nsa > 1) + { + sa_2 = val_cache.int_value (); + + if (! val_cache) + break; + } + } + } + + const char *fmt = elt->text; + + if (elt->type == '%') + { + os << "%"; + retval++; + } + else if (elt->args == 0 && elt->text) + { + os << elt->text; + retval += strlen (elt->text); + } + else if (elt->type == 's') + { + std::string val = val_cache.string_value (); + + if (val_cache) + retval += do_printf_conv (os, fmt, nsa, sa_1, + sa_2, val.c_str (), who); + else + break; + } + else + { + double val = val_cache.double_value (); + + if (val_cache) + { + if (lo_ieee_isnan (val) || xisinf (val)) + { + std::string tfmt = fmt; + std::string::size_type i1, i2; + + tfmt.replace ((i1 = tfmt.rfind (elt->type)), + 1, 1, 's'); + + if ((i2 = tfmt.rfind ('.')) != std::string::npos && i2 < i1) + { + tfmt.erase (i2, i1-i2); + if (elt->prec < 0) + nsa--; + } + + const char *tval = xisinf (val) + ? (val < 0 ? "-Inf" : "Inf") + : (lo_ieee_is_NA (val) ? "NA" : "NaN"); + + retval += do_printf_conv (os, tfmt.c_str (), + nsa, sa_1, sa_2, + tval, who); + } + else + { + char type = elt->type; + + switch (type) + { + case 'd': case 'i': case 'c': + DO_DOUBLE_CONV (OCTAVE_EMPTY_CPP_ARG); + break; + + case 'o': case 'x': case 'X': case 'u': + DO_DOUBLE_CONV (unsigned); + break; + + case 'f': case 'e': case 'E': + case 'g': case 'G': + retval + += do_printf_conv (os, fmt, nsa, sa_1, sa_2, + val, who); + break; + + default: + error ("%s: invalid format specifier", + who.c_str ()); + return -1; + break; + } + } + } + else + break; + } + + if (! os) + { + error ("%s: write error", who.c_str ()); + break; + } + } + else + { + ::error ("%s: internal error handling format", who.c_str ()); + retval = -1; + break; + } + + elt = fmt_list.next (nconv > 0 && ! val_cache.exhausted ()); + + if (! elt || (val_cache.exhausted () && elt->args > 0)) + break; + } + } + else + invalid_operation (who, "writing"); + + return retval; +} + +int +octave_base_stream::printf (const std::string& fmt, + const octave_value_list& args, + const std::string& who) +{ + int retval = 0; + + printf_format_list fmt_list (fmt); + + if (fmt_list.num_conversions () == -1) + ::error ("%s: invalid format specified", who.c_str ()); + else + retval = do_printf (fmt_list, args, who); + + return retval; +} + +int +octave_base_stream::puts (const std::string& s, const std::string& who) +{ + int retval = -1; + + std::ostream *osp = output_stream (); + + if (osp) + { + std::ostream& os = *osp; + + os << s; + + if (os) + { + // FIXME -- why does this seem to be necessary? + // Without it, output from a loop like + // + // for i = 1:100, fputs (stdout, "foo\n"); endfor + // + // doesn't seem to go to the pager immediately. + + os.flush (); + + if (os) + retval = 0; + else + error ("%s: write error", who.c_str ()); + } + else + error ("%s: write error", who.c_str ()); + } + else + invalid_operation (who, "writing"); + + return retval; +} + +// Return current error message for this stream. + +std::string +octave_base_stream::error (bool clear_err, int& err_num) +{ + err_num = fail ? -1 : 0; + + std::string tmp = errmsg; + + if (clear_err) + clear (); + + return tmp; +} + +void +octave_base_stream::invalid_operation (const std::string& who, const char *rw) +{ + // Note that this is not ::error () ! + + error (who, std::string ("stream not open for ") + rw); +} + +octave_stream::octave_stream (octave_base_stream *bs) + : rep (bs) +{ + if (rep) + rep->count = 1; +} + +octave_stream::~octave_stream (void) +{ + if (rep && --rep->count == 0) + delete rep; +} + +octave_stream::octave_stream (const octave_stream& s) + : rep (s.rep) +{ + if (rep) + rep->count++; +} + +octave_stream& +octave_stream::operator = (const octave_stream& s) +{ + if (rep != s.rep) + { + if (rep && --rep->count == 0) + delete rep; + + rep = s.rep; + + if (rep) + rep->count++; + } + + return *this; +} + +int +octave_stream::flush (void) +{ + int retval = -1; + + if (stream_ok ()) + retval = rep->flush (); + + return retval; +} + +std::string +octave_stream::getl (octave_idx_type max_len, bool& err, const std::string& who) +{ + std::string retval; + + if (stream_ok ()) + retval = rep->getl (max_len, err, who); + + return retval; +} + +std::string +octave_stream::getl (const octave_value& tc_max_len, bool& err, + const std::string& who) +{ + std::string retval; + + err = false; + + int conv_err = 0; + + int max_len = -1; + + if (tc_max_len.is_defined ()) + { + max_len = convert_to_valid_int (tc_max_len, conv_err); + + if (conv_err || max_len < 0) + { + err = true; + ::error ("%s: invalid maximum length specified", who.c_str ()); + } + } + + if (! error_state) + retval = getl (max_len, err, who); + + return retval; +} + +std::string +octave_stream::gets (octave_idx_type max_len, bool& err, const std::string& who) +{ + std::string retval; + + if (stream_ok ()) + retval = rep->gets (max_len, err, who); + + return retval; +} + +std::string +octave_stream::gets (const octave_value& tc_max_len, bool& err, + const std::string& who) +{ + std::string retval; + + err = false; + + int conv_err = 0; + + int max_len = -1; + + if (tc_max_len.is_defined ()) + { + max_len = convert_to_valid_int (tc_max_len, conv_err); + + if (conv_err || max_len < 0) + { + err = true; + ::error ("%s: invalid maximum length specified", who.c_str ()); + } + } + + if (! error_state) + retval = gets (max_len, err, who); + + return retval; +} + +long +octave_stream::skipl (long count, bool& err, const std::string& who) +{ + long retval = -1; + + if (stream_ok ()) + retval = rep->skipl (count, err, who); + + return retval; +} + +long +octave_stream::skipl (const octave_value& tc_count, bool& err, const std::string& who) +{ + long retval = -1; + + err = false; + + int conv_err = 0; + + int count = 1; + + if (tc_count.is_defined ()) + { + if (tc_count.is_scalar_type () && xisinf (tc_count.scalar_value ())) + count = -1; + else + { + count = convert_to_valid_int (tc_count, conv_err); + + if (conv_err || count < 0) + { + err = true; + ::error ("%s: invalid number of lines specified", who.c_str ()); + } + } + } + + if (! error_state) + retval = skipl (count, err, who); + + return retval; +} + +int +octave_stream::seek (long offset, int origin) +{ + int status = -1; + + if (stream_ok ()) + { + clearerr (); + + // Find current position so we can return to it if needed. + + long orig_pos = rep->tell (); + + // Move to end of file. If successful, find the offset of the end. + + status = rep->seek (0, SEEK_END); + + if (status == 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) + { + // 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; + } + } + } + + return status; +} + +int +octave_stream::seek (const octave_value& tc_offset, + const octave_value& tc_origin) +{ + int retval = -1; + + long xoffset = tc_offset.long_value (true); + + if (! error_state) + { + int conv_err = 0; + + int origin = SEEK_SET; + + if (tc_origin.is_string ()) + { + std::string xorigin = tc_origin.string_value (); + + if (xorigin == "bof") + origin = SEEK_SET; + else if (xorigin == "cof") + origin = SEEK_CUR; + else if (xorigin == "eof") + origin = SEEK_END; + else + conv_err = -1; + } + else + { + int xorigin = convert_to_valid_int (tc_origin, conv_err); + + if (! conv_err) + { + if (xorigin == -1) + origin = SEEK_SET; + else if (xorigin == 0) + origin = SEEK_CUR; + else if (xorigin == 1) + origin = SEEK_END; + else + conv_err = -1; + } + } + + if (! conv_err) + { + retval = seek (xoffset, origin); + + if (retval != 0) + error ("fseek: failed to seek to requested position"); + } + else + error ("fseek: invalid value for origin"); + } + else + error ("fseek: invalid value for offset"); + + return retval; +} + +long +octave_stream::tell (void) +{ + long retval = -1; + + if (stream_ok ()) + retval = rep->tell (); + + return retval; +} + +int +octave_stream::rewind (void) +{ + return seek (0, SEEK_SET); +} + +bool +octave_stream::is_open (void) const +{ + bool retval = false; + + if (stream_ok ()) + retval = rep->is_open (); + + return retval; +} + +void +octave_stream::close (void) +{ + if (stream_ok ()) + rep->close (); +} + +template +octave_value +do_read (octave_stream& strm, octave_idx_type nr, octave_idx_type nc, octave_idx_type block_size, + octave_idx_type skip, bool do_float_fmt_conv, bool do_NA_conv, + oct_mach_info::float_format from_flt_fmt, octave_idx_type& count) +{ + octave_value retval; + + RET_T nda; + + count = 0; + + typedef typename RET_T::element_type ELMT; + ELMT elt_zero = ELMT (); + + ELMT *dat = 0; + + octave_idx_type max_size = 0; + + octave_idx_type final_nr = 0; + octave_idx_type final_nc = 1; + + if (nr > 0) + { + if (nc > 0) + { + nda.resize (dim_vector (nr, nc), elt_zero); + dat = nda.fortran_vec (); + max_size = nr * nc; + } + else + { + nda.resize (dim_vector (nr, 32), elt_zero); + dat = nda.fortran_vec (); + max_size = nr * 32; + } + } + else + { + nda.resize (dim_vector (32, 1), elt_zero); + dat = nda.fortran_vec (); + max_size = 32; + } + + // FIXME -- byte order for Cray? + + bool swap = false; + + if (oct_mach_info::words_big_endian ()) + swap = (from_flt_fmt == oct_mach_info::flt_fmt_ieee_little_endian + || from_flt_fmt == oct_mach_info::flt_fmt_vax_g + || from_flt_fmt == oct_mach_info::flt_fmt_vax_g); + else + swap = (from_flt_fmt == oct_mach_info::flt_fmt_ieee_big_endian); + + union + { + char buf[sizeof (typename strip_template_param::type)]; + typename strip_template_param::type val; + } u; + + std::istream *isp = strm.input_stream (); + + if (isp) + { + std::istream& is = *isp; + + octave_idx_type elts_read = 0; + + for (;;) + { + // FIXME -- maybe there should be a special case for + // skip == 0. + + if (is) + { + if (nr > 0 && nc > 0 && count == max_size) + { + final_nr = nr; + final_nc = nc; + + break; + } + + is.read (u.buf, sizeof (typename strip_template_param::type)); + + // We only swap bytes for integer types. For float + // types, the format conversion will also handle byte + // swapping. + + if (swap) + swap_bytes::type)> (u.buf); + else if (do_float_fmt_conv) + do_float_format_conversion + (u.buf, + sizeof (typename strip_template_param::type), + 1, from_flt_fmt, oct_mach_info::float_format ()); + + typename RET_T::element_type tmp + = static_cast (u.val); + + if (is) + { + if (count == max_size) + { + max_size *= 2; + + if (nr > 0) + nda.resize (dim_vector (nr, max_size / nr), + elt_zero); + else + nda.resize (dim_vector (max_size, 1), elt_zero); + + dat = nda.fortran_vec (); + } + + if (do_NA_conv && __lo_ieee_is_old_NA (tmp)) + tmp = __lo_ieee_replace_old_NA (tmp); + + dat[count++] = tmp; + + elts_read++; + } + + int seek_status = 0; + + if (skip != 0 && elts_read == block_size) + { + seek_status = strm.seek (skip, SEEK_CUR); + elts_read = 0; + } + + if (is.eof () || seek_status < 0) + { + if (nr > 0) + { + if (count > nr) + { + final_nr = nr; + final_nc = (count - 1) / nr + 1; + } + else + { + final_nr = count; + final_nc = 1; + } + } + else + { + final_nr = count; + final_nc = 1; + } + + break; + } + } + else if (is.eof ()) + break; + } + } + + nda.resize (dim_vector (final_nr, final_nc), elt_zero); + + retval = nda; + + return retval; +} + +#define DO_READ_VAL_TEMPLATE(RET_T, READ_T) \ + template octave_value \ + do_read (octave_stream&, octave_idx_type, octave_idx_type, octave_idx_type, octave_idx_type, bool, bool, \ + oct_mach_info::float_format, octave_idx_type&) + +// FIXME -- should we only have float if it is a different +// size from double? + +#define INSTANTIATE_DO_READ(VAL_T) \ + DO_READ_VAL_TEMPLATE (VAL_T, octave_int8); \ + DO_READ_VAL_TEMPLATE (VAL_T, octave_uint8); \ + DO_READ_VAL_TEMPLATE (VAL_T, octave_int16); \ + DO_READ_VAL_TEMPLATE (VAL_T, octave_uint16); \ + DO_READ_VAL_TEMPLATE (VAL_T, octave_int32); \ + DO_READ_VAL_TEMPLATE (VAL_T, octave_uint32); \ + DO_READ_VAL_TEMPLATE (VAL_T, octave_int64); \ + DO_READ_VAL_TEMPLATE (VAL_T, octave_uint64); \ + DO_READ_VAL_TEMPLATE (VAL_T, float); \ + DO_READ_VAL_TEMPLATE (VAL_T, double); \ + DO_READ_VAL_TEMPLATE (VAL_T, char); \ + DO_READ_VAL_TEMPLATE (VAL_T, signed char); \ + DO_READ_VAL_TEMPLATE (VAL_T, unsigned char) + +INSTANTIATE_DO_READ (int8NDArray); +INSTANTIATE_DO_READ (uint8NDArray); +INSTANTIATE_DO_READ (int16NDArray); +INSTANTIATE_DO_READ (uint16NDArray); +INSTANTIATE_DO_READ (int32NDArray); +INSTANTIATE_DO_READ (uint32NDArray); +INSTANTIATE_DO_READ (int64NDArray); +INSTANTIATE_DO_READ (uint64NDArray); +INSTANTIATE_DO_READ (FloatNDArray); +INSTANTIATE_DO_READ (NDArray); +INSTANTIATE_DO_READ (charNDArray); +INSTANTIATE_DO_READ (boolNDArray); + +typedef octave_value (*read_fptr) (octave_stream&, octave_idx_type, octave_idx_type, octave_idx_type, octave_idx_type, bool, bool, + oct_mach_info::float_format ffmt, octave_idx_type&); + +#define FILL_TABLE_ROW(R, VAL_T) \ + read_fptr_table[R][oct_data_conv::dt_int8] = do_read; \ + read_fptr_table[R][oct_data_conv::dt_uint8] = do_read; \ + read_fptr_table[R][oct_data_conv::dt_int16] = do_read; \ + read_fptr_table[R][oct_data_conv::dt_uint16] = do_read; \ + read_fptr_table[R][oct_data_conv::dt_int32] = do_read; \ + read_fptr_table[R][oct_data_conv::dt_uint32] = do_read; \ + read_fptr_table[R][oct_data_conv::dt_int64] = do_read; \ + read_fptr_table[R][oct_data_conv::dt_uint64] = do_read; \ + read_fptr_table[R][oct_data_conv::dt_single] = do_read; \ + read_fptr_table[R][oct_data_conv::dt_double] = do_read; \ + read_fptr_table[R][oct_data_conv::dt_char] = do_read; \ + read_fptr_table[R][oct_data_conv::dt_schar] = do_read; \ + read_fptr_table[R][oct_data_conv::dt_uchar] = do_read; \ + read_fptr_table[R][oct_data_conv::dt_logical] = do_read + +octave_value +octave_stream::read (const Array& size, octave_idx_type block_size, + oct_data_conv::data_type input_type, + oct_data_conv::data_type output_type, + octave_idx_type skip, oct_mach_info::float_format ffmt, + octave_idx_type& char_count) +{ + static bool initialized = false; + + // Table function pointers for return types x read types. + + static read_fptr read_fptr_table[oct_data_conv::dt_unknown][14]; + + if (! initialized) + { + for (int i = 0; i < oct_data_conv::dt_unknown; i++) + for (int j = 0; j < 14; j++) + read_fptr_table[i][j] = 0; + + FILL_TABLE_ROW (oct_data_conv::dt_int8, int8NDArray); + FILL_TABLE_ROW (oct_data_conv::dt_uint8, uint8NDArray); + FILL_TABLE_ROW (oct_data_conv::dt_int16, int16NDArray); + FILL_TABLE_ROW (oct_data_conv::dt_uint16, uint16NDArray); + FILL_TABLE_ROW (oct_data_conv::dt_int32, int32NDArray); + FILL_TABLE_ROW (oct_data_conv::dt_uint32, uint32NDArray); + FILL_TABLE_ROW (oct_data_conv::dt_int64, int64NDArray); + FILL_TABLE_ROW (oct_data_conv::dt_uint64, uint64NDArray); + FILL_TABLE_ROW (oct_data_conv::dt_single, FloatNDArray); + FILL_TABLE_ROW (oct_data_conv::dt_double, NDArray); + FILL_TABLE_ROW (oct_data_conv::dt_char, charNDArray); + FILL_TABLE_ROW (oct_data_conv::dt_schar, charNDArray); + FILL_TABLE_ROW (oct_data_conv::dt_uchar, charNDArray); + FILL_TABLE_ROW (oct_data_conv::dt_logical, boolNDArray); + + initialized = true; + } + + octave_value retval; + + if (stream_ok ()) + { + // FIXME -- we may eventually want to make this extensible. + + // FIXME -- we need a better way to ensure that this + // numbering stays consistent with the order of the elements in the + // data_type enum in the oct_data_conv class. + + char_count = 0; + + octave_idx_type nr = -1; + octave_idx_type nc = -1; + + bool ignore; + + get_size (size, nr, nc, ignore, "fread"); + + if (! error_state) + { + if (nr == 0 || nc == 0) + retval = Matrix (nr, nc); + else + { + if (ffmt == oct_mach_info::flt_fmt_unknown) + ffmt = float_format (); + + read_fptr fcn = read_fptr_table[output_type][input_type]; + + bool do_float_fmt_conv = ((input_type == oct_data_conv::dt_double + || input_type == oct_data_conv::dt_single) + && ffmt != float_format ()); + + bool do_NA_conv = (output_type == oct_data_conv::dt_double); + + if (fcn) + { + retval = (*fcn) (*this, nr, nc, block_size, skip, + do_float_fmt_conv, do_NA_conv, + ffmt, char_count); + + // FIXME -- kluge! + + if (! error_state + && (output_type == oct_data_conv::dt_char + || output_type == oct_data_conv::dt_schar + || output_type == oct_data_conv::dt_uchar)) + retval = retval.char_matrix_value (); + } + else + error ("fread: unable to read and convert requested types"); + } + } + else + invalid_operation ("fread", "reading"); + } + + return retval; +} + +octave_idx_type +octave_stream::write (const octave_value& data, octave_idx_type block_size, + oct_data_conv::data_type output_type, octave_idx_type skip, + oct_mach_info::float_format flt_fmt) +{ + octave_idx_type retval = -1; + + if (stream_ok ()) + { + if (! error_state) + { + if (flt_fmt == oct_mach_info::flt_fmt_unknown) + flt_fmt = float_format (); + + octave_idx_type status = data.write (*this, block_size, output_type, + skip, flt_fmt); + + if (status < 0) + error ("fwrite: write error"); + else + retval = status; + } + else + invalid_operation ("fwrite", "writing"); + } + + return retval; +} + +template +void +write_int (std::ostream& os, bool swap, const T& val) +{ + typename T::val_type tmp = val.value (); + + if (swap) + swap_bytes (&tmp); + + os.write (reinterpret_cast (&tmp), + sizeof (typename T::val_type)); +} + +template void write_int (std::ostream&, bool, const octave_int8&); +template void write_int (std::ostream&, bool, const octave_uint8&); +template void write_int (std::ostream&, bool, const octave_int16&); +template void write_int (std::ostream&, bool, const octave_uint16&); +template void write_int (std::ostream&, bool, const octave_int32&); +template void write_int (std::ostream&, bool, const octave_uint32&); +template void write_int (std::ostream&, bool, const octave_int64&); +template void write_int (std::ostream&, bool, const octave_uint64&); + +template +static inline bool +do_write (std::ostream& os, const T& val, oct_data_conv::data_type output_type, + oct_mach_info::float_format flt_fmt, bool swap, + bool do_float_conversion) +{ + bool retval = true; + + // For compatibility, Octave converts to the output type, then + // writes. This means that truncation happens on the conversion. + // For example, the following program prints 0: + // + // x = int8 (-1) + // f = fopen ("foo.dat", "w"); + // fwrite (f, x, "unsigned char"); + // fclose (f); + // f = fopen ("foo.dat", "r"); + // y = fread (f, 1, "unsigned char"); + // printf ("%d\n", y); + + switch (output_type) + { + case oct_data_conv::dt_char: + case oct_data_conv::dt_schar: + case oct_data_conv::dt_int8: + write_int (os, swap, octave_int8 (val)); + break; + + case oct_data_conv::dt_uchar: + case oct_data_conv::dt_uint8: + write_int (os, swap, octave_uint8 (val)); + break; + + case oct_data_conv::dt_int16: + write_int (os, swap, octave_int16 (val)); + break; + + case oct_data_conv::dt_uint16: + write_int (os, swap, octave_uint16 (val)); + break; + + case oct_data_conv::dt_int32: + write_int (os, swap, octave_int32 (val)); + break; + + case oct_data_conv::dt_uint32: + write_int (os, swap, octave_uint32 (val)); + break; + + case oct_data_conv::dt_int64: + write_int (os, swap, octave_int64 (val)); + break; + + case oct_data_conv::dt_uint64: + write_int (os, swap, octave_uint64 (val)); + break; + + case oct_data_conv::dt_single: + { + float f = static_cast (val); + + if (do_float_conversion) + do_float_format_conversion (&f, 1, flt_fmt); + + os.write (reinterpret_cast (&f), sizeof (float)); + } + break; + + case oct_data_conv::dt_double: + { + double d = static_cast (val); + if (do_float_conversion) + do_double_format_conversion (&d, 1, flt_fmt); + + os.write (reinterpret_cast (&d), sizeof (double)); + } + break; + + default: + retval = false; + (*current_liboctave_error_handler) + ("write: invalid type specification"); + break; + } + + return retval; +} + +template bool +do_write (std::ostream&, const octave_int8&, oct_data_conv::data_type, + oct_mach_info::float_format, bool, bool); + +template bool +do_write (std::ostream&, const octave_uint8&, oct_data_conv::data_type, + oct_mach_info::float_format, bool, bool); + +template bool +do_write (std::ostream&, const octave_int16&, oct_data_conv::data_type, + oct_mach_info::float_format, bool, bool); + +template bool +do_write (std::ostream&, const octave_uint16&, oct_data_conv::data_type, + oct_mach_info::float_format, bool, bool); + +template bool +do_write (std::ostream&, const octave_int32&, oct_data_conv::data_type, + oct_mach_info::float_format, bool, bool); + +template bool +do_write (std::ostream&, const octave_uint32&, oct_data_conv::data_type, + oct_mach_info::float_format, bool, bool); + +template bool +do_write (std::ostream&, const octave_int64&, oct_data_conv::data_type, + oct_mach_info::float_format, bool, bool); + +template bool +do_write (std::ostream&, const octave_uint64&, oct_data_conv::data_type, + oct_mach_info::float_format, bool, bool); + +template +octave_idx_type +octave_stream::write (const Array& data, octave_idx_type block_size, + oct_data_conv::data_type output_type, + octave_idx_type skip, oct_mach_info::float_format flt_fmt) +{ + octave_idx_type retval = -1; + + bool status = true; + + octave_idx_type count = 0; + + const T *d = data.data (); + + octave_idx_type n = data.length (); + + oct_mach_info::float_format native_flt_fmt + = oct_mach_info::float_format (); + + bool do_float_conversion = (flt_fmt != native_flt_fmt); + + // FIXME -- byte order for Cray? + + bool swap = false; + + if (oct_mach_info::words_big_endian ()) + swap = (flt_fmt == oct_mach_info::flt_fmt_ieee_little_endian + || flt_fmt == oct_mach_info::flt_fmt_vax_g + || flt_fmt == oct_mach_info::flt_fmt_vax_g); + else + swap = (flt_fmt == oct_mach_info::flt_fmt_ieee_big_endian); + + for (octave_idx_type i = 0; i < n; i++) + { + std::ostream *osp = output_stream (); + + if (osp) + { + std::ostream& os = *osp; + + if (skip != 0 && (i % block_size) == 0) + { + // Seek to skip when inside bounds of existing file. + // Otherwise, write NUL to skip. + + long orig_pos = tell (); + + seek (0, SEEK_END); + + long eof_pos = tell (); + + // Is it possible for this to fail to return us to the + // original position? + seek (orig_pos, SEEK_SET); + + long remaining = eof_pos - orig_pos; + + if (remaining < skip) + { + seek (0, SEEK_END); + + // FIXME -- probably should try to write larger + // blocks... + + unsigned char zero = 0; + for (octave_idx_type j = 0; j < skip - remaining; j++) + os.write (reinterpret_cast (&zero), 1); + } + else + seek (skip, SEEK_CUR); + } + + if (os) + { + status = do_write (os, d[i], output_type, flt_fmt, swap, + do_float_conversion); + + if (os && status) + count++; + else + break; + } + else + { + status = false; + break; + } + } + else + { + status = false; + break; + } + } + + if (status) + retval = count; + + return retval; +} + +template octave_idx_type +octave_stream::write (const Array&, octave_idx_type, + oct_data_conv::data_type, + octave_idx_type, oct_mach_info::float_format); + +template octave_idx_type +octave_stream::write (const Array&, octave_idx_type, + oct_data_conv::data_type, + octave_idx_type, oct_mach_info::float_format); + +template octave_idx_type +octave_stream::write (const Array&, octave_idx_type, + oct_data_conv::data_type, + octave_idx_type, oct_mach_info::float_format); + +template octave_idx_type +octave_stream::write (const Array&, octave_idx_type, + oct_data_conv::data_type, + octave_idx_type, oct_mach_info::float_format); + +template octave_idx_type +octave_stream::write (const Array&, octave_idx_type, + oct_data_conv::data_type, + octave_idx_type, oct_mach_info::float_format); + +template octave_idx_type +octave_stream::write (const Array&, octave_idx_type, + oct_data_conv::data_type, + octave_idx_type, oct_mach_info::float_format); + +template octave_idx_type +octave_stream::write (const Array&, octave_idx_type, + oct_data_conv::data_type, + octave_idx_type, oct_mach_info::float_format); + +template octave_idx_type +octave_stream::write (const Array&, octave_idx_type, + oct_data_conv::data_type, + octave_idx_type, oct_mach_info::float_format); + +template octave_idx_type +octave_stream::write (const Array&, octave_idx_type, + oct_data_conv::data_type, + octave_idx_type, oct_mach_info::float_format); + +template octave_idx_type +octave_stream::write (const Array&, octave_idx_type, + oct_data_conv::data_type, + octave_idx_type, oct_mach_info::float_format); + +template octave_idx_type +octave_stream::write (const Array&, octave_idx_type, + oct_data_conv::data_type, + octave_idx_type, oct_mach_info::float_format); + +template octave_idx_type +octave_stream::write (const Array&, octave_idx_type, + oct_data_conv::data_type, + octave_idx_type, oct_mach_info::float_format); + +octave_value +octave_stream::scanf (const std::string& fmt, const Array& size, + octave_idx_type& count, const std::string& who) +{ + octave_value retval; + + if (stream_ok ()) + retval = rep->scanf (fmt, size, count, who); + + return retval; +} + +octave_value +octave_stream::scanf (const octave_value& fmt, const Array& size, + octave_idx_type& count, const std::string& who) +{ + octave_value retval = Matrix (); + + if (fmt.is_string ()) + { + std::string sfmt = fmt.string_value (); + + if (fmt.is_sq_string ()) + sfmt = do_string_escapes (sfmt); + + retval = scanf (sfmt, size, count, who); + } + else + { + // Note that this is not ::error () ! + + error (who + ": format must be a string"); + } + + return retval; +} + +octave_value_list +octave_stream::oscanf (const std::string& fmt, const std::string& who) +{ + octave_value_list retval; + + if (stream_ok ()) + retval = rep->oscanf (fmt, who); + + return retval; +} + +octave_value_list +octave_stream::oscanf (const octave_value& fmt, const std::string& who) +{ + octave_value_list retval; + + if (fmt.is_string ()) + { + std::string sfmt = fmt.string_value (); + + if (fmt.is_sq_string ()) + sfmt = do_string_escapes (sfmt); + + retval = oscanf (sfmt, who); + } + else + { + // Note that this is not ::error () ! + + error (who + ": format must be a string"); + } + + return retval; +} + +int +octave_stream::printf (const std::string& fmt, const octave_value_list& args, + const std::string& who) +{ + int retval = -1; + + if (stream_ok ()) + retval = rep->printf (fmt, args, who); + + return retval; +} + +int +octave_stream::printf (const octave_value& fmt, const octave_value_list& args, + const std::string& who) +{ + int retval = 0; + + if (fmt.is_string ()) + { + std::string sfmt = fmt.string_value (); + + if (fmt.is_sq_string ()) + sfmt = do_string_escapes (sfmt); + + retval = printf (sfmt, args, who); + } + else + { + // Note that this is not ::error () ! + + error (who + ": format must be a string"); + } + + return retval; +} + +int +octave_stream::puts (const std::string& s, const std::string& who) +{ + int retval = -1; + + if (stream_ok ()) + retval = rep->puts (s, who); + + return retval; +} + +// FIXME -- maybe this should work for string arrays too. + +int +octave_stream::puts (const octave_value& tc_s, const std::string& who) +{ + int retval = -1; + + if (tc_s.is_string ()) + { + std::string s = tc_s.string_value (); + retval = puts (s, who); + } + else + { + // Note that this is not ::error () ! + + error (who + ": argument must be a string"); + } + + return retval; +} + +bool +octave_stream::eof (void) const +{ + int retval = -1; + + if (stream_ok ()) + retval = rep->eof (); + + return retval; +} + +std::string +octave_stream::error (bool clear, int& err_num) +{ + std::string retval = "invalid stream object"; + + if (stream_ok (false)) + retval = rep->error (clear, err_num); + + return retval; +} + +std::string +octave_stream::name (void) const +{ + std::string retval; + + if (stream_ok ()) + retval = rep->name (); + + return retval; +} + +int +octave_stream::mode (void) const +{ + int retval = 0; + + if (stream_ok ()) + retval = rep->mode (); + + return retval; +} + +oct_mach_info::float_format +octave_stream::float_format (void) const +{ + oct_mach_info::float_format retval = oct_mach_info::flt_fmt_unknown; + + if (stream_ok ()) + retval = rep->float_format (); + + return retval; +} + +std::string +octave_stream::mode_as_string (int mode) +{ + std::string retval = "???"; + std::ios::openmode in_mode = static_cast (mode); + + if (in_mode == std::ios::in) + retval = "r"; + else if (in_mode == std::ios::out + || in_mode == (std::ios::out | std::ios::trunc)) + retval = "w"; + else if (in_mode == (std::ios::out | std::ios::app)) + retval = "a"; + else if (in_mode == (std::ios::in | std::ios::out)) + retval = "r+"; + else if (in_mode == (std::ios::in | std::ios::out | std::ios::trunc)) + retval = "w+"; + else if (in_mode == (std::ios::in | std::ios::out | std::ios::ate)) + retval = "a+"; + else if (in_mode == (std::ios::in | std::ios::binary)) + retval = "rb"; + else if (in_mode == (std::ios::out | std::ios::binary) + || in_mode == (std::ios::out | std::ios::trunc | std::ios::binary)) + retval = "wb"; + else if (in_mode == (std::ios::out | std::ios::app | std::ios::binary)) + retval = "ab"; + else if (in_mode == (std::ios::in | std::ios::out | std::ios::binary)) + retval = "r+b"; + else if (in_mode == (std::ios::in | std::ios::out | std::ios::trunc + | std::ios::binary)) + retval = "w+b"; + else if (in_mode == (std::ios::in | std::ios::out | std::ios::ate + | std::ios::binary)) + retval = "a+b"; + + return retval; +} + +octave_stream_list *octave_stream_list::instance = 0; + +bool +octave_stream_list::instance_ok (void) +{ + bool retval = true; + + if (! instance) + { + instance = new octave_stream_list (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } + + if (! instance) + { + ::error ("unable to create stream list object!"); + + retval = false; + } + + return retval; +} + +int +octave_stream_list::insert (octave_stream& os) +{ + return (instance_ok ()) ? instance->do_insert (os) : -1; +} + +octave_stream +octave_stream_list::lookup (int fid, const std::string& who) +{ + return (instance_ok ()) ? instance->do_lookup (fid, who) : octave_stream (); +} + +octave_stream +octave_stream_list::lookup (const octave_value& fid, const std::string& who) +{ + return (instance_ok ()) ? instance->do_lookup (fid, who) : octave_stream (); +} + +int +octave_stream_list::remove (int fid, const std::string& who) +{ + return (instance_ok ()) ? instance->do_remove (fid, who) : -1; +} + +int +octave_stream_list::remove (const octave_value& fid, const std::string& who) +{ + return (instance_ok ()) ? instance->do_remove (fid, who) : -1; +} + +void +octave_stream_list::clear (bool flush) +{ + if (instance) + instance->do_clear (flush); +} + +string_vector +octave_stream_list::get_info (int fid) +{ + return (instance_ok ()) ? instance->do_get_info (fid) : string_vector (); +} + +string_vector +octave_stream_list::get_info (const octave_value& fid) +{ + return (instance_ok ()) ? instance->do_get_info (fid) : string_vector (); +} + +std::string +octave_stream_list::list_open_files (void) +{ + return (instance_ok ()) ? instance->do_list_open_files () : std::string (); +} + +octave_value +octave_stream_list::open_file_numbers (void) +{ + return (instance_ok ()) + ? instance->do_open_file_numbers () : octave_value (); +} + +int +octave_stream_list::get_file_number (const octave_value& fid) +{ + return (instance_ok ()) ? instance->do_get_file_number (fid) : -1; +} + +int +octave_stream_list::do_insert (octave_stream& os) +{ + // Insert item with key corresponding to file-descriptor. + + int stream_number; + + if ((stream_number = os.file_number ()) == -1) + return stream_number; + + // Should we test for "(list.find (stream_number) != list.end ()) && + // list[stream_number].is_open ()" and respond with "error + // ("internal error: ...")"? It should not happen except for some + // bug or if the user has opened a stream with an interpreted + // command, but closed it directly with a system call in an + // oct-file; then the kernel knows the fd is free, but Octave does + // not know. If it happens, it should not do harm here to simply + // overwrite this entry, although the wrong entry might have done + // harm before. + + if (list.size () < list.max_size ()) + list[stream_number] = os; + else + { + stream_number = -1; + error ("could not create file id"); + } + + return stream_number; + +} + +static void +gripe_invalid_file_id (int fid, const std::string& who) +{ + if (who.empty ()) + ::error ("invalid stream number = %d", fid); + else + ::error ("%s: invalid stream number = %d", who.c_str (), fid); +} + +octave_stream +octave_stream_list::do_lookup (int fid, const std::string& who) const +{ + octave_stream retval; + + if (fid >= 0) + { + if (lookup_cache != list.end () && lookup_cache->first == fid) + retval = lookup_cache->second; + else + { + ostrl_map::const_iterator iter = list.find (fid); + + if (iter != list.end ()) + { + retval = iter->second; + lookup_cache = iter; + } + else + gripe_invalid_file_id (fid, who); + } + } + else + gripe_invalid_file_id (fid, who); + + return retval; +} + +octave_stream +octave_stream_list::do_lookup (const octave_value& fid, + const std::string& who) const +{ + octave_stream retval; + + int i = get_file_number (fid); + + if (! error_state) + retval = do_lookup (i, who); + + return retval; +} + +int +octave_stream_list::do_remove (int fid, const std::string& who) +{ + int retval = -1; + + // Can't remove stdin (std::cin), stdout (std::cout), or stderr + // (std::cerr). + + if (fid > 2) + { + ostrl_map::iterator iter = list.find (fid); + + if (iter != list.end ()) + { + octave_stream os = iter->second; + list.erase (iter); + lookup_cache = list.end (); + + // FIXME: is this check redundant? + if (os.is_valid ()) + { + os.close (); + retval = 0; + } + else + gripe_invalid_file_id (fid, who); + } + else + gripe_invalid_file_id (fid, who); + } + else + gripe_invalid_file_id (fid, who); + + return retval; +} + +int +octave_stream_list::do_remove (const octave_value& fid, const std::string& who) +{ + int retval = -1; + + if (fid.is_string () && fid.string_value () == "all") + { + do_clear (false); + + retval = 0; + } + else + { + int i = get_file_number (fid); + + if (! error_state) + retval = do_remove (i, who); + } + + return retval; +} + +void +octave_stream_list::do_clear (bool flush) +{ + if (flush) + { + // Do flush stdout and stderr. + + list[0].flush (); + list[1].flush (); + } + + octave_stream saved_os[3]; + // But don't delete them or stdin. + for (ostrl_map::iterator iter = list.begin (); iter != list.end (); iter++) + { + int fid = iter->first; + octave_stream os = iter->second; + if (fid < 3) + saved_os[fid] = os; + else if (os.is_valid ()) + os.close (); + } + list.clear (); + for (int fid = 0; fid < 3; fid++) list[fid] = saved_os[fid]; + lookup_cache = list.end (); +} + +string_vector +octave_stream_list::do_get_info (int fid) const +{ + string_vector retval; + + octave_stream os = do_lookup (fid); + + if (os.is_valid ()) + { + retval.resize (3); + + retval(2) = oct_mach_info::float_format_as_string (os.float_format ()); + retval(1) = octave_stream::mode_as_string (os.mode ()); + retval(0) = os.name (); + } + else + ::error ("invalid file id = %d", fid); + + return retval; +} + +string_vector +octave_stream_list::do_get_info (const octave_value& fid) const +{ + string_vector retval; + + int conv_err = 0; + + int int_fid = convert_to_valid_int (fid, conv_err); + + if (! conv_err) + retval = do_get_info (int_fid); + else + ::error ("file id must be a file object or integer value"); + + return retval; +} + +std::string +octave_stream_list::do_list_open_files (void) const +{ + std::string retval; + + std::ostringstream buf; + + buf << "\n" + << " number mode arch name\n" + << " ------ ---- ---- ----\n"; + + for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++) + { + octave_stream os = p->second; + + buf << " " + << std::setiosflags (std::ios::right) + << std::setw (4) << p->first << " " + << std::setiosflags (std::ios::left) + << std::setw (3) + << octave_stream::mode_as_string (os.mode ()) + << " " + << std::setw (9) + << oct_mach_info::float_format_as_string (os.float_format ()) + << " " + << os.name () << "\n"; + } + + buf << "\n"; + + retval = buf.str (); + + return retval; +} + +octave_value +octave_stream_list::do_open_file_numbers (void) const +{ + Matrix retval (1, list.size (), 0.0); + + int num_open = 0; + + for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++) + { + // Skip stdin, stdout, and stderr. + + if (p->first > 2 && p->second) + retval(0,num_open++) = p->first; + } + + retval.resize ((num_open > 0), num_open); + + return retval; +} + +int +octave_stream_list::do_get_file_number (const octave_value& fid) const +{ + int retval = -1; + + if (fid.is_string ()) + { + std::string nm = fid.string_value (); + + for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++) + { + // stdin (std::cin), stdout (std::cout), and stderr (std::cerr) + // are unnamed. + + if (p->first > 2) + { + octave_stream os = p->second; + + if (os && os.name () == nm) + { + retval = p->first; + break; + } + } + } + } + else + { + int conv_err = 0; + + int int_fid = convert_to_valid_int (fid, conv_err); + + if (conv_err) + ::error ("file id must be a file object, std::string, or integer value"); + else + retval = int_fid; + } + + return retval; +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-stream.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-stream.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,738 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_octave_stream_h) +#define octave_octave_stream_h 1 + +class Matrix; +class string_vector; +class octave_value; +class octave_value_list; + +#include +#include +#include +#include + +#include "Array.h" +#include "data-conv.h" +#include "lo-utils.h" +#include "mach-info.h" +#include "oct-refcount.h" + +class +OCTINTERP_API +scanf_format_elt +{ +public: + + enum special_conversion + { + whitespace_conversion = 1, + literal_conversion = 2 + }; + + scanf_format_elt (const char *txt = 0, int w = 0, bool d = false, + char typ = '\0', char mod = '\0', + const std::string& ch_class = std::string ()) + : text (strsave (txt)), width (w), discard (d), type (typ), + modifier (mod), char_class (ch_class) { } + + scanf_format_elt (const scanf_format_elt& e) + : text (strsave (e.text)), width (e.width), discard (e.discard), + type (e.type), modifier (e.modifier), char_class (e.char_class) { } + + scanf_format_elt& operator = (const scanf_format_elt& e) + { + if (this != &e) + { + text = strsave (e.text); + width = e.width; + discard = e.discard; + type = e.type; + modifier = e.modifier; + char_class = e.char_class; + } + + return *this; + } + + ~scanf_format_elt (void) { delete [] text; } + + // The C-style format string. + const char *text; + + // The maximum field width. + int width; + + // TRUE if we are not storing the result of this conversion. + bool discard; + + // Type of conversion -- `d', `i', `o', `u', `x', `e', `f', `g', + // `c', `s', `p', `%', or `['. + char type; + + // A length modifier -- `h', `l', or `L'. + char modifier; + + // The class of characters in a `[' format. + std::string char_class; +}; + +class +OCTINTERP_API +scanf_format_list +{ +public: + + scanf_format_list (const std::string& fmt = std::string ()); + + ~scanf_format_list (void); + + octave_idx_type num_conversions (void) { return nconv; } + + // The length can be different than the number of conversions. + // For example, "x %d y %d z" has 2 conversions but the length of + // the list is 3 because of the characters that appear after the + // last conversion. + + octave_idx_type length (void) { return list.length (); } + + const scanf_format_elt *first (void) + { + curr_idx = 0; + return current (); + } + + const scanf_format_elt *current (void) const + { return list.length () > 0 ? list.elem (curr_idx) : 0; } + + const scanf_format_elt *next (bool cycle = true) + { + curr_idx++; + + if (curr_idx >= list.length ()) + { + if (cycle) + curr_idx = 0; + else + return 0; + } + return current (); + } + + void printme (void) const; + + bool ok (void) const { return (nconv >= 0); } + + operator bool () const { return ok (); } + + bool all_character_conversions (void); + + bool all_numeric_conversions (void); + +private: + + // Number of conversions specified by this format string, or -1 if + // invalid conversions have been found. + octave_idx_type nconv; + + // Index to current element; + octave_idx_type curr_idx; + + // FIXME -- maybe LIST should be a std::list object? + // List of format elements. + Array list; + + // Temporary buffer. + std::ostringstream *buf; + + void add_elt_to_list (int width, bool discard, char type, char modifier, + octave_idx_type& num_elts, + const std::string& char_class = std::string ()); + + void process_conversion (const std::string& s, size_t& i, size_t n, + int& width, bool& discard, char& type, + char& modifier, octave_idx_type& num_elts); + + int finish_conversion (const std::string& s, size_t& i, size_t n, + int& width, bool discard, char& type, + char modifier, octave_idx_type& num_elts); + // No copying! + + scanf_format_list (const scanf_format_list&); + + scanf_format_list& operator = (const scanf_format_list&); +}; + +class +printf_format_elt +{ +public: + + printf_format_elt (const char *txt = 0, int n = 0, int w = 0, + int p = 0, const std::string& f = std::string (), + char typ = '\0', char mod = '\0') + : text (strsave (txt)), args (n), fw (w), prec (p), flags (f), + type (typ), modifier (mod) { } + + printf_format_elt (const printf_format_elt& e) + : text (strsave (e.text)), args (e.args), fw (e.fw), prec (e.prec), + flags (e.flags), type (e.type), modifier (e.modifier) { } + + printf_format_elt& operator = (const printf_format_elt& e) + { + if (this != &e) + { + text = strsave (e.text); + args = e.args; + fw = e.fw; + prec = e.prec; + flags = e.flags; + type = e.type; + modifier = e.modifier; + } + + return *this; + } + + ~printf_format_elt (void) { delete [] text; } + + // The C-style format string. + const char *text; + + // How many args do we expect to consume? + int args; + + // Field width. + int fw; + + // Precision. + int prec; + + // Flags -- `-', `+', ` ', `0', or `#'. + std::string flags; + + // Type of conversion -- `d', `i', `o', `x', `X', `u', `c', `s', + // `f', `e', `E', `g', `G', `p', or `%' + char type; + + // A length modifier -- `h', `l', or `L'. + char modifier; +}; + +class +OCTINTERP_API +printf_format_list +{ +public: + + printf_format_list (const std::string& fmt = std::string ()); + + ~printf_format_list (void); + + octave_idx_type num_conversions (void) { return nconv; } + + const printf_format_elt *first (void) + { + curr_idx = 0; + return current (); + } + + const printf_format_elt *current (void) const + { return list.length () > 0 ? list.elem (curr_idx) : 0; } + + const printf_format_elt *next (bool cycle = true) + { + curr_idx++; + + if (curr_idx >= list.length ()) + { + if (cycle) + curr_idx = 0; + else + return 0; + } + + return current (); + } + + bool last_elt_p (void) { return (curr_idx + 1 == list.length ()); } + + void printme (void) const; + + bool ok (void) const { return (nconv >= 0); } + + operator bool () const { return ok (); } + +private: + + // Number of conversions specified by this format string, or -1 if + // invalid conversions have been found. + octave_idx_type nconv; + + // Index to current element; + octave_idx_type curr_idx; + + // FIXME -- maybe LIST should be a std::list object? + // List of format elements. + Array list; + + // Temporary buffer. + std::ostringstream *buf; + + void add_elt_to_list (int args, const std::string& flags, int fw, + int prec, char type, char modifier, + octave_idx_type& num_elts); + + void process_conversion (const std::string& s, size_t& i, size_t n, + int& args, std::string& flags, int& fw, + int& prec, char& modifier, char& type, + octave_idx_type& num_elts); + + void finish_conversion (const std::string& s, size_t& i, int args, + const std::string& flags, int fw, int prec, + char modifier, char& type, + octave_idx_type& num_elts); + + // No copying! + + printf_format_list (const printf_format_list&); + + printf_format_list& operator = (const printf_format_list&); +}; + +// Provide an interface for Octave streams. + +class +OCTINTERP_API +octave_base_stream +{ +friend class octave_stream; + +public: + + octave_base_stream (std::ios::openmode arg_md = std::ios::in|std::ios::out, + oct_mach_info::float_format ff + = oct_mach_info::native_float_format ()) + : count (0), md (arg_md), flt_fmt (ff), fail (false), open_state (true), + errmsg () + { } + + virtual ~octave_base_stream (void) { } + + // The remaining functions are not specific to input or output only, + // and must be provided by the derived classes. + + // Position a stream at OFFSET relative to ORIGIN. + + virtual int seek (long offset, int origin) = 0; + + // Return current stream position. + + virtual long tell (void) = 0; + + // Return TRUE if EOF has been reached on this stream. + + virtual bool eof (void) const = 0; + + // The name of the file. + + virtual std::string name (void) const = 0; + + // If the derived class provides this function and it returns a + // pointer to a valid istream, scanf(), read(), getl(), and gets() + // will automatically work for this stream. + + virtual std::istream *input_stream (void) { return 0; } + + // If the derived class provides this function and it returns a + // pointer to a valid ostream, flush(), write(), and printf() will + // automatically work for this stream. + + virtual std::ostream *output_stream (void) { return 0; } + + // If the derived class is locale-aware, it must implement this function + // in order to set a new locale. By default, this function avoids messing + // with locales and ignores its input argument. + virtual std::locale imbue ( const std::locale &) + { return std::locale::classic (); } + + // Return TRUE if this stream is open. + + bool is_open (void) const { return open_state; } + + virtual void do_close (void) { } + + void close (void) + { + if (is_open ()) + { + open_state = false; + do_close (); + } + } + + virtual int file_number (void) const + { + // Kluge alert! + + if (name () == "stdin") + return 0; + else if (name () == "stdout") + return 1; + else if (name () == "stderr") + return 2; + else + return -1; + } + + bool ok (void) const { return ! fail; } + + // Return current error message for this stream. + + std::string error (bool clear, int& err_num); + +protected: + + int mode (void) const { return md; } + + oct_mach_info::float_format float_format (void) const { return flt_fmt; } + + // Set current error state and set fail to TRUE. + + void error (const std::string& msg); + void error (const std::string& who, const std::string& msg); + + // Clear any error message and set fail to FALSE. + + void clear (void); + + // Clear stream state. + + void clearerr (void); + +private: + + // A reference count. + octave_refcount count; + + // The permission bits for the file. Should be some combination of + // std::ios::open_mode bits. + int md; + + // Data format. + oct_mach_info::float_format flt_fmt; + + // TRUE if an error has occurred. + bool fail; + + // TRUE if this stream is open. + bool open_state; + + // Should contain error message if fail is TRUE. + std::string errmsg; + + // Functions that are defined for all input streams (input streams + // are those that define is). + + std::string do_gets (octave_idx_type max_len, bool& err, bool strip_newline, + const std::string& who /* = "gets" */); + + std::string getl (octave_idx_type max_len, bool& err, const std::string& who /* = "getl" */); + std::string gets (octave_idx_type max_len, bool& err, const std::string& who /* = "gets" */); + long skipl (long count, bool& err, const std::string& who /* = "skipl" */); + + octave_value do_scanf (scanf_format_list& fmt_list, octave_idx_type nr, octave_idx_type nc, + bool one_elt_size_spec, octave_idx_type& count, + const std::string& who /* = "scanf" */); + + octave_value scanf (const std::string& fmt, const Array& size, + octave_idx_type& count, const std::string& who /* = "scanf" */); + + bool do_oscanf (const scanf_format_elt *elt, octave_value&, + const std::string& who /* = "scanf" */); + + octave_value_list oscanf (const std::string& fmt, + const std::string& who /* = "scanf" */); + + // Functions that are defined for all output streams (output streams + // are those that define os). + + int flush (void); + + int do_printf (printf_format_list& fmt_list, const octave_value_list& args, + const std::string& who /* = "printf" */); + + int printf (const std::string& fmt, const octave_value_list& args, + const std::string& who /* = "printf" */); + + int puts (const std::string& s, const std::string& who /* = "puts" */); + + // We can always do this in terms of seek(), so the derived class + // only has to provide that. + + void invalid_operation (const std::string& who, const char *rw); + + // No copying! + + octave_base_stream (const octave_base_stream&); + + octave_base_stream& operator = (const octave_base_stream&); +}; + +class +OCTINTERP_API +octave_stream +{ +public: + + octave_stream (octave_base_stream *bs = 0); + + ~octave_stream (void); + + octave_stream (const octave_stream&); + + octave_stream& operator = (const octave_stream&); + + int flush (void); + + std::string getl (octave_idx_type max_len, bool& err, const std::string& who /* = "getl" */); + std::string getl (const octave_value& max_len, bool& err, + const std::string& who /* = "getl" */); + + std::string gets (octave_idx_type max_len, bool& err, const std::string& who /* = "gets" */); + std::string gets (const octave_value& max_len, bool& err, + const std::string& who /* = "gets" */); + + long skipl (long count, bool& err, const std::string& who /* = "skipl" */); + long skipl (const octave_value& count, bool& err, const std::string& who /* = "skipl" */); + + int seek (long offset, int origin); + int seek (const octave_value& offset, const octave_value& origin); + + long tell (void); + + int rewind (void); + + bool is_open (void) const; + + void close (void); + + octave_value read (const Array& size, octave_idx_type block_size, + oct_data_conv::data_type input_type, + oct_data_conv::data_type output_type, + octave_idx_type skip, oct_mach_info::float_format flt_fmt, + octave_idx_type& count); + + octave_idx_type write (const octave_value& data, octave_idx_type block_size, + oct_data_conv::data_type output_type, + octave_idx_type skip, oct_mach_info::float_format flt_fmt); + + template + octave_idx_type write (const Array&, octave_idx_type block_size, + oct_data_conv::data_type output_type, + octave_idx_type skip, oct_mach_info::float_format flt_fmt); + + octave_value scanf (const std::string& fmt, const Array& size, + octave_idx_type& count, const std::string& who /* = "scanf" */); + + octave_value scanf (const octave_value& fmt, const Array& size, + octave_idx_type& count, const std::string& who /* = "scanf" */); + + octave_value_list oscanf (const std::string& fmt, + const std::string& who /* = "scanf" */); + + octave_value_list oscanf (const octave_value& fmt, + const std::string& who /* = "scanf" */); + + int printf (const std::string& fmt, const octave_value_list& args, + const std::string& who /* = "printf" */); + + int printf (const octave_value& fmt, const octave_value_list& args, + const std::string& who /* = "printf" */); + + int puts (const std::string& s, const std::string& who /* = "puts" */); + int puts (const octave_value& s, const std::string& who /* = "puts" */); + + bool eof (void) const; + + std::string error (bool clear, int& err_num); + + std::string error (bool clear = false) + { + int err_num; + return error (clear, err_num); + } + + // Set the error message and state. + + void error (const std::string& msg) + { + if (rep) + rep->error (msg); + } + + void error (const char *msg) { error (std::string (msg)); } + + int file_number (void) { return rep ? rep->file_number () : -1; } + + bool is_valid (void) const { return (rep != 0); } + + bool ok (void) const { return rep && rep->ok (); } + + operator bool () const { return ok (); } + + std::string name (void) const; + + int mode (void) const; + + oct_mach_info::float_format float_format (void) const; + + static std::string mode_as_string (int mode); + + std::istream *input_stream (void) + { + return rep ? rep->input_stream () : 0; + } + + std::ostream *output_stream (void) + { + return rep ? rep->output_stream () : 0; + } + + std::locale imbue (const std::locale & loc ) + { + if (!rep) return std::locale::classic (); + + std::istream *is = rep->input_stream (); + std::ostream *os = rep->output_stream (); + + if (os) + { + if (is) + (void) is->imbue (loc); + return os->imbue (loc); + } + return is ? is->imbue (loc) : std::locale::classic (); + } + + void clearerr (void) { if (rep) rep->clearerr (); } + +private: + + // The actual representation of this stream. + octave_base_stream *rep; + + bool stream_ok (bool clear = true) const + { + bool retval = true; + + if (rep) + { + if (clear) + rep->clear (); + } + else + retval = false; + + return retval; + } + + void invalid_operation (const std::string& who, const char *rw) + { + if (rep) + rep->invalid_operation (who, rw); + } +}; + +class +OCTINTERP_API +octave_stream_list +{ +protected: + + octave_stream_list (void) : list (), lookup_cache (list.end ()) { } + +public: + + ~octave_stream_list (void) { } + + static bool instance_ok (void); + + static int insert (octave_stream& os); + + static octave_stream + lookup (int fid, const std::string& who = std::string ()); + + static octave_stream + lookup (const octave_value& fid, const std::string& who = std::string ()); + + static int remove (int fid, const std::string& who = std::string ()); + static int remove (const octave_value& fid, + const std::string& who = std::string ()); + + static void clear (bool flush = true); + + static string_vector get_info (int fid); + static string_vector get_info (const octave_value& fid); + + static std::string list_open_files (void); + + static octave_value open_file_numbers (void); + + static int get_file_number (const octave_value& fid); + +private: + + typedef std::map ostrl_map; + + ostrl_map list; + + mutable ostrl_map::const_iterator lookup_cache; + + static octave_stream_list *instance; + + static void cleanup_instance (void) { delete instance; instance = 0; } + + int do_insert (octave_stream& os); + + octave_stream do_lookup (int fid, const std::string& who = std::string ()) const; + octave_stream do_lookup (const octave_value& fid, + const std::string& who = std::string ()) const; + + int do_remove (int fid, const std::string& who = std::string ()); + int do_remove (const octave_value& fid, const std::string& who = std::string ()); + + void do_clear (bool flush = true); + + string_vector do_get_info (int fid) const; + string_vector do_get_info (const octave_value& fid) const; + + std::string do_list_open_files (void) const; + + octave_value do_open_file_numbers (void) const; + + int do_get_file_number (const octave_value& fid) const; +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-strstrm.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-strstrm.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,66 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "oct-strstrm.h" + +// Position a stream at OFFSET relative to ORIGIN. + +int +octave_base_strstream::seek (long, int) +{ + error ("fseek: invalid operation"); + return -1; +} + +// Return current stream position. + +long +octave_base_strstream::tell (void) +{ + error ("ftell: invalid operation"); + return -1; +} + +octave_stream +octave_istrstream::create (const char *data, std::ios::openmode arg_md, + oct_mach_info::float_format flt_fmt) +{ + return octave_stream (new octave_istrstream (data, arg_md, flt_fmt)); +} + +octave_stream +octave_istrstream::create (const std::string& data, std::ios::openmode arg_md, + oct_mach_info::float_format flt_fmt) +{ + return octave_stream (new octave_istrstream (data, arg_md, flt_fmt)); +} + +octave_stream +octave_ostrstream::create (std::ios::openmode arg_md, + oct_mach_info::float_format flt_fmt) +{ + return octave_stream (new octave_ostrstream (arg_md, flt_fmt)); +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct-strstrm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct-strstrm.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,176 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_octave_strstream_h) +#define octave_octave_strstream_h 1 + +#include +#include + +#include "oct-stream.h" + +class +octave_base_strstream : public octave_base_stream +{ +public: + + octave_base_strstream (std::ios::openmode m = std::ios::out, + oct_mach_info::float_format ff + = oct_mach_info::native_float_format ()) + : octave_base_stream (m, ff) { } + + // Position a stream at OFFSET relative to ORIGIN. + + int seek (long, int); + + // Return current stream position. + + virtual long tell (void); + + // The name of the file. + + std::string name (void) const { return std::string (); } + + virtual std::streambuf *rdbuf (void) = 0; + + virtual bool bad (void) const = 0; + + virtual void clear (void) = 0; + +protected: + + ~octave_base_strstream (void) { } + +private: + + // No copying! + + octave_base_strstream (const octave_base_strstream&); + + octave_base_strstream& operator = (const octave_base_strstream&); +}; + +class +octave_istrstream : public octave_base_strstream +{ +public: + + octave_istrstream (const char *data, + std::ios::openmode arg_md = std::ios::out, + oct_mach_info::float_format ff + = oct_mach_info::native_float_format ()) + : octave_base_strstream (arg_md, ff), is (data) { } + + octave_istrstream (const std::string& data, + std::ios::openmode arg_md = std::ios::out, + oct_mach_info::float_format ff + = oct_mach_info::native_float_format ()) + : octave_base_strstream (arg_md, ff), is (data.c_str ()) { } + + static octave_stream + create (const char *data, std::ios::openmode arg_md = std::ios::out, + oct_mach_info::float_format ff + = oct_mach_info::native_float_format ()); + + static octave_stream + create (const std::string& data, std::ios::openmode arg_md = std::ios::out, + oct_mach_info::float_format ff + = oct_mach_info::native_float_format ()); + + // Return non-zero if EOF has been reached on this stream. + + bool eof (void) const { return is.eof (); } + + std::istream *input_stream (void) { return &is; } + + std::ostream *output_stream (void) { return 0; } + + long tell (void) { return is.tellg (); } + + std::streambuf *rdbuf (void) { return is ? is.rdbuf () : 0; } + + bool bad (void) const { return is.bad (); } + + void clear (void) { is.clear (); } + +protected: + + ~octave_istrstream (void) { } + +private: + + std::istringstream is; + + // No copying! + + octave_istrstream (const octave_istrstream&); + + octave_istrstream& operator = (const octave_istrstream&); +}; + +class +octave_ostrstream : public octave_base_strstream +{ +public: + + octave_ostrstream (std::ios::openmode arg_md = std::ios::out, + oct_mach_info::float_format ff + = oct_mach_info::native_float_format ()) + : octave_base_strstream (arg_md, ff), os () { } + + static octave_stream + create (std::ios::openmode arg_md = std::ios::out, + oct_mach_info::float_format ff + = oct_mach_info::native_float_format ()); + + // Return non-zero if EOF has been reached on this stream. + + bool eof (void) const { return os.eof (); } + + std::istream *input_stream (void) { return 0; } + + std::ostream *output_stream (void) { return &os; } + + std::string str (void) { return os.str (); } + + std::streambuf *rdbuf (void) { return os ? os.rdbuf () : 0; } + + bool bad (void) const { return os.bad (); } + + void clear (void) { os.clear (); } + +protected: + + ~octave_ostrstream (void) { } + +private: + + std::ostringstream os; + + // No copying! + + octave_ostrstream (const octave_ostrstream&); + + octave_ostrstream& operator = (const octave_ostrstream&); +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/oct.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/oct.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,45 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_oct_h) +#define octave_oct_h 1 + +// Things that are often included to create .oct files. + +// config.h needs to be first because it includes #defines that can */ +// affect other header files. + +#include "config.h" + +#include "Matrix.h" + +#include "oct-locbuf.h" +#include "defun-dld.h" +#include "error.h" +#include "gripes.h" +#include "help.h" +#include "oct-obj.h" +#include "pager.h" +#include "utils.h" +#include "variables.h" + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/procstream.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/procstream.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,70 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "procstream.h" + +procstreambase::procstreambase (const std::string& command, int mode) +{ + pb_init (); + + if (! pb.open (command.c_str (), mode)) + std::ios::setstate (std::ios::badbit); +} + +procstreambase::procstreambase (const char *command, int mode) +{ + pb_init (); + + if (! pb.open (command, mode)) + std::ios::setstate (std::ios::badbit); +} + +void +procstreambase::open (const char *command, int mode) +{ + clear (); + + if (! pb.open (command, mode)) + std::ios::setstate (std::ios::badbit); +} + +int +procstreambase::close (void) +{ + int status = 0; + + if (is_open ()) + { + if (! pb.close ()) + std::ios::setstate (std::ios::failbit); + + status = pb.wait_status (); + } + + return status; +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/procstream.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/procstream.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,161 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_procstream_h) +#define octave_procstream_h 1 + +#include +#include + +#include + +#include "oct-procbuf.h" + +class +OCTINTERP_API +procstreambase : virtual public std::ios +{ +public: + + procstreambase (void) : pb () { pb_init (); } + + procstreambase (const std::string& name, int mode); + + procstreambase (const char *name, int mode); + + ~procstreambase (void) { close (); } + + void open (const std::string& name, int mode) + { open (name.c_str (), mode); } + + void open (const char *name, int mode); + + int is_open (void) const { return pb.is_open (); } + + int close (void); + + pid_t pid (void) const { return pb.pid (); } + + int file_number (void) const { return pb.file_number (); } + +private: + + octave_procbuf pb; + + void pb_init (void) { init (&pb); } + + procstreambase (const procstreambase&); + + procstreambase& operator = (const procstreambase&); +}; + +class +OCTINTERP_API +iprocstream : public std::istream, public procstreambase +// iprocstream : public procstreambase, public std::istream +{ +public: + + iprocstream (void) : std::istream (0), procstreambase () { } + + iprocstream (const std::string& name, int mode = std::ios::in) + : std::istream (0), procstreambase (name, mode) { } + + iprocstream (const char *name, int mode = std::ios::in) + : std::istream (0), procstreambase (name, mode) { } + + ~iprocstream (void) { } + + void open (const std::string& name, int mode = std::ios::in) + { procstreambase::open (name, mode); } + + void open (const char *name, int mode = std::ios::in) + { procstreambase::open (name, mode); } + +private: + + iprocstream (const iprocstream&); + + iprocstream& operator = (const iprocstream&); +}; + +class +OCTINTERP_API +oprocstream : public std::ostream, public procstreambase +// oprocstream : public procstreambase, public std::ostream +{ +public: + + oprocstream (void) : std::ostream (0), procstreambase () { } + + oprocstream (const std::string& name, int mode = std::ios::out) + : std::ostream (0), procstreambase (name, mode) { } + + oprocstream (const char *name, int mode = std::ios::out) + : std::ostream (0), procstreambase (name, mode) { } + + ~oprocstream (void) { } + + void open (const std::string& name, int mode = std::ios::out) + { procstreambase::open (name, mode); } + + void open (const char *name, int mode = std::ios::out) + { procstreambase::open (name, mode); } + +private: + + oprocstream (const oprocstream&); + + oprocstream& operator = (const oprocstream&); +}; + +class +OCTINTERP_API +procstream : public std::iostream, public procstreambase +// procstream : public procstreambase, public std::iostream +{ +public: + + procstream (void) : std::iostream (0), procstreambase () { } + + procstream (const std::string& name, int mode) + : std::iostream (0), procstreambase (name, mode) { } + + procstream (const char *name, int mode) + : std::iostream (0), procstreambase (name, mode) { } + + ~procstream (void) { } + + void open (const std::string& name, int mode) + { procstreambase::open (name, mode); } + + void open (const char *name, int mode) + { procstreambase::open (name, mode); } + +private: + + procstream (const procstream&); + + procstream& operator = (const procstream&); +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/pt-jit.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/pt-jit.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,1930 @@ +/* + +Copyright (C) 2012 Max Brister + +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 +. + +*/ + +#define __STDC_LIMIT_MACROS +#define __STDC_CONSTANT_MACROS + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_LLVM + +#include "pt-jit.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef OCTAVE_JIT_DEBUG +#include +#endif + +#include "symtab.h" +#include "pt-all.h" + +static llvm::IRBuilder<> builder (llvm::getGlobalContext ()); + +static llvm::LLVMContext& context = llvm::getGlobalContext (); + +// -------------------- jit_convert -------------------- +jit_convert::jit_convert (llvm::Module *module, tree &tee, + jit_type *for_bounds) + : iterator_count (0), for_bounds_count (0), short_count (0), breaking (false) +{ + jit_instruction::reset_ids (); + + entry_block = create ("body"); + final_block = create ("final"); + append (entry_block); + entry_block->mark_alive (); + block = entry_block; + + if (for_bounds) + create_variable (next_for_bounds (false), for_bounds); + + visit (tee); + + // FIXME: Remove if we no longer only compile loops + assert (! breaking); + assert (breaks.empty ()); + assert (continues.empty ()); + + block->append (create (final_block)); + append (final_block); + + for (vmap_t::iterator iter = vmap.begin (); iter != vmap.end (); ++iter) + { + jit_variable *var = iter->second; + const std::string& name = var->name (); + if (name.size () && name[0] != '#') + final_block->append (create (var)); + } + + construct_ssa (); + + // initialize the worklist to instructions derived from constants + for (std::list::iterator iter = constants.begin (); + iter != constants.end (); ++iter) + append_users (*iter); + + // the entry block terminator may be a regular branch statement + if (entry_block->terminator ()) + push_worklist (entry_block->terminator ()); + + // FIXME: Describe algorithm here + while (worklist.size ()) + { + jit_instruction *next = worklist.front (); + worklist.pop_front (); + next->stash_in_worklist (false); + + if (next->infer ()) + { + // terminators need to be handles specially + if (jit_terminator *term = dynamic_cast (next)) + append_users_term (term); + else + append_users (next); + } + } + + remove_dead (); + merge_blocks (); + final_block->label (); + place_releases (); + simplify_phi (); + +#ifdef OCTAVE_JIT_DEBUG + final_block->label (); + std::cout << "-------------------- Compiling tree --------------------\n"; + std::cout << tee.str_print_code () << std::endl; + print_blocks ("octave jit ir"); +#endif + + // for now just init arguments from entry, later we will have to do something + // more interesting + for (jit_block::iterator iter = entry_block->begin (); + iter != entry_block->end (); ++iter) + if (jit_extract_argument *extract + = dynamic_cast (*iter)) + arguments.push_back (std::make_pair (extract->name (), true)); + + convert_llvm to_llvm (*this); + function = to_llvm.convert (module, arguments, blocks, constants); + +#ifdef OCTAVE_JIT_DEBUG + std::cout << "-------------------- llvm ir --------------------"; + llvm::raw_os_ostream llvm_cout (std::cout); + function->print (llvm_cout); + std::cout << std::endl; + llvm::verifyFunction (*function); +#endif +} + +jit_convert::~jit_convert (void) +{ + for (std::list::iterator iter = all_values.begin (); + iter != all_values.end (); ++iter) + delete *iter; +} + +void +jit_convert::visit_anon_fcn_handle (tree_anon_fcn_handle&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_argument_list (tree_argument_list&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_binary_expression (tree_binary_expression& be) +{ + if (be.op_type () >= octave_value::num_binary_ops) + { + tree_boolean_expression *boole; + boole = dynamic_cast (&be); + assert (boole); + bool is_and = boole->op_type () == tree_boolean_expression::bool_and; + + std::string short_name = next_shortcircut_result (); + jit_variable *short_result = create (short_name); + vmap[short_name] = short_result; + + jit_block *done = create (block->name ()); + tree_expression *lhs = be.lhs (); + jit_value *lhsv = visit (lhs); + lhsv = create_checked (&jit_typeinfo::logically_true, lhsv); + + jit_block *short_early = create ("short_early"); + append (short_early); + + jit_block *short_cont = create ("short_cont"); + + if (is_and) + block->append (create (lhsv, short_cont, short_early)); + else + block->append (create (lhsv, short_early, short_cont)); + + block = short_early; + + jit_value *early_result = create (! is_and); + block->append (create (short_result, early_result)); + block->append (create (done)); + + append (short_cont); + block = short_cont; + + tree_expression *rhs = be.rhs (); + jit_value *rhsv = visit (rhs); + rhsv = create_checked (&jit_typeinfo::logically_true, rhsv); + block->append (create (short_result, rhsv)); + block->append (create (done)); + + append (done); + block = done; + result = short_result; + } + else + { + tree_expression *lhs = be.lhs (); + jit_value *lhsv = visit (lhs); + + tree_expression *rhs = be.rhs (); + jit_value *rhsv = visit (rhs); + + const jit_operation& fn = jit_typeinfo::binary_op (be.op_type ()); + result = create_checked (fn, lhsv, rhsv); + } +} + +void +jit_convert::visit_break_command (tree_break_command&) +{ + breaks.push_back (block); + breaking = true; +} + +void +jit_convert::visit_colon_expression (tree_colon_expression& expr) +{ + // in the futher we need to add support for classes and deal with rvalues + jit_value *base = visit (expr.base ()); + jit_value *limit = visit (expr.limit ()); + jit_value *increment; + tree_expression *tinc = expr.increment (); + + if (tinc) + increment = visit (tinc); + else + increment = create (1); + + result = block->append (create (jit_typeinfo::make_range, base, + limit, increment)); +} + +void +jit_convert::visit_continue_command (tree_continue_command&) +{ + continues.push_back (block); + breaking = true; +} + +void +jit_convert::visit_global_command (tree_global_command&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_persistent_command (tree_persistent_command&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_decl_elt (tree_decl_elt&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_decl_init_list (tree_decl_init_list&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_simple_for_command (tree_simple_for_command& cmd) +{ + // Note we do an initial check to see if the loop will run atleast once. + // This allows us to get better type inference bounds on variables defined + // and used only inside the for loop (e.g. the index variable) + + // If we are a nested for loop we need to store the previous breaks + assert (! breaking); + unwind_protect prot; + prot.protect_var (breaks); + prot.protect_var (continues); + prot.protect_var (breaking); + breaks.clear (); + continues.clear (); + + // we need a variable for our iterator, because it is used in multiple blocks + std::string iter_name = next_iterator (); + jit_variable *iterator = create (iter_name); + create (iter_name); + vmap[iter_name] = iterator; + + jit_block *body = create ("for_body"); + append (body); + + jit_block *tail = create ("for_tail"); + + // do control expression, iter init, and condition check in prev_block (block) + // if we are the top level for loop, the bounds is an input argument. + jit_value *control = find_variable (next_for_bounds ()); + if (! control) + control = visit (cmd.control_expr ()); + jit_call *init_iter = create (jit_typeinfo::for_init, control); + block->append (init_iter); + block->append (create (iterator, init_iter)); + + jit_value *check = block->append (create (jit_typeinfo::for_check, + control, iterator)); + block->append (create (check, body, tail)); + block = body; + + // compute the syntactical iterator + jit_call *idx_rhs = create (jit_typeinfo::for_index, control, + iterator); + block->append (idx_rhs); + do_assign (cmd.left_hand_side (), idx_rhs); + + // do loop + tree_statement_list *pt_body = cmd.body (); + pt_body->accept (*this); + + if (breaking && continues.empty ()) + { + // WTF are you doing user? Every branch was a continue, why did you have + // a loop??? Users are silly people... + finish_breaks (tail, breaks); + append (tail); + block = tail; + return; + } + + // check our condition, continues jump to this block + jit_block *check_block = create ("for_check"); + append (check_block); + + if (! breaking) + block->append (create (check_block)); + finish_breaks (check_block, continues); + + block = check_block; + const jit_operation& add_fn = jit_typeinfo::binary_op (octave_value::op_add); + jit_value *one = create (1); + jit_call *iter_inc = create (add_fn, iterator, one); + block->append (iter_inc); + block->append (create (iterator, iter_inc)); + check = block->append (create (jit_typeinfo::for_check, control, + iterator)); + block->append (create (check, body, tail)); + + // breaks will go to our tail + append (tail); + finish_breaks (tail, breaks); + block = tail; +} + +void +jit_convert::visit_complex_for_command (tree_complex_for_command&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_octave_user_script (octave_user_script&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_octave_user_function (octave_user_function&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_octave_user_function_header (octave_user_function&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_octave_user_function_trailer (octave_user_function&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_function_def (tree_function_def&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_identifier (tree_identifier& ti) +{ + if (ti.has_magic_end ()) + { + if (!end_context.size ()) + throw jit_fail_exception ("Illegal end"); + result = block->append (create (end_context)); + } + else + result = get_variable (ti.name ()); +} + +void +jit_convert::visit_if_clause (tree_if_clause&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_if_command (tree_if_command& cmd) +{ + tree_if_command_list *lst = cmd.cmd_list (); + assert (lst); // jwe: Can this be null? + lst->accept (*this); +} + +void +jit_convert::visit_if_command_list (tree_if_command_list& lst) +{ + tree_if_clause *last = lst.back (); + size_t last_else = static_cast (last->is_else_clause ()); + + // entry_blocks represents the block you need to enter in order to execute + // the condition check for the ith clause. For the else, it is simple the + // else body. If there is no else body, then it is padded with the tail + std::vector entry_blocks (lst.size () + 1 - last_else); + std::vector branch_blocks (lst.size (), 0); // final blocks + entry_blocks[0] = block; + + // we need to construct blocks first, because they have jumps to eachother + tree_if_command_list::iterator iter = lst.begin (); + ++iter; + for (size_t i = 1; iter != lst.end (); ++iter, ++i) + { + tree_if_clause *tic = *iter; + if (tic->is_else_clause ()) + entry_blocks[i] = create ("else"); + else + entry_blocks[i] = create ("ifelse_cond"); + } + + jit_block *tail = create ("if_tail"); + if (! last_else) + entry_blocks[entry_blocks.size () - 1] = tail; + + size_t num_incomming = 0; // number of incomming blocks to our tail + iter = lst.begin (); + for (size_t i = 0; iter != lst.end (); ++iter, ++i) + { + tree_if_clause *tic = *iter; + block = entry_blocks[i]; + assert (block); + + if (i) // the first block is prev_block, so it has already been added + append (entry_blocks[i]); + + if (! tic->is_else_clause ()) + { + tree_expression *expr = tic->condition (); + jit_value *cond = visit (expr); + jit_call *check = create_checked (&jit_typeinfo::logically_true, + cond); + jit_block *body = create (i == 0 ? "if_body" + : "ifelse_body"); + append (body); + + jit_instruction *br = create (check, body, + entry_blocks[i + 1]); + block->append (br); + block = body; + } + + tree_statement_list *stmt_lst = tic->commands (); + assert (stmt_lst); // jwe: Can this be null? + stmt_lst->accept (*this); + + if (breaking) + breaking = false; + else + { + ++num_incomming; + block->append (create (tail)); + } + } + + if (num_incomming || ! last_else) + { + append (tail); + block = tail; + } + else + // every branch broke, so we don't have a tail + breaking = true; +} + +void +jit_convert::visit_index_expression (tree_index_expression& exp) +{ + result = resolve (jit_typeinfo::paren_subsref (), exp); +} + +void +jit_convert::visit_matrix (tree_matrix&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_cell (tree_cell&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_multi_assignment (tree_multi_assignment&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_no_op_command (tree_no_op_command&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_constant (tree_constant& tc) +{ + octave_value v = tc.rvalue1 (); + if (v.is_real_scalar () && v.is_double_type ()) + { + double dv = v.double_value (); + result = create (dv); + } + else if (v.is_range ()) + { + Range rv = v.range_value (); + result = create (rv); + } + else if (v.is_complex_scalar ()) + { + Complex cv = v.complex_value (); + result = create (cv); + } + else + throw jit_fail_exception ("Unknown constant"); +} + +void +jit_convert::visit_fcn_handle (tree_fcn_handle&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_parameter_list (tree_parameter_list&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_postfix_expression (tree_postfix_expression&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_prefix_expression (tree_prefix_expression&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_return_command (tree_return_command&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_return_list (tree_return_list&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_simple_assignment (tree_simple_assignment& tsa) +{ + if (tsa.op_type () != octave_value::op_asn_eq) + throw jit_fail_exception ("Unsupported assign"); + + // resolve rhs + tree_expression *rhs = tsa.right_hand_side (); + jit_value *rhsv = visit (rhs); + + result = do_assign (tsa.left_hand_side (), rhsv); +} + +void +jit_convert::visit_statement (tree_statement& stmt) +{ + tree_command *cmd = stmt.command (); + tree_expression *expr = stmt.expression (); + + if (cmd) + visit (cmd); + else + { + // stolen from tree_evaluator::visit_statement + bool do_bind_ans = false; + + if (expr->is_identifier ()) + { + tree_identifier *id = dynamic_cast (expr); + + do_bind_ans = (! id->is_variable ()); + } + else + do_bind_ans = (! expr->is_assignment_expression ()); + + jit_value *expr_result = visit (expr); + + if (do_bind_ans) + do_assign ("ans", expr_result, expr->print_result ()); + else if (expr->is_identifier () && expr->print_result ()) + { + // FIXME: ugly hack, we need to come up with a way to pass + // nargout to visit_identifier + const jit_operation& fn = jit_typeinfo::print_value (); + jit_const_string *name = create (expr->name ()); + block->append (create (fn, name, expr_result)); + } + } +} + +void +jit_convert::visit_statement_list (tree_statement_list& lst) +{ + for (tree_statement_list::iterator iter = lst.begin (); iter != lst.end(); + ++iter) + { + tree_statement *elt = *iter; + // jwe: Can this ever be null? + assert (elt); + elt->accept (*this); + + if (breaking) + break; + } +} + +void +jit_convert::visit_switch_case (tree_switch_case&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_switch_case_list (tree_switch_case_list&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_switch_command (tree_switch_command&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_try_catch_command (tree_try_catch_command&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_unwind_protect_command (tree_unwind_protect_command&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::visit_while_command (tree_while_command& wc) +{ + assert (! breaking); + unwind_protect prot; + prot.protect_var (breaks); + prot.protect_var (continues); + prot.protect_var (breaking); + breaks.clear (); + continues.clear (); + + jit_block *cond_check = create ("while_cond_check"); + block->append (create (cond_check)); + append (cond_check); + block = cond_check; + + tree_expression *expr = wc.condition (); + assert (expr && "While expression can not be null"); + jit_value *check = visit (expr); + check = create_checked (&jit_typeinfo::logically_true, check); + + jit_block *body = create ("while_body"); + append (body); + + jit_block *tail = create ("while_tail"); + block->append (create (check, body, tail)); + block = body; + + tree_statement_list *loop_body = wc.body (); + if (loop_body) + loop_body->accept (*this); + + finish_breaks (tail, breaks); + finish_breaks (cond_check, continues); + + if (! breaking) + block->append (create (cond_check)); + + append (tail); + block = tail; +} + +void +jit_convert::visit_do_until_command (tree_do_until_command&) +{ + throw jit_fail_exception (); +} + +void +jit_convert::append (jit_block *ablock) +{ + blocks.push_back (ablock); + ablock->stash_location (--blocks.end ()); +} + +void +jit_convert::insert_before (block_iterator iter, jit_block *ablock) +{ + iter = blocks.insert (iter, ablock); + ablock->stash_location (iter); +} + +void +jit_convert::insert_after (block_iterator iter, jit_block *ablock) +{ + ++iter; + insert_before (iter, ablock); +} + +jit_variable * +jit_convert::find_variable (const std::string& vname) const +{ + vmap_t::const_iterator iter; + iter = vmap.find (vname); + return iter != vmap.end () ? iter->second : 0; +} + +jit_variable * +jit_convert::get_variable (const std::string& vname) +{ + jit_variable *ret = find_variable (vname); + if (ret) + return ret; + + octave_value val = symbol_table::find (vname); + jit_type *type = jit_typeinfo::type_of (val); + return create_variable (vname, type); +} + +jit_variable * +jit_convert::create_variable (const std::string& vname, jit_type *type) +{ + jit_variable *var = create (vname); + jit_extract_argument *extract; + extract = create (type, var); + entry_block->prepend (extract); + return vmap[vname] = var; +} + +std::string +jit_convert::next_name (const char *prefix, size_t& count, bool inc) +{ + std::stringstream ss; + ss << prefix << count; + if (inc) + ++count; + return ss.str (); +} + +jit_instruction * +jit_convert::resolve (const jit_operation& fres, tree_index_expression& exp, + jit_value *extra_arg) +{ + std::string type = exp.type_tags (); + if (! (type.size () == 1 && type[0] == '(')) + throw jit_fail_exception ("Unsupported index operation"); + + std::list args = exp.arg_lists (); + if (args.size () != 1) + throw jit_fail_exception ("Bad number of arguments in tree_index_expression"); + + tree_argument_list *arg_list = args.front (); + if (! arg_list) + throw jit_fail_exception ("null argument list"); + + if (arg_list->size () < 1) + throw jit_fail_exception ("Empty arg_list"); + + tree_expression *tree_object = exp.expression (); + jit_value *object = visit (tree_object); + + size_t narg = arg_list->size (); + tree_argument_list::iterator iter = arg_list->begin (); + bool have_extra = extra_arg; + std::vector call_args (narg + 1 + have_extra); + call_args[0] = object; + + for (size_t idx = 0; iter != arg_list->end (); ++idx, ++iter) + { + unwind_protect prot; + prot.add_method (&end_context, + &std::vector::pop_back); + end_context.push_back (jit_magic_end::context (object, idx, narg)); + call_args[idx + 1] = visit (*iter); + } + + if (extra_arg) + call_args[call_args.size () - 1] = extra_arg; + + return create_checked (fres, call_args); +} + +jit_value * +jit_convert::do_assign (tree_expression *exp, jit_value *rhs, bool artificial) +{ + if (! exp) + throw jit_fail_exception ("NULL lhs in assign"); + + if (isa (exp)) + return do_assign (exp->name (), rhs, exp->print_result (), artificial); + else if (tree_index_expression *idx + = dynamic_cast (exp)) + { + jit_value *new_object = resolve (jit_typeinfo::paren_subsasgn (), *idx, + rhs); + do_assign (idx->expression (), new_object, true); + + // FIXME: Will not work for values that must be release/grabed + return rhs; + } + else + throw jit_fail_exception ("Unsupported assignment"); +} + +jit_value * +jit_convert::do_assign (const std::string& lhs, jit_value *rhs, + bool print, bool artificial) +{ + jit_variable *var = get_variable (lhs); + jit_assign *assign = block->append (create (var, rhs)); + + if (artificial) + assign->mark_artificial (); + + if (print) + { + const jit_operation& print_fn = jit_typeinfo::print_value (); + jit_const_string *name = create (lhs); + block->append (create (print_fn, name, var)); + } + + return var; +} + +jit_value * +jit_convert::visit (tree& tee) +{ + result = 0; + tee.accept (*this); + + jit_value *ret = result; + result = 0; + return ret; +} + +void +jit_convert::append_users_term (jit_terminator *term) +{ + for (size_t i = 0; i < term->successor_count (); ++i) + { + if (term->alive (i)) + { + jit_block *succ = term->successor (i); + for (jit_block::iterator iter = succ->begin (); iter != succ->end () + && isa (*iter); ++iter) + push_worklist (*iter); + + jit_terminator *sterm = succ->terminator (); + if (sterm) + push_worklist (sterm); + } + } +} + +void +jit_convert::merge_blocks (void) +{ + std::vector dead; + for (block_list::iterator iter = blocks.begin (); iter != blocks.end (); + ++iter) + { + jit_block *b = *iter; + jit_block *merged = b->maybe_merge (); + + if (merged) + { + if (merged == final_block) + final_block = b; + + if (merged == entry_block) + entry_block = b; + + dead.push_back (merged); + } + } + + for (size_t i = 0; i < dead.size (); ++i) + blocks.erase (dead[i]->location ()); +} + +void +jit_convert::construct_ssa (void) +{ + merge_blocks (); + final_block->label (); + final_block->compute_idom (entry_block); + entry_block->compute_df (); + entry_block->create_dom_tree (); + + // insert phi nodes where needed, this is done on a per variable basis + for (vmap_t::iterator iter = vmap.begin (); iter != vmap.end (); ++iter) + { + jit_block::df_set visited, added_phi; + std::list ssa_worklist; + iter->second->use_blocks (visited); + ssa_worklist.insert (ssa_worklist.begin (), visited.begin (), + visited.end ()); + + while (ssa_worklist.size ()) + { + jit_block *b = ssa_worklist.front (); + ssa_worklist.pop_front (); + + for (jit_block::df_iterator diter = b->df_begin (); + diter != b->df_end (); ++diter) + { + jit_block *dblock = *diter; + if (! added_phi.count (dblock)) + { + jit_phi *phi = create (iter->second, + dblock->use_count ()); + dblock->prepend (phi); + added_phi.insert (dblock); + } + + if (! visited.count (dblock)) + { + ssa_worklist.push_back (dblock); + visited.insert (dblock); + } + } + } + } + + do_construct_ssa (*entry_block, entry_block->visit_count ()); +} + +void +jit_convert::do_construct_ssa (jit_block& ablock, size_t avisit_count) +{ + if (ablock.visited (avisit_count)) + return; + + // replace variables with their current SSA value + for (jit_block::iterator iter = ablock.begin (); iter != ablock.end (); ++iter) + { + jit_instruction *instr = *iter; + instr->construct_ssa (); + instr->push_variable (); + } + + // finish phi nodes of successors + for (size_t i = 0; i < ablock.successor_count (); ++i) + { + jit_block *finish = ablock.successor (i); + + for (jit_block::iterator iter = finish->begin (); iter != finish->end () + && isa (*iter);) + { + jit_phi *phi = static_cast (*iter); + jit_variable *var = phi->dest (); + if (var->has_top ()) + { + phi->add_incomming (&ablock, var->top ()); + ++iter; + } + else + { + // temporaries may have extranious phi nodes which can be removed + assert (! phi->use_count ()); + assert (var->name ().size () && var->name ()[0] == '#'); + iter = finish->remove (iter); + } + } + } + + for (size_t i = 0; i < ablock.dom_successor_count (); ++i) + do_construct_ssa (*ablock.dom_successor (i), avisit_count); + + ablock.pop_all (); +} + +void +jit_convert::remove_dead () +{ + block_list::iterator biter; + for (biter = blocks.begin (); biter != blocks.end (); ++biter) + { + jit_block *b = *biter; + if (b->alive ()) + { + for (jit_block::iterator iter = b->begin (); iter != b->end () + && isa (*iter);) + { + jit_phi *phi = static_cast (*iter); + if (phi->prune ()) + iter = b->remove (iter); + else + ++iter; + } + } + } + + for (biter = blocks.begin (); biter != blocks.end ();) + { + jit_block *b = *biter; + if (b->alive ()) + { + // FIXME: A special case for jit_error_check, if we generalize to + // we will need to change! + jit_terminator *term = b->terminator (); + if (term && term->successor_count () == 2 && ! term->alive (0)) + { + jit_block *succ = term->successor (1); + term->remove (); + jit_branch *abreak = b->append (create (succ)); + abreak->infer (); + } + + ++biter; + } + else + { + jit_terminator *term = b->terminator (); + if (term) + term->remove (); + biter = blocks.erase (biter); + } + } +} + +void +jit_convert::place_releases (void) +{ + std::set temporaries; + for (block_list::iterator iter = blocks.begin (); iter != blocks.end (); + ++iter) + { + jit_block& ablock = **iter; + if (ablock.id () != jit_block::NO_ID) + { + release_temp (ablock, temporaries); + release_dead_phi (ablock); + } + } +} + +void +jit_convert::release_temp (jit_block& ablock, std::set& temp) +{ + for (jit_block::iterator iter = ablock.begin (); iter != ablock.end (); + ++iter) + { + jit_instruction *instr = *iter; + + // check for temporaries that require release and live across + // multiple blocks + if (instr->needs_release ()) + { + jit_block *fu_block = instr->first_use_block (); + if (fu_block && fu_block != &ablock) + temp.insert (instr); + } + + if (isa (instr)) + { + // place releases for temporary arguments + for (size_t i = 0; i < instr->argument_count (); ++i) + { + jit_value *arg = instr->argument (i); + if (arg->needs_release ()) + { + jit_call *release = create (&jit_typeinfo::release, + arg); + release->infer (); + ablock.insert_after (iter, release); + ++iter; + temp.erase (arg); + } + } + } + } + + if (! temp.size () || ! isa (ablock.terminator ())) + return; + + // FIXME: If we support try/catch or unwind_protect final_block may not be the + // destination + jit_block *split = ablock.maybe_split (*this, final_block); + jit_terminator *term = split->terminator (); + for (std::set::const_iterator iter = temp.begin (); + iter != temp.end (); ++iter) + { + jit_value *value = *iter; + jit_call *release = create (&jit_typeinfo::release, value); + split->insert_before (term, release); + release->infer (); + } +} + +void +jit_convert::release_dead_phi (jit_block& ablock) +{ + jit_block::iterator iter = ablock.begin (); + while (iter != ablock.end () && isa (*iter)) + { + jit_phi *phi = static_cast (*iter); + ++iter; + + jit_use *use = phi->first_use (); + if (phi->use_count () == 1 && isa (use->user ())) + { + // instead of releasing on assign, release on all incomming branches, + // this can get rid of casts inside loops + for (size_t i = 0; i < phi->argument_count (); ++i) + { + jit_value *arg = phi->argument (i); + jit_block *inc = phi->incomming (i); + jit_block *split = inc->maybe_split (*this, ablock); + jit_terminator *term = split->terminator (); + jit_call *release = create (jit_typeinfo::release, arg); + release->infer (); + split->insert_before (term, release); + } + + phi->replace_with (0); + phi->remove (); + } + } +} + +void +jit_convert::simplify_phi (void) +{ + for (block_list::iterator biter = blocks.begin (); biter != blocks.end (); + ++biter) + { + jit_block &ablock = **biter; + for (jit_block::iterator iter = ablock.begin (); iter != ablock.end () + && isa (*iter); ++iter) + simplify_phi (*static_cast (*iter)); + } +} + +void +jit_convert::simplify_phi (jit_phi& phi) +{ + jit_block& pblock = *phi.parent (); + const jit_operation& cast_fn = jit_typeinfo::cast (phi.type ()); + jit_variable *dest = phi.dest (); + for (size_t i = 0; i < phi.argument_count (); ++i) + { + jit_value *arg = phi.argument (i); + if (arg->type () != phi.type ()) + { + jit_block *pred = phi.incomming (i); + jit_block *split = pred->maybe_split (*this, pblock); + jit_terminator *term = split->terminator (); + jit_instruction *cast = create (cast_fn, arg); + jit_assign *assign = create (dest, cast); + + split->insert_before (term, cast); + split->insert_before (term, assign); + cast->infer (); + assign->infer (); + phi.stash_argument (i, assign); + } + } +} + +void +jit_convert::finish_breaks (jit_block *dest, const block_list& lst) +{ + for (block_list::const_iterator iter = lst.begin (); iter != lst.end (); + ++iter) + { + jit_block *b = *iter; + b->append (create (dest)); + } +} + +// -------------------- jit_convert::convert_llvm -------------------- +llvm::Function * +jit_convert::convert_llvm::convert (llvm::Module *module, + const std::vector >& args, + const std::list& blocks, + const std::list& constants) +{ + jit_type *any = jit_typeinfo::get_any (); + + // argument is an array of octave_base_value*, or octave_base_value** + llvm::Type *arg_type = any->to_llvm (); // this is octave_base_value* + arg_type = arg_type->getPointerTo (); + llvm::FunctionType *ft = llvm::FunctionType::get (llvm::Type::getVoidTy (context), + arg_type, false); + function = llvm::Function::Create (ft, llvm::Function::ExternalLinkage, + "foobar", module); + + try + { + prelude = llvm::BasicBlock::Create (context, "prelude", function); + builder.SetInsertPoint (prelude); + + llvm::Value *arg = function->arg_begin (); + for (size_t i = 0; i < args.size (); ++i) + { + llvm::Value *loaded_arg = builder.CreateConstInBoundsGEP1_32 (arg, i); + arguments[args[i].first] = loaded_arg; + } + + std::list::const_iterator biter; + for (biter = blocks.begin (); biter != blocks.end (); ++biter) + { + jit_block *jblock = *biter; + llvm::BasicBlock *block = llvm::BasicBlock::Create (context, + jblock->name (), + function); + jblock->stash_llvm (block); + } + + jit_block *first = *blocks.begin (); + builder.CreateBr (first->to_llvm ()); + + // constants aren't in the IR, we visit those first + for (std::list::const_iterator iter = constants.begin (); + iter != constants.end (); ++iter) + if (! isa (*iter)) + visit (*iter); + + // convert all instructions + for (biter = blocks.begin (); biter != blocks.end (); ++biter) + visit (*biter); + + // now finish phi nodes + for (biter = blocks.begin (); biter != blocks.end (); ++biter) + { + jit_block& block = **biter; + for (jit_block::iterator piter = block.begin (); + piter != block.end () && isa (*piter); ++piter) + { + jit_instruction *phi = *piter; + finish_phi (static_cast (phi)); + } + } + + jit_block *last = blocks.back (); + builder.SetInsertPoint (last->to_llvm ()); + builder.CreateRetVoid (); + } catch (const jit_fail_exception& e) + { + function->eraseFromParent (); + throw; + } + + return function; +} + +void +jit_convert::convert_llvm::finish_phi (jit_phi *phi) +{ + llvm::PHINode *llvm_phi = phi->to_llvm (); + for (size_t i = 0; i < phi->argument_count (); ++i) + { + llvm::BasicBlock *pred = phi->incomming_llvm (i); + llvm_phi->addIncoming (phi->argument_llvm (i), pred); + } +} + +void +jit_convert::convert_llvm::visit (jit_const_string& cs) +{ + cs.stash_llvm (builder.CreateGlobalStringPtr (cs.value ())); +} + +void +jit_convert::convert_llvm::visit (jit_const_bool& cb) +{ + cb.stash_llvm (llvm::ConstantInt::get (cb.type_llvm (), cb.value ())); +} + +void +jit_convert::convert_llvm::visit (jit_const_scalar& cs) +{ + cs.stash_llvm (llvm::ConstantFP::get (cs.type_llvm (), cs.value ())); +} + +void +jit_convert::convert_llvm::visit (jit_const_complex& cc) +{ + llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm (); + llvm::Constant *values[2]; + Complex value = cc.value (); + values[0] = llvm::ConstantFP::get (scalar_t, value.real ()); + values[1] = llvm::ConstantFP::get (scalar_t, value.imag ()); + cc.stash_llvm (llvm::ConstantVector::get (values)); +} + +void jit_convert::convert_llvm::visit (jit_const_index& ci) +{ + ci.stash_llvm (llvm::ConstantInt::get (ci.type_llvm (), ci.value ())); +} + +void +jit_convert::convert_llvm::visit (jit_const_range& cr) +{ + llvm::StructType *stype = llvm::cast(cr.type_llvm ()); + llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm (); + llvm::Type *idx = jit_typeinfo::get_index_llvm (); + const jit_range& rng = cr.value (); + + llvm::Constant *constants[4]; + constants[0] = llvm::ConstantFP::get (scalar_t, rng.base); + constants[1] = llvm::ConstantFP::get (scalar_t, rng.limit); + constants[2] = llvm::ConstantFP::get (scalar_t, rng.inc); + constants[3] = llvm::ConstantInt::get (idx, rng.nelem); + + llvm::Value *as_llvm; + as_llvm = llvm::ConstantStruct::get (stype, + llvm::makeArrayRef (constants, 4)); + cr.stash_llvm (as_llvm); +} + +void +jit_convert::convert_llvm::visit (jit_block& b) +{ + llvm::BasicBlock *block = b.to_llvm (); + builder.SetInsertPoint (block); + for (jit_block::iterator iter = b.begin (); iter != b.end (); ++iter) + visit (*iter); +} + +void +jit_convert::convert_llvm::visit (jit_branch& b) +{ + b.stash_llvm (builder.CreateBr (b.successor_llvm ())); +} + +void +jit_convert::convert_llvm::visit (jit_cond_branch& cb) +{ + llvm::Value *cond = cb.cond_llvm (); + llvm::Value *br; + br = builder.CreateCondBr (cond, cb.successor_llvm (0), + cb.successor_llvm (1)); + cb.stash_llvm (br); +} + +void +jit_convert::convert_llvm::visit (jit_call& call) +{ + const jit_function& ol = call.overload (); + + std::vector args (call.arguments ().size ()); + for (size_t i = 0; i < args.size (); ++i) + args[i] = call.argument (i); + + llvm::Value *ret = ol.call (builder, args); + call.stash_llvm (ret); +} + +void +jit_convert::convert_llvm::visit (jit_extract_argument& extract) +{ + llvm::Value *arg = arguments[extract.name ()]; + assert (arg); + arg = builder.CreateLoad (arg); + + const jit_function& ol = extract.overload (); + extract.stash_llvm (ol.call (builder, arg)); +} + +void +jit_convert::convert_llvm::visit (jit_store_argument& store) +{ + const jit_function& ol = store.overload (); + llvm::Value *arg_value = ol.call (builder, store.result ()); + llvm::Value *arg = arguments[store.name ()]; + store.stash_llvm (builder.CreateStore (arg_value, arg)); +} + +void +jit_convert::convert_llvm::visit (jit_phi& phi) +{ + // we might not have converted all incoming branches, so we don't + // set incomming branches now + llvm::PHINode *node = llvm::PHINode::Create (phi.type_llvm (), + phi.argument_count ()); + builder.Insert (node); + phi.stash_llvm (node); +} + +void +jit_convert::convert_llvm::visit (jit_variable&) +{ + throw jit_fail_exception ("ERROR: SSA construction should remove all variables"); +} + +void +jit_convert::convert_llvm::visit (jit_error_check& check) +{ + llvm::Value *cond = jit_typeinfo::insert_error_check (builder); + llvm::Value *br = builder.CreateCondBr (cond, check.successor_llvm (0), + check.successor_llvm (1)); + check.stash_llvm (br); +} + +void +jit_convert::convert_llvm::visit (jit_assign& assign) +{ + jit_value *new_value = assign.src (); + assign.stash_llvm (new_value->to_llvm ()); + + if (assign.artificial ()) + return; + + if (isa (new_value)) + { + const jit_function& ol = jit_typeinfo::get_grab (new_value->type ()); + if (ol.valid ()) + assign.stash_llvm (ol.call (builder, new_value)); + } + + jit_value *overwrite = assign.overwrite (); + if (isa (overwrite)) + { + const jit_function& ol = jit_typeinfo::get_release (overwrite->type ()); + ol.call (builder, overwrite); + } +} + +void +jit_convert::convert_llvm::visit (jit_argument&) +{} + +void +jit_convert::convert_llvm::visit (jit_magic_end& me) +{ + const jit_function& ol = me.overload (); + llvm::Value *ret = ol.call (builder, me.resolve_context ()); + me.stash_llvm (ret); +} + +// -------------------- tree_jit -------------------- + +tree_jit::tree_jit (void) : module (0), engine (0) +{ +} + +tree_jit::~tree_jit (void) +{} + +bool +tree_jit::execute (tree_simple_for_command& cmd, const octave_value& bounds) +{ + const size_t MIN_TRIP_COUNT = 1000; + + size_t tc = trip_count (bounds); + if (! tc || ! initialize ()) + return false; + + jit_info::vmap extra_vars; + extra_vars["#for_bounds0"] = &bounds; + + jit_info *info = cmd.get_info (); + if (! info || ! info->match (extra_vars)) + { + if (tc < MIN_TRIP_COUNT) + return false; + + delete info; + info = new jit_info (*this, cmd, bounds); + cmd.stash_info (info); + } + + return info->execute (extra_vars); +} + +bool +tree_jit::execute (tree_while_command& cmd) +{ + if (! initialize ()) + return false; + + jit_info *info = cmd.get_info (); + if (! info || ! info->match ()) + { + delete info; + info = new jit_info (*this, cmd); + cmd.stash_info (info); + } + + return info->execute (); +} + +bool +tree_jit::initialize (void) +{ + if (engine) + return true; + + if (! module) + { + llvm::InitializeNativeTarget (); + module = new llvm::Module ("octave", context); + } + + // sometimes this fails pre main + engine = llvm::ExecutionEngine::createJIT (module); + + if (! engine) + return false; + + module_pass_manager = new llvm::PassManager (); + module_pass_manager->add (llvm::createAlwaysInlinerPass ()); + + pass_manager = new llvm::FunctionPassManager (module); + pass_manager->add (new llvm::TargetData(*engine->getTargetData ())); + pass_manager->add (llvm::createBasicAliasAnalysisPass ()); + pass_manager->add (llvm::createPromoteMemoryToRegisterPass ()); + pass_manager->add (llvm::createInstructionCombiningPass ()); + pass_manager->add (llvm::createReassociatePass ()); + pass_manager->add (llvm::createGVNPass ()); + pass_manager->add (llvm::createCFGSimplificationPass ()); + pass_manager->doInitialization (); + + jit_typeinfo::initialize (module, engine); + + return true; +} + +size_t +tree_jit::trip_count (const octave_value& bounds) const +{ + if (bounds.is_range ()) + { + Range rng = bounds.range_value (); + return rng.nelem (); + } + + // unsupported type + return 0; +} + + +void +tree_jit::optimize (llvm::Function *fn) +{ + module_pass_manager->run (*module); + pass_manager->run (*fn); + +#ifdef OCTAVE_JIT_DEBUG + std::string error; + llvm::raw_fd_ostream fout ("test.bc", error, + llvm::raw_fd_ostream::F_Binary); + llvm::WriteBitcodeToFile (module, fout); +#endif +} + +// -------------------- jit_info -------------------- +jit_info::jit_info (tree_jit& tjit, tree& tee) + : engine (tjit.get_engine ()), function (0), llvm_function (0) +{ + try + { + jit_convert conv (tjit.get_module (), tee); + initialize (tjit, conv); + } + catch (const jit_fail_exception& e) + { +#ifdef OCTAVE_JIT_DEBUG + if (e.known ()) + std::cout << "jit fail: " << e.what () << std::endl; +#endif + } +} + +jit_info::jit_info (tree_jit& tjit, tree& tee, const octave_value& for_bounds) + : engine (tjit.get_engine ()), function (0), llvm_function (0) +{ + try + { + jit_convert conv (tjit.get_module (), tee, + jit_typeinfo::type_of (for_bounds)); + initialize (tjit, conv); + } + catch (const jit_fail_exception& e) + { +#ifdef OCTAVE_JIT_DEBUG + if (e.known ()) + std::cout << "jit fail: " << e.what () << std::endl; +#endif + } +} + +jit_info::~jit_info (void) +{ + if (llvm_function) + llvm_function->eraseFromParent (); +} + +bool +jit_info::execute (const vmap& extra_vars) const +{ + if (! function) + return false; + + std::vector real_arguments (arguments.size ()); + for (size_t i = 0; i < arguments.size (); ++i) + { + if (arguments[i].second) + { + octave_value current = find (extra_vars, arguments[i].first); + octave_base_value *obv = current.internal_rep (); + obv->grab (); + real_arguments[i] = obv; + } + } + + function (&real_arguments[0]); + + for (size_t i = 0; i < arguments.size (); ++i) + { + const std::string& name = arguments[i].first; + + // do not store for loop bounds temporary + if (name.size () && name[0] != '#') + symbol_table::varref (arguments[i].first) = real_arguments[i]; + } + + return true; +} + +bool +jit_info::match (const vmap& extra_vars) const +{ + if (! function) + return true; + + for (size_t i = 0; i < bounds.size (); ++i) + { + const std::string& arg_name = bounds[i].second; + octave_value value = find (extra_vars, arg_name); + jit_type *type = jit_typeinfo::type_of (value); + + // FIXME: Check for a parent relationship + if (type != bounds[i].first) + return false; + } + + return true; +} + +void +jit_info::initialize (tree_jit& tjit, jit_convert& conv) +{ + llvm_function = conv.get_function (); + arguments = conv.get_arguments (); + bounds = conv.get_bounds (); + + if (llvm_function) + { + tjit.optimize (llvm_function); + +#ifdef OCTAVE_JIT_DEBUG + std::cout << "-------------------- optimized llvm ir " + << "--------------------\n"; + llvm::raw_os_ostream llvm_cout (std::cout); + llvm_function->print (llvm_cout); + llvm_cout.flush (); + std::cout << std::endl; +#endif + + void *void_fn = engine->getPointerToFunction (llvm_function); + function = reinterpret_cast (void_fn); + } +} + +octave_value +jit_info::find (const vmap& extra_vars, const std::string& vname) const +{ + vmap::const_iterator iter = extra_vars.find (vname); + return iter == extra_vars.end () ? symbol_table::varval (vname) + : *iter->second; +} + +#endif + + +/* +Test some simple cases that compile. + +%!test +%! inc = 1e-5; +%! result = 0; +%! for ii = 0:inc:1 +%! result = result + inc * (1/3 * ii * ii); +%! endfor +%! assert (abs (result - 1/9) < 1e-5); + +%!test +%! inc = 1e-5; +%! result = 0; +%! for ii = 0:inc:1 +%! # the ^ operator's result is complex +%! result = result + inc * (1/3 * ii ^ 2); +%! endfor +%! assert (abs (result - 1/9) < 1e-5); + +%!test +%! nr = 1001; +%! mat = zeros (1, nr); +%! for i = 1:nr +%! mat(i) = i; +%! endfor +%! assert (mat == 1:nr); + +%!test +%! nr = 1001; +%! mat = 1:nr; +%! mat(end) = 0; # force mat to a matrix +%! total = 0; +%! for i = 1:nr +%! total = mat(i) + total; +%! endfor +%! assert (sum (mat) == total); + +%!test +%! nr = 1001; +%! mat = [3 1 5]; +%! try +%! for i = 1:nr +%! if i > 500 +%! result = mat(100); +%! else +%! result = i; +%! endif +%! endfor +%! catch +%! end +%! assert (result == 500); + +%!function result = gen_test (n) +%! result = double (rand (1, n) > .01); +%!endfunction + +%!function z = vectorized (A, K) +%! temp = ones (1, K); +%! z = conv (A, temp); +%! z = z > K-1; +%! z = conv (z, temp); +%! z = z(K:end-K+1); +%! z = z >= 1; +%!endfunction + +%!function z = loopy (A, K) +%! z = A; +%! n = numel (A); +%! counter = 0; +%! for ii=1:n +%! if z(ii) +%! counter = counter + 1; +%! else +%! if counter > 0 && counter < K +%! z(ii-counter:ii-1) = 0; +%! endif +%! counter = 0; +%! endif +%! endfor +%! +%! if counter > 0 && counter < K +%! z(end-counter+1:end) = 0; +%! endif +%!endfunction + +%!test +%! test_set = gen_test (10000); +%! assert (all (vectorized (test_set, 3) == loopy (test_set, 3))); + +%!test +%! niter = 1001; +%! i = 0; +%! while (i < niter) +%! i = i + 1; +%! endwhile +%! assert (i == niter); + +%!test +%! niter = 1001; +%! result = 0; +%! m = [5 10]; +%! for i=1:niter +%! result = result + m(end); +%! endfor +%! assert (result == m(end) * niter); + +%!test +%! ndim = 100; +%! result = 0; +%! m = zeros (ndim); +%! m(:) = 1:ndim^2; +%! i = 1; +%! while (i <= ndim) +%! for j = 1:ndim +%! result = result + m(i, j); +%! endfor +%! i = i + 1; +%! endwhile +%! assert (result == sum (sum (m))); + +%!test +%! ndim = 100; +%! m = zeros (ndim); +%! i = 1; +%! while (i <= ndim) +%! for j = 1:ndim +%! m(i, j) = (j - 1) * ndim + i; +%! endfor +%! i = i + 1; +%! endwhile +%! m2 = zeros (ndim); +%! m2(:) = 1:(ndim^2); +%! assert (all (m == m2)); + +%!test +%! ndim = 2; +%! m = zeros (ndim, ndim, ndim, ndim); +%! result = 0; +%! i0 = 1; +%! while (i0 <= ndim) +%! for i1 = 1:ndim +%! for i2 = 1:ndim +%! for i3 = 1:ndim +%! m(i0, i1, i2, i3) = 1; +%! m(i0, i1, i2, i3, 1, 1, 1, 1, 1, 1) = 1; +%! result = result + m(i0, i1, i2, i3); +%! endfor +%! endfor +%! endfor +%! i0 = i0 + 1; +%! endwhile +%! expected = ones (ndim, ndim, ndim, ndim); +%! assert (all (m == expected)); +%! assert (result == sum (expected (:))); + +%!function test_divide () +%! state = warning ("query", "Octave:divide-by-zero").state; +%! unwind_protect +%! warning ("error", "Octave:divide-by-zero"); +%! for i=1:1e5 +%! a = 1; +%! a / 0; +%! endfor +%! unwind_protect_cleanup +%! warning (state, "Octave:divide-by-zero"); +%! end_unwind_protect +%!endfunction + +%!error test_divide () + +%!test +%! while 1 +%! a = 0; +%! result = a / 1; +%! break; +%! endwhile +%! assert (result, 0); + +*/ diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/pt-jit.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/pt-jit.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,491 @@ +/* + +Copyright (C) 2012 Max Brister + +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 (octave_tree_jit_h) +#define octave_tree_jit_h 1 + +#ifdef HAVE_LLVM + +#include "jit-ir.h" + +#include "pt-walk.h" + +// -------------------- Current status -------------------- +// Simple binary operations (+-*/) on octave_scalar's (doubles) are optimized. +// a = 5; +// b = a * 5 + a; +// +// Indexing matrices with scalars works. +// +// if, elseif, else, break, continue, and for compile. Compilation is triggered +// at the start of a simple for loop. +// +// The octave low level IR is a linear IR, it works by converting everything to +// calls to jit_operations. This turns expressions like c = a + b into +// c = call binary+ (a, b) +// The jit_operations contain information about overloads for different types. +// For, example, if we know a and b are scalars, then c must also be a scalar. +// +// Support for function calls is in progress. Currently, calls to sin with a +// scalar argument will compile. +// +// TODO: +// 1. Function calls (In progress) +// 2. Cleanup/documentation +// 3. ... +// --------------------------------------------------------- + +// convert between IRs +// FIXME: Class relationships are messy from here on down. They need to be +// cleaned up. +class +jit_convert : public tree_walker +{ +public: + typedef std::pair type_bound; + typedef std::vector type_bound_vector; + + jit_convert (llvm::Module *module, tree &tee, jit_type *for_bounds = 0); + + ~jit_convert (void); + + llvm::Function *get_function (void) const { return function; } + + const std::vector >& get_arguments(void) const + { return arguments; } + + const type_bound_vector& get_bounds (void) const { return bounds; } + + void visit_anon_fcn_handle (tree_anon_fcn_handle&); + + void visit_argument_list (tree_argument_list&); + + void visit_binary_expression (tree_binary_expression&); + + void visit_break_command (tree_break_command&); + + void visit_colon_expression (tree_colon_expression&); + + void visit_continue_command (tree_continue_command&); + + void visit_global_command (tree_global_command&); + + void visit_persistent_command (tree_persistent_command&); + + void visit_decl_elt (tree_decl_elt&); + + void visit_decl_init_list (tree_decl_init_list&); + + void visit_simple_for_command (tree_simple_for_command&); + + void visit_complex_for_command (tree_complex_for_command&); + + void visit_octave_user_script (octave_user_script&); + + void visit_octave_user_function (octave_user_function&); + + void visit_octave_user_function_header (octave_user_function&); + + void visit_octave_user_function_trailer (octave_user_function&); + + void visit_function_def (tree_function_def&); + + void visit_identifier (tree_identifier&); + + void visit_if_clause (tree_if_clause&); + + void visit_if_command (tree_if_command&); + + void visit_if_command_list (tree_if_command_list&); + + void visit_index_expression (tree_index_expression&); + + void visit_matrix (tree_matrix&); + + void visit_cell (tree_cell&); + + void visit_multi_assignment (tree_multi_assignment&); + + void visit_no_op_command (tree_no_op_command&); + + void visit_constant (tree_constant&); + + void visit_fcn_handle (tree_fcn_handle&); + + void visit_parameter_list (tree_parameter_list&); + + void visit_postfix_expression (tree_postfix_expression&); + + void visit_prefix_expression (tree_prefix_expression&); + + void visit_return_command (tree_return_command&); + + void visit_return_list (tree_return_list&); + + void visit_simple_assignment (tree_simple_assignment&); + + void visit_statement (tree_statement&); + + void visit_statement_list (tree_statement_list&); + + void visit_switch_case (tree_switch_case&); + + void visit_switch_case_list (tree_switch_case_list&); + + void visit_switch_command (tree_switch_command&); + + void visit_try_catch_command (tree_try_catch_command&); + + void visit_unwind_protect_command (tree_unwind_protect_command&); + + void visit_while_command (tree_while_command&); + + void visit_do_until_command (tree_do_until_command&); + + // this would be easier with variadic templates + template + T *create (void) + { + T *ret = new T(); + track_value (ret); + return ret; + } + +#define DECL_ARG(n) const ARG ## n& arg ## n +#define JIT_CREATE(N) \ + template \ + T *create (OCT_MAKE_LIST (DECL_ARG, N)) \ + { \ + T *ret = new T (OCT_MAKE_ARG_LIST (arg, N)); \ + track_value (ret); \ + return ret; \ + } + + JIT_CREATE (1) + JIT_CREATE (2) + JIT_CREATE (3) + JIT_CREATE (4) + +#undef JIT_CREATE + +#define JIT_CREATE_CHECKED(N) \ + template \ + jit_call *create_checked (OCT_MAKE_LIST (DECL_ARG, N)) \ + { \ + jit_call *ret = create (OCT_MAKE_ARG_LIST (arg, N)); \ + return create_checked_impl (ret); \ + } + + JIT_CREATE_CHECKED (1) + JIT_CREATE_CHECKED (2) + JIT_CREATE_CHECKED (3) + JIT_CREATE_CHECKED (4) + +#undef JIT_CREATE_CHECKED +#undef DECL_ARG + + typedef std::list block_list; + typedef block_list::iterator block_iterator; + + void append (jit_block *ablock); + + void insert_before (block_iterator iter, jit_block *ablock); + + void insert_before (jit_block *loc, jit_block *ablock) + { + insert_before (loc->location (), ablock); + } + + void insert_after (block_iterator iter, jit_block *ablock); + + void insert_after (jit_block *loc, jit_block *ablock) + { + insert_after (loc->location (), ablock); + } +private: + std::vector > arguments; + type_bound_vector bounds; + + // used instead of return values from visit_* functions + jit_value *result; + + jit_block *entry_block; + + jit_block *final_block; + + jit_block *block; + + llvm::Function *function; + + std::list blocks; + + std::list worklist; + + std::list constants; + + std::list all_values; + + std::vector end_context; + + size_t iterator_count; + size_t for_bounds_count; + size_t short_count; + + typedef std::map vmap_t; + vmap_t vmap; + + jit_call *create_checked_impl (jit_call *ret) + { + block->append (ret); + create_check (ret); + return ret; + } + + jit_error_check *create_check (jit_call *call) + { + jit_block *normal = create (block->name ()); + jit_error_check *ret + = block->append (create (call, normal, final_block)); + append (normal); + block = normal; + + return ret; + } + + // get an existing vairable. If the variable does not exist, it will not be + // created + jit_variable *find_variable (const std::string& vname) const; + + // get a variable, create it if it does not exist. The type will default to + // the variable's current type in the symbol table. + jit_variable *get_variable (const std::string& vname); + + // create a variable of the given name and given type. Will also insert an + // extract statement + jit_variable *create_variable (const std::string& vname, jit_type *type); + + // The name of the next for loop iterator. If inc is false, then the iterator + // counter will not be incremented. + std::string next_iterator (bool inc = true) + { return next_name ("#iter", iterator_count, inc); } + + std::string next_for_bounds (bool inc = true) + { return next_name ("#for_bounds", for_bounds_count, inc); } + + std::string next_shortcircut_result (bool inc = true) + { return next_name ("#shortcircut_result", short_count, inc); } + + std::string next_name (const char *prefix, size_t& count, bool inc); + + jit_instruction *resolve (const jit_operation& fres, + tree_index_expression& exp, + jit_value *extra_arg = 0); + + jit_value *do_assign (tree_expression *exp, jit_value *rhs, + bool artificial = false); + + jit_value *do_assign (const std::string& lhs, jit_value *rhs, bool print, + bool artificial = false); + + jit_value *visit (tree *tee) { return visit (*tee); } + + jit_value *visit (tree& tee); + + void push_worklist (jit_instruction *instr) + { + if (! instr->in_worklist ()) + { + instr->stash_in_worklist (true); + worklist.push_back (instr); + } + } + + void append_users (jit_value *v) + { + for (jit_use *use = v->first_use (); use; use = use->next ()) + push_worklist (use->user ()); + } + + void append_users_term (jit_terminator *term); + + void track_value (jit_value *value) + { + if (value->type ()) + constants.push_back (value); + all_values.push_back (value); + } + + void merge_blocks (void); + + void construct_ssa (void); + + void do_construct_ssa (jit_block& block, size_t avisit_count); + + void remove_dead (); + + void place_releases (void); + + void release_temp (jit_block& ablock, std::set& temp); + + void release_dead_phi (jit_block& ablock); + + void simplify_phi (void); + + void simplify_phi (jit_phi& phi); + + void print_blocks (const std::string& header) + { + std::cout << "-------------------- " << header << " --------------------\n"; + for (std::list::iterator iter = blocks.begin (); + iter != blocks.end (); ++iter) + { + assert (*iter); + (*iter)->print (std::cout, 0); + } + std::cout << std::endl; + } + + void print_dom (void) + { + std::cout << "-------------------- dom info --------------------\n"; + for (std::list::iterator iter = blocks.begin (); + iter != blocks.end (); ++iter) + { + assert (*iter); + (*iter)->print_dom (std::cout); + } + std::cout << std::endl; + } + + bool breaking; // true if we are breaking OR continuing + block_list breaks; + block_list continues; + + void finish_breaks (jit_block *dest, const block_list& lst); + + // this case is much simpler, just convert from the jit ir to llvm + class + convert_llvm : public jit_ir_walker + { + public: + convert_llvm (jit_convert& jc) : jthis (jc) {} + + llvm::Function *convert (llvm::Module *module, + const std::vector >& args, + const std::list& blocks, + const std::list& constants); + +#define JIT_METH(clname) \ + virtual void visit (jit_ ## clname&); + + JIT_VISIT_IR_CLASSES; + +#undef JIT_METH + private: + // name -> llvm argument + std::map arguments; + + void finish_phi (jit_phi *phi); + + void visit (jit_value *jvalue) + { + return visit (*jvalue); + } + + void visit (jit_value &jvalue) + { + jvalue.accept (*this); + } + private: + jit_convert &jthis; + llvm::Function *function; + llvm::BasicBlock *prelude; + }; +}; + +class jit_info; + +class +tree_jit +{ +public: + tree_jit (void); + + ~tree_jit (void); + + bool execute (tree_simple_for_command& cmd, const octave_value& bounds); + + bool execute (tree_while_command& cmd); + + llvm::ExecutionEngine *get_engine (void) const { return engine; } + + llvm::Module *get_module (void) const { return module; } + + void optimize (llvm::Function *fn); + private: + bool initialize (void); + + size_t trip_count (const octave_value& bounds) const; + + // FIXME: Temorary hack to test + typedef std::map compiled_map; + llvm::Module *module; + llvm::PassManager *module_pass_manager; + llvm::FunctionPassManager *pass_manager; + llvm::ExecutionEngine *engine; +}; + +class +jit_info +{ +public: + // we use a pointer here so we don't have to include ov.h + typedef std::map vmap; + + jit_info (tree_jit& tjit, tree& tee); + + jit_info (tree_jit& tjit, tree& tee, const octave_value& for_bounds); + + ~jit_info (void); + + bool execute (const vmap& extra_vars = vmap ()) const; + + bool match (const vmap& extra_vars = vmap ()) const; +private: + typedef jit_convert::type_bound type_bound; + typedef jit_convert::type_bound_vector type_bound_vector; + typedef void (*jited_function)(octave_base_value**); + + void initialize (tree_jit& tjit, jit_convert& conv); + + octave_value find (const vmap& extra_vars, const std::string& vname) const; + + llvm::ExecutionEngine *engine; + jited_function function; + llvm::Function *llvm_function; + + std::vector > arguments; + type_bound_vector bounds; +}; + +#endif +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/siglist.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/siglist.c Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,232 @@ +/* + +Copyright (C) 2000-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "siglist.h" + +/* The following is all borrowed from Emacs. */ + +#if ! (defined HAVE_STRSIGNAL || HAVE_DECL_SYS_SIGLIST) + +static char *my_sys_siglist[NSIG]; + +#ifdef sys_siglist +#undef sys_siglist +#endif +#define sys_siglist my_sys_siglist + +#endif + +void +init_signals (void) +{ +#if ! (defined HAVE_STRSIGNAL || HAVE_DECL_SYS_SIGLIST) + + static int initialized = 0; + + if (! initialized) + { + initialized = 1; + +# ifdef SIGABRT + sys_siglist[SIGABRT] = "Aborted"; +# endif +# ifdef SIGAIO + sys_siglist[SIGAIO] = "LAN I/O interrupt"; +# endif +# ifdef SIGALRM + sys_siglist[SIGALRM] = "Alarm clock"; +# endif +# ifdef SIGBUS + sys_siglist[SIGBUS] = "Bus error"; +# endif +# ifdef SIGCLD + sys_siglist[SIGCLD] = "Child status changed"; +# endif +# ifdef SIGCHLD + sys_siglist[SIGCHLD] = "Child status changed"; +# endif +# ifdef SIGCONT + sys_siglist[SIGCONT] = "Continued"; +# endif +# ifdef SIGDANGER + sys_siglist[SIGDANGER] = "Swap space dangerously low"; +# endif +# ifdef SIGDGNOTIFY + sys_siglist[SIGDGNOTIFY] = "Notification message in queue"; +# endif +# ifdef SIGEMT + sys_siglist[SIGEMT] = "Emulation trap"; +# endif +# ifdef SIGFPE + sys_siglist[SIGFPE] = "Arithmetic exception"; +# endif +# ifdef SIGFREEZE + sys_siglist[SIGFREEZE] = "SIGFREEZE"; +# endif +# ifdef SIGGRANT + sys_siglist[SIGGRANT] = "Monitor mode granted"; +# endif +# ifdef SIGHUP + sys_siglist[SIGHUP] = "Hangup"; +# endif +# ifdef SIGILL + sys_siglist[SIGILL] = "Illegal instruction"; +# endif +# ifdef SIGINT + sys_siglist[SIGINT] = "Interrupt"; +# endif +# ifdef SIGIO + sys_siglist[SIGIO] = "I/O possible"; +# endif +# ifdef SIGIOINT + sys_siglist[SIGIOINT] = "I/O intervention required"; +# endif +# ifdef SIGIOT + sys_siglist[SIGIOT] = "IOT trap"; +# endif +# ifdef SIGKILL + sys_siglist[SIGKILL] = "Killed"; +# endif +# ifdef SIGLOST + sys_siglist[SIGLOST] = "Resource lost"; +# endif +# ifdef SIGLWP + sys_siglist[SIGLWP] = "SIGLWP"; +# endif +# ifdef SIGMSG + sys_siglist[SIGMSG] = "Monitor mode data available"; +# endif +# ifdef SIGPHONE + sys_siglist[SIGWIND] = "SIGPHONE"; +# endif +# ifdef SIGPIPE + sys_siglist[SIGPIPE] = "Broken pipe"; +# endif +# ifdef SIGPOLL + sys_siglist[SIGPOLL] = "Pollable event occurred"; +# endif +# ifdef SIGPROF + sys_siglist[SIGPROF] = "Profiling timer expired"; +# endif +# ifdef SIGPTY + sys_siglist[SIGPTY] = "PTY I/O interrupt"; +# endif +# ifdef SIGPWR + sys_siglist[SIGPWR] = "Power-fail restart"; +# endif +# ifdef SIGQUIT + sys_siglist[SIGQUIT] = "Quit"; +# endif +# ifdef SIGRETRACT + sys_siglist[SIGRETRACT] = "Need to relinguish monitor mode"; +# endif +# ifdef SIGSAK + sys_siglist[SIGSAK] = "Secure attention"; +# endif +# ifdef SIGSEGV + sys_siglist[SIGSEGV] = "Segmentation violation"; +# endif +# ifdef SIGSOUND + sys_siglist[SIGSOUND] = "Sound completed"; +# endif +# ifdef SIGSTOP + sys_siglist[SIGSTOP] = "Stopped (signal)"; +# endif +# ifdef SIGSTP + sys_siglist[SIGSTP] = "Stopped (user)"; +# endif +# ifdef SIGSYS + sys_siglist[SIGSYS] = "Bad argument to system call"; +# endif +# ifdef SIGTERM + sys_siglist[SIGTERM] = "Terminated"; +# endif +# ifdef SIGTHAW + sys_siglist[SIGTHAW] = "SIGTHAW"; +# endif +# ifdef SIGTRAP + sys_siglist[SIGTRAP] = "Trace/breakpoint trap"; +# endif +# ifdef SIGTSTP + sys_siglist[SIGTSTP] = "Stopped (user)"; +# endif +# ifdef SIGTTIN + sys_siglist[SIGTTIN] = "Stopped (tty input)"; +# endif +# ifdef SIGTTOU + sys_siglist[SIGTTOU] = "Stopped (tty output)"; +# endif +# ifdef SIGURG + sys_siglist[SIGURG] = "Urgent I/O condition"; +# endif +# ifdef SIGUSR1 + sys_siglist[SIGUSR1] = "User defined signal 1"; +# endif +# ifdef SIGUSR2 + sys_siglist[SIGUSR2] = "User defined signal 2"; +# endif +# ifdef SIGVTALRM + sys_siglist[SIGVTALRM] = "Virtual timer expired"; +# endif +# ifdef SIGWAITING + sys_siglist[SIGWAITING] = "Process's LWPs are blocked"; +# endif +# ifdef SIGWINCH + sys_siglist[SIGWINCH] = "Window size changed"; +# endif +# ifdef SIGWIND + sys_siglist[SIGWIND] = "SIGWIND"; +# endif +# ifdef SIGXCPU + sys_siglist[SIGXCPU] = "CPU time limit exceeded"; +# endif +# ifdef SIGXFSZ + sys_siglist[SIGXFSZ] = "File size limit exceeded"; +# endif + } + +#endif +} + +#if ! defined (HAVE_STRSIGNAL) + +char * +strsignal (int code) +{ + char *signame = ""; + + if (0 <= code && code < NSIG) + { + /* Cast to suppress warning if the table has const char *. */ + signame = (char *) sys_siglist[code]; + } + + return signame; +} + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/siglist.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/siglist.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,47 @@ +/* + +Copyright (C) 2000-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_siglist_h) +#define octave_siglist_h 1 + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* This is borrowed from Emacs. */ + +#if ! defined (HAVE_DECL_SYS_SIGLIST) +extern char *sys_siglist[]; +#endif + +extern void init_signals (void); + +#if ! defined (HAVE_STRSIGNAL) +extern char *strsignal (int); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/sparse-xdiv.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/sparse-xdiv.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,633 @@ +/* + +Copyright (C) 2004-2012 David Bateman +Copyright (C) 1998-2004 Andy Adler + +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 +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "Array-util.h" +#include "oct-cmplx.h" +#include "quit.h" +#include "error.h" +#include "lo-ieee.h" + +#include "dSparse.h" +#include "dDiagMatrix.h" +#include "CSparse.h" +#include "CDiagMatrix.h" +#include "oct-spparms.h" +#include "sparse-xdiv.h" + +static void +solve_singularity_warning (double rcond) +{ + warning ("matrix singular to machine precision, rcond = %g", rcond); + warning ("attempting to find minimum norm solution"); +} + +template +bool +mx_leftdiv_conform (const T1& a, const T2& b) +{ + octave_idx_type a_nr = a.rows (); + octave_idx_type b_nr = b.rows (); + + if (a_nr != b_nr) + { + octave_idx_type a_nc = a.cols (); + octave_idx_type b_nc = b.cols (); + + gripe_nonconformant ("operator \\", a_nr, a_nc, b_nr, b_nc); + return false; + } + + return true; +} + +#define INSTANTIATE_MX_LEFTDIV_CONFORM(T1, T2) \ + template bool mx_leftdiv_conform (const T1&, const T2&) + +INSTANTIATE_MX_LEFTDIV_CONFORM (SparseMatrix, SparseMatrix); +INSTANTIATE_MX_LEFTDIV_CONFORM (SparseMatrix, SparseComplexMatrix); +INSTANTIATE_MX_LEFTDIV_CONFORM (SparseComplexMatrix, SparseMatrix); +INSTANTIATE_MX_LEFTDIV_CONFORM (SparseComplexMatrix, SparseComplexMatrix); +INSTANTIATE_MX_LEFTDIV_CONFORM (SparseMatrix, Matrix); +INSTANTIATE_MX_LEFTDIV_CONFORM (SparseMatrix, ComplexMatrix); +INSTANTIATE_MX_LEFTDIV_CONFORM (SparseComplexMatrix, Matrix); +INSTANTIATE_MX_LEFTDIV_CONFORM (SparseComplexMatrix, ComplexMatrix); +INSTANTIATE_MX_LEFTDIV_CONFORM (DiagMatrix, SparseMatrix); +INSTANTIATE_MX_LEFTDIV_CONFORM (DiagMatrix, SparseComplexMatrix); +INSTANTIATE_MX_LEFTDIV_CONFORM (ComplexDiagMatrix, SparseMatrix); +INSTANTIATE_MX_LEFTDIV_CONFORM (ComplexDiagMatrix, SparseComplexMatrix); + +template +bool +mx_div_conform (const T1& a, const T2& b) +{ + octave_idx_type a_nc = a.cols (); + octave_idx_type b_nc = b.cols (); + + if (a_nc != b_nc) + { + octave_idx_type a_nr = a.rows (); + octave_idx_type b_nr = b.rows (); + + gripe_nonconformant ("operator /", a_nr, a_nc, b_nr, b_nc); + return false; + } + + return true; +} + +#define INSTANTIATE_MX_DIV_CONFORM(T1, T2) \ + template bool mx_div_conform (const T1&, const T2&) + +INSTANTIATE_MX_DIV_CONFORM (SparseMatrix, SparseMatrix); +INSTANTIATE_MX_DIV_CONFORM (SparseMatrix, SparseComplexMatrix); +INSTANTIATE_MX_DIV_CONFORM (SparseComplexMatrix, SparseMatrix); +INSTANTIATE_MX_DIV_CONFORM (SparseComplexMatrix, SparseComplexMatrix); +INSTANTIATE_MX_DIV_CONFORM (Matrix, SparseMatrix); +INSTANTIATE_MX_DIV_CONFORM (Matrix, SparseComplexMatrix); +INSTANTIATE_MX_DIV_CONFORM (ComplexMatrix, SparseMatrix); +INSTANTIATE_MX_DIV_CONFORM (ComplexMatrix, SparseComplexMatrix); +INSTANTIATE_MX_DIV_CONFORM (SparseMatrix, DiagMatrix); +INSTANTIATE_MX_DIV_CONFORM (SparseMatrix, ComplexDiagMatrix); +INSTANTIATE_MX_DIV_CONFORM (SparseComplexMatrix, DiagMatrix); +INSTANTIATE_MX_DIV_CONFORM (SparseComplexMatrix, ComplexDiagMatrix); + +// Right division functions. X / Y = X * inv (Y) = (inv (Y') * X')' +// +// Y / X: m cm sm scm +// +-- +---+----+----+----+ +// sparse matrix | 1 | 3 | 5 | 7 | +// +---+----+----+----+ +// sparse complex_matrix | 2 | 4 | 6 | 8 | +// +---+----+----+----+ +// diagonal matrix | 9 | 11 | +// +----+----+ +// complex diag. matrix | 10 | 12 | +// +----+----+ + +// -*- 1 -*- +Matrix +xdiv (const Matrix& a, const SparseMatrix& b, MatrixType &typ) +{ + if (! mx_div_conform (a, b)) + return Matrix (); + + Matrix atmp = a.transpose (); + SparseMatrix btmp = b.transpose (); + MatrixType btyp = typ.transpose (); + + octave_idx_type info; + double rcond = 0.0; + Matrix result = btmp.solve (btyp, atmp, info, rcond, + solve_singularity_warning); + + typ = btyp.transpose (); + return result.transpose (); +} + +// -*- 2 -*- +ComplexMatrix +xdiv (const Matrix& a, const SparseComplexMatrix& b, MatrixType &typ) +{ + if (! mx_div_conform (a, b)) + return ComplexMatrix (); + + Matrix atmp = a.transpose (); + SparseComplexMatrix btmp = b.hermitian (); + MatrixType btyp = typ.transpose (); + + octave_idx_type info; + double rcond = 0.0; + ComplexMatrix result + = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning); + + typ = btyp.transpose (); + return result.hermitian (); +} + +// -*- 3 -*- +ComplexMatrix +xdiv (const ComplexMatrix& a, const SparseMatrix& b, MatrixType &typ) +{ + if (! mx_div_conform (a, b)) + return ComplexMatrix (); + + ComplexMatrix atmp = a.hermitian (); + SparseMatrix btmp = b.transpose (); + MatrixType btyp = typ.transpose (); + + octave_idx_type info; + double rcond = 0.0; + ComplexMatrix result + = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning); + + typ = btyp.transpose (); + return result.hermitian (); +} + +// -*- 4 -*- +ComplexMatrix +xdiv (const ComplexMatrix& a, const SparseComplexMatrix& b, MatrixType &typ) +{ + if (! mx_div_conform (a, b)) + return ComplexMatrix (); + + ComplexMatrix atmp = a.hermitian (); + SparseComplexMatrix btmp = b.hermitian (); + MatrixType btyp = typ.transpose (); + + octave_idx_type info; + double rcond = 0.0; + ComplexMatrix result + = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning); + + typ = btyp.transpose (); + return result.hermitian (); +} + +// -*- 5 -*- +SparseMatrix +xdiv (const SparseMatrix& a, const SparseMatrix& b, MatrixType &typ) +{ + if (! mx_div_conform (a, b)) + return SparseMatrix (); + + SparseMatrix atmp = a.transpose (); + SparseMatrix btmp = b.transpose (); + MatrixType btyp = typ.transpose (); + + octave_idx_type info; + double rcond = 0.0; + SparseMatrix result = btmp.solve (btyp, atmp, info, rcond, + solve_singularity_warning); + + typ = btyp.transpose (); + return result.transpose (); +} + +// -*- 6 -*- +SparseComplexMatrix +xdiv (const SparseMatrix& a, const SparseComplexMatrix& b, MatrixType &typ) +{ + if (! mx_div_conform (a, b)) + return SparseComplexMatrix (); + + SparseMatrix atmp = a.transpose (); + SparseComplexMatrix btmp = b.hermitian (); + MatrixType btyp = typ.transpose (); + + octave_idx_type info; + double rcond = 0.0; + SparseComplexMatrix result + = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning); + + typ = btyp.transpose (); + return result.hermitian (); +} + +// -*- 7 -*- +SparseComplexMatrix +xdiv (const SparseComplexMatrix& a, const SparseMatrix& b, MatrixType &typ) +{ + if (! mx_div_conform (a, b)) + return SparseComplexMatrix (); + + SparseComplexMatrix atmp = a.hermitian (); + SparseMatrix btmp = b.transpose (); + MatrixType btyp = typ.transpose (); + + octave_idx_type info; + double rcond = 0.0; + SparseComplexMatrix result + = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning); + + typ = btyp.transpose (); + return result.hermitian (); +} + +// -*- 8 -*- +SparseComplexMatrix +xdiv (const SparseComplexMatrix& a, const SparseComplexMatrix& b, MatrixType &typ) +{ + if (! mx_div_conform (a, b)) + return SparseComplexMatrix (); + + SparseComplexMatrix atmp = a.hermitian (); + SparseComplexMatrix btmp = b.hermitian (); + MatrixType btyp = typ.transpose (); + + octave_idx_type info; + double rcond = 0.0; + SparseComplexMatrix result + = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning); + + typ = btyp.transpose (); + return result.hermitian (); +} + +template +RT do_rightdiv_sm_dm (const SM& a, const DM& d) +{ + const octave_idx_type d_nr = d.rows (); + + const octave_idx_type a_nr = a.rows (); + const octave_idx_type a_nc = a.cols (); + + using std::min; + const octave_idx_type nc = min (d_nr, a_nc); + + if ( ! mx_div_conform (a, d)) + return RT (); + + const octave_idx_type nz = a.nnz (); + RT r (a_nr, nc, nz); + + typedef typename DM::element_type DM_elt_type; + const DM_elt_type zero = DM_elt_type (); + + octave_idx_type k_result = 0; + for (octave_idx_type j = 0; j < nc; ++j) + { + octave_quit (); + const DM_elt_type s = d.dgelem (j); + const octave_idx_type colend = a.cidx (j+1); + r.xcidx (j) = k_result; + if (s != zero) + for (octave_idx_type k = a.cidx (j); k < colend; ++k) + { + r.xdata (k_result) = a.data (k) / s; + r.xridx (k_result) = a.ridx (k); + ++k_result; + } + } + r.xcidx (nc) = k_result; + + r.maybe_compress (true); + return r; +} + +// -*- 9 -*- +SparseMatrix +xdiv (const SparseMatrix& a, const DiagMatrix& b, MatrixType &) +{ + return do_rightdiv_sm_dm (a, b); +} + +// -*- 10 -*- +SparseComplexMatrix +xdiv (const SparseMatrix& a, const ComplexDiagMatrix& b, MatrixType &) +{ + return do_rightdiv_sm_dm (a, b); +} + +// -*- 11 -*- +SparseComplexMatrix +xdiv (const SparseComplexMatrix& a, const DiagMatrix& b, MatrixType &) +{ + return do_rightdiv_sm_dm (a, b); +} + +// -*- 12 -*- +SparseComplexMatrix +xdiv (const SparseComplexMatrix& a, const ComplexDiagMatrix& b, MatrixType &) +{ + return do_rightdiv_sm_dm (a, b); +} + +// Funny element by element division operations. +// +// op2 \ op1: s cs +// +-- +---+----+ +// matrix | 1 | 3 | +// +---+----+ +// complex_matrix | 2 | 4 | +// +---+----+ + +Matrix +x_el_div (double a, const SparseMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + Matrix result; + if (a == 0.) + result = Matrix (nr, nc, octave_NaN); + else if (a > 0.) + result = Matrix (nr, nc, octave_Inf); + else + result = Matrix (nr, nc, -octave_Inf); + + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = b.cidx (j); i < b.cidx (j+1); i++) + { + octave_quit (); + result.elem (b.ridx (i), j) = a / b.data (i); + } + + return result; +} + +ComplexMatrix +x_el_div (double a, const SparseComplexMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + ComplexMatrix result (nr, nc, Complex (octave_NaN, octave_NaN)); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = b.cidx (j); i < b.cidx (j+1); i++) + { + octave_quit (); + result.elem (b.ridx (i), j) = a / b.data (i); + } + + return result; +} + +ComplexMatrix +x_el_div (const Complex a, const SparseMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + ComplexMatrix result (nr, nc, (a / 0.0)); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = b.cidx (j); i < b.cidx (j+1); i++) + { + octave_quit (); + result.elem (b.ridx (i), j) = a / b.data (i); + } + + return result; +} + +ComplexMatrix +x_el_div (const Complex a, const SparseComplexMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + ComplexMatrix result (nr, nc, (a / 0.0)); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = b.cidx (j); i < b.cidx (j+1); i++) + { + octave_quit (); + result.elem (b.ridx (i), j) = a / b.data (i); + } + + return result; +} + +// Left division functions. X \ Y = inv (X) * Y +// +// Y \ X : sm scm dm dcm +// +-- +---+----+ +// matrix | 1 | 5 | +// +---+----+ +// complex_matrix | 2 | 6 | +// +---+----+----+----+ +// sparse matrix | 3 | 7 | 9 | 11 | +// +---+----+----+----+ +// sparse complex_matrix | 4 | 8 | 10 | 12 | +// +---+----+----+----+ + +// -*- 1 -*- +Matrix +xleftdiv (const SparseMatrix& a, const Matrix& b, MatrixType &typ) +{ + if (! mx_leftdiv_conform (a, b)) + return Matrix (); + + octave_idx_type info; + double rcond = 0.0; + return a.solve (typ, b, info, rcond, solve_singularity_warning); +} + +// -*- 2 -*- +ComplexMatrix +xleftdiv (const SparseMatrix& a, const ComplexMatrix& b, MatrixType &typ) +{ + if (! mx_leftdiv_conform (a, b)) + return ComplexMatrix (); + + octave_idx_type info; + double rcond = 0.0; + return a.solve (typ, b, info, rcond, solve_singularity_warning); +} + +// -*- 3 -*- +SparseMatrix +xleftdiv (const SparseMatrix& a, const SparseMatrix& b, MatrixType &typ) +{ + if (! mx_leftdiv_conform (a, b)) + return SparseMatrix (); + + octave_idx_type info; + double rcond = 0.0; + return a.solve (typ, b, info, rcond, solve_singularity_warning); +} + +// -*- 4 -*- +SparseComplexMatrix +xleftdiv (const SparseMatrix& a, const SparseComplexMatrix& b, MatrixType &typ) +{ + if (! mx_leftdiv_conform (a, b)) + return SparseComplexMatrix (); + + octave_idx_type info; + double rcond = 0.0; + return a.solve (typ, b, info, rcond, solve_singularity_warning); +} + +// -*- 5 -*- +ComplexMatrix +xleftdiv (const SparseComplexMatrix& a, const Matrix& b, MatrixType &typ) +{ + if (! mx_leftdiv_conform (a, b)) + return ComplexMatrix (); + + octave_idx_type info; + double rcond = 0.0; + return a.solve (typ, b, info, rcond, solve_singularity_warning); +} + +// -*- 6 -*- +ComplexMatrix +xleftdiv (const SparseComplexMatrix& a, const ComplexMatrix& b, MatrixType &typ) +{ + if (! mx_leftdiv_conform (a, b)) + return ComplexMatrix (); + + octave_idx_type info; + double rcond = 0.0; + return a.solve (typ, b, info, rcond, solve_singularity_warning); +} + +// -*- 7 -*- +SparseComplexMatrix +xleftdiv (const SparseComplexMatrix& a, const SparseMatrix& b, MatrixType &typ) +{ + if (! mx_leftdiv_conform (a, b)) + return SparseComplexMatrix (); + + octave_idx_type info; + double rcond = 0.0; + return a.solve (typ, b, info, rcond, solve_singularity_warning); +} + +// -*- 8 -*- +SparseComplexMatrix +xleftdiv (const SparseComplexMatrix& a, const SparseComplexMatrix& b, + MatrixType &typ) +{ + if (! mx_leftdiv_conform (a, b)) + return SparseComplexMatrix (); + + octave_idx_type info; + double rcond = 0.0; + return a.solve (typ, b, info, rcond, solve_singularity_warning); +} + +template +RT do_leftdiv_dm_sm (const DM& d, const SM& a) +{ + const octave_idx_type a_nr = a.rows (); + const octave_idx_type a_nc = a.cols (); + + const octave_idx_type d_nc = d.cols (); + + using std::min; + const octave_idx_type nr = min (d_nc, a_nr); + + if ( ! mx_leftdiv_conform (d, a)) + return RT (); + + const octave_idx_type nz = a.nnz (); + RT r (nr, a_nc, nz); + + typedef typename DM::element_type DM_elt_type; + const DM_elt_type zero = DM_elt_type (); + + octave_idx_type k_result = 0; + for (octave_idx_type j = 0; j < a_nc; ++j) + { + octave_quit (); + const octave_idx_type colend = a.cidx (j+1); + r.xcidx (j) = k_result; + for (octave_idx_type k = a.cidx (j); k < colend; ++k) + { + const octave_idx_type i = a.ridx (k); + if (i < nr) + { + const DM_elt_type s = d.dgelem (i); + if (s != zero) + { + r.xdata (k_result) = a.data (k) / s; + r.xridx (k_result) = i; + ++k_result; + } + } + } + } + r.xcidx (a_nc) = k_result; + + r.maybe_compress (true); + return r; +} + +// -*- 9 -*- +SparseMatrix +xleftdiv (const DiagMatrix& d, const SparseMatrix& a, MatrixType&) +{ + return do_leftdiv_dm_sm (d, a); +} + +// -*- 10 -*- +SparseComplexMatrix +xleftdiv (const DiagMatrix& d, const SparseComplexMatrix& a, MatrixType&) +{ + return do_leftdiv_dm_sm (d, a); +} + +// -*- 11 -*- +SparseComplexMatrix +xleftdiv (const ComplexDiagMatrix& d, const SparseMatrix& a, MatrixType&) +{ + return do_leftdiv_dm_sm (d, a); +} + +// -*- 12 -*- +SparseComplexMatrix +xleftdiv (const ComplexDiagMatrix& d, const SparseComplexMatrix& a, MatrixType&) +{ + return do_leftdiv_dm_sm (d, a); +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/sparse-xdiv.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/sparse-xdiv.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,93 @@ +/* + +Copyright (C) 2004-2012 David Bateman +Copyright (C) 1998-2004 Andy Adler + +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 (octave_sparse_xdiv_h) +#define octave_sparse_xdiv_h 1 + +#include "oct-cmplx.h" +#include "MatrixType.h" + +class DiagMatrix; +class ComplexDiagMatrix; +class SparseMatrix; +class SparseComplexMatrix; + +extern Matrix xdiv (const Matrix& a, const SparseMatrix& b, MatrixType &typ); +extern ComplexMatrix xdiv (const Matrix& a, const SparseComplexMatrix& b, + MatrixType &typ); +extern ComplexMatrix xdiv (const ComplexMatrix& a, const SparseMatrix& b, + MatrixType &typ); +extern ComplexMatrix xdiv (const ComplexMatrix& a, + const SparseComplexMatrix& b, MatrixType &typ); + +extern SparseMatrix xdiv (const SparseMatrix& a, const SparseMatrix& b, + MatrixType &typ); +extern SparseComplexMatrix xdiv (const SparseMatrix& a, + const SparseComplexMatrix& b, MatrixType &typ); +extern SparseComplexMatrix xdiv (const SparseComplexMatrix& a, + const SparseMatrix& b, MatrixType &typ); +extern SparseComplexMatrix xdiv (const SparseComplexMatrix& a, + const SparseComplexMatrix& b, MatrixType &typ); + +extern SparseMatrix xdiv (const SparseMatrix& a, + const DiagMatrix& b, MatrixType &typ); +extern SparseComplexMatrix xdiv (const SparseMatrix& a, + const ComplexDiagMatrix& b, MatrixType &typ); +extern SparseComplexMatrix xdiv (const SparseComplexMatrix& a, + const DiagMatrix& b, MatrixType &typ); +extern SparseComplexMatrix xdiv (const SparseComplexMatrix& a, + const ComplexDiagMatrix& b, MatrixType &typ); + +extern Matrix x_el_div (double a, const SparseMatrix& b); +extern ComplexMatrix x_el_div (double a, const SparseComplexMatrix& b); +extern ComplexMatrix x_el_div (const Complex a, const SparseMatrix& b); +extern ComplexMatrix x_el_div (const Complex a, + const SparseComplexMatrix& b); + +extern Matrix xleftdiv (const SparseMatrix& a, const Matrix& b, + MatrixType& typ); +extern ComplexMatrix xleftdiv (const SparseMatrix& a, const ComplexMatrix& b, + MatrixType &typ); +extern ComplexMatrix xleftdiv (const SparseComplexMatrix& a, const Matrix& b, + MatrixType &typ); +extern ComplexMatrix xleftdiv (const SparseComplexMatrix& a, + const ComplexMatrix& b, MatrixType &typ); + +extern SparseMatrix xleftdiv (const SparseMatrix& a, const SparseMatrix& b, + MatrixType &typ); +extern SparseComplexMatrix xleftdiv (const SparseMatrix& a, + const SparseComplexMatrix& b, MatrixType &typ); +extern SparseComplexMatrix xleftdiv (const SparseComplexMatrix& a, + const SparseMatrix& b, MatrixType &typ); +extern SparseComplexMatrix xleftdiv (const SparseComplexMatrix& a, + const SparseComplexMatrix& b, MatrixType &typ); + +extern SparseMatrix xleftdiv (const DiagMatrix&, const SparseMatrix&, MatrixType&); +extern SparseComplexMatrix xleftdiv (const ComplexDiagMatrix&, const SparseMatrix&, + MatrixType&); +extern SparseComplexMatrix xleftdiv (const DiagMatrix&, const SparseComplexMatrix&, + MatrixType&); +extern SparseComplexMatrix xleftdiv (const ComplexDiagMatrix&, const SparseComplexMatrix&, + MatrixType&); + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/sparse-xpow.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/sparse-xpow.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,730 @@ +/* + +Copyright (C) 2004-2012 David Bateman +Copyright (C) 1998-2004 Andy Adler + +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 +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "Array-util.h" +#include "oct-cmplx.h" +#include "quit.h" + +#include "error.h" +#include "oct-obj.h" +#include "utils.h" + +#include "dSparse.h" +#include "CSparse.h" +#include "ov-re-sparse.h" +#include "ov-cx-sparse.h" +#include "sparse-xpow.h" + +static inline int +xisint (double x) +{ + return (D_NINT (x) == x + && ((x >= 0 && x < INT_MAX) + || (x <= 0 && x > INT_MIN))); +} + + +// Safer pow functions. Only two make sense for sparse matrices, the +// others should all promote to full matrices. + +octave_value +xpow (const SparseMatrix& a, double b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for A^b, A must be a square matrix"); + else + { + if (static_cast (b) == b) + { + int btmp = static_cast (b); + if (btmp == 0) + { + SparseMatrix tmp = SparseMatrix (nr, nr, nr); + for (octave_idx_type i = 0; i < nr; i++) + { + tmp.data (i) = 1.0; + tmp.ridx (i) = i; + } + for (octave_idx_type i = 0; i < nr + 1; i++) + tmp.cidx (i) = i; + + retval = tmp; + } + else + { + SparseMatrix atmp; + if (btmp < 0) + { + btmp = -btmp; + + octave_idx_type info; + double rcond = 0.0; + MatrixType mattyp (a); + + atmp = a.inverse (mattyp, info, rcond, 1); + + if (info == -1) + warning ("inverse: matrix singular to machine\ + precision, rcond = %g", rcond); + } + else + atmp = a; + + SparseMatrix result (atmp); + + btmp--; + + while (btmp > 0) + { + if (btmp & 1) + result = result * atmp; + + btmp >>= 1; + + if (btmp > 0) + atmp = atmp * atmp; + } + + retval = result; + } + } + else + error ("use full(a) ^ full(b)"); + } + + return retval; +} + +octave_value +xpow (const SparseComplexMatrix& a, double b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for A^b, A must be a square matrix"); + else + { + if (static_cast (b) == b) + { + int btmp = static_cast (b); + if (btmp == 0) + { + SparseMatrix tmp = SparseMatrix (nr, nr, nr); + for (octave_idx_type i = 0; i < nr; i++) + { + tmp.data (i) = 1.0; + tmp.ridx (i) = i; + } + for (octave_idx_type i = 0; i < nr + 1; i++) + tmp.cidx (i) = i; + + retval = tmp; + } + else + { + SparseComplexMatrix atmp; + if (btmp < 0) + { + btmp = -btmp; + + octave_idx_type info; + double rcond = 0.0; + MatrixType mattyp (a); + + atmp = a.inverse (mattyp, info, rcond, 1); + + if (info == -1) + warning ("inverse: matrix singular to machine\ + precision, rcond = %g", rcond); + } + else + atmp = a; + + SparseComplexMatrix result (atmp); + + btmp--; + + while (btmp > 0) + { + if (btmp & 1) + result = result * atmp; + + btmp >>= 1; + + if (btmp > 0) + atmp = atmp * atmp; + } + + retval = result; + } + } + else + error ("use full(a) ^ full(b)"); + } + + return retval; +} + +// Safer pow functions that work elementwise for matrices. +// +// op2 \ op1: s m cs cm +// +-- +---+---+----+----+ +// scalar | | * | 3 | * | 9 | +// +---+---+----+----+ +// matrix | 1 | 4 | 7 | 10 | +// +---+---+----+----+ +// complex_scalar | * | 5 | * | 11 | +// +---+---+----+----+ +// complex_matrix | 2 | 6 | 8 | 12 | +// +---+---+----+----+ +// +// * -> not needed. + +// FIXME -- these functions need to be fixed so that things +// like +// +// a = -1; b = [ 0, 0.5, 1 ]; r = a .^ b +// +// and +// +// a = -1; b = [ 0, 0.5, 1 ]; for i = 1:3, r(i) = a .^ b(i), end +// +// produce identical results. Also, it would be nice if -1^0.5 +// produced a pure imaginary result instead of a complex number with a +// small real part. But perhaps that's really a problem with the math +// library... + +// -*- 1 -*- +octave_value +elem_xpow (double a, const SparseMatrix& b) +{ + octave_value retval; + + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + double d1, d2; + + if (a < 0.0 && ! b.all_integers (d1, d2)) + { + Complex atmp (a); + ComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + { + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result(i, j) = std::pow (atmp, b(i,j)); + } + } + + retval = result; + } + else + { + Matrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + { + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result(i, j) = std::pow (a, b(i,j)); + } + } + + retval = result; + } + + return retval; +} + +// -*- 2 -*- +octave_value +elem_xpow (double a, const SparseComplexMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + Complex atmp (a); + ComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + { + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result(i, j) = std::pow (atmp, b(i,j)); + } + } + + return result; +} + +// -*- 3 -*- +octave_value +elem_xpow (const SparseMatrix& a, double b) +{ + // FIXME What should a .^ 0 give?? Matlab gives a + // sparse matrix with same structure as a, which is strictly + // incorrect. Keep compatiability. + + octave_value retval; + + octave_idx_type nz = a.nnz (); + + if (b <= 0.0) + { + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (static_cast (b) != b && a.any_element_is_negative ()) + { + ComplexMatrix result (nr, nc, Complex (std::pow (0.0, b))); + + // FIXME -- avoid apparent GNU libm bug by + // converting A and B to complex instead of just A. + Complex btmp (b); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) + { + octave_quit (); + + Complex atmp (a.data (i)); + + result(a.ridx (i), j) = std::pow (atmp, btmp); + } + + retval = octave_value (result); + } + else + { + Matrix result (nr, nc, (std::pow (0.0, b))); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) + { + octave_quit (); + result(a.ridx (i), j) = std::pow (a.data (i), b); + } + + retval = octave_value (result); + } + } + else if (static_cast (b) != b && a.any_element_is_negative ()) + { + SparseComplexMatrix result (a); + + for (octave_idx_type i = 0; i < nz; i++) + { + octave_quit (); + + // FIXME -- avoid apparent GNU libm bug by + // converting A and B to complex instead of just A. + + Complex atmp (a.data (i)); + Complex btmp (b); + + result.data (i) = std::pow (atmp, btmp); + } + + result.maybe_compress (true); + + retval = result; + } + else + { + SparseMatrix result (a); + + for (octave_idx_type i = 0; i < nz; i++) + { + octave_quit (); + result.data (i) = std::pow (a.data (i), b); + } + + result.maybe_compress (true); + + retval = result; + } + + return retval; +} + +// -*- 4 -*- +octave_value +elem_xpow (const SparseMatrix& a, const SparseMatrix& b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + octave_idx_type b_nr = b.rows (); + octave_idx_type b_nc = b.cols (); + + if (nr != b_nr || nc != b_nc) + { + gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); + return octave_value (); + } + + int convert_to_complex = 0; + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) + { + if (a.data(i) < 0.0) + { + double btmp = b (a.ridx (i), j); + if (static_cast (btmp) != btmp) + { + convert_to_complex = 1; + goto done; + } + } + } + +done: + + // This is a dumb operator for sparse matrices anyway, and there is + // no sensible way to handle the 0.^0 versus the 0.^x cases. Therefore + // allocate a full matrix filled for the 0.^0 case and shrink it later + // as needed + + if (convert_to_complex) + { + SparseComplexMatrix complex_result (nr, nc, Complex (1.0, 0.0)); + + for (octave_idx_type j = 0; j < nc; j++) + { + for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) + { + octave_quit (); + complex_result.xelem (a.ridx (i), j) = + std::pow (Complex (a.data (i)), Complex (b(a.ridx (i), j))); + } + } + complex_result.maybe_compress (true); + retval = complex_result; + } + else + { + SparseMatrix result (nr, nc, 1.0); + + for (octave_idx_type j = 0; j < nc; j++) + { + for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) + { + octave_quit (); + result.xelem (a.ridx (i), j) = std::pow (a.data (i), + b(a.ridx (i), j)); + } + } + result.maybe_compress (true); + retval = result; + } + + return retval; +} + +// -*- 5 -*- +octave_value +elem_xpow (const SparseMatrix& a, const Complex& b) +{ + octave_value retval; + + if (b == 0.0) + // Can this case ever happen, due to automatic retyping with maybe_mutate? + retval = octave_value (NDArray (a.dims (), 1)); + else + { + octave_idx_type nz = a.nnz (); + SparseComplexMatrix result (a); + + for (octave_idx_type i = 0; i < nz; i++) + { + octave_quit (); + result.data (i) = std::pow (Complex (a.data (i)), b); + } + + result.maybe_compress (true); + + retval = result; + } + + return retval; +} + +// -*- 6 -*- +octave_value +elem_xpow (const SparseMatrix& a, const SparseComplexMatrix& b) +{ + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + octave_idx_type b_nr = b.rows (); + octave_idx_type b_nc = b.cols (); + + if (nr != b_nr || nc != b_nc) + { + gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); + return octave_value (); + } + + SparseComplexMatrix result (nr, nc, Complex (1.0, 0.0)); + for (octave_idx_type j = 0; j < nc; j++) + { + for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) + { + octave_quit (); + result.xelem (a.ridx(i), j) = std::pow (a.data (i), b(a.ridx (i), j)); + } + } + + result.maybe_compress (true); + + return result; +} + +// -*- 7 -*- +octave_value +elem_xpow (const Complex& a, const SparseMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + ComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + { + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + double btmp = b (i, j); + if (xisint (btmp)) + result (i, j) = std::pow (a, static_cast (btmp)); + else + result (i, j) = std::pow (a, btmp); + } + } + + return result; +} + +// -*- 8 -*- +octave_value +elem_xpow (const Complex& a, const SparseComplexMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + ComplexMatrix result (nr, nc); + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a, b (i, j)); + } + + return result; +} + +// -*- 9 -*- +octave_value +elem_xpow (const SparseComplexMatrix& a, double b) +{ + octave_value retval; + + if (b <= 0) + { + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + ComplexMatrix result (nr, nc, Complex (std::pow (0.0, b))); + + if (xisint (b)) + { + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) + { + octave_quit (); + result (a.ridx (i), j) = + std::pow (a.data (i), static_cast (b)); + } + } + else + { + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) + { + octave_quit (); + result (a.ridx (i), j) = std::pow (a.data (i), b); + } + } + + retval = result; + } + else + { + octave_idx_type nz = a.nnz (); + + SparseComplexMatrix result (a); + + if (xisint (b)) + { + for (octave_idx_type i = 0; i < nz; i++) + { + octave_quit (); + result.data (i) = std::pow (a.data (i), static_cast (b)); + } + } + else + { + for (octave_idx_type i = 0; i < nz; i++) + { + octave_quit (); + result.data (i) = std::pow (a.data (i), b); + } + } + + result.maybe_compress (true); + + retval = result; + } + + return retval; +} + +// -*- 10 -*- +octave_value +elem_xpow (const SparseComplexMatrix& a, const SparseMatrix& b) +{ + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + octave_idx_type b_nr = b.rows (); + octave_idx_type b_nc = b.cols (); + + if (nr != b_nr || nc != b_nc) + { + gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); + return octave_value (); + } + + SparseComplexMatrix result (nr, nc, Complex (1.0, 0.0)); + for (octave_idx_type j = 0; j < nc; j++) + { + for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) + { + octave_quit (); + double btmp = b(a.ridx (i), j); + Complex tmp; + + if (xisint (btmp)) + result.xelem (a.ridx (i), j) = std::pow (a.data (i), + static_cast (btmp)); + else + result.xelem (a.ridx (i), j) = std::pow (a.data (i), btmp); + } + } + + result.maybe_compress (true); + + return result; +} + +// -*- 11 -*- +octave_value +elem_xpow (const SparseComplexMatrix& a, const Complex& b) +{ + octave_value retval; + + if (b == 0.0) + // Can this case ever happen, due to automatic retyping with maybe_mutate? + retval = octave_value (NDArray (a.dims (), 1)); + else + { + + octave_idx_type nz = a.nnz (); + + SparseComplexMatrix result (a); + + for (octave_idx_type i = 0; i < nz; i++) + { + octave_quit (); + result.data (i) = std::pow (a.data (i), b); + } + + result.maybe_compress (true); + + retval = result; + } + + return retval; +} + +// -*- 12 -*- +octave_value +elem_xpow (const SparseComplexMatrix& a, const SparseComplexMatrix& b) +{ + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + octave_idx_type b_nr = b.rows (); + octave_idx_type b_nc = b.cols (); + + if (nr != b_nr || nc != b_nc) + { + gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); + return octave_value (); + } + + SparseComplexMatrix result (nr, nc, Complex (1.0, 0.0)); + for (octave_idx_type j = 0; j < nc; j++) + { + for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) + { + octave_quit (); + result.xelem (a.ridx (i), j) = std::pow (a.data (i), b(a.ridx (i), j)); + } + } + result.maybe_compress (true); + + return result; +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/sparse-xpow.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/sparse-xpow.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,57 @@ +/* + +Copyright (C) 2004-2012 David Bateman +Copyright (C) 1998-2004 Andy Adler + +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 (octave_sparse_xpow_h) +#define octave_sparse_xpow_h 1 + +#include "oct-cmplx.h" + +class SparseMatrix; +class SparseComplexMatrix; +class octave_value; + +extern octave_value xpow (const SparseMatrix& a, double b); +extern octave_value xpow (const SparseComplexMatrix& a, double b); + +extern octave_value elem_xpow (double a, const SparseMatrix& b); +extern octave_value elem_xpow (double a, const SparseComplexMatrix& b); + +extern octave_value elem_xpow (const SparseMatrix& a, double b); +extern octave_value elem_xpow (const SparseMatrix& a, const SparseMatrix& b); +extern octave_value elem_xpow (const SparseMatrix& a, const Complex& b); +extern octave_value elem_xpow (const SparseMatrix& a, + const SparseComplexMatrix& b); + +extern octave_value elem_xpow (const Complex& a, const SparseMatrix& b); +extern octave_value elem_xpow (const Complex& a, + const SparseComplexMatrix& b); + +extern octave_value elem_xpow (const SparseComplexMatrix& a, double b); +extern octave_value elem_xpow (const SparseComplexMatrix& a, + const SparseMatrix& b); +extern octave_value elem_xpow (const SparseComplexMatrix& a, + const Complex& b); +extern octave_value elem_xpow (const SparseComplexMatrix& a, + const SparseComplexMatrix& b); + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/txt-eng-ft.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/txt-eng-ft.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,669 @@ +/* + +Copyright (C) 2009-2012 Michael Goffioul + +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 +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined (HAVE_FREETYPE) + +#if defined (HAVE_FONTCONFIG) +#include +#endif + +#include + +#include "singleton-cleanup.h" + +#include "error.h" +#include "pr-output.h" +#include "txt-eng-ft.h" + +// FIXME -- maybe issue at most one warning per glyph/font/size/weight +// combination. + +static void +gripe_missing_glyph (char c) +{ + warning_with_id ("Octave:missing-glyph", + "ft_render: skipping missing glyph for character `%c'", + c); +} + +static void +gripe_glyph_render (char c) +{ + warning_with_id ("Octave:glyph-render", + "ft_render: unable to render glyph for character `%c'", + c); +} + +#ifdef _MSC_VER +// This is just a trick to avoid multiply symbols definition. +// PermMatrix.h contains a dllexport'ed Array +// that will make MSVC not to generate new instantiation and +// use the imported one. +#include "PermMatrix.h" +#endif + +class +ft_manager +{ +public: + static bool instance_ok (void) + { + bool retval = true; + + if (! instance) + { + instance = new ft_manager (); + + if (instance) + singleton_cleanup_list::add (cleanup_instance); + } + + if (! instance) + { + ::error ("unable to create ft_manager!"); + + retval = false; + } + + return retval; + } + + static void cleanup_instance (void) { delete instance; instance = 0; } + + static FT_Face get_font (const std::string& name, const std::string& weight, + const std::string& angle, double size) + { return (instance_ok () + ? instance->do_get_font (name, weight, angle, size) + : 0); } + +private: + + static ft_manager *instance; + +private: + + // No copying! + + ft_manager (const ft_manager&); + + ft_manager& operator = (const ft_manager&); + + ft_manager (void) + : library (), freetype_initialized (false), fontconfig_initialized (false) + { + if (FT_Init_FreeType (&library)) + ::error ("unable to initialize freetype library"); + else + freetype_initialized = true; + +#if defined (HAVE_FONTCONFIG) + if (! FcInit ()) + ::error ("unable to initialize fontconfig library"); + else + fontconfig_initialized = true; +#endif + } + + ~ft_manager (void) + { + if (freetype_initialized) + FT_Done_FreeType (library); + +#if defined (HAVE_FONTCONFIG) + // FIXME -- Skip the call to FcFini because it can trigger the + // assertion + // + // octave: fccache.c:507: FcCacheFini: Assertion `fcCacheChains[i] == ((void *)0)' failed. + // + // if (fontconfig_initialized) + // FcFini (); +#endif + } + + + FT_Face do_get_font (const std::string& name, const std::string& weight, + const std::string& angle, double size) + { + FT_Face retval = 0; + + std::string file; + +#if defined (HAVE_FONTCONFIG) + if (fontconfig_initialized) + { + int fc_weight, fc_angle; + + if (weight == "bold") + fc_weight = FC_WEIGHT_BOLD; + else if (weight == "light") + fc_weight = FC_WEIGHT_LIGHT; + else if (weight == "demi") + fc_weight = FC_WEIGHT_DEMIBOLD; + else + fc_weight = FC_WEIGHT_NORMAL; + + if (angle == "italic") + fc_angle = FC_SLANT_ITALIC; + else if (angle == "oblique") + fc_angle = FC_SLANT_OBLIQUE; + else + fc_angle = FC_SLANT_ROMAN; + + FcPattern *pat = FcPatternCreate (); + + FcPatternAddString (pat, FC_FAMILY, + (reinterpret_cast + (name == "*" ? "sans" : name.c_str ()))); + + FcPatternAddInteger (pat, FC_WEIGHT, fc_weight); + FcPatternAddInteger (pat, FC_SLANT, fc_angle); + FcPatternAddDouble (pat, FC_PIXEL_SIZE, size); + + if (FcConfigSubstitute (0, pat, FcMatchPattern)) + { + FcResult res; + FcPattern *match; + + FcDefaultSubstitute (pat); + match = FcFontMatch (0, pat, &res); + + // FIXME -- originally, this test also required that + // res != FcResultNoMatch. Is that really needed? + if (match) + { + unsigned char *tmp; + + FcPatternGetString (match, FC_FILE, 0, &tmp); + file = reinterpret_cast (tmp); + } + else + ::warning ("could not match any font: %s-%s-%s-%g", + name.c_str (), weight.c_str (), angle.c_str (), + size); + + if (match) + FcPatternDestroy (match); + } + + FcPatternDestroy (pat); + } +#endif + + if (file.empty ()) + { +#ifdef __WIN32__ + file = "C:/WINDOWS/Fonts/verdana.ttf"; +#else + // FIXME: find a "standard" font for UNIX platforms +#endif + } + + if (! file.empty () && FT_New_Face (library, file.c_str (), 0, &retval)) + ::warning ("ft_manager: unable to load font: %s", file.c_str ()); + + return retval; + } + +private: + FT_Library library; + bool freetype_initialized; + bool fontconfig_initialized; +}; + +ft_manager* ft_manager::instance = 0; + +// --------------------------------------------------------------------------- + +ft_render::ft_render (void) + : text_processor (), face (0), bbox (1, 4, 0.0), + xoffset (0), yoffset (0), multiline_halign (0), + multiline_align_xoffsets (), mode (MODE_BBOX), + red (0), green (0), blue (0) +{ +} + +ft_render::~ft_render (void) +{ + if (face) + FT_Done_Face (face); +} + +void +ft_render::set_font (const std::string& name, const std::string& weight, + const std::string& angle, double size) +{ + if (face) + FT_Done_Face (face); + + // FIXME: take "fontunits" into account + face = ft_manager::get_font (name, weight, angle, size); + + if (face) + { + if (FT_Set_Char_Size (face, 0, size*64, 0, 0)) + ::warning ("ft_render: unable to set font size to %d", size); + } + else + ::warning ("ft_render: unable to load appropriate font"); +} + +void +ft_render::set_mode (int m) +{ + mode = m; + + switch (mode) + { + case MODE_BBOX: + xoffset = yoffset = 0; + bbox = Matrix (1, 4, 0.0); + break; + case MODE_RENDER: + if (bbox.numel () != 4) + { + ::warning ("ft_render: invalid bounding box, cannot render"); + + xoffset = yoffset = 0; + pixels = uint8NDArray (); + } + else + { + pixels = uint8NDArray (dim_vector (4, bbox(2), bbox(3)), + static_cast (0)); + xoffset = 0; + yoffset = -bbox(1)-1; + } + break; + default: + ::error ("ft_render: invalid mode `%d'", mode); + break; + } +} + +void +ft_render::visit (text_element_string& e) +{ + 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 (str[i] != '\n' + && (! glyph_index + || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))) + gripe_missing_glyph (str[i]); + else + { + switch (mode) + { + case MODE_RENDER: + if (str[i] == '\n') + { + glyph_index = FT_Get_Char_Index (face, ' '); + if (!glyph_index || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)) + { + gripe_missing_glyph (' '); + } + 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)) + { + gripe_glyph_render (str[i]); + } + else + { + FT_Bitmap& bitmap = face->glyph->bitmap; + int x0, y0; + + if (previous) + { + FT_Vector delta; + + FT_Get_Kerning (face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); + xoffset += (delta.x >> 6); + } + + 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++) + { + unsigned char pix = bitmap.buffer[r*bitmap.width+c]; + if (x0+c < 0 || x0+c >= pixels.dim2 () + || y0-r < 0 || y0-r >= pixels.dim3 ()) + { + //::error ("out-of-bound indexing!!"); + } + else if (pixels(3, x0+c, y0-r).value () == 0) + { + pixels(0, x0+c, y0-r) = red; + pixels(1, x0+c, y0-r) = green; + pixels(2, x0+c, y0-r) = blue; + pixels(3, x0+c, y0-r) = pix; + } + } + + xoffset += (face->glyph->advance.x >> 6); + } + break; + + case MODE_BBOX: + if (str[i] == '\n') + { + glyph_index = FT_Get_Char_Index (face, ' '); + if (! glyph_index + || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)) + { + gripe_missing_glyph (' '); + } + 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 + { + // 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; + + 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; + } + + 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); + + 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; + } + } + } +} + +void +ft_render::reset (void) +{ + set_mode (MODE_BBOX); + set_color (Matrix (1, 3, 0.0)); +} + +void +ft_render::set_color (Matrix c) +{ + if (c.numel () == 3) + { + red = static_cast (c(0)*255); + green = static_cast (c(1)*255); + blue = static_cast (c(2)*255); + } + else + ::warning ("ft_render::set_color: invalid color"); +} + +uint8NDArray +ft_render::render (text_element* elt, Matrix& box, int rotation) +{ + set_mode (MODE_BBOX); + elt->accept (*this); + box = bbox; + + set_mode (MODE_RENDER); + if (pixels.numel () > 0) + { + elt->accept (*this); + + switch (rotation) + { + case ROTATION_0: + break; + case ROTATION_90: + { + Array perm (dim_vector (3, 1)); + perm(0) = 0; + perm(1) = 2; + perm(2) = 1; + pixels = pixels.permute (perm); + + Array idx (dim_vector (3, 1)); + idx(0) = idx_vector (':'); + idx(1) = idx_vector (pixels.dim2 ()-1, -1, -1); + idx(2) = idx_vector (':'); + pixels = uint8NDArray (pixels.index (idx)); + } + break; + case ROTATION_180: + { + Array idx (dim_vector (3, 1)); + idx(0) = idx_vector (':'); + idx(1) = idx_vector (pixels.dim2 ()-1, -1, -1); + idx(2)= idx_vector (pixels.dim3 ()-1, -1, -1); + pixels = uint8NDArray (pixels.index (idx)); + } + break; + case ROTATION_270: + { + Array perm (dim_vector (3, 1)); + perm(0) = 0; + perm(1) = 2; + perm(2) = 1; + pixels = pixels.permute (perm); + + Array idx (dim_vector (3, 1)); + idx(0) = idx_vector (':'); + idx(1) = idx_vector (':'); + idx(2) = idx_vector (pixels.dim3 ()-1, -1, -1); + pixels = uint8NDArray (pixels.index (idx)); + } + break; + } + } + + return pixels; +} + +Matrix +ft_render::get_extent (text_element *elt, double rotation) +{ + set_mode (MODE_BBOX); + elt->accept (*this); + + Matrix extent (1, 2, 0.0); + + switch (rotation_to_mode (rotation)) + { + case ROTATION_0: + case ROTATION_180: + extent(0) = bbox(2); + extent(1) = bbox(3); + break; + case ROTATION_90: + case ROTATION_270: + extent(0) = bbox(3); + extent(1) = bbox(2); + } + + return extent; +} + +Matrix +ft_render::get_extent (const std::string& txt, double rotation) +{ + text_element *elt = text_parser_none ().parse (txt); + Matrix extent = get_extent (elt, rotation); + delete elt; + + return extent; +} + +int +ft_render::rotation_to_mode (double rotation) const +{ + if (rotation == 0.0) + return ROTATION_0; + else if (rotation == 90.0) + return ROTATION_90; + else if (rotation == 180.0) + return ROTATION_180; + else if (rotation == 270.0) + return ROTATION_270; + else + return ROTATION_0; +} + +void +ft_render::text_to_pixels (const std::string& txt, + uint8NDArray& pixels_, Matrix& box, + int halign, int valign, double rotation) +{ + // 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); + delete elt; + + if (pixels_.numel () == 0) + { + // nothing to render + return; + } + + switch (halign) + { + default: box(0) = 0; break; + case 1: box(0) = -box(2)/2; break; + case 2: box(0) = -box(2); break; + } + switch (valign) + { + default: box(1) = 0; break; + case 1: box(1) = -box(3)/2; break; + case 2: box(1) = -box(3); break; + case 3: break; + } + + switch (rot_mode) + { + case ROTATION_90: + std::swap (box(0), box(1)); + std::swap (box(2), box(3)); + box(0) = -box(0)-box(2); + break; + case ROTATION_180: + box(0) = -box(0)-box(2); + box(1) = -box(1)-box(3); + break; + case ROTATION_270: + std::swap (box(0), box(1)); + std::swap (box(2), box(3)); + box(1) = -box(1)-box(3); + break; + } +} + +#endif // HAVE_FREETYPE diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/txt-eng-ft.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/txt-eng-ft.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,107 @@ +/* + +Copyright (C) 2009-2012 Michael Goffioul + +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 (txt_eng_ft_h) +#define txt_eng_ft_h 1 + +#if HAVE_FREETYPE + +#include + +#include +#include FT_FREETYPE_H + +#include +#include +#include "txt-eng.h" + +class +OCTINTERP_API +ft_render : public text_processor +{ +public: + enum { + MODE_BBOX = 0, + MODE_RENDER = 1 + }; + + enum { + ROTATION_0 = 0, + ROTATION_90 = 1, + ROTATION_180 = 2, + ROTATION_270 = 3 + }; + +public: + ft_render (void); + + ~ft_render (void); + + void visit (text_element_string& e); + + void reset (void); + + uint8NDArray get_pixels (void) const { return pixels; } + + Matrix get_boundingbox (void) const { return bbox; } + + uint8NDArray render (text_element* elt, Matrix& box, + int rotation = ROTATION_0); + + Matrix get_extent (text_element *elt, double rotation = 0.0); + Matrix get_extent (const std::string& txt, double rotation = 0.0); + + void set_font (const std::string& name, const std::string& weight, + const std::string& angle, double size); + + void set_color (Matrix c); + + void set_mode (int m); + + void text_to_pixels (const std::string& txt, + uint8NDArray& pixels_, Matrix& bbox, + int halign, int valign, double rotation); + +private: + int rotation_to_mode (double rotation) const; + + // No copying! + + ft_render (const ft_render&); + + ft_render& operator = (const ft_render&); + +private: + FT_Face face; + Matrix bbox; + uint8NDArray pixels; + int xoffset; + int yoffset; + int multiline_halign; + std::vector multiline_align_xoffsets; + int mode; + uint8_t red, green, blue; +}; + +#endif // HAVE_FREETYPE + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/txt-eng.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/txt-eng.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,193 @@ +/* + +Copyright (C) 2009-2012 Michael Goffioul + +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 (txt_eng_h) +#define txt_eng_h 1 + +#include "base-list.h" + +class text_element; +class text_element_string; +class text_element_list; +class text_subscript_element; +class text_superscript_element; + +class text_processor; + +class +OCTINTERP_API +text_element +{ +public: + text_element (void) { } + + virtual ~text_element (void) { } + + virtual void accept (text_processor& p) = 0; + +private: + text_element (const text_element&); +}; + +class +OCTINTERP_API +text_element_string : public text_element +{ +public: + text_element_string (const std::string& s = "") + : text_element (), str (s) { } + + ~text_element_string (void) { } + + std::string string_value (void) const { return str; } + + void accept (text_processor& p); + +private: + std::string str; + +private: + text_element_string (const text_element_string &); +}; + +class +OCTINTERP_API +text_element_list : + public text_element, + public octave_base_list +{ +public: + text_element_list (void) + : text_element (), octave_base_list () { } + + ~text_element_list (void) + { + while (! empty ()) + { + iterator it = begin (); + delete (*it); + erase (it); + } + } + + void accept (text_processor& p); +}; + +class +OCTINTERP_API +text_subscript_element : public text_element_list +{ +public: + text_subscript_element (void) + : text_element_list () { } + + ~text_subscript_element (void) { } + + void accept (text_processor& p); +}; + +class +OCTINTERP_API +text_superscript_element : public text_element_list +{ +public: + text_superscript_element (void) + : text_element_list () { } + + ~text_superscript_element (void) { } + + void accept (text_processor& p); +}; + +class +OCTINTERP_API +text_processor +{ +public: + virtual void visit (text_element_string& e) = 0; + + virtual void visit (text_element_list& e) + { + for (text_element_list::iterator it = e.begin (); + it != e.end (); ++it) + { + (*it)->accept (*this); + } + } + + virtual void visit (text_subscript_element& e) + { visit (dynamic_cast (e)); } + + virtual void visit (text_superscript_element& e) + { visit (dynamic_cast (e)); } + + virtual void reset (void) { } + +protected: + text_processor (void) { } + + virtual ~text_processor (void) { } +}; + +#define TEXT_ELEMENT_ACCEPT(cls) \ +inline void \ +cls::accept (text_processor& p) \ +{ p.visit (*this); } + +TEXT_ELEMENT_ACCEPT(text_element_string) +TEXT_ELEMENT_ACCEPT(text_element_list) +TEXT_ELEMENT_ACCEPT(text_subscript_element) +TEXT_ELEMENT_ACCEPT(text_superscript_element) + +class +OCTINTERP_API +text_parser +{ +public: + text_parser (void) { } + + virtual ~text_parser (void) { } + + virtual text_element* parse (const std::string& s) = 0; +}; + +class +OCTINTERP_API +text_parser_none : public text_parser +{ +public: + text_parser_none (void) : text_parser () { } + + ~text_parser_none (void) { } + + // FIXME: is it possible to use reference counting to manage the + // memory for the object returned by the text parser? That would be + // preferable to having to know when and where to delete the object it + // creates... + + text_element* parse (const std::string& s) + { + return new text_element_string (s); + } +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/unwind-prot.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/unwind-prot.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,39 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton +Copyright (C) 2009 VZLU Prague + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "error.h" +#include "unwind-prot.h" +#include "utils.h" + +void unwind_protect_safe::gripe_exception (void) +{ + // FIXME: can this throw an exception? + error ("internal: unhandled exception in unwind_protect handler"); +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/unwind-prot.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/unwind-prot.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,344 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton +Copyright (C) 2009-2010 VZLU Prague + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_unwind_prot_h) +#define octave_unwind_prot_h 1 + +#include + +#include +#include + +// This class allows registering cleanup actions. +class +OCTINTERP_API +unwind_protect +{ +public: + + // A generic unwind_protect element. Knows how to run itself and discard itself. + // Also, contains a pointer to the next element. + class elem + { + elem *next; + + public: + elem (void) : next (0) { } + + virtual void run (void) { } + + virtual ~elem (void) { } + + friend class unwind_protect; + + private: + + // No copying! + + elem (const elem&); + + elem& operator = (const elem&); + }; + + // An element that merely runs a void (*)(void) function. + + class fcn_elem : public elem + { + public: + fcn_elem (void (*fptr) (void)) + : e_fptr (fptr) { } + + void run (void) { e_fptr (); } + + private: + void (*e_fptr) (void); + }; + + // An element that stores a variable of type T along with a void (*) (T) + // function pointer, and calls the function with the parameter. + + template + class fcn_arg_elem : public elem + { + public: + fcn_arg_elem (void (*fcn) (T), T arg) + : e_fcn (fcn), e_arg (arg) { } + + void run (void) { e_fcn (e_arg); } + + private: + + // No copying! + + fcn_arg_elem (const fcn_arg_elem&); + + fcn_arg_elem& operator = (const fcn_arg_elem&); + + void (*e_fcn) (T); + T e_arg; + }; + + // An element that stores a variable of type T along with a void (*) (const T&) + // function pointer, and calls the function with the parameter. + + template + class fcn_crefarg_elem : public elem + { + public: + fcn_crefarg_elem (void (*fcn) (const T&), T arg) + : e_fcn (fcn), e_arg (arg) { } + + void run (void) { e_fcn (e_arg); } + + private: + void (*e_fcn) (const T&); + T e_arg; + }; + + // An element for calling a member function. + + template + class method_elem : public elem + { + public: + method_elem (T *obj, void (T::*method) (void)) + : e_obj (obj), e_method (method) { } + + void run (void) { (e_obj->*e_method) (); } + + private: + + T *e_obj; + void (T::*e_method) (void); + + // No copying! + + method_elem (const method_elem&); + + method_elem operator = (const method_elem&); + }; + + // An element that stores arbitrary variable, and restores it. + + template + class restore_var_elem : public elem + { + public: + restore_var_elem (T& ref, const T& val) + : e_ptr (&ref), e_val (val) { } + + void run (void) { *e_ptr = e_val; } + + private: + + // No copying! + + restore_var_elem (const restore_var_elem&); + + restore_var_elem& operator = (const restore_var_elem&); + + T *e_ptr, e_val; + }; + + // Deletes a class allocated using new. + + template + class delete_ptr_elem : public elem + { + public: + delete_ptr_elem (T *ptr) + : e_ptr (ptr) { } + + void run (void) { delete e_ptr; } + + private: + + T *e_ptr; + + // No copying! + + delete_ptr_elem (const delete_ptr_elem&); + + delete_ptr_elem operator = (const delete_ptr_elem&); + }; + + unwind_protect (void) : head () { } + + void add (elem *new_elem) + { + new_elem->next = head; + head = new_elem; + } + + // For backward compatibility. + void add (void (*fcn) (void *), void *ptr = 0) + { + add (new fcn_arg_elem (fcn, ptr)); + } + + // Call to void func (void). + void add_fcn (void (*fcn) (void)) + { + add (new fcn_elem (fcn)); + } + + // Call to void func (T). + template + void add_fcn (void (*action) (T), T val) + { + add (new fcn_arg_elem (action, val)); + } + + // Call to void func (const T&). + template + void add_fcn (void (*action) (const T&), T val) + { + add (new fcn_crefarg_elem (action, val)); + } + + // Call to T::method (void). + template + void add_method (T *obj, void (T::*method) (void)) + { + add (new method_elem (obj, method)); + } + + // Call to delete (T*). + + template + void add_delete (T *obj) + { + add (new delete_ptr_elem (obj)); + } + + // Protect any variable. + template + void protect_var (T& var) + { + add (new restore_var_elem (var, var)); + } + + // Protect any variable, value given. + template + void protect_var (T& var, const T& val) + { + add (new restore_var_elem (var, val)); + } + + operator bool (void) const + { + return head != 0; + } + + void run_top (void) + { + if (head) + { + // No leak on exception! + std::auto_ptr ptr (head); + head = ptr->next; + ptr->run (); + } + } + + void run_top (int num) + { + while (num-- > 0) + run_top (); + } + + void discard_top (void) + { + if (head) + { + elem *ptr = head; + head = ptr->next; + delete ptr; + } + } + + void discard_top (int num) + { + while (num-- > 0) + discard_top (); + } + + void run (void) + { + while (head) + run_top (); + } + + void discard (void) + { + while (head) + discard_top (); + } + + // Destructor should not raise an exception, so all actions registered should + // be exception-safe (but setting error_state is allowed). If you're not sure, + // see unwind_protect_safe. + ~unwind_protect (void) + { + run (); + } + +private: + + elem *head; + + // No copying! + + unwind_protect (const unwind_protect&); + + unwind_protect& operator = (const unwind_protect&); +}; + +// Like unwind_protect, but this one will guard against the possibility of seeing +// an exception (or interrupt) in the cleanup actions. Not that we can do much about +// it, but at least we won't crash. + +class +OCTINTERP_API +unwind_protect_safe : public unwind_protect +{ + static void gripe_exception (void); + +public: + ~unwind_protect_safe (void) + { + while (*this) + { + try + { + run_top (); + } + catch (...) // Yes, the black hole. Remember we're in a dtor. + { + gripe_exception (); + } + } + } +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/xdiv.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/xdiv.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,1000 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton +Copyright (C) 2008 Jaroslav Hajek +Copyright (C) 2009-2010 VZLU Prague + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "Array-util.h" +#include "CMatrix.h" +#include "dMatrix.h" +#include "CNDArray.h" +#include "dNDArray.h" +#include "fCMatrix.h" +#include "fMatrix.h" +#include "fCNDArray.h" +#include "fNDArray.h" +#include "oct-cmplx.h" +#include "dDiagMatrix.h" +#include "fDiagMatrix.h" +#include "CDiagMatrix.h" +#include "fCDiagMatrix.h" +#include "quit.h" + +#include "error.h" +#include "xdiv.h" + +static inline bool +result_ok (octave_idx_type info) +{ + assert (info != -1); + + return (info != -2); +} + +static void +solve_singularity_warning (double rcond) +{ + warning_with_id ("Octave:singular-matrix-div", + "matrix singular to machine precision, rcond = %g", rcond); +} + +template +bool +mx_leftdiv_conform (const T1& a, const T2& b, blas_trans_type blas_trans) +{ + 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 = 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); + return false; + } + + return true; +} + +#define INSTANTIATE_MX_LEFTDIV_CONFORM(T1, 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); +INSTANTIATE_MX_LEFTDIV_CONFORM (ComplexMatrix, Matrix); +INSTANTIATE_MX_LEFTDIV_CONFORM (ComplexMatrix, ComplexMatrix); + +template +bool +mx_div_conform (const T1& a, const T2& b) +{ + octave_idx_type a_nc = a.cols (); + octave_idx_type b_nc = b.cols (); + + if (a_nc != b_nc) + { + octave_idx_type a_nr = a.rows (); + octave_idx_type b_nr = b.rows (); + + gripe_nonconformant ("operator /", a_nr, a_nc, b_nr, b_nc); + return false; + } + + return true; +} + +#define INSTANTIATE_MX_DIV_CONFORM(T1, T2) \ + template bool mx_div_conform (const T1&, const T2&) + +INSTANTIATE_MX_DIV_CONFORM (Matrix, Matrix); +INSTANTIATE_MX_DIV_CONFORM (Matrix, ComplexMatrix); +INSTANTIATE_MX_DIV_CONFORM (ComplexMatrix, Matrix); +INSTANTIATE_MX_DIV_CONFORM (ComplexMatrix, ComplexMatrix); + +// Right division functions. +// +// op2 / op1: m cm +// +-- +---+----+ +// matrix | 1 | 3 | +// +---+----+ +// complex_matrix | 2 | 4 | +// +---+----+ + +// -*- 1 -*- +Matrix +xdiv (const Matrix& a, const Matrix& b, MatrixType &typ) +{ + if (! mx_div_conform (a, b)) + return Matrix (); + + octave_idx_type info; + double rcond = 0.0; + + Matrix result + = b.solve (typ, a.transpose (), info, rcond, + solve_singularity_warning, true, blas_trans); + + return result.transpose (); +} + +// -*- 2 -*- +ComplexMatrix +xdiv (const Matrix& a, const ComplexMatrix& b, MatrixType &typ) +{ + if (! mx_div_conform (a, b)) + return ComplexMatrix (); + + octave_idx_type info; + double rcond = 0.0; + + ComplexMatrix result + = b.solve (typ, a.transpose (), info, rcond, + solve_singularity_warning, true, blas_trans); + + return result.transpose (); +} + +// -*- 3 -*- +ComplexMatrix +xdiv (const ComplexMatrix& a, const Matrix& b, MatrixType &typ) +{ + if (! mx_div_conform (a, b)) + return ComplexMatrix (); + + octave_idx_type info; + double rcond = 0.0; + + ComplexMatrix result + = b.solve (typ, a.transpose (), info, rcond, + solve_singularity_warning, true, blas_trans); + + return result.transpose (); +} + +// -*- 4 -*- +ComplexMatrix +xdiv (const ComplexMatrix& a, const ComplexMatrix& b, MatrixType &typ) +{ + if (! mx_div_conform (a, b)) + return ComplexMatrix (); + + octave_idx_type info; + double rcond = 0.0; + + ComplexMatrix result + = b.solve (typ, a.transpose (), info, rcond, + solve_singularity_warning, true, blas_trans); + + return result.transpose (); +} + +// Funny element by element division operations. +// +// op2 \ op1: s cs +// +-- +---+----+ +// matrix | 1 | 3 | +// +---+----+ +// complex_matrix | 2 | 4 | +// +---+----+ + +Matrix +x_el_div (double a, const Matrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.columns (); + + Matrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = a / b (i, j); + } + + return result; +} + +ComplexMatrix +x_el_div (double a, const ComplexMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.columns (); + + ComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = a / b (i, j); + } + + return result; +} + +ComplexMatrix +x_el_div (const Complex a, const Matrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.columns (); + + ComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = a / b (i, j); + } + + return result; +} + +ComplexMatrix +x_el_div (const Complex a, const ComplexMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.columns (); + + ComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = a / b (i, j); + } + + return result; +} + +// Funny element by element division operations. +// +// op2 \ op1: s cs +// +-- +---+----+ +// N-d array | 1 | 3 | +// +---+----+ +// complex N-d array | 2 | 4 | +// +---+----+ + +NDArray +x_el_div (double a, const NDArray& b) +{ + NDArray result (b.dims ()); + + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + result (i) = a / b (i); + } + + return result; +} + +ComplexNDArray +x_el_div (double a, const ComplexNDArray& b) +{ + ComplexNDArray result (b.dims ()); + + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + result (i) = a / b (i); + } + + return result; +} + +ComplexNDArray +x_el_div (const Complex a, const NDArray& b) +{ + ComplexNDArray result (b.dims ()); + + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + result (i) = a / b (i); + } + + return result; +} + +ComplexNDArray +x_el_div (const Complex a, const ComplexNDArray& b) +{ + ComplexNDArray result (b.dims ()); + + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + result (i) = a / b (i); + } + + return result; +} + +// Left division functions. +// +// op2 \ op1: m cm +// +-- +---+----+ +// matrix | 1 | 3 | +// +---+----+ +// complex_matrix | 2 | 4 | +// +---+----+ + +// -*- 1 -*- +Matrix +xleftdiv (const Matrix& a, const Matrix& b, MatrixType &typ, blas_trans_type transt) +{ + if (! mx_leftdiv_conform (a, b, transt)) + return Matrix (); + + octave_idx_type info; + double rcond = 0.0; + return a.solve (typ, b, info, rcond, solve_singularity_warning, true, transt); +} + +// -*- 2 -*- +ComplexMatrix +xleftdiv (const Matrix& a, const ComplexMatrix& b, MatrixType &typ, blas_trans_type transt) +{ + if (! mx_leftdiv_conform (a, b, transt)) + return ComplexMatrix (); + + octave_idx_type info; + double rcond = 0.0; + + return a.solve (typ, b, info, rcond, solve_singularity_warning, true, transt); +} + +// -*- 3 -*- +ComplexMatrix +xleftdiv (const ComplexMatrix& a, const Matrix& b, MatrixType &typ, blas_trans_type transt) +{ + if (! mx_leftdiv_conform (a, b, transt)) + return ComplexMatrix (); + + octave_idx_type info; + double rcond = 0.0; + return a.solve (typ, b, info, rcond, solve_singularity_warning, true, transt); +} + +// -*- 4 -*- +ComplexMatrix +xleftdiv (const ComplexMatrix& a, const ComplexMatrix& b, MatrixType &typ, blas_trans_type transt) +{ + if (! mx_leftdiv_conform (a, b, transt)) + return ComplexMatrix (); + + octave_idx_type info; + double rcond = 0.0; + return a.solve (typ, b, info, rcond, solve_singularity_warning, true, transt); +} + +static void +solve_singularity_warning (float rcond) +{ + warning ("matrix singular to machine precision, rcond = %g", rcond); + warning ("attempting to find minimum norm solution"); +} + +INSTANTIATE_MX_LEFTDIV_CONFORM (FloatMatrix, FloatMatrix); +INSTANTIATE_MX_LEFTDIV_CONFORM (FloatMatrix, FloatComplexMatrix); +INSTANTIATE_MX_LEFTDIV_CONFORM (FloatComplexMatrix, FloatMatrix); +INSTANTIATE_MX_LEFTDIV_CONFORM (FloatComplexMatrix, FloatComplexMatrix); + +INSTANTIATE_MX_DIV_CONFORM (FloatMatrix, FloatMatrix); +INSTANTIATE_MX_DIV_CONFORM (FloatMatrix, FloatComplexMatrix); +INSTANTIATE_MX_DIV_CONFORM (FloatComplexMatrix, FloatMatrix); +INSTANTIATE_MX_DIV_CONFORM (FloatComplexMatrix, FloatComplexMatrix); + +// Right division functions. +// +// op2 / op1: m cm +// +-- +---+----+ +// matrix | 1 | 3 | +// +---+----+ +// complex_matrix | 2 | 4 | +// +---+----+ + +// -*- 1 -*- +FloatMatrix +xdiv (const FloatMatrix& a, const FloatMatrix& b, MatrixType &typ) +{ + if (! mx_div_conform (a, b)) + return FloatMatrix (); + + octave_idx_type info; + float rcond = 0.0; + + FloatMatrix result + = b.solve (typ, a.transpose (), info, rcond, + solve_singularity_warning, true, blas_trans); + + return result.transpose (); +} + +// -*- 2 -*- +FloatComplexMatrix +xdiv (const FloatMatrix& a, const FloatComplexMatrix& b, MatrixType &typ) +{ + if (! mx_div_conform (a, b)) + return FloatComplexMatrix (); + + octave_idx_type info; + float rcond = 0.0; + + FloatComplexMatrix result + = b.solve (typ, a.transpose (), info, rcond, + solve_singularity_warning, true, blas_trans); + + return result.transpose (); +} + +// -*- 3 -*- +FloatComplexMatrix +xdiv (const FloatComplexMatrix& a, const FloatMatrix& b, MatrixType &typ) +{ + if (! mx_div_conform (a, b)) + return FloatComplexMatrix (); + + octave_idx_type info; + float rcond = 0.0; + + FloatComplexMatrix result + = b.solve (typ, a.transpose (), info, rcond, + solve_singularity_warning, true, blas_trans); + + return result.transpose (); +} + +// -*- 4 -*- +FloatComplexMatrix +xdiv (const FloatComplexMatrix& a, const FloatComplexMatrix& b, MatrixType &typ) +{ + if (! mx_div_conform (a, b)) + return FloatComplexMatrix (); + + octave_idx_type info; + float rcond = 0.0; + + FloatComplexMatrix result + = b.solve (typ, a.transpose (), info, rcond, + solve_singularity_warning, true, blas_trans); + + return result.transpose (); +} + +// Funny element by element division operations. +// +// op2 \ op1: s cs +// +-- +---+----+ +// matrix | 1 | 3 | +// +---+----+ +// complex_matrix | 2 | 4 | +// +---+----+ + +FloatMatrix +x_el_div (float a, const FloatMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.columns (); + + FloatMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = a / b (i, j); + } + + return result; +} + +FloatComplexMatrix +x_el_div (float a, const FloatComplexMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.columns (); + + FloatComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = a / b (i, j); + } + + return result; +} + +FloatComplexMatrix +x_el_div (const FloatComplex a, const FloatMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.columns (); + + FloatComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = a / b (i, j); + } + + return result; +} + +FloatComplexMatrix +x_el_div (const FloatComplex a, const FloatComplexMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.columns (); + + FloatComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = a / b (i, j); + } + + return result; +} + +// Funny element by element division operations. +// +// op2 \ op1: s cs +// +-- +---+----+ +// N-d array | 1 | 3 | +// +---+----+ +// complex N-d array | 2 | 4 | +// +---+----+ + +FloatNDArray +x_el_div (float a, const FloatNDArray& b) +{ + FloatNDArray result (b.dims ()); + + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + result (i) = a / b (i); + } + + return result; +} + +FloatComplexNDArray +x_el_div (float a, const FloatComplexNDArray& b) +{ + FloatComplexNDArray result (b.dims ()); + + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + result (i) = a / b (i); + } + + return result; +} + +FloatComplexNDArray +x_el_div (const FloatComplex a, const FloatNDArray& b) +{ + FloatComplexNDArray result (b.dims ()); + + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + result (i) = a / b (i); + } + + return result; +} + +FloatComplexNDArray +x_el_div (const FloatComplex a, const FloatComplexNDArray& b) +{ + FloatComplexNDArray result (b.dims ()); + + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + result (i) = a / b (i); + } + + return result; +} + +// Left division functions. +// +// op2 \ op1: m cm +// +-- +---+----+ +// matrix | 1 | 3 | +// +---+----+ +// complex_matrix | 2 | 4 | +// +---+----+ + +// -*- 1 -*- +FloatMatrix +xleftdiv (const FloatMatrix& a, const FloatMatrix& b, MatrixType &typ, blas_trans_type transt) +{ + if (! mx_leftdiv_conform (a, b, transt)) + return FloatMatrix (); + + octave_idx_type info; + float rcond = 0.0; + return a.solve (typ, b, info, rcond, solve_singularity_warning, true, transt); +} + +// -*- 2 -*- +FloatComplexMatrix +xleftdiv (const FloatMatrix& a, const FloatComplexMatrix& b, MatrixType &typ, blas_trans_type transt) +{ + if (! mx_leftdiv_conform (a, b, transt)) + return FloatComplexMatrix (); + + octave_idx_type info; + float rcond = 0.0; + + return a.solve (typ, b, info, rcond, solve_singularity_warning, true, transt); +} + +// -*- 3 -*- +FloatComplexMatrix +xleftdiv (const FloatComplexMatrix& a, const FloatMatrix& b, MatrixType &typ, blas_trans_type transt) +{ + if (! mx_leftdiv_conform (a, b, transt)) + return FloatComplexMatrix (); + + octave_idx_type info; + float rcond = 0.0; + return a.solve (typ, b, info, rcond, solve_singularity_warning, true, transt); +} + +// -*- 4 -*- +FloatComplexMatrix +xleftdiv (const FloatComplexMatrix& a, const FloatComplexMatrix& b, MatrixType &typ, blas_trans_type transt) +{ + if (! mx_leftdiv_conform (a, b, transt)) + return FloatComplexMatrix (); + + octave_idx_type info; + float rcond = 0.0; + return a.solve (typ, b, info, rcond, solve_singularity_warning, true, transt); +} + +// Diagonal matrix division. + +template +MT +mdm_div_impl (const MT& a, const DMT& d) +{ + if (! mx_div_conform (a, d)) + return MT (); + + octave_idx_type m = a.rows (), n = d.rows (), l = d.length (); + MT x (m, n); + typedef typename DMT::element_type S; + typedef typename MT::element_type T; + const T *aa = a.data (); + const S *dd = d.data (); + T *xx = x.fortran_vec (); + + for (octave_idx_type j = 0; j < l; j++) + { + const S del = dd[j]; + if (del != S ()) + for (octave_idx_type i = 0; i < m; i++) + xx[i] = aa[i] / del; + else + for (octave_idx_type i = 0; i < m; i++) + xx[i] = T (); + aa += m; xx += m; + } + + for (octave_idx_type i = l*m; i < n*m; i++) + xx[i] = T (); + + return x; +} + +// Right division functions. +// +// op2 / op1: dm cdm +// +-- +---+----+ +// matrix | 1 | | +// +---+----+ +// complex_matrix | 2 | 3 | +// +---+----+ + +// -*- 1 -*- +Matrix +xdiv (const Matrix& a, const DiagMatrix& b) +{ return mdm_div_impl (a, b); } + +// -*- 2 -*- +ComplexMatrix +xdiv (const ComplexMatrix& a, const DiagMatrix& b) +{ return mdm_div_impl (a, b); } + +// -*- 3 -*- +ComplexMatrix +xdiv (const ComplexMatrix& a, const ComplexDiagMatrix& b) +{ return mdm_div_impl (a, b); } + +// Right division functions, float type. +// +// op2 / op1: dm cdm +// +-- +---+----+ +// matrix | 1 | | +// +---+----+ +// complex_matrix | 2 | 3 | +// +---+----+ + +// -*- 1 -*- +FloatMatrix +xdiv (const FloatMatrix& a, const FloatDiagMatrix& b) +{ return mdm_div_impl (a, b); } + +// -*- 2 -*- +FloatComplexMatrix +xdiv (const FloatComplexMatrix& a, const FloatDiagMatrix& b) +{ return mdm_div_impl (a, b); } + +// -*- 3 -*- +FloatComplexMatrix +xdiv (const FloatComplexMatrix& a, const FloatComplexDiagMatrix& b) +{ return mdm_div_impl (a, b); } + +template +MT +dmm_leftdiv_impl (const DMT& d, const MT& 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 (); + MT x (m, n); + typedef typename DMT::element_type S; + typedef typename MT::element_type T; + const T *aa = a.data (); + const S *dd = d.data (); + T *xx = x.fortran_vec (); + + for (octave_idx_type j = 0; j < n; j++) + { + for (octave_idx_type i = 0; i < l; i++) + xx[i] = dd[i] != S () ? aa[i] / dd[i] : T (); + for (octave_idx_type i = l; i < m; i++) + xx[i] = T (); + aa += k; xx += m; + } + + return x; +} + +// Left division functions. +// +// op2 \ op1: m cm +// +---+----+ +// diag_matrix | 1 | 2 | +// +---+----+ +// complex_diag_matrix | | 3 | +// +---+----+ + +// -*- 1 -*- +Matrix +xleftdiv (const DiagMatrix& a, const Matrix& b) +{ return dmm_leftdiv_impl (a, b); } + +// -*- 2 -*- +ComplexMatrix +xleftdiv (const DiagMatrix& a, const ComplexMatrix& b) +{ return dmm_leftdiv_impl (a, b); } + +// -*- 3 -*- +ComplexMatrix +xleftdiv (const ComplexDiagMatrix& a, const ComplexMatrix& b) +{ return dmm_leftdiv_impl (a, b); } + +// Left division functions, float type. +// +// op2 \ op1: m cm +// +---+----+ +// diag_matrix | 1 | 2 | +// +---+----+ +// complex_diag_matrix | | 3 | +// +---+----+ + +// -*- 1 -*- +FloatMatrix +xleftdiv (const FloatDiagMatrix& a, const FloatMatrix& b) +{ return dmm_leftdiv_impl (a, b); } + +// -*- 2 -*- +FloatComplexMatrix +xleftdiv (const FloatDiagMatrix& a, const FloatComplexMatrix& b) +{ return dmm_leftdiv_impl (a, b); } + +// -*- 3 -*- +FloatComplexMatrix +xleftdiv (const FloatComplexDiagMatrix& a, const FloatComplexMatrix& b) +{ return dmm_leftdiv_impl (a, b); } + +// Diagonal by diagonal matrix division. + +template +MT +dmdm_div_impl (const MT& a, const DMT& d) +{ + if (! mx_div_conform (a, d)) + return MT (); + + octave_idx_type m = a.rows (), n = d.rows (), k = d.cols (); + octave_idx_type l = std::min (m, n), lk = std::min (l, k); + MT x (m, n); + typedef typename DMT::element_type S; + typedef typename MT::element_type T; + const T *aa = a.data (); + const S *dd = d.data (); + T *xx = x.fortran_vec (); + + for (octave_idx_type i = 0; i < lk; i++) + xx[i] = dd[i] != S () ? aa[i] / dd[i] : T (); + for (octave_idx_type i = lk; i < l; i++) + xx[i] = T (); + + return x; +} + +// Right division functions. +// +// op2 / op1: dm cdm +// +-- +---+----+ +// diag_matrix | 1 | | +// +---+----+ +// complex_diag_matrix | 2 | 3 | +// +---+----+ + +// -*- 1 -*- +DiagMatrix +xdiv (const DiagMatrix& a, const DiagMatrix& b) +{ return dmdm_div_impl (a, b); } + +// -*- 2 -*- +ComplexDiagMatrix +xdiv (const ComplexDiagMatrix& a, const DiagMatrix& b) +{ return dmdm_div_impl (a, b); } + +// -*- 3 -*- +ComplexDiagMatrix +xdiv (const ComplexDiagMatrix& a, const ComplexDiagMatrix& b) +{ return dmdm_div_impl (a, b); } + +// Right division functions, float type. +// +// op2 / op1: dm cdm +// +-- +---+----+ +// diag_matrix | 1 | | +// +---+----+ +// complex_diag_matrix | 2 | 3 | +// +---+----+ + +// -*- 1 -*- +FloatDiagMatrix +xdiv (const FloatDiagMatrix& a, const FloatDiagMatrix& b) +{ return dmdm_div_impl (a, b); } + +// -*- 2 -*- +FloatComplexDiagMatrix +xdiv (const FloatComplexDiagMatrix& a, const FloatDiagMatrix& b) +{ return dmdm_div_impl (a, b); } + +// -*- 3 -*- +FloatComplexDiagMatrix +xdiv (const FloatComplexDiagMatrix& a, const FloatComplexDiagMatrix& b) +{ return dmdm_div_impl (a, b); } + +template +MT +dmdm_leftdiv_impl (const DMT& d, const MT& a) +{ + if (! mx_leftdiv_conform (d, a, blas_no_trans)) + return MT (); + + octave_idx_type m = d.cols (), n = a.cols (), k = d.rows (); + octave_idx_type l = std::min (m, n), lk = std::min (l, k); + MT x (m, n); + typedef typename DMT::element_type S; + typedef typename MT::element_type T; + const T *aa = a.data (); + const S *dd = d.data (); + T *xx = x.fortran_vec (); + + for (octave_idx_type i = 0; i < lk; i++) + xx[i] = dd[i] != S () ? aa[i] / dd[i] : T (); + for (octave_idx_type i = lk; i < l; i++) + xx[i] = T (); + + return x; +} + +// Left division functions. +// +// op2 \ op1: dm cdm +// +---+----+ +// diag_matrix | 1 | 2 | +// +---+----+ +// complex_diag_matrix | | 3 | +// +---+----+ + +// -*- 1 -*- +DiagMatrix +xleftdiv (const DiagMatrix& a, const DiagMatrix& b) +{ return dmdm_leftdiv_impl (a, b); } + +// -*- 2 -*- +ComplexDiagMatrix +xleftdiv (const DiagMatrix& a, const ComplexDiagMatrix& b) +{ return dmdm_leftdiv_impl (a, b); } + +// -*- 3 -*- +ComplexDiagMatrix +xleftdiv (const ComplexDiagMatrix& a, const ComplexDiagMatrix& b) +{ return dmdm_leftdiv_impl (a, b); } + +// Left division functions, float type. +// +// op2 \ op1: dm cdm +// +---+----+ +// diag_matrix | 1 | 2 | +// +---+----+ +// complex_diag_matrix | | 3 | +// +---+----+ + +// -*- 1 -*- +FloatDiagMatrix +xleftdiv (const FloatDiagMatrix& a, const FloatDiagMatrix& b) +{ return dmdm_leftdiv_impl (a, b); } + +// -*- 2 -*- +FloatComplexDiagMatrix +xleftdiv (const FloatDiagMatrix& a, const FloatComplexDiagMatrix& b) +{ return dmdm_leftdiv_impl (a, b); } + +// -*- 3 -*- +FloatComplexDiagMatrix +xleftdiv (const FloatComplexDiagMatrix& a, const FloatComplexDiagMatrix& b) +{ return dmdm_leftdiv_impl (a, b); } diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/xdiv.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/xdiv.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,129 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton +Copyright (C) 2008 Jaroslav Hajek + +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 (octave_xdiv_h) +#define octave_xdiv_h 1 + +#include "mx-defs.h" +#include "MatrixType.h" + +extern Matrix xdiv (const Matrix& a, const Matrix& b, MatrixType &typ); +extern ComplexMatrix xdiv (const Matrix& a, const ComplexMatrix& b, + MatrixType &typ); +extern ComplexMatrix xdiv (const ComplexMatrix& a, const Matrix& b, + MatrixType &typ); +extern ComplexMatrix xdiv (const ComplexMatrix& a, const ComplexMatrix& b, + MatrixType &typ); + +extern Matrix x_el_div (double a, const Matrix& b); +extern ComplexMatrix x_el_div (double a, const ComplexMatrix& b); +extern ComplexMatrix x_el_div (const Complex a, const Matrix& b); +extern ComplexMatrix x_el_div (const Complex a, const ComplexMatrix& b); + +extern NDArray x_el_div (double a, const NDArray& b); +extern ComplexNDArray x_el_div (double a, const ComplexNDArray& b); +extern ComplexNDArray x_el_div (const Complex a, const NDArray& b); +extern ComplexNDArray x_el_div (const Complex a, const ComplexNDArray& b); + +extern Matrix xleftdiv (const Matrix& a, const Matrix& b, MatrixType &typ, + blas_trans_type transt = blas_no_trans); +extern ComplexMatrix xleftdiv (const Matrix& a, const ComplexMatrix& b, + MatrixType &typ, blas_trans_type transt = blas_no_trans); +extern ComplexMatrix xleftdiv (const ComplexMatrix& a, const Matrix& b, + MatrixType &typ, blas_trans_type transt = blas_no_trans); +extern ComplexMatrix xleftdiv (const ComplexMatrix& a, const ComplexMatrix& b, + MatrixType &typ, blas_trans_type transt = blas_no_trans); + +extern FloatMatrix xdiv (const FloatMatrix& a, const FloatMatrix& b, MatrixType &typ); +extern FloatComplexMatrix xdiv (const FloatMatrix& a, const FloatComplexMatrix& b, + MatrixType &typ); +extern FloatComplexMatrix xdiv (const FloatComplexMatrix& a, const FloatMatrix& b, + MatrixType &typ); +extern FloatComplexMatrix xdiv (const FloatComplexMatrix& a, const FloatComplexMatrix& b, + MatrixType &typ); + +extern FloatMatrix x_el_div (float a, const FloatMatrix& b); +extern FloatComplexMatrix x_el_div (float a, const FloatComplexMatrix& b); +extern FloatComplexMatrix x_el_div (const FloatComplex a, const FloatMatrix& b); +extern FloatComplexMatrix x_el_div (const FloatComplex a, const FloatComplexMatrix& b); + +extern FloatNDArray x_el_div (float a, const FloatNDArray& b); +extern FloatComplexNDArray x_el_div (float a, const FloatComplexNDArray& b); +extern FloatComplexNDArray x_el_div (const FloatComplex a, const FloatNDArray& b); +extern FloatComplexNDArray x_el_div (const FloatComplex a, const FloatComplexNDArray& b); + +extern FloatMatrix xleftdiv (const FloatMatrix& a, const FloatMatrix& b, MatrixType &typ, + blas_trans_type transt = blas_no_trans); +extern FloatComplexMatrix xleftdiv (const FloatMatrix& a, const FloatComplexMatrix& b, + MatrixType &typ, blas_trans_type transt = blas_no_trans); +extern FloatComplexMatrix xleftdiv (const FloatComplexMatrix& a, const FloatMatrix& b, + MatrixType &typ, blas_trans_type transt = blas_no_trans); +extern FloatComplexMatrix xleftdiv (const FloatComplexMatrix& a, const FloatComplexMatrix& b, + MatrixType &typ, blas_trans_type transt = blas_no_trans); + + +extern Matrix xdiv (const Matrix& a, const DiagMatrix& b); +extern ComplexMatrix xdiv (const ComplexMatrix& a, const DiagMatrix& b); +extern ComplexMatrix xdiv (const ComplexMatrix& a, const ComplexDiagMatrix& b); + +extern DiagMatrix xdiv (const DiagMatrix& a, const DiagMatrix& b); +extern ComplexDiagMatrix xdiv (const ComplexDiagMatrix& a, const DiagMatrix& b); +extern ComplexDiagMatrix xdiv (const ComplexDiagMatrix& a, const ComplexDiagMatrix& b); + +extern FloatMatrix xdiv (const FloatMatrix& a, const FloatDiagMatrix& b); +extern FloatComplexMatrix xdiv (const FloatComplexMatrix& a, + const FloatDiagMatrix& b); +extern FloatComplexMatrix xdiv (const FloatMatrix& a, + const FloatComplexDiagMatrix& b); +extern FloatComplexMatrix xdiv (const FloatComplexMatrix& a, + const FloatComplexDiagMatrix& b); + +extern FloatDiagMatrix xdiv (const FloatDiagMatrix& a, const FloatDiagMatrix& b); +extern FloatComplexDiagMatrix xdiv (const FloatComplexDiagMatrix& a, + const FloatDiagMatrix& b); +extern FloatComplexDiagMatrix xdiv (const FloatComplexDiagMatrix& a, + const FloatComplexDiagMatrix& b); + +extern Matrix xleftdiv (const DiagMatrix& a, const Matrix& b); +extern ComplexMatrix xleftdiv (const DiagMatrix& a, const ComplexMatrix& b); +extern ComplexMatrix xleftdiv (const ComplexDiagMatrix& a, const ComplexMatrix& b); + +extern DiagMatrix xleftdiv (const DiagMatrix& a, const DiagMatrix& b); +extern ComplexDiagMatrix xleftdiv (const DiagMatrix& a, const ComplexDiagMatrix& b); +extern ComplexDiagMatrix xleftdiv (const ComplexDiagMatrix& a, const ComplexDiagMatrix& b); + +extern FloatMatrix xleftdiv (const FloatDiagMatrix& a, + const FloatMatrix& b); +extern FloatComplexMatrix xleftdiv (const FloatDiagMatrix& a, + const FloatComplexMatrix& b); +extern FloatComplexMatrix xleftdiv (const FloatComplexDiagMatrix& a, + const FloatComplexMatrix& b); + +extern FloatDiagMatrix xleftdiv (const FloatDiagMatrix& a, + const FloatDiagMatrix& b); +extern FloatComplexDiagMatrix xleftdiv (const FloatDiagMatrix& a, + const FloatComplexDiagMatrix& b); +extern FloatComplexDiagMatrix xleftdiv (const FloatComplexDiagMatrix& a, + const FloatComplexDiagMatrix& b); + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/xgl2ps.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/xgl2ps.c Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,34 @@ +/* + +Copyright (C) 2009-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +// Wrapper for "imported" file gl2ps.c so that config.h will be included +// before any other system or gnulib headers. + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined (HAVE_OPENGL) + +#include "gl2ps.c" + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/xnorm.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/xnorm.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,212 @@ +/* + +Copyright (C) 2008-2012 VZLU Prague, a.s. + +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 +. + +*/ + +// author: Jaroslav Hajek + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "oct-norm.h" + +#include "error.h" +#include "xnorm.h" +#include "ov.h" +#include "gripes.h" + +octave_value xnorm (const octave_value& x, const octave_value& p) +{ + octave_value retval; + + bool isvector = (x.columns () == 1 || x.rows () == 1); + bool iscomplex = x.is_complex_type (); + bool issparse = x.is_sparse_type (); + bool isfloat = x.is_single_type (); + + if (isfloat || x.is_double_type ()) + { + if (isvector) + { + if (isfloat & iscomplex) + retval = xnorm (x.float_complex_column_vector_value (), + p.float_value ()); + else if (isfloat) + retval = xnorm (x.float_column_vector_value (), + p.float_value ()); + else if (iscomplex) + retval = xnorm (x.complex_column_vector_value (), + p.double_value ()); + else + retval = xnorm (x.column_vector_value (), + p.double_value ()); + } + else if (issparse) + { + if (iscomplex) + retval = xnorm (x.sparse_complex_matrix_value (), + p.double_value ()); + else + retval = xnorm (x.sparse_matrix_value (), + p.double_value ()); + } + else + { + if (isfloat & iscomplex) + retval = xnorm (x.float_complex_matrix_value (), + p.float_value ()); + else if (isfloat) + retval = xnorm (x.float_matrix_value (), + p.float_value ()); + else if (iscomplex) + retval = xnorm (x.complex_matrix_value (), + p.double_value ()); + else + retval = xnorm (x.matrix_value (), + p.double_value ()); + } + } + else + gripe_wrong_type_arg ("xnorm", x, true); + + return retval; +} + +octave_value xcolnorms (const octave_value& x, const octave_value& p) +{ + octave_value retval; + + bool iscomplex = x.is_complex_type (); + bool issparse = x.is_sparse_type (); + bool isfloat = x.is_single_type (); + + if (isfloat || x.is_double_type ()) + { + if (issparse) + { + if (iscomplex) + retval = xcolnorms (x.sparse_complex_matrix_value (), + p.double_value ()); + else + retval = xcolnorms (x.sparse_matrix_value (), + p.double_value ()); + } + else + { + if (isfloat & iscomplex) + retval = xcolnorms (x.float_complex_matrix_value (), + p.float_value ()); + else if (isfloat) + retval = xcolnorms (x.float_matrix_value (), + p.float_value ()); + else if (iscomplex) + retval = xcolnorms (x.complex_matrix_value (), + p.double_value ()); + else + retval = xcolnorms (x.matrix_value (), + p.double_value ()); + } + } + else + gripe_wrong_type_arg ("xcolnorms", x, true); + + return retval; +} + +octave_value xrownorms (const octave_value& x, const octave_value& p) +{ + octave_value retval; + + bool iscomplex = x.is_complex_type (); + bool issparse = x.is_sparse_type (); + bool isfloat = x.is_single_type (); + + if (isfloat || x.is_double_type ()) + { + if (issparse) + { + if (iscomplex) + retval = xrownorms (x.sparse_complex_matrix_value (), + p.double_value ()); + else + retval = xrownorms (x.sparse_matrix_value (), + p.double_value ()); + } + else + { + if (isfloat & iscomplex) + retval = xrownorms (x.float_complex_matrix_value (), + p.float_value ()); + else if (isfloat) + retval = xrownorms (x.float_matrix_value (), + p.float_value ()); + else if (iscomplex) + retval = xrownorms (x.complex_matrix_value (), + p.double_value ()); + else + retval = xrownorms (x.matrix_value (), + p.double_value ()); + } + } + else + gripe_wrong_type_arg ("xrownorms", x, true); + + return retval; +} + +octave_value xfrobnorm (const octave_value& x) +{ + octave_value retval; + + bool iscomplex = x.is_complex_type (); + bool issparse = x.is_sparse_type (); + bool isfloat = x.is_single_type (); + + if (isfloat || x.is_double_type ()) + { + if (issparse) + { + if (iscomplex) + retval = xfrobnorm (x.sparse_complex_matrix_value ()); + else + retval = xfrobnorm (x.sparse_matrix_value ()); + } + else + { + if (isfloat & iscomplex) + retval = xfrobnorm (x.float_complex_matrix_value ()); + else if (isfloat) + retval = xfrobnorm (x.float_matrix_value ()); + else if (iscomplex) + retval = xfrobnorm (x.complex_matrix_value ()); + else + retval = xfrobnorm (x.matrix_value ()); + } + } + else + gripe_wrong_type_arg ("xfrobnorm", x, true); + + return retval; +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/xnorm.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/xnorm.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,37 @@ +/* + +Copyright (C) 2008-2012 VZLU Prague, a.s. + +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 +. + +*/ + +// author: Jaroslav Hajek + +#if !defined (octave_xnorm_h) +#define octave_xnorm_h 1 + +#include "oct-norm.h" + +class octave_value; + +extern OCTINTERP_API octave_value xnorm (const octave_value& x, const octave_value& p); +extern OCTINTERP_API octave_value xcolnorms (const octave_value& x, const octave_value& p); +extern OCTINTERP_API octave_value xrownorms (const octave_value& x, const octave_value& p); +extern OCTINTERP_API octave_value xfrobnorm (const octave_value& x); + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/xpow.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/xpow.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,2858 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton +Copyright (C) 2009-2010 VZLU Prague + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "Array-util.h" +#include "CColVector.h" +#include "CDiagMatrix.h" +#include "fCDiagMatrix.h" +#include "CMatrix.h" +#include "EIG.h" +#include "fEIG.h" +#include "dDiagMatrix.h" +#include "fDiagMatrix.h" +#include "dMatrix.h" +#include "PermMatrix.h" +#include "mx-cm-cdm.h" +#include "oct-cmplx.h" +#include "Range.h" +#include "quit.h" + +#include "error.h" +#include "oct-obj.h" +#include "utils.h" +#include "xpow.h" + +#include "bsxfun.h" + +#ifdef _OPENMP +#include +#endif + +static inline int +xisint (double x) +{ + return (D_NINT (x) == x + && ((x >= 0 && x < INT_MAX) + || (x <= 0 && x > INT_MIN))); +} + +// Safer pow functions. +// +// op2 \ op1: s m cs cm +// +-- +---+---+----+----+ +// scalar | | 1 | 5 | 7 | 11 | +// +---+---+----+----+ +// matrix | 2 | * | 8 | * | +// +---+---+----+----+ +// complex_scalar | 3 | 6 | 9 | 12 | +// +---+---+----+----+ +// complex_matrix | 4 | * | 10 | * | +// +---+---+----+----+ + +// -*- 1 -*- +octave_value +xpow (double a, double b) +{ + double retval; + + if (a < 0.0 && ! xisint (b)) + { + Complex atmp (a); + + return std::pow (atmp, b); + } + else + retval = std::pow (a, b); + + return retval; +} + +// -*- 2 -*- +octave_value +xpow (double a, const Matrix& b) +{ + octave_value retval; + + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for x^A, A must be a square matrix"); + else + { + EIG b_eig (b); + + if (! error_state) + { + ComplexColumnVector lambda (b_eig.eigenvalues ()); + ComplexMatrix Q (b_eig.eigenvectors ()); + + for (octave_idx_type i = 0; i < nr; i++) + { + Complex elt = lambda(i); + if (std::imag (elt) == 0.0) + lambda(i) = std::pow (a, std::real (elt)); + else + lambda(i) = std::pow (a, elt); + } + ComplexDiagMatrix D (lambda); + + ComplexMatrix C = Q * D * Q.inverse (); + if (a > 0) + retval = real (C); + else + retval = C; + } + else + error ("xpow: matrix diagonalization failed"); + } + + return retval; +} + +// -*- 3 -*- +octave_value +xpow (double a, const Complex& b) +{ + Complex result = std::pow (a, b); + return result; +} + +// -*- 4 -*- +octave_value +xpow (double a, const ComplexMatrix& b) +{ + octave_value retval; + + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for x^A, A must be a square matrix"); + else + { + EIG b_eig (b); + + if (! error_state) + { + ComplexColumnVector lambda (b_eig.eigenvalues ()); + ComplexMatrix Q (b_eig.eigenvectors ()); + + for (octave_idx_type i = 0; i < nr; i++) + { + Complex elt = lambda(i); + if (std::imag (elt) == 0.0) + lambda(i) = std::pow (a, std::real (elt)); + else + lambda(i) = std::pow (a, elt); + } + ComplexDiagMatrix D (lambda); + + retval = ComplexMatrix (Q * D * Q.inverse ()); + } + else + error ("xpow: matrix diagonalization failed"); + } + + return retval; +} + +// -*- 5 -*- +octave_value +xpow (const Matrix& a, double b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for A^b, A must be a square matrix"); + else + { + if (static_cast (b) == b) + { + int btmp = static_cast (b); + if (btmp == 0) + { + retval = DiagMatrix (nr, nr, 1.0); + } + else + { + // Too much copying? + // FIXME -- we shouldn't do this if the exponent is + // large... + + Matrix atmp; + if (btmp < 0) + { + btmp = -btmp; + + octave_idx_type info; + double rcond = 0.0; + MatrixType mattype (a); + + atmp = a.inverse (mattype, info, rcond, 1); + + if (info == -1) + warning ("inverse: matrix singular to machine\ + precision, rcond = %g", rcond); + } + else + atmp = a; + + Matrix result (atmp); + + btmp--; + + while (btmp > 0) + { + if (btmp & 1) + result = result * atmp; + + btmp >>= 1; + + if (btmp > 0) + atmp = atmp * atmp; + } + + retval = result; + } + } + else + { + EIG a_eig (a); + + if (! error_state) + { + ComplexColumnVector lambda (a_eig.eigenvalues ()); + ComplexMatrix Q (a_eig.eigenvectors ()); + + for (octave_idx_type i = 0; i < nr; i++) + lambda(i) = std::pow (lambda(i), b); + + ComplexDiagMatrix D (lambda); + + retval = ComplexMatrix (Q * D * Q.inverse ()); + } + else + error ("xpow: matrix diagonalization failed"); + } + } + + return retval; +} + +// -*- 5d -*- +octave_value +xpow (const DiagMatrix& a, double b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for A^b, A must be a square matrix"); + else + { + if (static_cast (b) == b) + { + DiagMatrix r (nr, nc); + for (octave_idx_type i = 0; i < nc; i++) + r.dgelem (i) = std::pow (a.dgelem (i), b); + retval = r; + } + else + { + ComplexDiagMatrix r (nr, nc); + for (octave_idx_type i = 0; i < nc; i++) + r.dgelem (i) = std::pow (static_cast (a.dgelem (i)), b); + retval = r; + } + } + + return retval; +} + +// -*- 5p -*- +octave_value +xpow (const PermMatrix& a, double b) +{ + octave_value retval; + int btmp = static_cast (b); + if (btmp == b) + return a.power (btmp); + else + return xpow (Matrix (a), b); +} + +// -*- 6 -*- +octave_value +xpow (const Matrix& a, const Complex& b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for A^b, A must be a square matrix"); + else + { + EIG a_eig (a); + + if (! error_state) + { + ComplexColumnVector lambda (a_eig.eigenvalues ()); + ComplexMatrix Q (a_eig.eigenvectors ()); + + for (octave_idx_type i = 0; i < nr; i++) + lambda(i) = std::pow (lambda(i), b); + + ComplexDiagMatrix D (lambda); + + retval = ComplexMatrix (Q * D * Q.inverse ()); + } + else + error ("xpow: matrix diagonalization failed"); + } + + return retval; +} + +// -*- 7 -*- +octave_value +xpow (const Complex& a, double b) +{ + Complex result; + + if (xisint (b)) + result = std::pow (a, static_cast (b)); + else + result = std::pow (a, b); + + return result; +} + +// -*- 8 -*- +octave_value +xpow (const Complex& a, const Matrix& b) +{ + octave_value retval; + + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for x^A, A must be a square matrix"); + else + { + EIG b_eig (b); + + if (! error_state) + { + ComplexColumnVector lambda (b_eig.eigenvalues ()); + ComplexMatrix Q (b_eig.eigenvectors ()); + + for (octave_idx_type i = 0; i < nr; i++) + { + Complex elt = lambda(i); + if (std::imag (elt) == 0.0) + lambda(i) = std::pow (a, std::real (elt)); + else + lambda(i) = std::pow (a, elt); + } + ComplexDiagMatrix D (lambda); + + retval = ComplexMatrix (Q * D * Q.inverse ()); + } + else + error ("xpow: matrix diagonalization failed"); + } + + return retval; +} + +// -*- 9 -*- +octave_value +xpow (const Complex& a, const Complex& b) +{ + Complex result; + result = std::pow (a, b); + return result; +} + +// -*- 10 -*- +octave_value +xpow (const Complex& a, const ComplexMatrix& b) +{ + octave_value retval; + + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for x^A, A must be a square matrix"); + else + { + EIG b_eig (b); + + if (! error_state) + { + ComplexColumnVector lambda (b_eig.eigenvalues ()); + ComplexMatrix Q (b_eig.eigenvectors ()); + + for (octave_idx_type i = 0; i < nr; i++) + { + Complex elt = lambda(i); + if (std::imag (elt) == 0.0) + lambda(i) = std::pow (a, std::real (elt)); + else + lambda(i) = std::pow (a, elt); + } + ComplexDiagMatrix D (lambda); + + retval = ComplexMatrix (Q * D * Q.inverse ()); + } + else + error ("xpow: matrix diagonalization failed"); + } + + return retval; +} + +// -*- 11 -*- +octave_value +xpow (const ComplexMatrix& a, double b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for A^b, A must be a square matrix"); + else + { + if (static_cast (b) == b) + { + int btmp = static_cast (b); + if (btmp == 0) + { + retval = DiagMatrix (nr, nr, 1.0); + } + else + { + // Too much copying? + // FIXME -- we shouldn't do this if the exponent is + // large... + + ComplexMatrix atmp; + if (btmp < 0) + { + btmp = -btmp; + + octave_idx_type info; + double rcond = 0.0; + MatrixType mattype (a); + + atmp = a.inverse (mattype, info, rcond, 1); + + if (info == -1) + warning ("inverse: matrix singular to machine\ + precision, rcond = %g", rcond); + } + else + atmp = a; + + ComplexMatrix result (atmp); + + btmp--; + + while (btmp > 0) + { + if (btmp & 1) + result = result * atmp; + + btmp >>= 1; + + if (btmp > 0) + atmp = atmp * atmp; + } + + retval = result; + } + } + else + { + EIG a_eig (a); + + if (! error_state) + { + ComplexColumnVector lambda (a_eig.eigenvalues ()); + ComplexMatrix Q (a_eig.eigenvectors ()); + + for (octave_idx_type i = 0; i < nr; i++) + lambda(i) = std::pow (lambda(i), b); + + ComplexDiagMatrix D (lambda); + + retval = ComplexMatrix (Q * D * Q.inverse ()); + } + else + error ("xpow: matrix diagonalization failed"); + } + } + + return retval; +} + +// -*- 12 -*- +octave_value +xpow (const ComplexMatrix& a, const Complex& b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for A^b, A must be a square matrix"); + else + { + EIG a_eig (a); + + if (! error_state) + { + ComplexColumnVector lambda (a_eig.eigenvalues ()); + ComplexMatrix Q (a_eig.eigenvectors ()); + + for (octave_idx_type i = 0; i < nr; i++) + lambda(i) = std::pow (lambda(i), b); + + ComplexDiagMatrix D (lambda); + + retval = ComplexMatrix (Q * D * Q.inverse ()); + } + else + error ("xpow: matrix diagonalization failed"); + } + + return retval; +} + +// -*- 12d -*- +octave_value +xpow (const ComplexDiagMatrix& a, const Complex& b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for A^b, A must be a square matrix"); + else + { + ComplexDiagMatrix r (nr, nc); + for (octave_idx_type i = 0; i < nc; i++) + r(i, i) = std::pow (a(i, i), b); + retval = r; + } + + return retval; +} + +// mixed +octave_value +xpow (const ComplexDiagMatrix& a, double b) +{ + return xpow (a, static_cast (b)); +} + +octave_value +xpow (const DiagMatrix& a, const Complex& b) +{ + return xpow (ComplexDiagMatrix (a), b); +} + + +// Safer pow functions that work elementwise for matrices. +// +// op2 \ op1: s m cs cm +// +-- +---+---+----+----+ +// scalar | | * | 3 | * | 9 | +// +---+---+----+----+ +// matrix | 1 | 4 | 7 | 10 | +// +---+---+----+----+ +// complex_scalar | * | 5 | * | 11 | +// +---+---+----+----+ +// complex_matrix | 2 | 6 | 8 | 12 | +// +---+---+----+----+ +// +// * -> not needed. + +// FIXME -- these functions need to be fixed so that things +// like +// +// a = -1; b = [ 0, 0.5, 1 ]; r = a .^ b +// +// and +// +// a = -1; b = [ 0, 0.5, 1 ]; for i = 1:3, r(i) = a .^ b(i), end +// +// produce identical results. Also, it would be nice if -1^0.5 +// produced a pure imaginary result instead of a complex number with a +// small real part. But perhaps that's really a problem with the math +// library... + +// -*- 1 -*- +octave_value +elem_xpow (double a, const Matrix& b) +{ + octave_value retval; + + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + double d1, d2; + + if (a < 0.0 && ! b.all_integers (d1, d2)) + { + Complex atmp (a); + ComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (atmp, b (i, j)); + } + + retval = result; + } + else + { + Matrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a, b (i, j)); + } + + retval = result; + } + + return retval; +} + +// -*- 2 -*- +octave_value +elem_xpow (double a, const ComplexMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + ComplexMatrix result (nr, nc); + Complex atmp (a); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (atmp, b (i, j)); + } + + return result; +} + +static inline bool +same_sign (double a, double b) +{ + return (a >= 0 && b >= 0) || (a <= 0 && b <= 0); +} + +octave_value +elem_xpow (double a, const Range& r) +{ + octave_value retval; + + // Only optimize powers with ranges that are integer and monotonic in + // magnitude. + if (r.nelem () > 1 && r.all_elements_are_ints () + && same_sign (r.base (), r.limit ())) + { + octave_idx_type n = r.nelem (); + Matrix result (1, n); + if (same_sign (r.base (), r.inc ())) + { + double base = std::pow (a, r.base ()); + double inc = std::pow (a, r.inc ()); + result(0) = base; + for (octave_idx_type i = 1; i < n; i++) + result(i) = (base *= inc); + } + else + { + // Don't use Range::limit () here. + double limit = std::pow (a, r.base () + (n-1) * r.inc ()); + double inc = std::pow (a, -r.inc ()); + result(n-1) = limit; + for (octave_idx_type i = n-2; i >= 0; i--) + result(i) = (limit *= inc); + } + + retval = result; + } + else + retval = elem_xpow (a, r.matrix_value ()); + + return retval; +} + +// -*- 3 -*- +octave_value +elem_xpow (const Matrix& a, double b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (! xisint (b) && a.any_element_is_negative ()) + { + ComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + + Complex atmp (a (i, j)); + + result (i, j) = std::pow (atmp, b); + } + + retval = result; + } + else + { + Matrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a (i, j), b); + } + + retval = result; + } + + return retval; +} + +// -*- 4 -*- +octave_value +elem_xpow (const Matrix& a, const Matrix& b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + octave_idx_type b_nr = b.rows (); + octave_idx_type b_nc = b.cols (); + + if (nr != b_nr || nc != b_nc) + { + gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); + return octave_value (); + } + + int convert_to_complex = 0; + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + double atmp = a (i, j); + double btmp = b (i, j); + if (atmp < 0.0 && static_cast (btmp) != btmp) + { + convert_to_complex = 1; + goto done; + } + } + +done: + + if (convert_to_complex) + { + ComplexMatrix complex_result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + Complex atmp (a (i, j)); + Complex btmp (b (i, j)); + complex_result (i, j) = std::pow (atmp, btmp); + } + + retval = complex_result; + } + else + { + Matrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a (i, j), b (i, j)); + } + + retval = result; + } + + return retval; +} + +// -*- 5 -*- +octave_value +elem_xpow (const Matrix& a, const Complex& b) +{ + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + ComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (Complex (a (i, j)), b); + } + + return result; +} + +// -*- 6 -*- +octave_value +elem_xpow (const Matrix& a, const ComplexMatrix& b) +{ + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + octave_idx_type b_nr = b.rows (); + octave_idx_type b_nc = b.cols (); + + if (nr != b_nr || nc != b_nc) + { + gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); + return octave_value (); + } + + ComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (Complex (a (i, j)), b (i, j)); + } + + return result; +} + +// -*- 7 -*- +octave_value +elem_xpow (const Complex& a, const Matrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + ComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + double btmp = b (i, j); + if (xisint (btmp)) + result (i, j) = std::pow (a, static_cast (btmp)); + else + result (i, j) = std::pow (a, btmp); + } + + return result; +} + +// -*- 8 -*- +octave_value +elem_xpow (const Complex& a, const ComplexMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + ComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a, b (i, j)); + } + + return result; +} + +octave_value +elem_xpow (const Complex& a, const Range& r) +{ + octave_value retval; + + // Only optimize powers with ranges that are integer and monotonic in + // magnitude. + if (r.nelem () > 1 && r.all_elements_are_ints () + && same_sign (r.base (), r.limit ())) + { + octave_idx_type n = r.nelem (); + ComplexMatrix result (1, n); + + if (same_sign (r.base (), r.inc ())) + { + Complex base = std::pow (a, r.base ()); + Complex inc = std::pow (a, r.inc ()); + result(0) = base; + for (octave_idx_type i = 1; i < n; i++) + result(i) = (base *= inc); + } + else + { + // Don't use Range::limit () here. + Complex limit = std::pow (a, r.base () + (n-1) * r.inc ()); + Complex inc = std::pow (a, -r.inc ()); + result(n-1) = limit; + for (octave_idx_type i = n-2; i >= 0; i--) + result(i) = (limit *= inc); + } + + retval = result; + } + else + retval = elem_xpow (a, r.matrix_value ()); + + + return retval; +} + +// -*- 9 -*- +octave_value +elem_xpow (const ComplexMatrix& a, double b) +{ + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + ComplexMatrix result (nr, nc); + + if (xisint (b)) + { + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a (i, j), static_cast (b)); + } + } + else + { + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a (i, j), b); + } + } + + return result; +} + +// -*- 10 -*- +octave_value +elem_xpow (const ComplexMatrix& a, const Matrix& b) +{ + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + octave_idx_type b_nr = b.rows (); + octave_idx_type b_nc = b.cols (); + + if (nr != b_nr || nc != b_nc) + { + gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); + return octave_value (); + } + + ComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + double btmp = b (i, j); + if (xisint (btmp)) + result (i, j) = std::pow (a (i, j), static_cast (btmp)); + else + result (i, j) = std::pow (a (i, j), btmp); + } + + return result; +} + +// -*- 11 -*- +octave_value +elem_xpow (const ComplexMatrix& a, const Complex& b) +{ + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + ComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a (i, j), b); + } + + return result; +} + +// -*- 12 -*- +octave_value +elem_xpow (const ComplexMatrix& a, const ComplexMatrix& b) +{ + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + octave_idx_type b_nr = b.rows (); + octave_idx_type b_nc = b.cols (); + + if (nr != b_nr || nc != b_nc) + { + gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); + return octave_value (); + } + + ComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a (i, j), b (i, j)); + } + + return result; +} + +// Safer pow functions that work elementwise for N-d arrays. +// +// op2 \ op1: s nd cs cnd +// +-- +---+---+----+----+ +// scalar | | * | 3 | * | 9 | +// +---+---+----+----+ +// N_d | 1 | 4 | 7 | 10 | +// +---+---+----+----+ +// complex_scalar | * | 5 | * | 11 | +// +---+---+----+----+ +// complex_N_d | 2 | 6 | 8 | 12 | +// +---+---+----+----+ +// +// * -> not needed. + +// FIXME -- these functions need to be fixed so that things +// like +// +// a = -1; b = [ 0, 0.5, 1 ]; r = a .^ b +// +// and +// +// a = -1; b = [ 0, 0.5, 1 ]; for i = 1:3, r(i) = a .^ b(i), end +// +// produce identical results. Also, it would be nice if -1^0.5 +// produced a pure imaginary result instead of a complex number with a +// small real part. But perhaps that's really a problem with the math +// library... + +// -*- 1 -*- +octave_value +elem_xpow (double a, const NDArray& b) +{ + octave_value retval; + + if (a < 0.0 && ! b.all_integers ()) + { + Complex atmp (a); + ComplexNDArray result (b.dims ()); + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + result(i) = std::pow (atmp, b(i)); + } + + retval = result; + } + else + { + NDArray result (b.dims ()); + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + result (i) = std::pow (a, b(i)); + } + + retval = result; + } + + return retval; +} + +// -*- 2 -*- +octave_value +elem_xpow (double a, const ComplexNDArray& b) +{ + ComplexNDArray result (b.dims ()); + + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + result(i) = std::pow (a, b(i)); + } + + return result; +} + +// -*- 3 -*- +octave_value +elem_xpow (const NDArray& a, double b) +{ + octave_value retval; + + if (! xisint (b)) + { + if (a.any_element_is_negative ()) + { + ComplexNDArray result (a.dims ()); + + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + + Complex atmp (a (i)); + + result(i) = std::pow (atmp, b); + } + + retval = result; + } + else + { + NDArray result (a.dims ()); + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + result(i) = std::pow (a(i), b); + } + + retval = result; + } + } + else + { + NoAlias result (a.dims ()); + + int ib = static_cast (b); + if (ib == 2) + { + for (octave_idx_type i = 0; i < a.length (); i++) + result(i) = a(i) * a(i); + } + else if (ib == 3) + { + for (octave_idx_type i = 0; i < a.length (); i++) + result(i) = a(i) * a(i) * a(i); + } + else if (ib == -1) + { + for (octave_idx_type i = 0; i < a.length (); i++) + result(i) = 1.0 / a(i); + } + else + { + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + result(i) = std::pow (a(i), ib); + } + } + + retval = result; + } + + return retval; +} + +// -*- 4 -*- +octave_value +elem_xpow (const NDArray& a, const NDArray& b) +{ + octave_value retval; + + dim_vector a_dims = a.dims (); + dim_vector b_dims = b.dims (); + + if (a_dims != b_dims) + { + if (is_valid_bsxfun ("operator .^", 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 (); + + bool convert_to_complex = false; + + for (octave_idx_type i = 0; i < len; i++) + { + octave_quit (); + double atmp = a(i); + double btmp = b(i); + if (atmp < 0.0 && static_cast (btmp) != btmp) + { + convert_to_complex = true; + goto done; + } + } + +done: + + if (convert_to_complex) + { + ComplexNDArray complex_result (a_dims); + + for (octave_idx_type i = 0; i < len; i++) + { + octave_quit (); + Complex atmp (a(i)); + complex_result(i) = std::pow (atmp, b(i)); + } + + retval = complex_result; + } + else + { + NDArray result (a_dims); + + for (octave_idx_type i = 0; i < len; i++) + { + octave_quit (); + result(i) = std::pow (a(i), b(i)); + } + + retval = result; + } + + return retval; +} + +// -*- 5 -*- +octave_value +elem_xpow (const NDArray& a, const Complex& b) +{ + ComplexNDArray result (a.dims ()); + + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + result(i) = std::pow (a(i), b); + } + + return result; +} + +// -*- 6 -*- +octave_value +elem_xpow (const NDArray& a, const ComplexNDArray& b) +{ + dim_vector a_dims = a.dims (); + dim_vector b_dims = b.dims (); + + if (a_dims != b_dims) + { + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) + { + return bsxfun_pow (a, b); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } + } + + ComplexNDArray result (a_dims); + + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + result(i) = std::pow (a(i), b(i)); + } + + return result; +} + +// -*- 7 -*- +octave_value +elem_xpow (const Complex& a, const NDArray& b) +{ + ComplexNDArray result (b.dims ()); + + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + double btmp = b(i); + if (xisint (btmp)) + result(i) = std::pow (a, static_cast (btmp)); + else + result(i) = std::pow (a, btmp); + } + + return result; +} + +// -*- 8 -*- +octave_value +elem_xpow (const Complex& a, const ComplexNDArray& b) +{ + ComplexNDArray result (b.dims ()); + + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + result(i) = std::pow (a, b(i)); + } + + return result; +} + +// -*- 9 -*- +octave_value +elem_xpow (const ComplexNDArray& a, double b) +{ + ComplexNDArray result (a.dims ()); + + if (xisint (b)) + { + if (b == -1) + { + for (octave_idx_type i = 0; i < a.length (); i++) + result.xelem (i) = 1.0 / a(i); + } + else + { + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + result(i) = std::pow (a(i), static_cast (b)); + } + } + } + else + { + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + result(i) = std::pow (a(i), b); + } + } + + return result; +} + +// -*- 10 -*- +octave_value +elem_xpow (const ComplexNDArray& a, const NDArray& b) +{ + dim_vector a_dims = a.dims (); + dim_vector b_dims = b.dims (); + + if (a_dims != b_dims) + { + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) + { + return bsxfun_pow (a, b); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } + } + + ComplexNDArray result (a_dims); + + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + double btmp = b(i); + if (xisint (btmp)) + result(i) = std::pow (a(i), static_cast (btmp)); + else + result(i) = std::pow (a(i), btmp); + } + + return result; +} + +// -*- 11 -*- +octave_value +elem_xpow (const ComplexNDArray& a, const Complex& b) +{ + ComplexNDArray result (a.dims ()); + + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + result(i) = std::pow (a(i), b); + } + + return result; +} + +// -*- 12 -*- +octave_value +elem_xpow (const ComplexNDArray& a, const ComplexNDArray& b) +{ + dim_vector a_dims = a.dims (); + dim_vector b_dims = b.dims (); + + if (a_dims != b_dims) + { + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) + { + return bsxfun_pow (a, b); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } + } + + ComplexNDArray result (a_dims); + + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + result(i) = std::pow (a(i), b(i)); + } + + return result; +} + +static inline int +xisint (float x) +{ + return (D_NINT (x) == x + && ((x >= 0 && x < INT_MAX) + || (x <= 0 && x > INT_MIN))); +} + +// Safer pow functions. +// +// op2 \ op1: s m cs cm +// +-- +---+---+----+----+ +// scalar | | 1 | 5 | 7 | 11 | +// +---+---+----+----+ +// matrix | 2 | * | 8 | * | +// +---+---+----+----+ +// complex_scalar | 3 | 6 | 9 | 12 | +// +---+---+----+----+ +// complex_matrix | 4 | * | 10 | * | +// +---+---+----+----+ + +// -*- 1 -*- +octave_value +xpow (float a, float b) +{ + float retval; + + if (a < 0.0 && ! xisint (b)) + { + FloatComplex atmp (a); + + return std::pow (atmp, b); + } + else + retval = std::pow (a, b); + + return retval; +} + +// -*- 2 -*- +octave_value +xpow (float a, const FloatMatrix& b) +{ + octave_value retval; + + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for x^A, A must be a square matrix"); + else + { + FloatEIG b_eig (b); + + if (! error_state) + { + FloatComplexColumnVector lambda (b_eig.eigenvalues ()); + FloatComplexMatrix Q (b_eig.eigenvectors ()); + + for (octave_idx_type i = 0; i < nr; i++) + { + FloatComplex elt = lambda(i); + if (std::imag (elt) == 0.0) + lambda(i) = std::pow (a, std::real (elt)); + else + lambda(i) = std::pow (a, elt); + } + FloatComplexDiagMatrix D (lambda); + + FloatComplexMatrix C = Q * D * Q.inverse (); + + if (a > 0) + retval = real (C); + else + retval = C; + } + else + error ("xpow: matrix diagonalization failed"); + } + + return retval; +} + +// -*- 3 -*- +octave_value +xpow (float a, const FloatComplex& b) +{ + FloatComplex result = std::pow (a, b); + return result; +} + +// -*- 4 -*- +octave_value +xpow (float a, const FloatComplexMatrix& b) +{ + octave_value retval; + + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for x^A, A must be a square matrix"); + else + { + FloatEIG b_eig (b); + + if (! error_state) + { + FloatComplexColumnVector lambda (b_eig.eigenvalues ()); + FloatComplexMatrix Q (b_eig.eigenvectors ()); + + for (octave_idx_type i = 0; i < nr; i++) + { + FloatComplex elt = lambda(i); + if (std::imag (elt) == 0.0) + lambda(i) = std::pow (a, std::real (elt)); + else + lambda(i) = std::pow (a, elt); + } + FloatComplexDiagMatrix D (lambda); + + retval = FloatComplexMatrix (Q * D * Q.inverse ()); + } + else + error ("xpow: matrix diagonalization failed"); + } + + return retval; +} + +// -*- 5 -*- +octave_value +xpow (const FloatMatrix& a, float b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for A^b, A must be a square matrix"); + else + { + if (static_cast (b) == b) + { + int btmp = static_cast (b); + if (btmp == 0) + { + retval = FloatDiagMatrix (nr, nr, 1.0); + } + else + { + // Too much copying? + // FIXME -- we shouldn't do this if the exponent is + // large... + + FloatMatrix atmp; + if (btmp < 0) + { + btmp = -btmp; + + octave_idx_type info; + float rcond = 0.0; + MatrixType mattype (a); + + atmp = a.inverse (mattype, info, rcond, 1); + + if (info == -1) + warning ("inverse: matrix singular to machine\ + precision, rcond = %g", rcond); + } + else + atmp = a; + + FloatMatrix result (atmp); + + btmp--; + + while (btmp > 0) + { + if (btmp & 1) + result = result * atmp; + + btmp >>= 1; + + if (btmp > 0) + atmp = atmp * atmp; + } + + retval = result; + } + } + else + { + FloatEIG a_eig (a); + + if (! error_state) + { + FloatComplexColumnVector lambda (a_eig.eigenvalues ()); + FloatComplexMatrix Q (a_eig.eigenvectors ()); + + for (octave_idx_type i = 0; i < nr; i++) + lambda(i) = std::pow (lambda(i), b); + + FloatComplexDiagMatrix D (lambda); + + retval = FloatComplexMatrix (Q * D * Q.inverse ()); + } + else + error ("xpow: matrix diagonalization failed"); + } + } + + return retval; +} + +// -*- 5d -*- +octave_value +xpow (const FloatDiagMatrix& a, float b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for A^b, A must be a square matrix"); + else + { + if (static_cast (b) == b) + { + FloatDiagMatrix r (nr, nc); + for (octave_idx_type i = 0; i < nc; i++) + r.dgelem (i) = std::pow (a.dgelem (i), b); + retval = r; + } + else + { + FloatComplexDiagMatrix r (nr, nc); + for (octave_idx_type i = 0; i < nc; i++) + r.dgelem (i) = std::pow (static_cast (a.dgelem (i)), b); + retval = r; + } + } + + return retval; +} + +// -*- 6 -*- +octave_value +xpow (const FloatMatrix& a, const FloatComplex& b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for A^b, A must be a square matrix"); + else + { + FloatEIG a_eig (a); + + if (! error_state) + { + FloatComplexColumnVector lambda (a_eig.eigenvalues ()); + FloatComplexMatrix Q (a_eig.eigenvectors ()); + + for (octave_idx_type i = 0; i < nr; i++) + lambda(i) = std::pow (lambda(i), b); + + FloatComplexDiagMatrix D (lambda); + + retval = FloatComplexMatrix (Q * D * Q.inverse ()); + } + else + error ("xpow: matrix diagonalization failed"); + } + + return retval; +} + +// -*- 7 -*- +octave_value +xpow (const FloatComplex& a, float b) +{ + FloatComplex result; + + if (xisint (b)) + result = std::pow (a, static_cast (b)); + else + result = std::pow (a, b); + + return result; +} + +// -*- 8 -*- +octave_value +xpow (const FloatComplex& a, const FloatMatrix& b) +{ + octave_value retval; + + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for x^A, A must be a square matrix"); + else + { + FloatEIG b_eig (b); + + if (! error_state) + { + FloatComplexColumnVector lambda (b_eig.eigenvalues ()); + FloatComplexMatrix Q (b_eig.eigenvectors ()); + + for (octave_idx_type i = 0; i < nr; i++) + { + FloatComplex elt = lambda(i); + if (std::imag (elt) == 0.0) + lambda(i) = std::pow (a, std::real (elt)); + else + lambda(i) = std::pow (a, elt); + } + FloatComplexDiagMatrix D (lambda); + + retval = FloatComplexMatrix (Q * D * Q.inverse ()); + } + else + error ("xpow: matrix diagonalization failed"); + } + + return retval; +} + +// -*- 9 -*- +octave_value +xpow (const FloatComplex& a, const FloatComplex& b) +{ + FloatComplex result; + result = std::pow (a, b); + return result; +} + +// -*- 10 -*- +octave_value +xpow (const FloatComplex& a, const FloatComplexMatrix& b) +{ + octave_value retval; + + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for x^A, A must be a square matrix"); + else + { + FloatEIG b_eig (b); + + if (! error_state) + { + FloatComplexColumnVector lambda (b_eig.eigenvalues ()); + FloatComplexMatrix Q (b_eig.eigenvectors ()); + + for (octave_idx_type i = 0; i < nr; i++) + { + FloatComplex elt = lambda(i); + if (std::imag (elt) == 0.0) + lambda(i) = std::pow (a, std::real (elt)); + else + lambda(i) = std::pow (a, elt); + } + FloatComplexDiagMatrix D (lambda); + + retval = FloatComplexMatrix (Q * D * Q.inverse ()); + } + else + error ("xpow: matrix diagonalization failed"); + } + + return retval; +} + +// -*- 11 -*- +octave_value +xpow (const FloatComplexMatrix& a, float b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for A^b, A must be a square matrix"); + else + { + if (static_cast (b) == b) + { + int btmp = static_cast (b); + if (btmp == 0) + { + retval = FloatDiagMatrix (nr, nr, 1.0); + } + else + { + // Too much copying? + // FIXME -- we shouldn't do this if the exponent is + // large... + + FloatComplexMatrix atmp; + if (btmp < 0) + { + btmp = -btmp; + + octave_idx_type info; + float rcond = 0.0; + MatrixType mattype (a); + + atmp = a.inverse (mattype, info, rcond, 1); + + if (info == -1) + warning ("inverse: matrix singular to machine\ + precision, rcond = %g", rcond); + } + else + atmp = a; + + FloatComplexMatrix result (atmp); + + btmp--; + + while (btmp > 0) + { + if (btmp & 1) + result = result * atmp; + + btmp >>= 1; + + if (btmp > 0) + atmp = atmp * atmp; + } + + retval = result; + } + } + else + { + FloatEIG a_eig (a); + + if (! error_state) + { + FloatComplexColumnVector lambda (a_eig.eigenvalues ()); + FloatComplexMatrix Q (a_eig.eigenvectors ()); + + for (octave_idx_type i = 0; i < nr; i++) + lambda(i) = std::pow (lambda(i), b); + + FloatComplexDiagMatrix D (lambda); + + retval = FloatComplexMatrix (Q * D * Q.inverse ()); + } + else + error ("xpow: matrix diagonalization failed"); + } + } + + return retval; +} + +// -*- 12 -*- +octave_value +xpow (const FloatComplexMatrix& a, const FloatComplex& b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for A^b, A must be a square matrix"); + else + { + FloatEIG a_eig (a); + + if (! error_state) + { + FloatComplexColumnVector lambda (a_eig.eigenvalues ()); + FloatComplexMatrix Q (a_eig.eigenvectors ()); + + for (octave_idx_type i = 0; i < nr; i++) + lambda(i) = std::pow (lambda(i), b); + + FloatComplexDiagMatrix D (lambda); + + retval = FloatComplexMatrix (Q * D * Q.inverse ()); + } + else + error ("xpow: matrix diagonalization failed"); + } + + return retval; +} + +// -*- 12d -*- +octave_value +xpow (const FloatComplexDiagMatrix& a, const FloatComplex& b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (nr == 0 || nc == 0 || nr != nc) + error ("for A^b, A must be a square matrix"); + else + { + FloatComplexDiagMatrix r (nr, nc); + for (octave_idx_type i = 0; i < nc; i++) + r(i, i) = std::pow (a(i, i), b); + retval = r; + } + + return retval; +} + +// mixed +octave_value +xpow (const FloatComplexDiagMatrix& a, float b) +{ + return xpow (a, static_cast (b)); +} + +octave_value +xpow (const FloatDiagMatrix& a, const FloatComplex& b) +{ + return xpow (FloatComplexDiagMatrix (a), b); +} + +// Safer pow functions that work elementwise for matrices. +// +// op2 \ op1: s m cs cm +// +-- +---+---+----+----+ +// scalar | | * | 3 | * | 9 | +// +---+---+----+----+ +// matrix | 1 | 4 | 7 | 10 | +// +---+---+----+----+ +// complex_scalar | * | 5 | * | 11 | +// +---+---+----+----+ +// complex_matrix | 2 | 6 | 8 | 12 | +// +---+---+----+----+ +// +// * -> not needed. + +// FIXME -- these functions need to be fixed so that things +// like +// +// a = -1; b = [ 0, 0.5, 1 ]; r = a .^ b +// +// and +// +// a = -1; b = [ 0, 0.5, 1 ]; for i = 1:3, r(i) = a .^ b(i), end +// +// produce identical results. Also, it would be nice if -1^0.5 +// produced a pure imaginary result instead of a complex number with a +// small real part. But perhaps that's really a problem with the math +// library... + +// -*- 1 -*- +octave_value +elem_xpow (float a, const FloatMatrix& b) +{ + octave_value retval; + + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + float d1, d2; + + if (a < 0.0 && ! b.all_integers (d1, d2)) + { + FloatComplex atmp (a); + FloatComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (atmp, b (i, j)); + } + + retval = result; + } + else + { + FloatMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a, b (i, j)); + } + + retval = result; + } + + return retval; +} + +// -*- 2 -*- +octave_value +elem_xpow (float a, const FloatComplexMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + FloatComplexMatrix result (nr, nc); + FloatComplex atmp (a); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (atmp, b (i, j)); + } + + return result; +} + +// -*- 3 -*- +octave_value +elem_xpow (const FloatMatrix& a, float b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + if (! xisint (b) && a.any_element_is_negative ()) + { + FloatComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + + FloatComplex atmp (a (i, j)); + + result (i, j) = std::pow (atmp, b); + } + + retval = result; + } + else + { + FloatMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a (i, j), b); + } + + retval = result; + } + + return retval; +} + +// -*- 4 -*- +octave_value +elem_xpow (const FloatMatrix& a, const FloatMatrix& b) +{ + octave_value retval; + + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + octave_idx_type b_nr = b.rows (); + octave_idx_type b_nc = b.cols (); + + if (nr != b_nr || nc != b_nc) + { + gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); + return octave_value (); + } + + int convert_to_complex = 0; + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + float atmp = a (i, j); + float btmp = b (i, j); + if (atmp < 0.0 && static_cast (btmp) != btmp) + { + convert_to_complex = 1; + goto done; + } + } + +done: + + if (convert_to_complex) + { + FloatComplexMatrix complex_result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + FloatComplex atmp (a (i, j)); + FloatComplex btmp (b (i, j)); + complex_result (i, j) = std::pow (atmp, btmp); + } + + retval = complex_result; + } + else + { + FloatMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a (i, j), b (i, j)); + } + + retval = result; + } + + return retval; +} + +// -*- 5 -*- +octave_value +elem_xpow (const FloatMatrix& a, const FloatComplex& b) +{ + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + FloatComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (FloatComplex (a (i, j)), b); + } + + return result; +} + +// -*- 6 -*- +octave_value +elem_xpow (const FloatMatrix& a, const FloatComplexMatrix& b) +{ + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + octave_idx_type b_nr = b.rows (); + octave_idx_type b_nc = b.cols (); + + if (nr != b_nr || nc != b_nc) + { + gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); + return octave_value (); + } + + FloatComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (FloatComplex (a (i, j)), b (i, j)); + } + + return result; +} + +// -*- 7 -*- +octave_value +elem_xpow (const FloatComplex& a, const FloatMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + FloatComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + float btmp = b (i, j); + if (xisint (btmp)) + result (i, j) = std::pow (a, static_cast (btmp)); + else + result (i, j) = std::pow (a, btmp); + } + + return result; +} + +// -*- 8 -*- +octave_value +elem_xpow (const FloatComplex& a, const FloatComplexMatrix& b) +{ + octave_idx_type nr = b.rows (); + octave_idx_type nc = b.cols (); + + FloatComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a, b (i, j)); + } + + return result; +} + +// -*- 9 -*- +octave_value +elem_xpow (const FloatComplexMatrix& a, float b) +{ + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + FloatComplexMatrix result (nr, nc); + + if (xisint (b)) + { + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a (i, j), static_cast (b)); + } + } + else + { + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a (i, j), b); + } + } + + return result; +} + +// -*- 10 -*- +octave_value +elem_xpow (const FloatComplexMatrix& a, const FloatMatrix& b) +{ + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + octave_idx_type b_nr = b.rows (); + octave_idx_type b_nc = b.cols (); + + if (nr != b_nr || nc != b_nc) + { + gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); + return octave_value (); + } + + FloatComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + float btmp = b (i, j); + if (xisint (btmp)) + result (i, j) = std::pow (a (i, j), static_cast (btmp)); + else + result (i, j) = std::pow (a (i, j), btmp); + } + + return result; +} + +// -*- 11 -*- +octave_value +elem_xpow (const FloatComplexMatrix& a, const FloatComplex& b) +{ + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + FloatComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a (i, j), b); + } + + return result; +} + +// -*- 12 -*- +octave_value +elem_xpow (const FloatComplexMatrix& a, const FloatComplexMatrix& b) +{ + octave_idx_type nr = a.rows (); + octave_idx_type nc = a.cols (); + + octave_idx_type b_nr = b.rows (); + octave_idx_type b_nc = b.cols (); + + if (nr != b_nr || nc != b_nc) + { + gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); + return octave_value (); + } + + FloatComplexMatrix result (nr, nc); + + for (octave_idx_type j = 0; j < nc; j++) + for (octave_idx_type i = 0; i < nr; i++) + { + octave_quit (); + result (i, j) = std::pow (a (i, j), b (i, j)); + } + + return result; +} + +// Safer pow functions that work elementwise for N-d arrays. +// +// op2 \ op1: s nd cs cnd +// +-- +---+---+----+----+ +// scalar | | * | 3 | * | 9 | +// +---+---+----+----+ +// N_d | 1 | 4 | 7 | 10 | +// +---+---+----+----+ +// complex_scalar | * | 5 | * | 11 | +// +---+---+----+----+ +// complex_N_d | 2 | 6 | 8 | 12 | +// +---+---+----+----+ +// +// * -> not needed. + +// FIXME -- these functions need to be fixed so that things +// like +// +// a = -1; b = [ 0, 0.5, 1 ]; r = a .^ b +// +// and +// +// a = -1; b = [ 0, 0.5, 1 ]; for i = 1:3, r(i) = a .^ b(i), end +// +// produce identical results. Also, it would be nice if -1^0.5 +// produced a pure imaginary result instead of a complex number with a +// small real part. But perhaps that's really a problem with the math +// library... + +// -*- 1 -*- +octave_value +elem_xpow (float a, const FloatNDArray& b) +{ + octave_value retval; + + if (a < 0.0 && ! b.all_integers ()) + { + FloatComplex atmp (a); + FloatComplexNDArray result (b.dims ()); + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + result(i) = std::pow (atmp, b(i)); + } + + retval = result; + } + else + { + FloatNDArray result (b.dims ()); + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + result (i) = std::pow (a, b(i)); + } + + retval = result; + } + + return retval; +} + +// -*- 2 -*- +octave_value +elem_xpow (float a, const FloatComplexNDArray& b) +{ + FloatComplexNDArray result (b.dims ()); + + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + result(i) = std::pow (a, b(i)); + } + + return result; +} + +// -*- 3 -*- +octave_value +elem_xpow (const FloatNDArray& a, float b) +{ + octave_value retval; + + if (! xisint (b)) + { + if (a.any_element_is_negative ()) + { + FloatComplexNDArray result (a.dims ()); + + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + + FloatComplex atmp (a (i)); + + result(i) = std::pow (atmp, b); + } + + retval = result; + } + else + { + FloatNDArray result (a.dims ()); + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + result(i) = std::pow (a(i), b); + } + + retval = result; + } + } + else + { + NoAlias result (a.dims ()); + + int ib = static_cast (b); + if (ib == 2) + { + for (octave_idx_type i = 0; i < a.length (); i++) + result(i) = a(i) * a(i); + } + else if (ib == 3) + { + for (octave_idx_type i = 0; i < a.length (); i++) + result(i) = a(i) * a(i) * a(i); + } + else if (ib == -1) + { + for (octave_idx_type i = 0; i < a.length (); i++) + result(i) = 1.0f / a(i); + } + else + { + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + result(i) = std::pow (a(i), ib); + } + } + + retval = result; + } + + return retval; +} + +// -*- 4 -*- +octave_value +elem_xpow (const FloatNDArray& a, const FloatNDArray& b) +{ + octave_value retval; + + dim_vector a_dims = a.dims (); + dim_vector b_dims = b.dims (); + + if (a_dims != b_dims) + { + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) + { + //Potentially complex results + FloatNDArray xa = octave_value_extract (a); + FloatNDArray xb = octave_value_extract (b); + if (! xb.all_integers () && xa.any_element_is_negative ()) + return octave_value (bsxfun_pow (FloatComplexNDArray (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 (); + + bool convert_to_complex = false; + + for (octave_idx_type i = 0; i < len; i++) + { + octave_quit (); + float atmp = a(i); + float btmp = b(i); + if (atmp < 0.0 && static_cast (btmp) != btmp) + { + convert_to_complex = true; + goto done; + } + } + +done: + + if (convert_to_complex) + { + FloatComplexNDArray complex_result (a_dims); + + for (octave_idx_type i = 0; i < len; i++) + { + octave_quit (); + FloatComplex atmp (a(i)); + complex_result(i) = std::pow (atmp, b(i)); + } + + retval = complex_result; + } + else + { + FloatNDArray result (a_dims); + + for (octave_idx_type i = 0; i < len; i++) + { + octave_quit (); + result(i) = std::pow (a(i), b(i)); + } + + retval = result; + } + + return retval; +} + +// -*- 5 -*- +octave_value +elem_xpow (const FloatNDArray& a, const FloatComplex& b) +{ + FloatComplexNDArray result (a.dims ()); + + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + result(i) = std::pow (a(i), b); + } + + return result; +} + +// -*- 6 -*- +octave_value +elem_xpow (const FloatNDArray& a, const FloatComplexNDArray& b) +{ + dim_vector a_dims = a.dims (); + dim_vector b_dims = b.dims (); + + if (a_dims != b_dims) + { + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) + { + return bsxfun_pow (a, b); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } + } + + FloatComplexNDArray result (a_dims); + + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + result(i) = std::pow (a(i), b(i)); + } + + return result; +} + +// -*- 7 -*- +octave_value +elem_xpow (const FloatComplex& a, const FloatNDArray& b) +{ + FloatComplexNDArray result (b.dims ()); + + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + float btmp = b(i); + if (xisint (btmp)) + result(i) = std::pow (a, static_cast (btmp)); + else + result(i) = std::pow (a, btmp); + } + + return result; +} + +// -*- 8 -*- +octave_value +elem_xpow (const FloatComplex& a, const FloatComplexNDArray& b) +{ + FloatComplexNDArray result (b.dims ()); + + for (octave_idx_type i = 0; i < b.length (); i++) + { + octave_quit (); + result(i) = std::pow (a, b(i)); + } + + return result; +} + +// -*- 9 -*- +octave_value +elem_xpow (const FloatComplexNDArray& a, float b) +{ + FloatComplexNDArray result (a.dims ()); + + if (xisint (b)) + { + if (b == -1) + { + for (octave_idx_type i = 0; i < a.length (); i++) + result.xelem (i) = 1.0f / a(i); + } + else + { + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + result(i) = std::pow (a(i), static_cast (b)); + } + } + } + else + { + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + result(i) = std::pow (a(i), b); + } + } + + return result; +} + +// -*- 10 -*- +octave_value +elem_xpow (const FloatComplexNDArray& a, const FloatNDArray& b) +{ + dim_vector a_dims = a.dims (); + dim_vector b_dims = b.dims (); + + if (a_dims != b_dims) + { + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) + { + return bsxfun_pow (a, b); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } + } + + FloatComplexNDArray result (a_dims); + + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + float btmp = b(i); + if (xisint (btmp)) + result(i) = std::pow (a(i), static_cast (btmp)); + else + result(i) = std::pow (a(i), btmp); + } + + return result; +} + +// -*- 11 -*- +octave_value +elem_xpow (const FloatComplexNDArray& a, const FloatComplex& b) +{ + FloatComplexNDArray result (a.dims ()); + + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + result(i) = std::pow (a(i), b); + } + + return result; +} + +// -*- 12 -*- +octave_value +elem_xpow (const FloatComplexNDArray& a, const FloatComplexNDArray& b) +{ + dim_vector a_dims = a.dims (); + dim_vector b_dims = b.dims (); + + if (a_dims != b_dims) + { + if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) + { + return bsxfun_pow (a, b); + } + else + { + gripe_nonconformant ("operator .^", a_dims, b_dims); + return octave_value (); + } + } + + FloatComplexNDArray result (a_dims); + + for (octave_idx_type i = 0; i < a.length (); i++) + { + octave_quit (); + result(i) = std::pow (a(i), b(i)); + } + + return result; +} diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/xpow.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/xpow.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,158 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_xpow_h) +#define octave_xpow_h 1 + +#include "oct-cmplx.h" + +class Matrix; +class ComplexMatrix; +class FloatMatrix; +class FloatComplexMatrix; +class DiagMatrix; +class ComplexDiagMatrix; +class FloatDiagMatrix; +class FloatComplexDiagMatrix; +class PermMatrix; +class NDArray; +class FloatNDArray; +class ComplexNDArray; +class FloatComplexNDArray; +class octave_value; +class Range; + +extern OCTINTERP_API octave_value xpow (double a, double b); +extern OCTINTERP_API octave_value xpow (double a, const Matrix& b); +extern OCTINTERP_API octave_value xpow (double a, const Complex& b); +extern OCTINTERP_API octave_value xpow (double a, const ComplexMatrix& b); + +extern OCTINTERP_API octave_value xpow (const Matrix& a, double b); +extern OCTINTERP_API octave_value xpow (const Matrix& a, const Complex& b); + +extern OCTINTERP_API octave_value xpow (const DiagMatrix& a, double b); +extern OCTINTERP_API octave_value xpow (const DiagMatrix& a, const Complex& b); + +extern OCTINTERP_API octave_value xpow (const PermMatrix& a, double b); + +extern OCTINTERP_API octave_value xpow (const Complex& a, double b); +extern OCTINTERP_API octave_value xpow (const Complex& a, const Matrix& b); +extern OCTINTERP_API octave_value xpow (const Complex& a, const Complex& b); +extern OCTINTERP_API octave_value xpow (const Complex& a, const ComplexMatrix& b); + +extern OCTINTERP_API octave_value xpow (const ComplexMatrix& a, double b); +extern OCTINTERP_API octave_value xpow (const ComplexMatrix& a, const Complex& b); + +extern OCTINTERP_API octave_value xpow (const ComplexDiagMatrix& a, double b); +extern OCTINTERP_API octave_value xpow (const ComplexDiagMatrix& a, const Complex& b); + +extern OCTINTERP_API octave_value elem_xpow (double a, const Matrix& b); +extern OCTINTERP_API octave_value elem_xpow (double a, const ComplexMatrix& b); +extern OCTINTERP_API octave_value elem_xpow (double a, const Range& r); + +extern OCTINTERP_API octave_value elem_xpow (const Matrix& a, double b); +extern OCTINTERP_API octave_value elem_xpow (const Matrix& a, const Matrix& b); +extern OCTINTERP_API octave_value elem_xpow (const Matrix& a, const Complex& b); +extern OCTINTERP_API octave_value elem_xpow (const Matrix& a, const ComplexMatrix& b); + +extern OCTINTERP_API octave_value elem_xpow (const Complex& a, const Matrix& b); +extern OCTINTERP_API octave_value elem_xpow (const Complex& a, const ComplexMatrix& b); +extern OCTINTERP_API octave_value elem_xpow (const Complex& a, const Range& r); + +extern OCTINTERP_API octave_value elem_xpow (const ComplexMatrix& a, double b); +extern OCTINTERP_API octave_value elem_xpow (const ComplexMatrix& a, const Matrix& b); +extern OCTINTERP_API octave_value elem_xpow (const ComplexMatrix& a, const Complex& b); +extern OCTINTERP_API octave_value elem_xpow (const ComplexMatrix& a, const ComplexMatrix& b); + + +extern OCTINTERP_API octave_value elem_xpow (double a, const NDArray& b); +extern OCTINTERP_API octave_value elem_xpow (double a, const ComplexNDArray& b); + +extern OCTINTERP_API octave_value elem_xpow (const NDArray& a, double b); +extern OCTINTERP_API octave_value elem_xpow (const NDArray& a, const NDArray& b); +extern OCTINTERP_API octave_value elem_xpow (const NDArray& a, const Complex& b); +extern OCTINTERP_API octave_value elem_xpow (const NDArray& a, const ComplexNDArray& b); + +extern OCTINTERP_API octave_value elem_xpow (const Complex& a, const NDArray& b); +extern OCTINTERP_API octave_value elem_xpow (const Complex& a, const ComplexNDArray& b); + +extern OCTINTERP_API octave_value elem_xpow (const ComplexNDArray& a, double b); +extern OCTINTERP_API octave_value elem_xpow (const ComplexNDArray& a, const NDArray& b); +extern OCTINTERP_API octave_value elem_xpow (const ComplexNDArray& a, const Complex& b); +extern OCTINTERP_API octave_value elem_xpow (const ComplexNDArray& a, const ComplexNDArray& b); + +extern OCTINTERP_API octave_value xpow (float a, float b); +extern OCTINTERP_API octave_value xpow (float a, const FloatMatrix& b); +extern OCTINTERP_API octave_value xpow (float a, const FloatComplex& b); +extern OCTINTERP_API octave_value xpow (float a, const FloatComplexMatrix& b); + +extern OCTINTERP_API octave_value xpow (const FloatMatrix& a, float b); +extern OCTINTERP_API octave_value xpow (const FloatMatrix& a, const FloatComplex& b); + +extern OCTINTERP_API octave_value xpow (const FloatDiagMatrix& a, float b); +extern OCTINTERP_API octave_value xpow (const FloatDiagMatrix& a, const FloatComplex& b); + +extern OCTINTERP_API octave_value xpow (const FloatComplex& a, float b); +extern OCTINTERP_API octave_value xpow (const FloatComplex& a, const FloatMatrix& b); +extern OCTINTERP_API octave_value xpow (const FloatComplex& a, const FloatComplex& b); +extern OCTINTERP_API octave_value xpow (const FloatComplex& a, const FloatComplexMatrix& b); + +extern OCTINTERP_API octave_value xpow (const FloatComplexMatrix& a, float b); +extern OCTINTERP_API octave_value xpow (const FloatComplexMatrix& a, const FloatComplex& b); + +extern OCTINTERP_API octave_value xpow (const FloatComplexDiagMatrix& a, float b); +extern OCTINTERP_API octave_value xpow (const FloatComplexDiagMatrix& a, const FloatComplex& b); + +extern OCTINTERP_API octave_value elem_xpow (float a, const FloatMatrix& b); +extern OCTINTERP_API octave_value elem_xpow (float a, const FloatComplexMatrix& b); + +extern OCTINTERP_API octave_value elem_xpow (const FloatMatrix& a, float b); +extern OCTINTERP_API octave_value elem_xpow (const FloatMatrix& a, const FloatMatrix& b); +extern OCTINTERP_API octave_value elem_xpow (const FloatMatrix& a, const FloatComplex& b); +extern OCTINTERP_API octave_value elem_xpow (const FloatMatrix& a, const FloatComplexMatrix& b); + +extern OCTINTERP_API octave_value elem_xpow (const FloatComplex& a, const FloatMatrix& b); +extern OCTINTERP_API octave_value elem_xpow (const FloatComplex& a, const FloatComplexMatrix& b); + +extern OCTINTERP_API octave_value elem_xpow (const FloatComplexMatrix& a, float b); +extern OCTINTERP_API octave_value elem_xpow (const FloatComplexMatrix& a, const FloatMatrix& b); +extern OCTINTERP_API octave_value elem_xpow (const FloatComplexMatrix& a, const FloatComplex& b); +extern OCTINTERP_API octave_value elem_xpow (const FloatComplexMatrix& a, const FloatComplexMatrix& b); + + +extern OCTINTERP_API octave_value elem_xpow (float a, const FloatNDArray& b); +extern OCTINTERP_API octave_value elem_xpow (float a, const FloatComplexNDArray& b); + +extern OCTINTERP_API octave_value elem_xpow (const FloatNDArray& a, float b); +extern OCTINTERP_API octave_value elem_xpow (const FloatNDArray& a, const FloatNDArray& b); +extern OCTINTERP_API octave_value elem_xpow (const FloatNDArray& a, const FloatComplex& b); +extern OCTINTERP_API octave_value elem_xpow (const FloatNDArray& a, const FloatComplexNDArray& b); + +extern OCTINTERP_API octave_value elem_xpow (const FloatComplex& a, const FloatNDArray& b); +extern OCTINTERP_API octave_value elem_xpow (const FloatComplex& a, const FloatComplexNDArray& b); + +extern OCTINTERP_API octave_value elem_xpow (const FloatComplexNDArray& a, float b); +extern OCTINTERP_API octave_value elem_xpow (const FloatComplexNDArray& a, const FloatNDArray& b); +extern OCTINTERP_API octave_value elem_xpow (const FloatComplexNDArray& a, const FloatComplex& b); +extern OCTINTERP_API octave_value elem_xpow (const FloatComplexNDArray& a, const FloatComplexNDArray& b); + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/zfstream.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/zfstream.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,625 @@ +/* + +Copyright (C) 2005-2012 Ludwig Schwardt, Kevin Ruland + + +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 +. + +*/ + +/* + + This file is adapted from the zlib 1.2.2 contrib/iostream3 code, + written by + + Ludwig Schwardt + original version by Kevin Ruland + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "zfstream.h" + +#ifdef HAVE_ZLIB + +#include // for strcpy, strcat, strlen (mode strings) +#include // for BUFSIZ + +// Internal buffer sizes (default and "unbuffered" versions) +#define STASHED_CHARACTERS 16 +#define BIGBUFSIZE (256 * 1024 + STASHED_CHARACTERS) +#define SMALLBUFSIZE 1 + +/*****************************************************************************/ + +// Default constructor +gzfilebuf::gzfilebuf () +: file(0), io_mode(std::ios_base::openmode(0)), own_fd(false), + buffer(0), buffer_size(BIGBUFSIZE), own_buffer(true) +{ + // No buffers to start with + this->disable_buffer (); +} + +// Destructor +gzfilebuf::~gzfilebuf () +{ + // Sync output buffer and close only if responsible for file + // (i.e. attached streams should be left open at this stage) + this->sync (); + if (own_fd) + this->close (); + // Make sure internal buffer is deallocated + this->disable_buffer (); +} + +// Set compression level and strategy +int +gzfilebuf::setcompression (int comp_level, + int comp_strategy) +{ + return gzsetparams (file, comp_level, comp_strategy); +} + +// Open gzipped file +gzfilebuf* +gzfilebuf::open (const char *name, + std::ios_base::openmode mode) +{ + // Fail if file already open + if (this->is_open ()) + return 0; + // Don't support simultaneous read/write access (yet) + if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) + return 0; + + // Build mode string for gzopen and check it [27.8.1.3.2] + char char_mode[6] = "\0\0\0\0\0"; + if (! this->open_mode (mode, char_mode)) + return 0; + + // Attempt to open file + if ((file = gzopen (name, char_mode)) == 0) + return 0; + + // On success, allocate internal buffer and set flags + this->enable_buffer (); + io_mode = mode; + own_fd = true; + return this; +} + +// Attach to gzipped file +gzfilebuf* +gzfilebuf::attach (int fd, + std::ios_base::openmode mode) +{ + // Fail if file already open + if (this->is_open ()) + return 0; + // Don't support simultaneous read/write access (yet) + if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) + return 0; + + // Build mode string for gzdopen and check it [27.8.1.3.2] + char char_mode[6] = "\0\0\0\0\0"; + if (! this->open_mode (mode, char_mode)) + return 0; + + // Attempt to attach to file + if ((file = gzdopen (fd, char_mode)) == 0) + return 0; + + // On success, allocate internal buffer and set flags + this->enable_buffer (); + io_mode = mode; + own_fd = false; + return this; +} + +// Close gzipped file +gzfilebuf* +gzfilebuf::close () +{ + // Fail immediately if no file is open + if (! this->is_open ()) + return 0; + // Assume success + gzfilebuf* retval = this; + // Attempt to sync and close gzipped file + if (this->sync () == -1) + retval = 0; + if (gzclose (file) < 0) + retval = 0; + // File is now gone anyway (postcondition [27.8.1.3.8]) + file = 0; + own_fd = false; + // Destroy internal buffer if it exists + this->disable_buffer (); + return retval; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// Convert int open mode to mode string +bool +gzfilebuf::open_mode (std::ios_base::openmode mode, + char* c_mode) const +{ + // FIXME -- do we need testb? + // bool testb = mode & std::ios_base::binary; + bool testi = mode & std::ios_base::in; + bool testo = mode & std::ios_base::out; + bool testt = mode & std::ios_base::trunc; + bool testa = mode & std::ios_base::app; + + // Check for valid flag combinations - see [27.8.1.3.2] (Table 92) + // Original zfstream hardcoded the compression level to maximum here... + // Double the time for less than 1% size improvement seems + // excessive though - keeping it at the default level + // To change back, just append "9" to the next three mode strings + if (!testi && testo && !testt && !testa) + strcpy (c_mode, "w"); + if (!testi && testo && !testt && testa) + strcpy (c_mode, "a"); + if (!testi && testo && testt && !testa) + strcpy (c_mode, "w"); + if (testi && !testo && !testt && !testa) + strcpy (c_mode, "r"); + // No read/write mode yet +// if (testi && testo && !testt && !testa) +// strcpy(c_mode, "r+"); +// if (testi && testo && testt && !testa) +// strcpy(c_mode, "w+"); + + // Mode string should be empty for invalid combination of flags + if (strlen (c_mode) == 0) + return false; + + strcat (c_mode, "b"); + + return true; +} + +// Determine number of characters in internal get buffer +std::streamsize +gzfilebuf::showmanyc () +{ + // Calls to underflow will fail if file not opened for reading + if (! this->is_open () || !(io_mode & std::ios_base::in)) + return -1; + // Make sure get area is in use + if (this->gptr () && (this->gptr () < this->egptr ())) + return std::streamsize (this->egptr () - this->gptr ()); + else + return 0; +} + +// Puts back a character to the stream in two cases. Firstly, when there +// is no putback position available, and secondly when the character putback +// differs from the one in the file. We can only support the first case +// with gzipped files. +gzfilebuf::int_type +gzfilebuf::pbackfail (gzfilebuf::int_type c) +{ + if (this->is_open ()) + { + if (gzseek (file, this->gptr () - this->egptr () - 1, SEEK_CUR) < 0) + return traits_type::eof (); + + // Invalidates contents of the buffer + enable_buffer (); + + // Attempt to fill internal buffer from gzipped file + // (buffer must be guaranteed to exist...) + int bytes_read = gzread (file, buffer, buffer_size); + // Indicates error or EOF + if (bytes_read <= 0) + { + // Reset get area + this->setg (buffer, buffer, buffer); + return traits_type::eof (); + } + + // Make all bytes read from file available as get area + this->setg (buffer, buffer, buffer + bytes_read); + + // If next character in get area differs from putback character + // flag a failure + gzfilebuf::int_type ret = traits_type::to_int_type (*(this->gptr ())); + if (ret != c) + return traits_type::eof (); + else + return ret; + } + else + return traits_type::eof (); +} + +// Fill get area from gzipped file +gzfilebuf::int_type +gzfilebuf::underflow () +{ + // If something is left in the get area by chance, return it + // (this shouldn't normally happen, as underflow is only supposed + // to be called when gptr >= egptr, but it serves as error check) + if (this->gptr () && (this->gptr () < this->egptr ())) + return traits_type::to_int_type (*(this->gptr ())); + + // If the file hasn't been opened for reading, produce error + if (! this->is_open () || !(io_mode & std::ios_base::in)) + return traits_type::eof (); + + // Copy the final characters to the front of the buffer + int stash = 0; + if (this->eback () && buffer && buffer_size > STASHED_CHARACTERS) + { + char_type *ptr1 = buffer; + char_type *ptr2 = this->egptr () - STASHED_CHARACTERS + 1; + if (ptr2 > this->eback ()) + while (stash++ <= STASHED_CHARACTERS) + *ptr1++ = *ptr2++; + } + + // Attempt to fill internal buffer from gzipped file + // (buffer must be guaranteed to exist...) + int bytes_read = gzread (file, buffer + stash, buffer_size - stash); + + // Indicates error or EOF + if (bytes_read <= 0) + { + // Reset get area + this->setg (buffer, buffer, buffer); + return traits_type::eof (); + } + // Make all bytes read from file plus the stash available as get area + this->setg (buffer, buffer + stash, buffer + bytes_read + stash); + + // Return next character in get area + return traits_type::to_int_type (*(this->gptr ())); +} + +// Write put area to gzipped file +gzfilebuf::int_type +gzfilebuf::overflow (int_type c) +{ + // Determine whether put area is in use + if (this->pbase ()) + { + // Double-check pointer range + if (this->pptr () > this->epptr () || this->pptr () < this->pbase ()) + return traits_type::eof (); + // Add extra character to buffer if not EOF + if (! traits_type::eq_int_type (c, traits_type::eof ())) + { + *(this->pptr ()) = traits_type::to_char_type (c); + this->pbump (1); + } + // Number of characters to write to file + int bytes_to_write = this->pptr () - this->pbase (); + // Overflow doesn't fail if nothing is to be written + if (bytes_to_write > 0) + { + // If the file hasn't been opened for writing, produce error + if (! this->is_open () || !(io_mode & std::ios_base::out)) + return traits_type::eof (); + // If gzipped file won't accept all bytes written to it, fail + if (gzwrite (file, this->pbase (), bytes_to_write) != bytes_to_write) + return traits_type::eof (); + // Reset next pointer to point to pbase on success + this->pbump (-bytes_to_write); + } + } + // Write extra character to file if not EOF + else if (! traits_type::eq_int_type (c, traits_type::eof ())) + { + // If the file hasn't been opened for writing, produce error + if (! this->is_open () || !(io_mode & std::ios_base::out)) + return traits_type::eof (); + // Impromptu char buffer (allows "unbuffered" output) + char_type last_char = traits_type::to_char_type (c); + // If gzipped file won't accept this character, fail + if (gzwrite (file, &last_char, 1) != 1) + return traits_type::eof (); + } + + // If you got here, you have succeeded (even if c was EOF) + // The return value should therefore be non-EOF + if (traits_type::eq_int_type (c, traits_type::eof ())) + return traits_type::not_eof (c); + else + return c; +} + +// Assign new buffer +std::streambuf* +gzfilebuf::setbuf (char_type* p, + std::streamsize n) +{ + // First make sure stuff is sync'ed, for safety + if (this->sync () == -1) + return 0; + // If buffering is turned off on purpose via setbuf(0,0), still allocate one... + // "Unbuffered" only really refers to put [27.8.1.4.10], while get needs at + // least a buffer of size 1 (very inefficient though, therefore make it bigger?) + // This follows from [27.5.2.4.3]/12 (gptr needs to point at something, it seems) + if (!p || !n) + { + // Replace existing buffer (if any) with small internal buffer + this->disable_buffer (); + buffer = 0; + buffer_size = 0; + own_buffer = true; + this->enable_buffer (); + } + else + { + // Replace existing buffer (if any) with external buffer + this->disable_buffer (); + buffer = p; + buffer_size = n; + own_buffer = false; + this->enable_buffer (); + } + return this; +} + +// Write put area to gzipped file (i.e. ensures that put area is empty) +int +gzfilebuf::sync () +{ + return traits_type::eq_int_type (this->overflow (), traits_type::eof ()) ? -1 : 0; +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// Allocate internal buffer +void +gzfilebuf::enable_buffer () +{ + // If internal buffer required, allocate one + if (own_buffer && !buffer) + { + // Check for buffered vs. "unbuffered" + if (buffer_size > 0) + { + // Allocate internal buffer + buffer = new char_type [buffer_size]; + // Get area starts empty and will be expanded by underflow as need arises + this->setg (buffer, buffer, buffer); + // Setup entire internal buffer as put area. + // The one-past-end pointer actually points to the last element of the buffer, + // so that overflow(c) can safely add the extra character c to the sequence. + // These pointers remain in place for the duration of the buffer + this->setp (buffer, buffer + buffer_size - 1); + } + else + { + // Even in "unbuffered" case, (small?) get buffer is still required + buffer_size = SMALLBUFSIZE; + buffer = new char_type [buffer_size]; + this->setg (buffer, buffer, buffer); + // "Unbuffered" means no put buffer + this->setp (0, 0); + } + } + else + { + // If buffer already allocated, reset buffer pointers just to make sure no + // stale chars are lying around + this->setg (buffer, buffer, buffer); + this->setp (buffer, buffer + buffer_size - 1); + } +} + +// Destroy internal buffer +void +gzfilebuf::disable_buffer () +{ + // If internal buffer exists, deallocate it + if (own_buffer && buffer) + { + // Preserve unbuffered status by zeroing size + if (! this->pbase ()) + buffer_size = 0; + delete[] buffer; + buffer = 0; + this->setg (0, 0, 0); + this->setp (0, 0); + } + else + { + // Reset buffer pointers to initial state if external buffer exists + this->setg (buffer, buffer, buffer); + if (buffer) + this->setp (buffer, buffer + buffer_size - 1); + else + this->setp (0, 0); + } +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +// Seek functions +gzfilebuf::pos_type +gzfilebuf::seekoff (off_type off, std::ios_base::seekdir way, + std::ios_base::openmode) +{ + pos_type ret = pos_type (off_type (-1)); + + if (this->is_open ()) + { + off_type computed_off = off; + + if ((io_mode & std::ios_base::in) && way == std::ios_base::cur) + computed_off += this->gptr () - this->egptr (); + + if (way == std::ios_base::beg) + ret = pos_type (gzseek (file, computed_off, SEEK_SET)); + else if (way == std::ios_base::cur) + ret = pos_type (gzseek (file, computed_off, SEEK_CUR)); + else + // Can't seek from end of a gzipped file, so this will give -1 + ret = pos_type (gzseek (file, computed_off, SEEK_END)); + + if (io_mode & std::ios_base::in) + // Invalidates contents of the buffer + enable_buffer (); + else + // flush contents of buffer to file + overflow (); + } + + return ret; +} + +gzfilebuf::pos_type +gzfilebuf::seekpos (pos_type sp, std::ios_base::openmode) +{ + pos_type ret = pos_type (off_type (-1)); + + if (this->is_open ()) + { + ret = pos_type (gzseek (file, sp, SEEK_SET)); + + if (io_mode & std::ios_base::in) + // Invalidates contents of the buffer + enable_buffer (); + else + // flush contents of buffer to file + overflow (); + } + + return ret; +} + +/*****************************************************************************/ + +// Default constructor initializes stream buffer +gzifstream::gzifstream () +: std::istream (0), sb () +{ this->init (&sb); } + +// Initialize stream buffer and open file +gzifstream::gzifstream (const char* name, + std::ios_base::openmode mode) +: std::istream (0), sb () +{ + this->init (&sb); + this->open (name, mode); +} + +// Initialize stream buffer and attach to file +gzifstream::gzifstream (int fd, + std::ios_base::openmode mode) +: std::istream (0), sb () +{ + this->init (&sb); + this->attach (fd, mode); +} + +// Open file and go into fail() state if unsuccessful +void +gzifstream::open (const char* name, + std::ios_base::openmode mode) +{ + if (! sb.open (name, mode | std::ios_base::in)) + this->setstate (std::ios_base::failbit); + else + this->clear (); +} + +// Attach to file and go into fail() state if unsuccessful +void +gzifstream::attach (int fd, + std::ios_base::openmode mode) +{ + if (! sb.attach (fd, mode | std::ios_base::in)) + this->setstate (std::ios_base::failbit); + else + this->clear (); +} + +// Close file +void +gzifstream::close () +{ + if (! sb.close ()) + this->setstate (std::ios_base::failbit); +} + +/*****************************************************************************/ + +// Default constructor initializes stream buffer +gzofstream::gzofstream () +: std::ostream (0), sb () +{ this->init (&sb); } + +// Initialize stream buffer and open file +gzofstream::gzofstream (const char* name, + std::ios_base::openmode mode) +: std::ostream (0), sb () +{ + this->init (&sb); + this->open (name, mode); +} + +// Initialize stream buffer and attach to file +gzofstream::gzofstream (int fd, + std::ios_base::openmode mode) +: std::ostream (0), sb () +{ + this->init (&sb); + this->attach (fd, mode); +} + +// Open file and go into fail() state if unsuccessful +void +gzofstream::open (const char* name, + std::ios_base::openmode mode) +{ + if (! sb.open (name, mode | std::ios_base::out)) + this->setstate (std::ios_base::failbit); + else + this->clear (); +} + +// Attach to file and go into fail() state if unsuccessful +void +gzofstream::attach (int fd, + std::ios_base::openmode mode) +{ + if (! sb.attach (fd, mode | std::ios_base::out)) + this->setstate (std::ios_base::failbit); + else + this->clear (); +} + +// Close file +void +gzofstream::close () +{ + if (! sb.close ()) + this->setstate (std::ios_base::failbit); +} + +#endif // HAVE_ZLIB diff -r a132d206a36a -r b9b6a310ad97 src/interp-core/zfstream.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/interp-core/zfstream.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,515 @@ +/* + +Copyright (C) 2005-2012 Ludwig Schwardt, Kevin Ruland + +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 +. + +*/ + +/* + + This file is adapted from the zlib 1.2.2 contrib/iostream3 code, + written by + + Ludwig Schwardt + original version by Kevin Ruland + +*/ + +#ifndef ZFSTREAM_H +#define ZFSTREAM_H + +#ifdef HAVE_ZLIB + +#include + +#include "zlib.h" + +/*****************************************************************************/ + +/** + * @brief Gzipped file stream buffer class. + * + * This class implements basic_filebuf for gzipped files. It doesn't yet support + * seeking (allowed by zlib but slow/limited), putback and read/write access + * (tricky). Otherwise, it attempts to be a drop-in replacement for the standard + * file streambuf. +*/ +class gzfilebuf : public std::streambuf +{ +public: + // Default constructor. + gzfilebuf (); + + // Destructor. + virtual + ~gzfilebuf (); + + /** + * @brief Set compression level and strategy on the fly. + * @param comp_level Compression level (see zlib.h for allowed values) + * @param comp_strategy Compression strategy (see zlib.h for allowed values) + * @return Z_OK on success, Z_STREAM_ERROR otherwise. + * + * Unfortunately, these parameters cannot be modified separately, as the + * previous zfstream version assumed. Since the strategy is seldom changed, + * it can default and setcompression(level) then becomes like the old + * setcompressionlevel(level). + */ + int + setcompression (int comp_level, + int comp_strategy = Z_DEFAULT_STRATEGY); + + /** + * @brief Check if file is open. + * @return True if file is open. + */ + bool + is_open () const { return (file != 0); } + + /** + * @brief Open gzipped file. + * @param name File name. + * @param mode Open mode flags. + * @return @c this on success, NULL on failure. + */ + gzfilebuf* + open (const char* name, + std::ios_base::openmode mode); + + /** + * @brief Attach to already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags. + * @return @c this on success, NULL on failure. + */ + gzfilebuf* + attach (int fd, + std::ios_base::openmode mode); + + /** + * @brief Close gzipped file. + * @return @c this on success, NULL on failure. + */ + gzfilebuf* + close (); + +protected: + /** + * @brief Convert ios open mode int to mode string used by zlib. + * @return True if valid mode flag combination. + */ + bool + open_mode (std::ios_base::openmode mode, + char* c_mode) const; + + /** + * @brief Number of characters available in stream buffer. + * @return Number of characters. + * + * This indicates number of characters in get area of stream buffer. + * These characters can be read without accessing the gzipped file. + */ + virtual std::streamsize + showmanyc (); + + /** + * @brief Fill get area from gzipped file. + * @return First character in get area on success, EOF on error. + * + * This actually reads characters from gzipped file to stream + * buffer. Always buffered. + */ + virtual int_type + underflow (); + + /** + * @brief Write put area to gzipped file. + * @param c Extra character to add to buffer contents. + * @return Non-EOF on success, EOF on error. + * + * This actually writes characters in stream buffer to + * gzipped file. With unbuffered output this is done one + * character at a time. + */ + virtual int_type + overflow (int_type c = traits_type::eof ()); + + /** + * @brief Installs external stream buffer. + * @param p Pointer to char buffer. + * @param n Size of external buffer. + * @return @c this on success, NULL on failure. + * + * Call setbuf(0,0) to enable unbuffered output. + */ + virtual std::streambuf* + setbuf (char_type* p, + std::streamsize n); + + /** + * @brief Flush stream buffer to file. + * @return 0 on success, -1 on error. + * + * This calls underflow(EOF) to do the job. + */ + virtual int + sync (); + + /** + * @brief Alters the stream positions. + * + * Each derived class provides its own appropriate behavior. + */ + virtual pos_type + seekoff (off_type off, std::ios_base::seekdir way, + std::ios_base::openmode mode = + std::ios_base::in|std::ios_base::out); + + /** + * @brief Alters the stream positions. + * + * Each derived class provides its own appropriate behavior. + */ + virtual pos_type + seekpos (pos_type sp, std::ios_base::openmode mode = + std::ios_base::in|std::ios_base::out); + + virtual int_type + pbackfail (int_type c = traits_type::eof ()); + +// +// Some future enhancements +// +// virtual int_type uflow(); +// virtual int_type pbackfail(int_type c = traits_type::eof()); + +private: + + // No copying! + + gzfilebuf (const gzfilebuf&); + + gzfilebuf& operator = (const gzfilebuf&); + + /** + * @brief Allocate internal buffer. + * + * This function is safe to call multiple times. It will ensure + * that a proper internal buffer exists if it is required. If the + * buffer already exists or is external, the buffer pointers will be + * reset to their original state. + */ + void + enable_buffer (); + + /** + * @brief Destroy internal buffer. + * + * This function is safe to call multiple times. It will ensure + * that the internal buffer is deallocated if it exists. In any + * case, it will also reset the buffer pointers. + */ + void + disable_buffer (); + + /** + * Underlying file pointer. + */ + gzFile file; + + /** + * Mode in which file was opened. + */ + std::ios_base::openmode io_mode; + + /** + * @brief True if this object owns file descriptor. + * + * This makes the class responsible for closing the file + * upon destruction. + */ + bool own_fd; + + /** + * @brief Stream buffer. + * + * For simplicity this remains allocated on the free store for the + * entire life span of the gzfilebuf object, unless replaced by setbuf. + */ + char_type* buffer; + + /** + * @brief Stream buffer size. + * + * Defaults to system default buffer size (typically 8192 bytes). + * Modified by setbuf. + */ + std::streamsize buffer_size; + + /** + * @brief True if this object owns stream buffer. + * + * This makes the class responsible for deleting the buffer + * upon destruction. + */ + bool own_buffer; +}; + +/*****************************************************************************/ + +/** + * @brief Gzipped file input stream class. + * + * This class implements ifstream for gzipped files. Seeking and putback + * is not supported yet. +*/ +class gzifstream : public std::istream +{ +public: + // Default constructor + gzifstream (); + + /** + * @brief Construct stream on gzipped file to be opened. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::in). + */ + explicit + gzifstream (const char* name, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * @brief Construct stream on already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::in). + */ + explicit + gzifstream (int fd, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * Obtain underlying stream buffer. + */ + gzfilebuf* + rdbuf () const + { return const_cast(&sb); } + + /** + * @brief Check if file is open. + * @return True if file is open. + */ + bool + is_open () { return sb.is_open (); } + + /** + * @brief Open gzipped file. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::in). + * + * Stream will be in state good() if file opens successfully; + * otherwise in state fail(). This differs from the behavior of + * ifstream, which never sets the state to good() and therefore + * won't allow you to reuse the stream for a second file unless + * you manually clear() the state. The choice is a matter of + * convenience. + */ + void + open (const char* name, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * @brief Attach to already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::in). + * + * Stream will be in state good() if attach succeeded; otherwise + * in state fail(). + */ + void + attach (int fd, + std::ios_base::openmode mode = std::ios_base::in); + + /** + * @brief Close gzipped file. + * + * Stream will be in state fail() if close failed. + */ + void + close (); + +private: + /** + * Underlying stream buffer. + */ + gzfilebuf sb; +}; + +/*****************************************************************************/ + +/** + * @brief Gzipped file output stream class. + * + * This class implements ofstream for gzipped files. Seeking and putback + * is not supported yet. +*/ +class gzofstream : public std::ostream +{ +public: + // Default constructor + gzofstream (); + + /** + * @brief Construct stream on gzipped file to be opened. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::out). + */ + explicit + gzofstream (const char* name, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * @brief Construct stream on already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::out). + */ + explicit + gzofstream (int fd, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * Obtain underlying stream buffer. + */ + gzfilebuf* + rdbuf () const + { return const_cast(&sb); } + + /** + * @brief Check if file is open. + * @return True if file is open. + */ + bool + is_open () { return sb.is_open (); } + + /** + * @brief Open gzipped file. + * @param name File name. + * @param mode Open mode flags (forced to contain ios::out). + * + * Stream will be in state good() if file opens successfully; + * otherwise in state fail(). This differs from the behavior of + * ofstream, which never sets the state to good() and therefore + * won't allow you to reuse the stream for a second file unless + * you manually clear() the state. The choice is a matter of + * convenience. + */ + void + open (const char* name, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * @brief Attach to already open gzipped file. + * @param fd File descriptor. + * @param mode Open mode flags (forced to contain ios::out). + * + * Stream will be in state good() if attach succeeded; otherwise + * in state fail(). + */ + void + attach (int fd, + std::ios_base::openmode mode = std::ios_base::out); + + /** + * @brief Close gzipped file. + * + * Stream will be in state fail() if close failed. + */ + void + close (); + +private: + /** + * Underlying stream buffer. + */ + gzfilebuf sb; +}; + +/*****************************************************************************/ + +/** + * @brief Gzipped file output stream manipulator class. + * + * This class defines a two-argument manipulator for gzofstream. It is used + * as base for the setcompression(int,int) manipulator. +*/ +template + class gzomanip2 + { + public: + // Allows insertor to peek at internals + template + friend gzofstream& + operator<<(gzofstream&, + const gzomanip2&); + + // Constructor + gzomanip2 (gzofstream& (*f)(gzofstream&, T1, T2), + T1 v1, + T2 v2); + private: + // Underlying manipulator function + gzofstream& + (*func)(gzofstream&, T1, T2); + + // Arguments for manipulator function + T1 val1; + T2 val2; + }; + +/*****************************************************************************/ + +// Manipulator function thunks through to stream buffer +inline gzofstream& +setcompression (gzofstream &gzs, int l, int s = Z_DEFAULT_STRATEGY) +{ + (gzs.rdbuf ())->setcompression (l, s); + return gzs; +} + +// Manipulator constructor stores arguments +template + inline + gzomanip2::gzomanip2 (gzofstream &(*f)(gzofstream &, T1, T2), + T1 v1, + T2 v2) + : func(f), val1(v1), val2(v2) + { } + +// Insertor applies underlying manipulator function to stream +template + inline gzofstream& + operator<<(gzofstream& s, const gzomanip2& m) + { return (*m.func)(s, m.val1, m.val2); } + +// Insert this onto stream to simplify setting of compression level +inline gzomanip2 +setcompression (int l, int s = Z_DEFAULT_STRATEGY) +{ return gzomanip2(&setcompression, l, s); } + +#endif // HAVE_ZLIB + +#endif // ZFSTREAM_H diff -r a132d206a36a -r b9b6a310ad97 src/interpfcn/data.cc --- a/src/interpfcn/data.cc Fri Aug 03 14:59:40 2012 -0400 +++ b/src/interpfcn/data.cc Fri Aug 03 18:05:18 2012 -0400 @@ -38,10 +38,7 @@ #include #include -extern "C" -{ #include -} #include "lo-ieee.h" #include "lo-math.h" diff -r a132d206a36a -r b9b6a310ad97 src/interpfcn/module.mk --- a/src/interpfcn/module.mk Fri Aug 03 14:59:40 2012 -0400 +++ b/src/interpfcn/module.mk Fri Aug 03 18:05:18 2012 -0400 @@ -1,5 +1,7 @@ EXTRA_DIST += \ - interpfcn/module.mk + interpfcn/module.mk \ + interpfcn/defaults.in.h \ + interpfcn/graphics.in.h INTERPFCN_INCLUDES = \ interpfcn/data.h \ @@ -63,3 +65,9 @@ $(AWK) -v emit_graphics_props=1 -f $(srcdir)/genprops.awk $< > $@-t mv $@-t $@ +## FIXME: Do these rules work correctly after transplant to interpfcn/ dir? +__fltk_uigetfile__.lo __fltk_uigetfile__.o: \ + AM_CXXFLAGS := $(filter-out $(DLL_CXXDEFS), $(AM_CXXFLAGS) $(GRAPHICS_CFLAGS)) + +__init_fltk__.lo __init_fltk__.o: \ + AM_CXXFLAGS := $(filter-out $(DLL_CXXDEFS), $(AM_CXXFLAGS) $(GRAPHICS_CFLAGS)) diff -r a132d206a36a -r b9b6a310ad97 src/jit-ir.cc --- a/src/jit-ir.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,649 +0,0 @@ -/* - -Copyright (C) 2012 Max Brister - -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 -. - -*/ - -// defines required by llvm -#define __STDC_LIMIT_MACROS -#define __STDC_CONSTANT_MACROS - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef HAVE_LLVM - -#include "jit-ir.h" - -#include -#include - -#include "error.h" -#include "pt-jit.h" - -// -------------------- jit_use -------------------- -jit_block * -jit_use::user_parent (void) const -{ - return muser->parent (); -} - -// -------------------- jit_value -------------------- -jit_value::~jit_value (void) -{} - -jit_block * -jit_value::first_use_block (void) -{ - jit_use *use = first_use (); - while (use) - { - if (! isa (use->user ())) - return use->user_parent (); - - use = use->next (); - } - - return 0; -} - -void -jit_value::replace_with (jit_value *value) -{ - while (first_use ()) - { - jit_instruction *user = first_use ()->user (); - size_t idx = first_use ()->index (); - user->stash_argument (idx, value); - } -} - -#define JIT_METH(clname) \ - void \ - jit_ ## clname::accept (jit_ir_walker& walker) \ - { \ - walker.visit (*this); \ - } - -JIT_VISIT_IR_NOTEMPLATE -#undef JIT_METH - -std::ostream& -operator<< (std::ostream& os, const jit_value& value) -{ - return value.short_print (os); -} - -std::ostream& -jit_print (std::ostream& os, jit_value *avalue) -{ - if (avalue) - return avalue->print (os); - return os << "NULL"; -} - -// -------------------- jit_instruction -------------------- -void -jit_instruction::remove (void) -{ - if (mparent) - mparent->remove (mlocation); - resize_arguments (0); -} - -llvm::BasicBlock * -jit_instruction::parent_llvm (void) const -{ - return mparent->to_llvm (); -} - -std::ostream& -jit_instruction::short_print (std::ostream& os) const -{ - if (type ()) - jit_print (os, type ()) << ": "; - return os << "#" << mid; -} - -void -jit_instruction::do_construct_ssa (size_t start, size_t end) -{ - for (size_t i = start; i < end; ++i) - { - jit_value *arg = argument (i); - jit_variable *var = dynamic_cast (arg); - if (var && var->has_top ()) - stash_argument (i, var->top ()); - } -} - -// -------------------- jit_block -------------------- -void -jit_block::replace_with (jit_value *value) -{ - assert (isa (value)); - jit_block *block = static_cast (value); - - jit_value::replace_with (block); - - while (ILIST_T::first_use ()) - { - jit_phi_incomming *incomming = ILIST_T::first_use (); - incomming->stash_value (block); - } -} - -void -jit_block::replace_in_phi (jit_block *ablock, jit_block *with) -{ - jit_phi_incomming *node = ILIST_T::first_use (); - while (node) - { - jit_phi_incomming *prev = node; - node = node->next (); - - if (prev->user_parent () == ablock) - prev->stash_value (with); - } -} - -jit_block * -jit_block::maybe_merge () -{ - if (successor_count () == 1 && successor (0) != this - && (successor (0)->use_count () == 1 || instructions.size () == 1)) - { - jit_block *to_merge = successor (0); - merge (*to_merge); - return to_merge; - } - - return 0; -} - -void -jit_block::merge (jit_block& block) -{ - // the merge block will contain a new terminator - jit_terminator *old_term = terminator (); - if (old_term) - old_term->remove (); - - bool was_empty = end () == begin (); - iterator merge_begin = end (); - if (! was_empty) - --merge_begin; - - instructions.splice (end (), block.instructions); - if (was_empty) - merge_begin = begin (); - else - ++merge_begin; - - // now merge_begin points to the start of the new instructions, we must - // update their parent information - for (iterator iter = merge_begin; iter != end (); ++iter) - { - jit_instruction *instr = *iter; - instr->stash_parent (this, iter); - } - - block.replace_with (this); -} - -jit_instruction * -jit_block::prepend (jit_instruction *instr) -{ - instructions.push_front (instr); - instr->stash_parent (this, instructions.begin ()); - return instr; -} - -jit_instruction * -jit_block::prepend_after_phi (jit_instruction *instr) -{ - // FIXME: Make this O(1) - for (iterator iter = begin (); iter != end (); ++iter) - { - jit_instruction *temp = *iter; - if (! isa (temp)) - { - insert_before (iter, instr); - return instr; - } - } - - return append (instr); -} - -void -jit_block::internal_append (jit_instruction *instr) -{ - instructions.push_back (instr); - instr->stash_parent (this, --instructions.end ()); -} - -jit_instruction * -jit_block::insert_before (iterator loc, jit_instruction *instr) -{ - iterator iloc = instructions.insert (loc, instr); - instr->stash_parent (this, iloc); - return instr; -} - -jit_instruction * -jit_block::insert_after (iterator loc, jit_instruction *instr) -{ - ++loc; - iterator iloc = instructions.insert (loc, instr); - instr->stash_parent (this, iloc); - return instr; -} - -jit_terminator * -jit_block::terminator (void) const -{ - assert (this); - if (instructions.empty ()) - return 0; - - jit_instruction *last = instructions.back (); - return dynamic_cast (last); -} - -bool -jit_block::branch_alive (jit_block *asucc) const -{ - return terminator ()->alive (asucc); -} - -jit_block * -jit_block::successor (size_t i) const -{ - jit_terminator *term = terminator (); - return term->successor (i); -} - -size_t -jit_block::successor_count (void) const -{ - jit_terminator *term = terminator (); - return term ? term->successor_count () : 0; -} - -llvm::BasicBlock * -jit_block::to_llvm (void) const -{ - return llvm::cast (llvm_value); -} - -std::ostream& -jit_block::print_dom (std::ostream& os) const -{ - short_print (os); - os << ":\n"; - os << " mid: " << mid << std::endl; - os << " predecessors: "; - for (jit_use *use = first_use (); use; use = use->next ()) - os << *use->user_parent () << " "; - os << std::endl; - - os << " successors: "; - for (size_t i = 0; i < successor_count (); ++i) - os << *successor (i) << " "; - os << std::endl; - - os << " idom: "; - if (idom) - os << *idom; - else - os << "NULL"; - os << std::endl; - os << " df: "; - for (df_iterator iter = df_begin (); iter != df_end (); ++iter) - os << **iter << " "; - os << std::endl; - - os << " dom_succ: "; - for (size_t i = 0; i < dom_succ.size (); ++i) - os << *dom_succ[i] << " "; - - return os << std::endl; -} - -void -jit_block::compute_df (size_t avisit_count) -{ - if (visited (avisit_count)) - return; - - if (use_count () >= 2) - { - for (jit_use *use = first_use (); use; use = use->next ()) - { - jit_block *runner = use->user_parent (); - while (runner != idom) - { - runner->mdf.insert (this); - runner = runner->idom; - } - } - } - - for (size_t i = 0; i < successor_count (); ++i) - successor (i)->compute_df (avisit_count); -} - -bool -jit_block::update_idom (size_t avisit_count) -{ - if (visited (avisit_count) || ! use_count ()) - return false; - - bool changed = false; - for (jit_use *use = first_use (); use; use = use->next ()) - { - jit_block *pred = use->user_parent (); - changed = pred->update_idom (avisit_count) || changed; - } - - jit_use *use = first_use (); - jit_block *new_idom = use->user_parent (); - use = use->next (); - - for (; use; use = use->next ()) - { - jit_block *pred = use->user_parent (); - jit_block *pidom = pred->idom; - if (pidom) - new_idom = idom_intersect (pidom, new_idom); - } - - if (idom != new_idom) - { - idom = new_idom; - return true; - } - - return changed; -} - -void -jit_block::pop_all (void) -{ - for (iterator iter = begin (); iter != end (); ++iter) - { - jit_instruction *instr = *iter; - instr->pop_variable (); - } -} - -jit_block * -jit_block::maybe_split (jit_convert& convert, jit_block *asuccessor) -{ - if (successor_count () > 1) - { - jit_terminator *term = terminator (); - size_t idx = term->successor_index (asuccessor); - jit_block *split = convert.create ("phi_split", mvisit_count); - - // try to place splits where they make sense - if (id () < asuccessor->id ()) - convert.insert_before (asuccessor, split); - else - convert.insert_after (this, split); - - term->stash_argument (idx, split); - jit_branch *br = split->append (convert.create (asuccessor)); - replace_in_phi (asuccessor, split); - - if (alive ()) - { - split->mark_alive (); - br->infer (); - } - - return split; - } - - return this; -} - -void -jit_block::create_dom_tree (size_t avisit_count) -{ - if (visited (avisit_count)) - return; - - if (idom != this) - idom->dom_succ.push_back (this); - - for (size_t i = 0; i < successor_count (); ++i) - successor (i)->create_dom_tree (avisit_count); -} - -jit_block * -jit_block::idom_intersect (jit_block *i, jit_block *j) -{ - while (i && j && i != j) - { - while (i && i->id () > j->id ()) - i = i->idom; - - while (i && j && j->id () > i->id ()) - j = j->idom; - } - - return i ? i : j; -} - -// -------------------- jit_phi_incomming -------------------- - -jit_block * -jit_phi_incomming::user_parent (void) const -{ return muser->parent (); } - -// -------------------- jit_phi -------------------- -bool -jit_phi::prune (void) -{ - jit_block *p = parent (); - size_t new_idx = 0; - jit_value *unique = argument (1); - - for (size_t i = 0; i < argument_count (); ++i) - { - jit_block *inc = incomming (i); - if (inc->branch_alive (p)) - { - if (unique != argument (i)) - unique = 0; - - if (new_idx != i) - { - stash_argument (new_idx, argument (i)); - mincomming[new_idx].stash_value (inc); - } - - ++new_idx; - } - } - - if (new_idx != argument_count ()) - { - resize_arguments (new_idx); - mincomming.resize (new_idx); - } - - assert (argument_count () > 0); - if (unique) - { - replace_with (unique); - return true; - } - - return false; -} - -bool -jit_phi::infer (void) -{ - jit_block *p = parent (); - if (! p->alive ()) - return false; - - jit_type *infered = 0; - for (size_t i = 0; i < argument_count (); ++i) - { - jit_block *inc = incomming (i); - if (inc->branch_alive (p)) - infered = jit_typeinfo::join (infered, argument_type (i)); - } - - if (infered != type ()) - { - stash_type (infered); - return true; - } - - return false; -} - -llvm::PHINode * -jit_phi::to_llvm (void) const -{ - return llvm::cast (jit_value::to_llvm ()); -} - -// -------------------- jit_terminator -------------------- -size_t -jit_terminator::successor_index (const jit_block *asuccessor) const -{ - size_t scount = successor_count (); - for (size_t i = 0; i < scount; ++i) - if (successor (i) == asuccessor) - return i; - - panic_impossible (); -} - -bool -jit_terminator::infer (void) -{ - if (! parent ()->alive ()) - return false; - - bool changed = false; - for (size_t i = 0; i < malive.size (); ++i) - if (! malive[i] && check_alive (i)) - { - changed = true; - malive[i] = true; - successor (i)->mark_alive (); - } - - return changed; -} - -llvm::TerminatorInst * -jit_terminator::to_llvm (void) const -{ - return llvm::cast (jit_value::to_llvm ()); -} - -// -------------------- jit_call -------------------- -bool -jit_call::infer (void) -{ - // FIXME: explain algorithm - for (size_t i = 0; i < argument_count (); ++i) - { - already_infered[i] = argument_type (i); - if (! already_infered[i]) - return false; - } - - jit_type *infered = moperation.result (already_infered); - if (! infered && use_count ()) - { - std::stringstream ss; - ss << "Missing overload in type inference for "; - print (ss, 0); - throw jit_fail_exception (ss.str ()); - } - - if (infered != type ()) - { - stash_type (infered); - return true; - } - - return false; -} - -// -------------------- jit_magic_end -------------------- -jit_magic_end::jit_magic_end (const std::vector& full_context) -{ - // for now we only support end in 1 dimensional indexing - resize_arguments (full_context.size ()); - - size_t i; - std::vector::const_iterator iter; - for (iter = full_context.begin (), i = 0; iter != full_context.end (); ++iter, - ++i) - { - if (iter->count != 1) - throw jit_fail_exception ("end is only supported in linear contexts"); - stash_argument (i, iter->value); - } -} - -const jit_function& -jit_magic_end::overload () const -{ - jit_value *ctx = resolve_context (); - if (ctx) - return jit_typeinfo::end (ctx->type ()); - - static jit_function null_ret; - return null_ret; -} - -jit_value * -jit_magic_end::resolve_context (void) const -{ - // FIXME: We need to have a way of marking functions so we can skip them here - return argument_count () ? argument (0) : 0; -} - -bool -jit_magic_end::infer (void) -{ - jit_type *new_type = overload ().result (); - if (new_type != type ()) - { - stash_type (new_type); - return true; - } - - return false; -} - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/jit-ir.h --- a/src/jit-ir.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1302 +0,0 @@ -/* - -Copyright (C) 2012 Max Brister - -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 (octave_jit_ir_h) -#define octave_jit_ir_h 1 - -#ifdef HAVE_LLVM - -#include -#include -#include - -#include "jit-typeinfo.h" - -// The low level octave jit ir -// this ir is close to llvm, but contains information for doing type inference. -// We convert the octave parse tree to this IR directly. - -#define JIT_VISIT_IR_NOTEMPLATE \ - JIT_METH(block); \ - JIT_METH(branch); \ - JIT_METH(cond_branch); \ - JIT_METH(call); \ - JIT_METH(extract_argument); \ - JIT_METH(store_argument); \ - JIT_METH(phi); \ - JIT_METH(variable); \ - JIT_METH(error_check); \ - JIT_METH(assign) \ - JIT_METH(argument) \ - JIT_METH(magic_end) - -#define JIT_VISIT_IR_CONST \ - JIT_METH(const_bool); \ - JIT_METH(const_scalar); \ - JIT_METH(const_complex); \ - JIT_METH(const_index); \ - JIT_METH(const_string); \ - JIT_METH(const_range) - -#define JIT_VISIT_IR_CLASSES \ - JIT_VISIT_IR_NOTEMPLATE \ - JIT_VISIT_IR_CONST - -// forward declare all ir classes -#define JIT_METH(cname) \ - class jit_ ## cname; - -JIT_VISIT_IR_NOTEMPLATE - -#undef JIT_METH - -class jit_convert; - -// ABCs which aren't included in JIT_VISIT_IR_ALL -class jit_instruction; -class jit_terminator; - -template -class jit_const; - -typedef jit_const jit_const_bool; -typedef jit_const jit_const_scalar; -typedef jit_const jit_const_complex; -typedef jit_const jit_const_index; - -typedef jit_const jit_const_string; -typedef jit_const -jit_const_range; - -class jit_ir_walker; -class jit_use; - -class -jit_value : public jit_internal_list -{ -public: - jit_value (void) : llvm_value (0), ty (0), mlast_use (0), - min_worklist (false) {} - - virtual ~jit_value (void); - - bool in_worklist (void) const - { - return min_worklist; - } - - void stash_in_worklist (bool ain_worklist) - { - min_worklist = ain_worklist; - } - - // The block of the first use which is not a jit_error_check - // So this is not necessarily first_use ()->parent (). - jit_block *first_use_block (void); - - // replace all uses with - virtual void replace_with (jit_value *value); - - jit_type *type (void) const { return ty; } - - llvm::Type *type_llvm (void) const - { - return ty ? ty->to_llvm () : 0; - } - - const std::string& type_name (void) const - { - return ty->name (); - } - - void stash_type (jit_type *new_ty) { ty = new_ty; } - - std::string print_string (void) - { - std::stringstream ss; - print (ss); - return ss.str (); - } - - jit_instruction *last_use (void) const { return mlast_use; } - - void stash_last_use (jit_instruction *alast_use) - { - mlast_use = alast_use; - } - - virtual bool needs_release (void) const { return false; } - - virtual std::ostream& print (std::ostream& os, size_t indent = 0) const = 0; - - virtual std::ostream& short_print (std::ostream& os) const - { return print (os); } - - virtual void accept (jit_ir_walker& walker) = 0; - - bool has_llvm (void) const - { - return llvm_value; - } - - llvm::Value *to_llvm (void) const - { - assert (llvm_value); - return llvm_value; - } - - void stash_llvm (llvm::Value *compiled) - { - llvm_value = compiled; - } - -protected: - std::ostream& print_indent (std::ostream& os, size_t indent = 0) const - { - for (size_t i = 0; i < indent * 8; ++i) - os << " "; - return os; - } - - llvm::Value *llvm_value; -private: - jit_type *ty; - jit_instruction *mlast_use; - bool min_worklist; -}; - -std::ostream& operator<< (std::ostream& os, const jit_value& value); -std::ostream& jit_print (std::ostream& os, jit_value *avalue); - -class -jit_use : public jit_internal_node -{ -public: - jit_use (void) : muser (0), mindex (0) {} - - // we should really have a move operator, but not until c++11 :( - jit_use (const jit_use& use) : muser (0), mindex (0) - { - *this = use; - } - - jit_use& operator= (const jit_use& use) - { - stash_value (use.value (), use.user (), use.index ()); - return *this; - } - - size_t index (void) const { return mindex; } - - jit_instruction *user (void) const { return muser; } - - jit_block *user_parent (void) const; - - std::list user_parent_location (void) const; - - void stash_value (jit_value *avalue, jit_instruction *auser = 0, - size_t aindex = -1) - { - jit_internal_node::stash_value (avalue); - mindex = aindex; - muser = auser; - } -private: - jit_instruction *muser; - size_t mindex; -}; - -class -jit_instruction : public jit_value -{ -public: - // FIXME: this code could be so much pretier with varadic templates... - jit_instruction (void) : mid (next_id ()), mparent (0) - {} - - jit_instruction (size_t nargs) : mid (next_id ()), mparent (0) - { - already_infered.reserve (nargs); - marguments.reserve (nargs); - } - -#define STASH_ARG(i) stash_argument (i, arg ## i); -#define JIT_INSTRUCTION_CTOR(N) \ - jit_instruction (OCT_MAKE_DECL_LIST (jit_value *, arg, N)) \ - : already_infered (N), marguments (N), mid (next_id ()), mparent (0) \ - { \ - OCT_ITERATE_MACRO (STASH_ARG, N); \ - } - - JIT_INSTRUCTION_CTOR(1) - JIT_INSTRUCTION_CTOR(2) - JIT_INSTRUCTION_CTOR(3) - JIT_INSTRUCTION_CTOR(4) - -#undef STASH_ARG -#undef JIT_INSTRUCTION_CTOR - - jit_instruction (const std::vector& aarguments) - : already_infered (aarguments.size ()), marguments (aarguments.size ()), - mid (next_id ()), mparent (0) - { - for (size_t i = 0; i < aarguments.size (); ++i) - stash_argument (i, aarguments[i]); - } - - static void reset_ids (void) - { - next_id (true); - } - - jit_value *argument (size_t i) const - { - return marguments[i].value (); - } - - llvm::Value *argument_llvm (size_t i) const - { - assert (argument (i)); - return argument (i)->to_llvm (); - } - - jit_type *argument_type (size_t i) const - { - return argument (i)->type (); - } - - llvm::Type *argument_type_llvm (size_t i) const - { - assert (argument (i)); - return argument_type (i)->to_llvm (); - } - - std::ostream& print_argument (std::ostream& os, size_t i) const - { - if (argument (i)) - return argument (i)->short_print (os); - else - return os << "NULL"; - } - - void stash_argument (size_t i, jit_value *arg) - { - marguments[i].stash_value (arg, this, i); - } - - void push_argument (jit_value *arg) - { - marguments.push_back (jit_use ()); - stash_argument (marguments.size () - 1, arg); - already_infered.push_back (0); - } - - size_t argument_count (void) const - { - return marguments.size (); - } - - void resize_arguments (size_t acount, jit_value *adefault = 0) - { - size_t old = marguments.size (); - marguments.resize (acount); - already_infered.resize (acount); - - if (adefault) - for (size_t i = old; i < acount; ++i) - stash_argument (i, adefault); - } - - const std::vector& arguments (void) const { return marguments; } - - // argument types which have been infered already - const std::vector& argument_types (void) const - { return already_infered; } - - virtual void push_variable (void) {} - - virtual void pop_variable (void) {} - - virtual void construct_ssa (void) - { - do_construct_ssa (0, argument_count ()); - } - - virtual bool infer (void) { return false; } - - void remove (void); - - virtual std::ostream& short_print (std::ostream& os) const; - - jit_block *parent (void) const { return mparent; } - - std::list::iterator location (void) const - { - return mlocation; - } - - llvm::BasicBlock *parent_llvm (void) const; - - void stash_parent (jit_block *aparent, - std::list::iterator alocation) - { - mparent = aparent; - mlocation = alocation; - } - - size_t id (void) const { return mid; } -protected: - - // Do SSA replacement on arguments in [start, end) - void do_construct_ssa (size_t start, size_t end); - - std::vector already_infered; -private: - static size_t next_id (bool reset = false) - { - static size_t ret = 0; - if (reset) - return ret = 0; - - return ret++; - } - - std::vector marguments; - - size_t mid; - jit_block *mparent; - std::list::iterator mlocation; -}; - -// defnie accept methods for subclasses -#define JIT_VALUE_ACCEPT \ - virtual void accept (jit_ir_walker& walker); - -// for use as a dummy argument during conversion to LLVM -class -jit_argument : public jit_value -{ -public: - jit_argument (jit_type *atype, llvm::Value *avalue) - { - stash_type (atype); - stash_llvm (avalue); - } - - virtual std::ostream& print (std::ostream& os, size_t indent = 0) const - { - print_indent (os, indent); - return jit_print (os, type ()) << ": DUMMY"; - } - - JIT_VALUE_ACCEPT; -}; - -template -class -jit_const : public jit_value -{ -public: - typedef PASS_T pass_t; - - jit_const (PASS_T avalue) : mvalue (avalue) - { - stash_type (EXTRACT_T ()); - } - - PASS_T value (void) const { return mvalue; } - - virtual std::ostream& print (std::ostream& os, size_t indent = 0) const - { - print_indent (os, indent); - jit_print (os, type ()) << ": "; - if (QUOTE) - os << "\""; - os << mvalue; - if (QUOTE) - os << "\""; - return os; - } - - JIT_VALUE_ACCEPT; -private: - T mvalue; -}; - -class jit_phi_incomming; - -class -jit_block : public jit_value, public jit_internal_list -{ - typedef jit_internal_list ILIST_T; -public: - typedef std::list instruction_list; - typedef instruction_list::iterator iterator; - typedef instruction_list::const_iterator const_iterator; - - typedef std::set df_set; - typedef df_set::const_iterator df_iterator; - - static const size_t NO_ID = static_cast (-1); - - jit_block (const std::string& aname, size_t avisit_count = 0) - : mvisit_count (avisit_count), mid (NO_ID), idom (0), mname (aname), - malive (false) - {} - - virtual void replace_with (jit_value *value); - - void replace_in_phi (jit_block *ablock, jit_block *with); - - // we have a new internal list, but we want to stay compatable with jit_value - jit_use *first_use (void) const { return jit_value::first_use (); } - - size_t use_count (void) const { return jit_value::use_count (); } - - // if a block is alive, then it might be visited during execution - bool alive (void) const { return malive; } - - void mark_alive (void) { malive = true; } - - // If we can merge with a successor, do so and return the now empty block - jit_block *maybe_merge (); - - // merge another block into this block, leaving the merge block empty - void merge (jit_block& merge); - - const std::string& name (void) const { return mname; } - - jit_instruction *prepend (jit_instruction *instr); - - jit_instruction *prepend_after_phi (jit_instruction *instr); - - template - T *append (T *instr) - { - internal_append (instr); - return instr; - } - - jit_instruction *insert_before (iterator loc, jit_instruction *instr); - - jit_instruction *insert_before (jit_instruction *loc, jit_instruction *instr) - { - return insert_before (loc->location (), instr); - } - - jit_instruction *insert_after (iterator loc, jit_instruction *instr); - - jit_instruction *insert_after (jit_instruction *loc, jit_instruction *instr) - { - return insert_after (loc->location (), instr); - } - - iterator remove (iterator iter) - { - jit_instruction *instr = *iter; - iter = instructions.erase (iter); - instr->stash_parent (0, instructions.end ()); - return iter; - } - - jit_terminator *terminator (void) const; - - // is the jump from pred alive? - bool branch_alive (jit_block *asucc) const; - - jit_block *successor (size_t i) const; - - size_t successor_count (void) const; - - iterator begin (void) { return instructions.begin (); } - - const_iterator begin (void) const { return instructions.begin (); } - - iterator end (void) { return instructions.end (); } - - const_iterator end (void) const { return instructions.end (); } - - iterator phi_begin (void); - - iterator phi_end (void); - - iterator nonphi_begin (void); - - // must label before id is valid - size_t id (void) const { return mid; } - - // dominance frontier - const df_set& df (void) const { return mdf; } - - df_iterator df_begin (void) const { return mdf.begin (); } - - df_iterator df_end (void) const { return mdf.end (); } - - // label with a RPO walk - void label (void) - { - size_t number = 0; - label (mvisit_count, number); - } - - void label (size_t avisit_count, size_t& number) - { - if (visited (avisit_count)) - return; - - for (jit_use *use = first_use (); use; use = use->next ()) - { - jit_block *pred = use->user_parent (); - pred->label (avisit_count, number); - } - - mid = number++; - } - - // See for idom computation algorithm - // Cooper, Keith D.; Harvey, Timothy J; and Kennedy, Ken (2001). - // "A Simple, Fast Dominance Algorithm" - void compute_idom (jit_block *entry_block) - { - bool changed; - entry_block->idom = entry_block; - do - changed = update_idom (mvisit_count); - while (changed); - } - - // compute dominance frontier - void compute_df (void) - { - compute_df (mvisit_count); - } - - void create_dom_tree (void) - { - create_dom_tree (mvisit_count); - } - - jit_block *dom_successor (size_t idx) const - { - return dom_succ[idx]; - } - - size_t dom_successor_count (void) const - { - return dom_succ.size (); - } - - // call pop_varaible on all instructions - void pop_all (void); - - virtual std::ostream& print (std::ostream& os, size_t indent = 0) const - { - print_indent (os, indent); - short_print (os) << ": %pred = "; - for (jit_use *use = first_use (); use; use = use->next ()) - { - jit_block *pred = use->user_parent (); - os << *pred; - if (use->next ()) - os << ", "; - } - os << std::endl; - - for (const_iterator iter = begin (); iter != end (); ++iter) - { - jit_instruction *instr = *iter; - instr->print (os, indent + 1) << std::endl; - } - return os; - } - - // ... - jit_block *maybe_split (jit_convert& convert, jit_block *asuccessor); - - jit_block *maybe_split (jit_convert& convert, jit_block& asuccessor) - { - return maybe_split (convert, &asuccessor); - } - - // print dominator infomration - std::ostream& print_dom (std::ostream& os) const; - - virtual std::ostream& short_print (std::ostream& os) const - { - os << mname; - if (mid != NO_ID) - os << mid; - return os; - } - - llvm::BasicBlock *to_llvm (void) const; - - std::list::iterator location (void) const - { return mlocation; } - - void stash_location (std::list::iterator alocation) - { mlocation = alocation; } - - // used to prevent visiting the same node twice in the graph - size_t visit_count (void) const { return mvisit_count; } - - // check if this node has been visited yet at the given visit count. If we - // have not been visited yet, mark us as visited. - bool visited (size_t avisit_count) - { - if (mvisit_count <= avisit_count) - { - mvisit_count = avisit_count + 1; - return false; - } - - return true; - } - - JIT_VALUE_ACCEPT; -private: - void internal_append (jit_instruction *instr); - - void compute_df (size_t avisit_count); - - bool update_idom (size_t avisit_count); - - void create_dom_tree (size_t avisit_count); - - static jit_block *idom_intersect (jit_block *i, jit_block *j); - - size_t mvisit_count; - size_t mid; - jit_block *idom; - df_set mdf; - std::vector dom_succ; - std::string mname; - instruction_list instructions; - bool malive; - std::list::iterator mlocation; -}; - -// keeps track of phi functions that use a block on incomming edges -class -jit_phi_incomming : public jit_internal_node -{ -public: - jit_phi_incomming (void) : muser (0) {} - - jit_phi_incomming (jit_phi *auser) : muser (auser) {} - - jit_phi_incomming (const jit_phi_incomming& use) : jit_internal_node () - { - *this = use; - } - - jit_phi_incomming& operator= (const jit_phi_incomming& use) - { - stash_value (use.value ()); - muser = use.muser; - return *this; - } - - jit_phi *user (void) const { return muser; } - - jit_block *user_parent (void) const; -private: - jit_phi *muser; -}; - -// A non-ssa variable -class -jit_variable : public jit_value -{ -public: - jit_variable (const std::string& aname) : mname (aname), mlast_use (0) {} - - const std::string &name (void) const { return mname; } - - // manipulate the value_stack, for use during SSA construction. The top of the - // value stack represents the current value for this variable - bool has_top (void) const - { - return ! value_stack.empty (); - } - - jit_value *top (void) const - { - return value_stack.top (); - } - - void push (jit_instruction *v) - { - value_stack.push (v); - mlast_use = v; - } - - void pop (void) - { - value_stack.pop (); - } - - jit_instruction *last_use (void) const - { - return mlast_use; - } - - void stash_last_use (jit_instruction *instr) - { - mlast_use = instr; - } - - // blocks in which we are used - void use_blocks (jit_block::df_set& result) - { - jit_use *use = first_use (); - while (use) - { - result.insert (use->user_parent ()); - use = use->next (); - } - } - - virtual std::ostream& print (std::ostream& os, size_t indent = 0) const - { - return print_indent (os, indent) << mname; - } - - JIT_VALUE_ACCEPT; -private: - std::string mname; - std::stack value_stack; - jit_instruction *mlast_use; -}; - -class -jit_assign_base : public jit_instruction -{ -public: - jit_assign_base (jit_variable *adest) : jit_instruction (), mdest (adest) {} - - jit_assign_base (jit_variable *adest, size_t npred) : jit_instruction (npred), - mdest (adest) {} - - jit_assign_base (jit_variable *adest, jit_value *arg0, jit_value *arg1) - : jit_instruction (arg0, arg1), mdest (adest) {} - - jit_variable *dest (void) const { return mdest; } - - virtual void push_variable (void) - { - mdest->push (this); - } - - virtual void pop_variable (void) - { - mdest->pop (); - } - - virtual std::ostream& short_print (std::ostream& os) const - { - if (type ()) - jit_print (os, type ()) << ": "; - - dest ()->short_print (os); - return os << "#" << id (); - } -private: - jit_variable *mdest; -}; - -class -jit_assign : public jit_assign_base -{ -public: - jit_assign (jit_variable *adest, jit_value *asrc) - : jit_assign_base (adest, adest, asrc), martificial (false) {} - - jit_value *overwrite (void) const - { - return argument (0); - } - - jit_value *src (void) const - { - return argument (1); - } - - // variables don't get modified in an SSA, but COW requires we modify - // variables. An artificial assign is for when a variable gets modified. We - // need an assign in the SSA, but the reference counts shouldn't be updated. - bool artificial (void) const { return martificial; } - - void mark_artificial (void) { martificial = true; } - - virtual bool infer (void) - { - jit_type *stype = src ()->type (); - if (stype != type()) - { - stash_type (stype); - return true; - } - - return false; - } - - virtual std::ostream& print (std::ostream& os, size_t indent = 0) const - { - print_indent (os, indent) << *this << " = " << *src (); - - if (artificial ()) - os << " [artificial]"; - - return os; - } - - JIT_VALUE_ACCEPT; -private: - bool martificial; -}; - -class -jit_phi : public jit_assign_base -{ -public: - jit_phi (jit_variable *adest, size_t npred) - : jit_assign_base (adest, npred) - { - mincomming.reserve (npred); - } - - // removes arguments form dead incomming jumps - bool prune (void); - - void add_incomming (jit_block *from, jit_value *value) - { - push_argument (value); - mincomming.push_back (jit_phi_incomming (this)); - mincomming[mincomming.size () - 1].stash_value (from); - } - - jit_block *incomming (size_t i) const - { - return mincomming[i].value (); - } - - llvm::BasicBlock *incomming_llvm (size_t i) const - { - return incomming (i)->to_llvm (); - } - - virtual void construct_ssa (void) {} - - virtual bool infer (void); - - virtual std::ostream& print (std::ostream& os, size_t indent = 0) const - { - std::stringstream ss; - print_indent (ss, indent); - short_print (ss) << " phi "; - std::string ss_str = ss.str (); - std::string indent_str (ss_str.size (), ' '); - os << ss_str; - - for (size_t i = 0; i < argument_count (); ++i) - { - if (i > 0) - os << indent_str; - os << "| "; - - os << *incomming (i) << " -> "; - os << *argument (i); - - if (i + 1 < argument_count ()) - os << std::endl; - } - - return os; - } - - llvm::PHINode *to_llvm (void) const; - - JIT_VALUE_ACCEPT; -private: - std::vector mincomming; -}; - -class -jit_terminator : public jit_instruction -{ -public: -#define JIT_TERMINATOR_CONST(N) \ - jit_terminator (size_t asuccessor_count, \ - OCT_MAKE_DECL_LIST (jit_value *, arg, N)) \ - : jit_instruction (OCT_MAKE_ARG_LIST (arg, N)), \ - malive (asuccessor_count, false) {} - - JIT_TERMINATOR_CONST (1) - JIT_TERMINATOR_CONST (2) - JIT_TERMINATOR_CONST (3) - -#undef JIT_TERMINATOR_CONST - - jit_block *successor (size_t idx = 0) const - { - return static_cast (argument (idx)); - } - - llvm::BasicBlock *successor_llvm (size_t idx = 0) const - { - return successor (idx)->to_llvm (); - } - - size_t successor_index (const jit_block *asuccessor) const; - - std::ostream& print_successor (std::ostream& os, size_t idx = 0) const - { - if (alive (idx)) - os << "[live] "; - else - os << "[dead] "; - - return successor (idx)->short_print (os); - } - - // Check if the jump to successor is live - bool alive (const jit_block *asuccessor) const - { - return alive (successor_index (asuccessor)); - } - - bool alive (size_t idx) const { return malive[idx]; } - - bool alive (int idx) const { return malive[idx]; } - - size_t successor_count (void) const { return malive.size (); } - - virtual bool infer (void); - - llvm::TerminatorInst *to_llvm (void) const; -protected: - virtual bool check_alive (size_t) const { return true; } -private: - std::vector malive; -}; - -class -jit_branch : public jit_terminator -{ -public: - jit_branch (jit_block *succ) : jit_terminator (1, succ) {} - - virtual size_t successor_count (void) const { return 1; } - - virtual std::ostream& print (std::ostream& os, size_t indent = 0) const - { - print_indent (os, indent) << "branch: "; - return print_successor (os); - } - - JIT_VALUE_ACCEPT; -}; - -class -jit_cond_branch : public jit_terminator -{ -public: - jit_cond_branch (jit_value *c, jit_block *ctrue, jit_block *cfalse) - : jit_terminator (2, ctrue, cfalse, c) {} - - jit_value *cond (void) const { return argument (2); } - - std::ostream& print_cond (std::ostream& os) const - { - return cond ()->short_print (os); - } - - llvm::Value *cond_llvm (void) const - { - return cond ()->to_llvm (); - } - - virtual size_t successor_count (void) const { return 2; } - - virtual std::ostream& print (std::ostream& os, size_t indent = 0) const - { - print_indent (os, indent) << "cond_branch: "; - print_cond (os) << ", "; - print_successor (os, 0) << ", "; - return print_successor (os, 1); - } - - JIT_VALUE_ACCEPT; -}; - -class -jit_call : public jit_instruction -{ -public: -#define JIT_CALL_CONST(N) \ - jit_call (const jit_operation& aoperation, \ - OCT_MAKE_DECL_LIST (jit_value *, arg, N)) \ - : jit_instruction (OCT_MAKE_ARG_LIST (arg, N)), moperation (aoperation) {} \ - \ - jit_call (const jit_operation& (*aoperation) (void), \ - OCT_MAKE_DECL_LIST (jit_value *, arg, N)) \ - : jit_instruction (OCT_MAKE_ARG_LIST (arg, N)), moperation (aoperation ()) \ - {} - - JIT_CALL_CONST (1) - JIT_CALL_CONST (2) - JIT_CALL_CONST (3) - JIT_CALL_CONST (4) - -#undef JIT_CALL_CONST - - jit_call (const jit_operation& aoperation, - const std::vector& args) - : jit_instruction (args), moperation (aoperation) - {} - - const jit_operation& operation (void) const { return moperation; } - - bool can_error (void) const - { - return overload ().can_error (); - } - - const jit_function& overload (void) const - { - return moperation.overload (argument_types ()); - } - - virtual bool needs_release (void) const - { - return type () && jit_typeinfo::get_release (type ()).valid (); - } - - virtual std::ostream& print (std::ostream& os, size_t indent = 0) const - { - print_indent (os, indent); - - if (use_count ()) - short_print (os) << " = "; - os << "call " << moperation.name () << " ("; - - for (size_t i = 0; i < argument_count (); ++i) - { - print_argument (os, i); - if (i + 1 < argument_count ()) - os << ", "; - } - return os << ")"; - } - - virtual bool infer (void); - - JIT_VALUE_ACCEPT; -private: - const jit_operation& moperation; -}; - -// FIXME: This is just ugly... -// checks error_state, if error_state is false then goto the normal branche, -// otherwise goto the error branch -class -jit_error_check : public jit_terminator -{ -public: - jit_error_check (jit_call *acheck_for, jit_block *normal, jit_block *error) - : jit_terminator (2, error, normal, acheck_for) {} - - jit_call *check_for (void) const - { - return static_cast (argument (2)); - } - - virtual std::ostream& print (std::ostream& os, size_t indent = 0) const - { - print_indent (os, indent) << "error_check " << *check_for () << ", "; - print_successor (os, 1) << ", "; - return print_successor (os, 0); - } - - JIT_VALUE_ACCEPT; -protected: - virtual bool check_alive (size_t idx) const - { - return idx == 1 ? true : check_for ()->can_error (); - } -}; - -// for now only handles the 1D case -class -jit_magic_end : public jit_instruction -{ -public: - class - context - { - public: - context (void) : value (0), index (0), count (0) - {} - - context (jit_value *avalue, size_t aindex, size_t acount) - : value (avalue), index (aindex), count (acount) - {} - - jit_value *value; - size_t index; - size_t count; - }; - - jit_magic_end (const std::vector& full_context); - - const jit_function& overload () const; - - jit_value *resolve_context (void) const; - - virtual bool infer (void); - - virtual std::ostream& short_print (std::ostream& os) const - { - return os << "magic_end"; - } - - virtual std::ostream& print (std::ostream& os, size_t indent = 0) const - { - return short_print (print_indent (os, indent)); - } - - JIT_VALUE_ACCEPT; -}; - -class -jit_extract_argument : public jit_assign_base -{ -public: - jit_extract_argument (jit_type *atype, jit_variable *adest) - : jit_assign_base (adest) - { - stash_type (atype); - } - - const std::string& name (void) const - { - return dest ()->name (); - } - - const jit_function& overload (void) const - { - return jit_typeinfo::cast (type (), jit_typeinfo::get_any ()); - } - - virtual std::ostream& print (std::ostream& os, size_t indent = 0) const - { - print_indent (os, indent); - - return short_print (os) << " = extract " << name (); - } - - JIT_VALUE_ACCEPT; -}; - -class -jit_store_argument : public jit_instruction -{ -public: - jit_store_argument (jit_variable *var) - : jit_instruction (var), dest (var) - {} - - const std::string& name (void) const - { - return dest->name (); - } - - const jit_function& overload (void) const - { - return jit_typeinfo::cast (jit_typeinfo::get_any (), result_type ()); - } - - jit_value *result (void) const - { - return argument (0); - } - - jit_type *result_type (void) const - { - return result ()->type (); - } - - llvm::Value *result_llvm (void) const - { - return result ()->to_llvm (); - } - - virtual std::ostream& print (std::ostream& os, size_t indent = 0) const - { - jit_value *res = result (); - print_indent (os, indent) << "store "; - dest->short_print (os); - - if (! isa (res)) - { - os << " = "; - res->short_print (os); - } - - return os; - } - - JIT_VALUE_ACCEPT; -private: - jit_variable *dest; -}; - -class -jit_ir_walker -{ -public: - virtual ~jit_ir_walker () {} - -#define JIT_METH(clname) \ - virtual void visit (jit_ ## clname&) = 0; - - JIT_VISIT_IR_CLASSES; - -#undef JIT_METH -}; - -template -void -jit_const::accept (jit_ir_walker& walker) -{ - walker.visit (*this); -} - -#undef JIT_VALUE_ACCEPT - -#endif -#endif diff -r a132d206a36a -r b9b6a310ad97 src/jit-typeinfo.cc --- a/src/jit-typeinfo.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2071 +0,0 @@ -/* - -Copyright (C) 2012 Max Brister - -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 -. - -*/ - -// defines required by llvm -#define __STDC_LIMIT_MACROS -#define __STDC_CONSTANT_MACROS - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef HAVE_LLVM - -#include "jit-typeinfo.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "jit-ir.h" -#include "ov.h" -#include "ov-builtin.h" -#include "ov-complex.h" -#include "ov-scalar.h" -#include "pager.h" - -static llvm::LLVMContext& context = llvm::getGlobalContext (); - -jit_typeinfo *jit_typeinfo::instance = 0; - -std::ostream& jit_print (std::ostream& os, jit_type *atype) -{ - if (! atype) - return os << "null"; - return os << atype->name (); -} - -// function that jit code calls -extern "C" void -octave_jit_print_any (const char *name, octave_base_value *obv) -{ - obv->print_with_name (octave_stdout, name, true); -} - -extern "C" void -octave_jit_print_scalar (const char *name, double value) -{ - // FIXME: We should avoid allocating a new octave_scalar each time - octave_value ov (value); - ov.print_with_name (octave_stdout, name); -} - -extern "C" octave_base_value* -octave_jit_binary_any_any (octave_value::binary_op op, octave_base_value *lhs, - octave_base_value *rhs) -{ - octave_value olhs (lhs, true); - octave_value orhs (rhs, true); - octave_value result = do_binary_op (op, olhs, orhs); - octave_base_value *rep = result.internal_rep (); - rep->grab (); - return rep; -} - -extern "C" octave_idx_type -octave_jit_compute_nelem (double base, double limit, double inc) -{ - Range rng = Range (base, limit, inc); - return rng.nelem (); -} - -extern "C" void -octave_jit_release_any (octave_base_value *obv) -{ - obv->release (); -} - -extern "C" void -octave_jit_release_matrix (jit_matrix *m) -{ - delete m->array; -} - -extern "C" octave_base_value * -octave_jit_grab_any (octave_base_value *obv) -{ - obv->grab (); - return obv; -} - -extern "C" void -octave_jit_grab_matrix (jit_matrix *result, jit_matrix *m) -{ - *result = *m->array; -} - -extern "C" octave_base_value * -octave_jit_cast_any_matrix (jit_matrix *m) -{ - octave_value ret (*m->array); - octave_base_value *rep = ret.internal_rep (); - rep->grab (); - delete m->array; - - return rep; -} - -extern "C" void -octave_jit_cast_matrix_any (jit_matrix *ret, octave_base_value *obv) -{ - NDArray m = obv->array_value (); - *ret = m; - obv->release (); -} - -extern "C" octave_base_value * -octave_jit_cast_any_range (jit_range *rng) -{ - Range temp (*rng); - octave_value ret (temp); - octave_base_value *rep = ret.internal_rep (); - rep->grab (); - - return rep; -} -extern "C" void -octave_jit_cast_range_any (jit_range *ret, octave_base_value *obv) -{ - - jit_range r (obv->range_value ()); - *ret = r; - obv->release (); -} - -extern "C" double -octave_jit_cast_scalar_any (octave_base_value *obv) -{ - double ret = obv->double_value (); - obv->release (); - return ret; -} - -extern "C" octave_base_value * -octave_jit_cast_any_scalar (double value) -{ - return new octave_scalar (value); -} - -extern "C" Complex -octave_jit_cast_complex_any (octave_base_value *obv) -{ - Complex ret = obv->complex_value (); - obv->release (); - return ret; -} - -extern "C" octave_base_value * -octave_jit_cast_any_complex (Complex c) -{ - if (c.imag () == 0) - return new octave_scalar (c.real ()); - else - return new octave_complex (c); -} - -extern "C" void -octave_jit_gripe_nan_to_logical_conversion (void) -{ - try - { - gripe_nan_to_logical_conversion (); - } - catch (const octave_execution_exception&) - { - gripe_library_execution_error (); - } -} - -extern "C" void -octave_jit_ginvalid_index (void) -{ - try - { - gripe_invalid_index (); - } - catch (const octave_execution_exception&) - { - gripe_library_execution_error (); - } -} - -extern "C" void -octave_jit_gindex_range (int nd, int dim, octave_idx_type iext, - octave_idx_type ext) -{ - try - { - gripe_index_out_of_range (nd, dim, iext, ext); - } - catch (const octave_execution_exception&) - { - gripe_library_execution_error (); - } -} - -extern "C" void -octave_jit_paren_subsasgn_impl (jit_matrix *ret, jit_matrix *mat, - octave_idx_type index, double value) -{ - NDArray *array = mat->array; - if (array->nelem () < index) - array->resize1 (index); - - double *data = array->fortran_vec (); - data[index - 1] = value; - - mat->update (); - *ret = *mat; -} - -static void -make_indices (double *indices, octave_idx_type idx_count, - Array& result) -{ - result.resize (dim_vector (1, idx_count)); - for (octave_idx_type i = 0; i < idx_count; ++i) - result(i) = idx_vector (indices[i]); -} - -extern "C" double -octave_jit_paren_scalar (jit_matrix *mat, double *indicies, - octave_idx_type idx_count) -{ - // FIXME: Replace this with a more optimal version - try - { - Array idx; - make_indices (indicies, idx_count, idx); - - Array ret = mat->array->index (idx); - return ret.xelem (0); - } - catch (const octave_execution_exception&) - { - gripe_library_execution_error (); - return 0; - } -} - -extern "C" void -octave_jit_paren_scalar_subsasgn (jit_matrix *ret, jit_matrix *mat, - double *indices, octave_idx_type idx_count, - double value) -{ - // FIXME: Replace this with a more optimal version - try - { - Array idx; - make_indices (indices, idx_count, idx); - - Matrix temp (1, 1); - temp.xelem(0) = value; - mat->array->assign (idx, temp); - ret->update (mat->array); - } - catch (const octave_execution_exception&) - { - gripe_library_execution_error (); - } -} - -extern "C" void -octave_jit_paren_subsasgn_matrix_range (jit_matrix *result, jit_matrix *mat, - jit_range *index, double value) -{ - NDArray *array = mat->array; - bool done = false; - - // optimize for the simple case (no resizing and no errors) - if (*array->jit_ref_count () == 1 - && index->all_elements_are_ints ()) - { - // this code is similar to idx_vector::fill, but we avoid allocating an - // idx_vector and its associated rep - octave_idx_type start = static_cast (index->base) - 1; - octave_idx_type step = static_cast (index->inc); - octave_idx_type nelem = index->nelem; - octave_idx_type final = start + nelem * step; - if (step < 0) - { - step = -step; - std::swap (final, start); - } - - if (start >= 0 && final < mat->slice_len) - { - done = true; - - double *data = array->jit_slice_data (); - if (step == 1) - std::fill (data + start, data + start + nelem, value); - else - { - for (octave_idx_type i = start; i < final; i += step) - data[i] = value; - } - } - } - - if (! done) - { - idx_vector idx (*index); - NDArray avalue (dim_vector (1, 1)); - avalue.xelem (0) = value; - array->assign (idx, avalue); - } - - result->update (array); -} - -extern "C" Complex -octave_jit_complex_div (Complex lhs, Complex rhs) -{ - // see src/OPERATORS/op-cs-cs.cc - if (rhs == 0.0) - gripe_divide_by_zero (); - - return lhs / rhs; -} - -// FIXME: CP form src/xpow.cc -static inline int -xisint (double x) -{ - return (D_NINT (x) == x - && ((x >= 0 && x < INT_MAX) - || (x <= 0 && x > INT_MIN))); -} - -extern "C" Complex -octave_jit_pow_scalar_scalar (double lhs, double rhs) -{ - // FIXME: almost CP from src/xpow.cc - if (lhs < 0.0 && ! xisint (rhs)) - return std::pow (Complex (lhs), rhs); - return std::pow (lhs, rhs); -} - -extern "C" Complex -octave_jit_pow_complex_complex (Complex lhs, Complex rhs) -{ - if (lhs.imag () == 0 && rhs.imag () == 0) - return octave_jit_pow_scalar_scalar (lhs.real (), rhs.real ()); - return std::pow (lhs, rhs); -} - -extern "C" Complex -octave_jit_pow_complex_scalar (Complex lhs, double rhs) -{ - if (lhs.imag () == 0) - return octave_jit_pow_scalar_scalar (lhs.real (), rhs); - return std::pow (lhs, rhs); -} - -extern "C" Complex -octave_jit_pow_scalar_complex (double lhs, Complex rhs) -{ - if (rhs.imag () == 0) - return octave_jit_pow_scalar_scalar (lhs, rhs.real ()); - return std::pow (lhs, rhs); -} - -extern "C" void -octave_jit_print_matrix (jit_matrix *m) -{ - std::cout << *m << std::endl; -} - -static void -gripe_bad_result (void) -{ - error ("incorrect type information given to the JIT compiler"); -} - -// FIXME: Add support for multiple outputs -extern "C" octave_base_value * -octave_jit_call (octave_builtin::fcn fn, size_t nargin, - octave_base_value **argin, jit_type *result_type) -{ - octave_value_list ovl (nargin); - for (size_t i = 0; i < nargin; ++i) - ovl.xelem (i) = octave_value (argin[i]); - - ovl = fn (ovl, 1); - - // These type checks are not strictly required, but I'm guessing that - // incorrect types will be entered on occasion. This will be very difficult to - // debug unless we do the sanity check here. - if (result_type) - { - if (ovl.length () != 1) - { - gripe_bad_result (); - return 0; - } - - octave_value& result = ovl.xelem (0); - jit_type *jtype = jit_typeinfo::join (jit_typeinfo::type_of (result), - result_type); - if (jtype != result_type) - { - gripe_bad_result (); - return 0; - } - - octave_base_value *ret = result.internal_rep (); - ret->grab (); - return ret; - } - - if (! (ovl.length () == 0 - || (ovl.length () == 1 && ovl.xelem (0).is_undefined ()))) - gripe_bad_result (); - - return 0; -} - -// -------------------- jit_range -------------------- -bool -jit_range::all_elements_are_ints () const -{ - Range r (*this); - return r.all_elements_are_ints (); -} - -std::ostream& -operator<< (std::ostream& os, const jit_range& rng) -{ - return os << "Range[" << rng.base << ", " << rng.limit << ", " << rng.inc - << ", " << rng.nelem << "]"; -} - -// -------------------- jit_matrix -------------------- - -std::ostream& -operator<< (std::ostream& os, const jit_matrix& mat) -{ - return os << "Matrix[" << mat.ref_count << ", " << mat.slice_data << ", " - << mat.slice_len << ", " << mat.dimensions << ", " - << mat.array << "]"; -} - -// -------------------- jit_type -------------------- -jit_type::jit_type (const std::string& aname, jit_type *aparent, - llvm::Type *allvm_type, int aid) : - mname (aname), mparent (aparent), llvm_type (allvm_type), mid (aid), - mdepth (aparent ? aparent->mdepth + 1 : 0) -{ - std::memset (msret, 0, sizeof (msret)); - std::memset (mpointer_arg, 0, sizeof (mpointer_arg)); - std::memset (mpack, 0, sizeof (mpack)); - std::memset (munpack, 0, sizeof (munpack)); - - for (size_t i = 0; i < jit_convention::length; ++i) - mpacked_type[i] = llvm_type; -} - -llvm::Type * -jit_type::to_llvm_arg (void) const -{ - return llvm_type ? llvm_type->getPointerTo () : 0; -} - -// -------------------- jit_function -------------------- -jit_function::jit_function () : module (0), llvm_function (0), mresult (0), - call_conv (jit_convention::length), - mcan_error (false) -{} - -jit_function::jit_function (llvm::Module *amodule, - jit_convention::type acall_conv, - const llvm::Twine& aname, jit_type *aresult, - const std::vector& aargs) - : module (amodule), mresult (aresult), args (aargs), call_conv (acall_conv), - mcan_error (false) -{ - llvm::SmallVector llvm_args; - - llvm::Type *rtype = llvm::Type::getVoidTy (context); - if (mresult) - { - rtype = mresult->packed_type (call_conv); - if (sret ()) - { - llvm_args.push_back (rtype->getPointerTo ()); - rtype = llvm::Type::getVoidTy (context); - } - } - - for (std::vector::const_iterator iter = args.begin (); - iter != args.end (); ++iter) - { - jit_type *ty = *iter; - assert (ty); - llvm::Type *argty = ty->packed_type (call_conv); - if (ty->pointer_arg (call_conv)) - argty = argty->getPointerTo (); - - llvm_args.push_back (argty); - } - - // we mark all functinos as external linkage because this prevents llvm - // from getting rid of always inline functions - llvm::FunctionType *ft = llvm::FunctionType::get (rtype, llvm_args, false); - llvm_function = llvm::Function::Create (ft, llvm::Function::ExternalLinkage, - aname, module); - if (call_conv == jit_convention::internal) - llvm_function->addFnAttr (llvm::Attribute::AlwaysInline); -} - -jit_function::jit_function (const jit_function& fn, jit_type *aresult, - const std::vector& aargs) - : module (fn.module), llvm_function (fn.llvm_function), mresult (aresult), - args (aargs), call_conv (fn.call_conv), mcan_error (fn.mcan_error) -{ -} - -jit_function::jit_function (const jit_function& fn) - : module (fn.module), llvm_function (fn.llvm_function), mresult (fn.mresult), - args (fn.args), call_conv (fn.call_conv), mcan_error (fn.mcan_error) -{} - -std::string -jit_function::name (void) const -{ - return llvm_function->getName (); -} - -llvm::BasicBlock * -jit_function::new_block (const std::string& aname, - llvm::BasicBlock *insert_before) -{ - return llvm::BasicBlock::Create (context, aname, llvm_function, - insert_before); -} - -llvm::Value * -jit_function::call (llvm::IRBuilderD& builder, - const std::vector& in_args) const -{ - if (! valid ()) - throw jit_fail_exception ("Call not implemented"); - - assert (in_args.size () == args.size ()); - std::vector llvm_args (args.size ()); - for (size_t i = 0; i < in_args.size (); ++i) - llvm_args[i] = in_args[i]->to_llvm (); - - return call (builder, llvm_args); -} - -llvm::Value * -jit_function::call (llvm::IRBuilderD& builder, - const std::vector& in_args) const -{ - if (! valid ()) - throw jit_fail_exception ("Call not implemented"); - - assert (in_args.size () == args.size ()); - llvm::Function *stacksave - = llvm::Intrinsic::getDeclaration (module, llvm::Intrinsic::stacksave); - llvm::SmallVector llvm_args; - llvm_args.reserve (in_args.size () + sret ()); - - llvm::Value *sret_mem = 0; - llvm::Value *saved_stack = 0; - if (sret ()) - { - saved_stack = builder.CreateCall (stacksave); - sret_mem = builder.CreateAlloca (mresult->packed_type (call_conv)); - llvm_args.push_back (sret_mem); - } - - for (size_t i = 0; i < in_args.size (); ++i) - { - llvm::Value *arg = in_args[i]; - jit_type::convert_fn convert = args[i]->pack (call_conv); - if (convert) - arg = convert (builder, arg); - - if (args[i]->pointer_arg (call_conv)) - { - if (! saved_stack) - saved_stack = builder.CreateCall (stacksave); - - arg = builder.CreateAlloca (args[i]->to_llvm ()); - builder.CreateStore (in_args[i], arg); - } - - llvm_args.push_back (arg); - } - - llvm::Value *ret = builder.CreateCall (llvm_function, llvm_args); - if (sret_mem) - ret = builder.CreateLoad (sret_mem); - - if (mresult) - { - jit_type::convert_fn unpack = mresult->unpack (call_conv); - if (unpack) - ret = unpack (builder, ret); - } - - if (saved_stack) - { - llvm::Function *stackrestore - = llvm::Intrinsic::getDeclaration (module, - llvm::Intrinsic::stackrestore); - builder.CreateCall (stackrestore, saved_stack); - } - - return ret; -} - -llvm::Value * -jit_function::argument (llvm::IRBuilderD& builder, size_t idx) const -{ - assert (idx < args.size ()); - - // FIXME: We should be treating arguments like a list, not a vector. Shouldn't - // matter much for now, as the number of arguments shouldn't be much bigger - // than 4 - llvm::Function::arg_iterator iter = llvm_function->arg_begin (); - if (sret ()) - ++iter; - - for (size_t i = 0; i < idx; ++i, ++iter); - - if (args[idx]->pointer_arg (call_conv)) - return builder.CreateLoad (iter); - - return iter; -} - -void -jit_function::do_return (llvm::IRBuilderD& builder, llvm::Value *rval) -{ - assert (! rval == ! mresult); - - if (rval) - { - jit_type::convert_fn convert = mresult->pack (call_conv); - if (convert) - rval = convert (builder, rval); - - if (sret ()) - builder.CreateStore (rval, llvm_function->arg_begin ()); - else - builder.CreateRet (rval); - } - else - builder.CreateRetVoid (); - - llvm::verifyFunction (*llvm_function); -} - -void -jit_function::do_add_mapping (llvm::ExecutionEngine *engine, void *fn) -{ - assert (valid ()); - engine->addGlobalMapping (llvm_function, fn); -} - -std::ostream& -operator<< (std::ostream& os, const jit_function& fn) -{ - llvm::Function *lfn = fn.to_llvm (); - os << "jit_function: cc=" << fn.call_conv; - llvm::raw_os_ostream llvm_out (os); - lfn->print (llvm_out); - llvm_out.flush (); - return os; -} - -// -------------------- jit_operation -------------------- -jit_operation::~jit_operation (void) -{ - for (generated_map::iterator iter = generated.begin (); - iter != generated.end (); ++iter) - { - delete iter->first; - delete iter->second; - } -} - -void -jit_operation::add_overload (const jit_function& func, - const std::vector& args) -{ - if (args.size () >= overloads.size ()) - overloads.resize (args.size () + 1); - - Array& over = overloads[args.size ()]; - dim_vector dv (over.dims ()); - Array idx = to_idx (args); - bool must_resize = false; - - if (dv.length () != idx.numel ()) - { - dv.resize (idx.numel ()); - must_resize = true; - } - - for (octave_idx_type i = 0; i < dv.length (); ++i) - if (dv(i) <= idx(i)) - { - must_resize = true; - dv(i) = idx(i) + 1; - } - - if (must_resize) - over.resize (dv); - - over(idx) = func; -} - -const jit_function& -jit_operation::overload (const std::vector& types) const -{ - static jit_function null_overload; - for (size_t i =0; i < types.size (); ++i) - if (! types[i]) - return null_overload; - - if (types.size () >= overloads.size ()) - return do_generate (types); - - const Array& over = overloads[types.size ()]; - dim_vector dv (over.dims ()); - Array idx = to_idx (types); - for (octave_idx_type i = 0; i < dv.length (); ++i) - if (idx(i) >= dv(i)) - return do_generate (types); - - const jit_function& ret = over(idx); - if (! ret.valid ()) - return do_generate (types); - - return ret; -} - -Array -jit_operation::to_idx (const std::vector& types) const -{ - octave_idx_type numel = types.size (); - if (numel == 1) - numel = 2; - - Array idx (dim_vector (1, numel)); - for (octave_idx_type i = 0; i < static_cast (types.size ()); - ++i) - idx(i) = types[i]->type_id (); - - if (types.size () == 1) - { - idx(1) = idx(0); - idx(0) = 0; - } - - return idx; -} - -const jit_function& -jit_operation::do_generate (const signature_vec& types) const -{ - static jit_function null_overload; - generated_map::const_iterator find = generated.find (&types); - if (find != generated.end ()) - { - if (find->second) - return *find->second; - else - return null_overload; - } - - jit_function *ret = generate (types); - generated[new signature_vec (types)] = ret; - return ret ? *ret : null_overload; -} - -jit_function * -jit_operation::generate (const signature_vec& types) const -{ - return 0; -} - -bool -jit_operation::signature_cmp -::operator() (const signature_vec *lhs, const signature_vec *rhs) -{ - const signature_vec& l = *lhs; - const signature_vec& r = *rhs; - - if (l.size () < r.size ()) - return true; - else if (l.size () > r.size ()) - return false; - - for (size_t i = 0; i < l.size (); ++i) - { - if (l[i]->type_id () < r[i]->type_id ()) - return true; - else if (l[i]->type_id () > r[i]->type_id ()) - return false; - } - - return false; -} - -// -------------------- jit_index_operation -------------------- -jit_function * -jit_index_operation::generate (const signature_vec& types) const -{ - if (types.size () > 2 && types[0] == jit_typeinfo::get_matrix ()) - { - // indexing a matrix with scalars - jit_type *scalar = jit_typeinfo::get_scalar (); - for (size_t i = 1; i < types.size (); ++i) - if (types[i] != scalar) - return 0; - - return generate_matrix (types); - } - - return 0; -} - -llvm::Value * -jit_index_operation::create_arg_array (llvm::IRBuilderD& builder, - const jit_function &fn, size_t start_idx, - size_t end_idx) const -{ - size_t n = end_idx - start_idx; - llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm (); - llvm::ArrayType *array_t = llvm::ArrayType::get (scalar_t, n); - llvm::Value *array = llvm::UndefValue::get (array_t); - for (size_t i = start_idx; i < end_idx; ++i) - { - llvm::Value *idx = fn.argument (builder, i); - array = builder.CreateInsertValue (array, idx, i - start_idx); - } - - llvm::Value *array_mem = builder.CreateAlloca (array_t); - builder.CreateStore (array, array_mem); - return builder.CreateBitCast (array_mem, scalar_t->getPointerTo ()); -} - -// -------------------- jit_paren_subsref -------------------- -jit_function * -jit_paren_subsref::generate_matrix (const signature_vec& types) const -{ - std::stringstream ss; - ss << "jit_paren_subsref_matrix_scalar" << (types.size () - 1); - - jit_type *scalar = jit_typeinfo::get_scalar (); - jit_function *fn = new jit_function (module, jit_convention::internal, - ss.str (), scalar, types); - fn->mark_can_error (); - llvm::BasicBlock *body = fn->new_block (); - llvm::IRBuilder<> builder (body); - - llvm::Value *array = create_arg_array (builder, *fn, 1, types.size ()); - jit_type *index = jit_typeinfo::get_index (); - llvm::Value *nelem = llvm::ConstantInt::get (index->to_llvm (), - types.size () - 1); - llvm::Value *mat = fn->argument (builder, 0); - llvm::Value *ret = paren_scalar.call (builder, mat, array, nelem); - fn->do_return (builder, ret); - return fn; -} - -void -jit_paren_subsref::do_initialize (void) -{ - std::vector types (3); - types[0] = jit_typeinfo::get_matrix (); - types[1] = jit_typeinfo::get_scalar_ptr (); - types[2] = jit_typeinfo::get_index (); - - jit_type *scalar = jit_typeinfo::get_scalar (); - paren_scalar = jit_function (module, jit_convention::external, - "octave_jit_paren_scalar", scalar, types); - paren_scalar.add_mapping (engine, &octave_jit_paren_scalar); - paren_scalar.mark_can_error (); -} - -// -------------------- jit_paren_subsasgn -------------------- -jit_function * -jit_paren_subsasgn::generate_matrix (const signature_vec& types) const -{ - std::stringstream ss; - ss << "jit_paren_subsasgn_matrix_scalar" << (types.size () - 2); - - jit_type *matrix = jit_typeinfo::get_matrix (); - jit_function *fn = new jit_function (module, jit_convention::internal, - ss.str (), matrix, types); - fn->mark_can_error (); - llvm::BasicBlock *body = fn->new_block (); - llvm::IRBuilder<> builder (body); - - llvm::Value *array = create_arg_array (builder, *fn, 1, types.size () - 1); - jit_type *index = jit_typeinfo::get_index (); - llvm::Value *nelem = llvm::ConstantInt::get (index->to_llvm (), - types.size () - 2); - - llvm::Value *mat = fn->argument (builder, 0); - llvm::Value *value = fn->argument (builder, types.size () - 1); - llvm::Value *ret = paren_scalar.call (builder, mat, array, nelem, value); - fn->do_return (builder, ret); - return fn; -} - -void -jit_paren_subsasgn::do_initialize (void) -{ - if (paren_scalar.valid ()) - return; - - jit_type *matrix = jit_typeinfo::get_matrix (); - std::vector types (4); - types[0] = matrix; - types[1] = jit_typeinfo::get_scalar_ptr (); - types[2] = jit_typeinfo::get_index (); - types[3] = jit_typeinfo::get_scalar (); - - paren_scalar = jit_function (module, jit_convention::external, - "octave_jit_paren_scalar", matrix, types); - paren_scalar.add_mapping (engine, &octave_jit_paren_scalar_subsasgn); - paren_scalar.mark_can_error (); -} - -// -------------------- jit_typeinfo -------------------- -void -jit_typeinfo::initialize (llvm::Module *m, llvm::ExecutionEngine *e) -{ - new jit_typeinfo (m, e); -} - -jit_typeinfo::jit_typeinfo (llvm::Module *m, llvm::ExecutionEngine *e) - : module (m), engine (e), next_id (0), - builder (*new llvm::IRBuilderD (context)) -{ - instance = this; - - // FIXME: We should be registering types like in octave_value_typeinfo - llvm::Type *any_t = llvm::StructType::create (context, "octave_base_value"); - any_t = any_t->getPointerTo (); - - llvm::Type *scalar_t = llvm::Type::getDoubleTy (context); - llvm::Type *bool_t = llvm::Type::getInt1Ty (context); - llvm::Type *string_t = llvm::Type::getInt8Ty (context); - string_t = string_t->getPointerTo (); - llvm::Type *index_t = llvm::Type::getIntNTy (context, - sizeof(octave_idx_type) * 8); - - llvm::StructType *range_t = llvm::StructType::create (context, "range"); - std::vector range_contents (4, scalar_t); - range_contents[3] = index_t; - range_t->setBody (range_contents); - - llvm::Type *refcount_t = llvm::Type::getIntNTy (context, sizeof(int) * 8); - - llvm::StructType *matrix_t = llvm::StructType::create (context, "matrix"); - llvm::Type *matrix_contents[5]; - matrix_contents[0] = refcount_t->getPointerTo (); - matrix_contents[1] = scalar_t->getPointerTo (); - matrix_contents[2] = index_t; - matrix_contents[3] = index_t->getPointerTo (); - matrix_contents[4] = string_t; - matrix_t->setBody (llvm::makeArrayRef (matrix_contents, 5)); - - llvm::Type *complex_t = llvm::VectorType::get (scalar_t, 2); - - // complex_ret is what is passed to C functions in order to get calling - // convention right - complex_ret = llvm::StructType::create (context, "complex_ret"); - llvm::Type *complex_ret_contents[] = {scalar_t, scalar_t}; - complex_ret->setBody (complex_ret_contents); - - // create types - any = new_type ("any", 0, any_t); - matrix = new_type ("matrix", any, matrix_t); - complex = new_type ("complex", any, complex_t); - scalar = new_type ("scalar", complex, scalar_t); - scalar_ptr = new_type ("scalar_ptr", 0, scalar_t->getPointerTo ()); - range = new_type ("range", any, range_t); - string = new_type ("string", any, string_t); - boolean = new_type ("bool", any, bool_t); - index = new_type ("index", any, index_t); - - create_int (8); - create_int (16); - create_int (32); - create_int (64); - - casts.resize (next_id + 1); - identities.resize (next_id + 1); - - // specify calling conventions - // FIXME: We should detect architecture and do something sane based on that - // here we assume x86 or x86_64 - matrix->mark_sret (); - matrix->mark_pointer_arg (); - - range->mark_sret (); - range->mark_pointer_arg (); - - complex->set_pack (jit_convention::external, &jit_typeinfo::pack_complex); - complex->set_unpack (jit_convention::external, &jit_typeinfo::unpack_complex); - complex->set_packed_type (jit_convention::external, complex_ret); - - if (sizeof (void *) == 4) - complex->mark_sret (); - - paren_subsref_fn.initialize (module, engine); - paren_subsasgn_fn.initialize (module, engine); - - // bind global variables - lerror_state = new llvm::GlobalVariable (*module, bool_t, false, - llvm::GlobalValue::ExternalLinkage, - 0, "error_state"); - engine->addGlobalMapping (lerror_state, - reinterpret_cast (&error_state)); - - // any with anything is an any op - jit_function fn; - jit_type *binary_op_type = intN (sizeof (octave_value::binary_op) * 8); - llvm::Type *llvm_bo_type = binary_op_type->to_llvm (); - jit_function any_binary = create_function (jit_convention::external, - "octave_jit_binary_any_any", - any, binary_op_type, any, any); - any_binary.add_mapping (engine, &octave_jit_binary_any_any); - any_binary.mark_can_error (); - binary_ops.resize (octave_value::num_binary_ops); - for (size_t i = 0; i < octave_value::num_binary_ops; ++i) - { - octave_value::binary_op op = static_cast (i); - std::string op_name = octave_value::binary_op_as_string (op); - binary_ops[i].stash_name ("binary" + op_name); - } - - for (int op = 0; op < octave_value::num_binary_ops; ++op) - { - llvm::Twine fn_name ("octave_jit_binary_any_any_"); - fn_name = fn_name + llvm::Twine (op); - - fn = create_function (jit_convention::internal, fn_name, any, any, any); - fn.mark_can_error (); - llvm::BasicBlock *block = fn.new_block (); - builder.SetInsertPoint (block); - llvm::APInt op_int(sizeof (octave_value::binary_op) * 8, op, - std::numeric_limits::is_signed); - llvm::Value *op_as_llvm = llvm::ConstantInt::get (llvm_bo_type, op_int); - llvm::Value *ret = any_binary.call (builder, op_as_llvm, - fn.argument (builder, 0), - fn.argument (builder, 1)); - fn.do_return (builder, ret); - binary_ops[op].add_overload (fn); - } - - // grab any - fn = create_function (jit_convention::external, "octave_jit_grab_any", any, - any); - fn.add_mapping (engine, &octave_jit_grab_any); - grab_fn.add_overload (fn); - grab_fn.stash_name ("grab"); - - // grab matrix - fn = create_function (jit_convention::external, "octave_jit_grab_matrix", - matrix, matrix); - fn.add_mapping (engine, &octave_jit_grab_matrix); - grab_fn.add_overload (fn); - - // release any - fn = create_function (jit_convention::external, "octave_jit_release_any", 0, - any); - fn.add_mapping (engine, &octave_jit_release_any); - release_fn.add_overload (fn); - release_fn.stash_name ("release"); - - // release matrix - fn = create_function (jit_convention::external, "octave_jit_release_matrix", - 0, matrix); - fn.add_mapping (engine, &octave_jit_release_matrix); - release_fn.add_overload (fn); - - // release scalar - fn = create_identity (scalar); - release_fn.add_overload (fn); - - // release complex - fn = create_identity (complex); - release_fn.add_overload (fn); - - // release index - fn = create_identity (index); - release_fn.add_overload (fn); - - // now for binary scalar operations - // FIXME: Finish all operations - add_binary_op (scalar, octave_value::op_add, llvm::Instruction::FAdd); - add_binary_op (scalar, octave_value::op_sub, llvm::Instruction::FSub); - add_binary_op (scalar, octave_value::op_mul, llvm::Instruction::FMul); - add_binary_op (scalar, octave_value::op_el_mul, llvm::Instruction::FMul); - - add_binary_fcmp (scalar, octave_value::op_lt, llvm::CmpInst::FCMP_ULT); - add_binary_fcmp (scalar, octave_value::op_le, llvm::CmpInst::FCMP_ULE); - add_binary_fcmp (scalar, octave_value::op_eq, llvm::CmpInst::FCMP_UEQ); - add_binary_fcmp (scalar, octave_value::op_ge, llvm::CmpInst::FCMP_UGE); - add_binary_fcmp (scalar, octave_value::op_gt, llvm::CmpInst::FCMP_UGT); - add_binary_fcmp (scalar, octave_value::op_ne, llvm::CmpInst::FCMP_UNE); - - jit_function gripe_div0 = create_function (jit_convention::external, - "gripe_divide_by_zero", 0); - gripe_div0.add_mapping (engine, &gripe_divide_by_zero); - gripe_div0.mark_can_error (); - - // divide is annoying because it might error - fn = create_function (jit_convention::internal, - "octave_jit_div_scalar_scalar", scalar, scalar, scalar); - fn.mark_can_error (); - - llvm::BasicBlock *body = fn.new_block (); - builder.SetInsertPoint (body); - { - llvm::BasicBlock *warn_block = fn.new_block ("warn"); - llvm::BasicBlock *normal_block = fn.new_block ("normal"); - - llvm::Value *zero = llvm::ConstantFP::get (scalar_t, 0); - llvm::Value *check = builder.CreateFCmpUEQ (zero, fn.argument (builder, 0)); - builder.CreateCondBr (check, warn_block, normal_block); - - builder.SetInsertPoint (warn_block); - gripe_div0.call (builder); - builder.CreateBr (normal_block); - - builder.SetInsertPoint (normal_block); - llvm::Value *ret = builder.CreateFDiv (fn.argument (builder, 0), - fn.argument (builder, 1)); - fn.do_return (builder, ret); - } - binary_ops[octave_value::op_div].add_overload (fn); - binary_ops[octave_value::op_el_div].add_overload (fn); - - // ldiv is the same as div with the operators reversed - fn = mirror_binary (fn); - binary_ops[octave_value::op_ldiv].add_overload (fn); - binary_ops[octave_value::op_el_ldiv].add_overload (fn); - - // In general, the result of scalar ^ scalar is a complex number. We might be - // able to improve on this if we keep track of the range of values varaibles - // can take on. - fn = create_function (jit_convention::external, - "octave_jit_pow_scalar_scalar", complex, scalar, - scalar); - fn.add_mapping (engine, &octave_jit_pow_scalar_scalar); - binary_ops[octave_value::op_pow].add_overload (fn); - binary_ops[octave_value::op_el_pow].add_overload (fn); - - // now for binary complex operations - add_binary_op (complex, octave_value::op_add, llvm::Instruction::FAdd); - add_binary_op (complex, octave_value::op_sub, llvm::Instruction::FSub); - - fn = create_function (jit_convention::internal, - "octave_jit_*_complex_complex", complex, complex, - complex); - body = fn.new_block (); - builder.SetInsertPoint (body); - { - // (x0*x1 - y0*y1, x0*y1 + y0*x1) = (x0,y0) * (x1,y1) - // We compute this in one vectorized multiplication, a subtraction, and an - // addition. - llvm::Value *lhs = fn.argument (builder, 0); - llvm::Value *rhs = fn.argument (builder, 1); - - // FIXME: We need a better way of doing this, working with llvm's IR - // directly is sort of a pain. - llvm::Value *zero = builder.getInt32 (0); - llvm::Value *one = builder.getInt32 (1); - llvm::Value *two = builder.getInt32 (2); - llvm::Value *three = builder.getInt32 (3); - - llvm::Type *vec4 = llvm::VectorType::get (scalar_t, 4); - llvm::Value *mlhs = llvm::UndefValue::get (vec4); - llvm::Value *mrhs = mlhs; - - llvm::Value *temp = complex_real (lhs); - mlhs = builder.CreateInsertElement (mlhs, temp, zero); - mlhs = builder.CreateInsertElement (mlhs, temp, two); - temp = complex_imag (lhs); - mlhs = builder.CreateInsertElement (mlhs, temp, one); - mlhs = builder.CreateInsertElement (mlhs, temp, three); - - temp = complex_real (rhs); - mrhs = builder.CreateInsertElement (mrhs, temp, zero); - mrhs = builder.CreateInsertElement (mrhs, temp, three); - temp = complex_imag (rhs); - mrhs = builder.CreateInsertElement (mrhs, temp, one); - mrhs = builder.CreateInsertElement (mrhs, temp, two); - - llvm::Value *mres = builder.CreateFMul (mlhs, mrhs); - llvm::Value *tlhs = builder.CreateExtractElement (mres, zero); - llvm::Value *trhs = builder.CreateExtractElement (mres, one); - llvm::Value *ret_real = builder.CreateFSub (tlhs, trhs); - - tlhs = builder.CreateExtractElement (mres, two); - trhs = builder.CreateExtractElement (mres, three); - llvm::Value *ret_imag = builder.CreateFAdd (tlhs, trhs); - fn.do_return (builder, complex_new (ret_real, ret_imag)); - } - - binary_ops[octave_value::op_mul].add_overload (fn); - binary_ops[octave_value::op_el_mul].add_overload (fn); - - jit_function complex_div = create_function (jit_convention::external, - "octave_jit_complex_div", - complex, complex, complex); - complex_div.add_mapping (engine, &octave_jit_complex_div); - complex_div.mark_can_error (); - binary_ops[octave_value::op_div].add_overload (fn); - binary_ops[octave_value::op_ldiv].add_overload (fn); - - fn = mirror_binary (complex_div); - binary_ops[octave_value::op_ldiv].add_overload (fn); - binary_ops[octave_value::op_el_ldiv].add_overload (fn); - - fn = create_function (jit_convention::external, - "octave_jit_pow_complex_complex", complex, complex, - complex); - fn.add_mapping (engine, &octave_jit_pow_complex_complex); - binary_ops[octave_value::op_pow].add_overload (fn); - binary_ops[octave_value::op_el_pow].add_overload (fn); - - fn = create_function (jit_convention::internal, - "octave_jit_*_scalar_complex", complex, scalar, - complex); - jit_function mul_scalar_complex = fn; - body = fn.new_block (); - builder.SetInsertPoint (body); - { - llvm::Value *lhs = fn.argument (builder, 0); - llvm::Value *tlhs = complex_new (lhs, lhs); - llvm::Value *rhs = fn.argument (builder, 1); - fn.do_return (builder, builder.CreateFMul (tlhs, rhs)); - } - binary_ops[octave_value::op_mul].add_overload (fn); - binary_ops[octave_value::op_el_mul].add_overload (fn); - - - fn = mirror_binary (mul_scalar_complex); - binary_ops[octave_value::op_mul].add_overload (fn); - binary_ops[octave_value::op_el_mul].add_overload (fn); - - fn = create_function (jit_convention::internal, "octave_jit_+_scalar_complex", - complex, scalar, complex); - body = fn.new_block (); - builder.SetInsertPoint (body); - { - llvm::Value *lhs = fn.argument (builder, 0); - llvm::Value *rhs = fn.argument (builder, 1); - llvm::Value *real = builder.CreateFAdd (lhs, complex_real (rhs)); - fn.do_return (builder, complex_real (rhs, real)); - } - binary_ops[octave_value::op_add].add_overload (fn); - - fn = mirror_binary (fn); - binary_ops[octave_value::op_add].add_overload (fn); - - fn = create_function (jit_convention::internal, "octave_jit_-_complex_scalar", - complex, complex, scalar); - body = fn.new_block (); - builder.SetInsertPoint (body); - { - llvm::Value *lhs = fn.argument (builder, 0); - llvm::Value *rhs = fn.argument (builder, 1); - llvm::Value *real = builder.CreateFSub (complex_real (lhs), rhs); - fn.do_return (builder, complex_real (lhs, real)); - } - binary_ops[octave_value::op_sub].add_overload (fn); - - fn = create_function (jit_convention::internal, "octave_jit_-_scalar_complex", - complex, scalar, complex); - body = fn.new_block (); - builder.SetInsertPoint (body); - { - llvm::Value *lhs = fn.argument (builder, 0); - llvm::Value *rhs = fn.argument (builder, 1); - llvm::Value *real = builder.CreateFSub (lhs, complex_real (rhs)); - fn.do_return (builder, complex_real (rhs, real)); - } - binary_ops[octave_value::op_sub].add_overload (fn); - - fn = create_function (jit_convention::external, - "octave_jit_pow_scalar_complex", complex, scalar, - complex); - fn.add_mapping (engine, &octave_jit_pow_scalar_complex); - binary_ops[octave_value::op_pow].add_overload (fn); - binary_ops[octave_value::op_el_pow].add_overload (fn); - - fn = create_function (jit_convention::external, - "octave_jit_pow_complex_scalar", complex, complex, - scalar); - fn.add_mapping (engine, &octave_jit_pow_complex_scalar); - binary_ops[octave_value::op_pow].add_overload (fn); - binary_ops[octave_value::op_el_pow].add_overload (fn); - - // now for binary index operators - add_binary_op (index, octave_value::op_add, llvm::Instruction::Add); - - // and binary bool operators - add_binary_op (boolean, octave_value::op_el_or, llvm::Instruction::Or); - add_binary_op (boolean, octave_value::op_el_and, llvm::Instruction::And); - - // now for printing functions - print_fn.stash_name ("print"); - add_print (any, reinterpret_cast (&octave_jit_print_any)); - add_print (scalar, reinterpret_cast (&octave_jit_print_scalar)); - - // initialize for loop - for_init_fn.stash_name ("for_init"); - - fn = create_function (jit_convention::internal, "octave_jit_for_range_init", - index, range); - body = fn.new_block (); - builder.SetInsertPoint (body); - { - llvm::Value *zero = llvm::ConstantInt::get (index_t, 0); - fn.do_return (builder, zero); - } - for_init_fn.add_overload (fn); - - // bounds check for for loop - for_check_fn.stash_name ("for_check"); - - fn = create_function (jit_convention::internal, "octave_jit_for_range_check", - boolean, range, index); - body = fn.new_block (); - builder.SetInsertPoint (body); - { - llvm::Value *nelem - = builder.CreateExtractValue (fn.argument (builder, 0), 3); - llvm::Value *idx = fn.argument (builder, 1); - llvm::Value *ret = builder.CreateICmpULT (idx, nelem); - fn.do_return (builder, ret); - } - for_check_fn.add_overload (fn); - - // index variabe for for loop - for_index_fn.stash_name ("for_index"); - - fn = create_function (jit_convention::internal, "octave_jit_for_range_idx", - scalar, range, index); - body = fn.new_block (); - builder.SetInsertPoint (body); - { - llvm::Value *idx = fn.argument (builder, 1); - llvm::Value *didx = builder.CreateSIToFP (idx, scalar_t); - llvm::Value *rng = fn.argument (builder, 0); - llvm::Value *base = builder.CreateExtractValue (rng, 0); - llvm::Value *inc = builder.CreateExtractValue (rng, 2); - - llvm::Value *ret = builder.CreateFMul (didx, inc); - ret = builder.CreateFAdd (base, ret); - fn.do_return (builder, ret); - } - for_index_fn.add_overload (fn); - - // logically true - logically_true_fn.stash_name ("logically_true"); - - jit_function gripe_nantl - = create_function (jit_convention::external, - "octave_jit_gripe_nan_to_logical_conversion", 0); - gripe_nantl.add_mapping (engine, &octave_jit_gripe_nan_to_logical_conversion); - gripe_nantl.mark_can_error (); - - fn = create_function (jit_convention::internal, - "octave_jit_logically_true_scalar", boolean, scalar); - fn.mark_can_error (); - - body = fn.new_block (); - builder.SetInsertPoint (body); - { - llvm::BasicBlock *error_block = fn.new_block ("error"); - llvm::BasicBlock *normal_block = fn.new_block ("normal"); - - llvm::Value *check = builder.CreateFCmpUNE (fn.argument (builder, 0), - fn.argument (builder, 0)); - builder.CreateCondBr (check, error_block, normal_block); - - builder.SetInsertPoint (error_block); - gripe_nantl.call (builder); - builder.CreateBr (normal_block); - builder.SetInsertPoint (normal_block); - - llvm::Value *zero = llvm::ConstantFP::get (scalar_t, 0); - llvm::Value *ret = builder.CreateFCmpONE (fn.argument (builder, 0), zero); - fn.do_return (builder, ret); - } - logically_true_fn.add_overload (fn); - - // logically_true boolean - fn = create_identity (boolean); - logically_true_fn.add_overload (fn); - - // make_range - // FIXME: May be benificial to implement all in LLVM - make_range_fn.stash_name ("make_range"); - jit_function compute_nelem - = create_function (jit_convention::external, "octave_jit_compute_nelem", - index, scalar, scalar, scalar); - compute_nelem.add_mapping (engine, &octave_jit_compute_nelem); - - fn = create_function (jit_convention::internal, "octave_jit_make_range", - range, scalar, scalar, scalar); - body = fn.new_block (); - builder.SetInsertPoint (body); - { - llvm::Value *base = fn.argument (builder, 0); - llvm::Value *limit = fn.argument (builder, 1); - llvm::Value *inc = fn.argument (builder, 2); - llvm::Value *nelem = compute_nelem.call (builder, base, limit, inc); - - llvm::Value *dzero = llvm::ConstantFP::get (scalar_t, 0); - llvm::Value *izero = llvm::ConstantInt::get (index_t, 0); - llvm::Value *rng = llvm::ConstantStruct::get (range_t, dzero, dzero, dzero, - izero, NULL); - rng = builder.CreateInsertValue (rng, base, 0); - rng = builder.CreateInsertValue (rng, limit, 1); - rng = builder.CreateInsertValue (rng, inc, 2); - rng = builder.CreateInsertValue (rng, nelem, 3); - fn.do_return (builder, rng); - } - make_range_fn.add_overload (fn); - - // paren_subsref - jit_type *jit_int = intN (sizeof (int) * 8); - llvm::Type *int_t = jit_int->to_llvm (); - jit_function ginvalid_index - = create_function (jit_convention::external, "octave_jit_ginvalid_index", - 0); - ginvalid_index.add_mapping (engine, &octave_jit_ginvalid_index); - jit_function gindex_range = create_function (jit_convention::external, - "octave_jit_gindex_range", - 0, jit_int, jit_int, index, - index); - gindex_range.add_mapping (engine, &octave_jit_gindex_range); - - fn = create_function (jit_convention::internal, "()subsref", scalar, matrix, - scalar); - fn.mark_can_error (); - - body = fn.new_block (); - builder.SetInsertPoint (body); - { - llvm::Value *one = llvm::ConstantInt::get (index_t, 1); - llvm::Value *ione; - if (index_t == int_t) - ione = one; - else - ione = llvm::ConstantInt::get (int_t, 1); - - llvm::Value *undef = llvm::UndefValue::get (scalar_t); - llvm::Value *mat = fn.argument (builder, 0); - llvm::Value *idx = fn.argument (builder, 1); - - // convert index to scalar to integer, and check index >= 1 - llvm::Value *int_idx = builder.CreateFPToSI (idx, index_t); - llvm::Value *check_idx = builder.CreateSIToFP (int_idx, scalar_t); - llvm::Value *cond0 = builder.CreateFCmpUNE (idx, check_idx); - llvm::Value *cond1 = builder.CreateICmpSLT (int_idx, one); - llvm::Value *cond = builder.CreateOr (cond0, cond1); - - llvm::BasicBlock *done = fn.new_block ("done"); - llvm::BasicBlock *conv_error = fn.new_block ("conv_error", done); - llvm::BasicBlock *normal = fn.new_block ("normal", done); - builder.CreateCondBr (cond, conv_error, normal); - - builder.SetInsertPoint (conv_error); - ginvalid_index.call (builder); - builder.CreateBr (done); - - builder.SetInsertPoint (normal); - llvm::Value *len = builder.CreateExtractValue (mat, - llvm::ArrayRef (2)); - cond = builder.CreateICmpSGT (int_idx, len); - - - llvm::BasicBlock *bounds_error = fn.new_block ("bounds_error", done); - llvm::BasicBlock *success = fn.new_block ("success", done); - builder.CreateCondBr (cond, bounds_error, success); - - builder.SetInsertPoint (bounds_error); - gindex_range.call (builder, ione, ione, int_idx, len); - builder.CreateBr (done); - - builder.SetInsertPoint (success); - llvm::Value *data = builder.CreateExtractValue (mat, - llvm::ArrayRef (1)); - llvm::Value *gep = builder.CreateInBoundsGEP (data, int_idx); - llvm::Value *ret = builder.CreateLoad (gep); - builder.CreateBr (done); - - builder.SetInsertPoint (done); - - llvm::PHINode *merge = llvm::PHINode::Create (scalar_t, 3); - builder.Insert (merge); - merge->addIncoming (undef, conv_error); - merge->addIncoming (undef, bounds_error); - merge->addIncoming (ret, success); - fn.do_return (builder, merge); - } - paren_subsref_fn.add_overload (fn); - - // paren subsasgn - paren_subsasgn_fn.stash_name ("()subsasgn"); - - jit_function resize_paren_subsasgn - = create_function (jit_convention::external, - "octave_jit_paren_subsasgn_impl", matrix, matrix, index, - scalar); - resize_paren_subsasgn.add_mapping (engine, &octave_jit_paren_subsasgn_impl); - fn = create_function (jit_convention::internal, "octave_jit_paren_subsasgn", - matrix, matrix, scalar, scalar); - fn.mark_can_error (); - body = fn.new_block (); - builder.SetInsertPoint (body); - { - llvm::Value *one = llvm::ConstantInt::get (index_t, 1); - - llvm::Value *mat = fn.argument (builder, 0); - llvm::Value *idx = fn.argument (builder, 1); - llvm::Value *value = fn.argument (builder, 2); - - llvm::Value *int_idx = builder.CreateFPToSI (idx, index_t); - llvm::Value *check_idx = builder.CreateSIToFP (int_idx, scalar_t); - llvm::Value *cond0 = builder.CreateFCmpUNE (idx, check_idx); - llvm::Value *cond1 = builder.CreateICmpSLT (int_idx, one); - llvm::Value *cond = builder.CreateOr (cond0, cond1); - - llvm::BasicBlock *done = fn.new_block ("done"); - - llvm::BasicBlock *conv_error = fn.new_block ("conv_error", done); - llvm::BasicBlock *normal = fn.new_block ("normal", done); - builder.CreateCondBr (cond, conv_error, normal); - builder.SetInsertPoint (conv_error); - ginvalid_index.call (builder); - builder.CreateBr (done); - - builder.SetInsertPoint (normal); - llvm::Value *len = builder.CreateExtractValue (mat, 2); - cond0 = builder.CreateICmpSGT (int_idx, len); - - llvm::Value *rcount = builder.CreateExtractValue (mat, 0); - rcount = builder.CreateLoad (rcount); - cond1 = builder.CreateICmpSGT (rcount, one); - cond = builder.CreateOr (cond0, cond1); - - llvm::BasicBlock *bounds_error = fn.new_block ("bounds_error", done); - llvm::BasicBlock *success = fn.new_block ("success", done); - builder.CreateCondBr (cond, bounds_error, success); - - // resize on out of bounds access - builder.SetInsertPoint (bounds_error); - llvm::Value *resize_result = resize_paren_subsasgn.call (builder, mat, - int_idx, value); - builder.CreateBr (done); - - builder.SetInsertPoint (success); - llvm::Value *data = builder.CreateExtractValue (mat, - llvm::ArrayRef (1)); - llvm::Value *gep = builder.CreateInBoundsGEP (data, int_idx); - builder.CreateStore (value, gep); - builder.CreateBr (done); - - builder.SetInsertPoint (done); - - llvm::PHINode *merge = llvm::PHINode::Create (matrix_t, 3); - builder.Insert (merge); - merge->addIncoming (mat, conv_error); - merge->addIncoming (resize_result, bounds_error); - merge->addIncoming (mat, success); - fn.do_return (builder, merge); - } - paren_subsasgn_fn.add_overload (fn); - - fn = create_function (jit_convention::external, - "octave_jit_paren_subsasgn_matrix_range", matrix, - matrix, range, scalar); - fn.add_mapping (engine, &octave_jit_paren_subsasgn_matrix_range); - fn.mark_can_error (); - paren_subsasgn_fn.add_overload (fn); - - end_fn.stash_name ("end"); - fn = create_function (jit_convention::internal, "octave_jit_end_matrix", - scalar, matrix); - body = fn.new_block (); - builder.SetInsertPoint (body); - { - llvm::Value *mat = fn.argument (builder, 0); - llvm::Value *ret = builder.CreateExtractValue (mat, 2); - fn.do_return (builder, builder.CreateSIToFP (ret, scalar_t)); - } - end_fn.add_overload (fn); - - casts[any->type_id ()].stash_name ("(any)"); - casts[scalar->type_id ()].stash_name ("(scalar)"); - casts[complex->type_id ()].stash_name ("(complex)"); - casts[matrix->type_id ()].stash_name ("(matrix)"); - casts[any->type_id ()].stash_name ("(range)"); - - // cast any <- matrix - fn = create_function (jit_convention::external, "octave_jit_cast_any_matrix", - any, matrix); - fn.add_mapping (engine, &octave_jit_cast_any_matrix); - casts[any->type_id ()].add_overload (fn); - - // cast matrix <- any - fn = create_function (jit_convention::external, "octave_jit_cast_matrix_any", - matrix, any); - fn.add_mapping (engine, &octave_jit_cast_matrix_any); - casts[matrix->type_id ()].add_overload (fn); - - // cast any <- range - fn = create_function (jit_convention::external, "octave_jit_cast_any_range", - any, range); - fn.add_mapping (engine, &octave_jit_cast_any_range); - casts[any->type_id ()].add_overload (fn); - - // cast range <- any - fn = create_function (jit_convention::external, "octave_jit_cast_range_any", - range, any); - fn.add_mapping (engine, &octave_jit_cast_range_any); - casts[range->type_id ()].add_overload (fn); - - // cast any <- scalar - fn = create_function (jit_convention::external, "octave_jit_cast_any_scalar", - any, scalar); - fn.add_mapping (engine, &octave_jit_cast_any_scalar); - casts[any->type_id ()].add_overload (fn); - - // cast scalar <- any - fn = create_function (jit_convention::external, "octave_jit_cast_scalar_any", - scalar, any); - fn.add_mapping (engine, &octave_jit_cast_scalar_any); - casts[scalar->type_id ()].add_overload (fn); - - // cast any <- complex - fn = create_function (jit_convention::external, "octave_jit_cast_any_complex", - any, complex); - fn.add_mapping (engine, &octave_jit_cast_any_complex); - casts[any->type_id ()].add_overload (fn); - - // cast complex <- any - fn = create_function (jit_convention::external, "octave_jit_cast_complex_any", - complex, any); - fn.add_mapping (engine, &octave_jit_cast_complex_any); - casts[complex->type_id ()].add_overload (fn); - - // cast complex <- scalar - fn = create_function (jit_convention::internal, - "octave_jit_cast_complex_scalar", complex, scalar); - body = fn.new_block (); - builder.SetInsertPoint (body); - { - llvm::Value *zero = llvm::ConstantFP::get (scalar_t, 0); - fn.do_return (builder, complex_new (fn.argument (builder, 0), zero)); - } - casts[complex->type_id ()].add_overload (fn); - - // cast scalar <- complex - fn = create_function (jit_convention::internal, - "octave_jit_cast_scalar_complex", scalar, complex); - body = fn.new_block (); - builder.SetInsertPoint (body); - fn.do_return (builder, complex_real (fn.argument (builder, 0))); - casts[scalar->type_id ()].add_overload (fn); - - // cast any <- any - fn = create_identity (any); - casts[any->type_id ()].add_overload (fn); - - // cast scalar <- scalar - fn = create_identity (scalar); - casts[scalar->type_id ()].add_overload (fn); - - // cast complex <- complex - fn = create_identity (complex); - casts[complex->type_id ()].add_overload (fn); - - // -------------------- builtin functions -------------------- - add_builtin ("#unknown_function"); - unknown_function = builtins["#unknown_function"]; - - add_builtin ("sin"); - register_intrinsic ("sin", llvm::Intrinsic::sin, scalar, scalar); - register_generic ("sin", matrix, matrix); - - add_builtin ("cos"); - register_intrinsic ("cos", llvm::Intrinsic::cos, scalar, scalar); - register_generic ("cos", matrix, matrix); - - add_builtin ("exp"); - register_intrinsic ("exp", llvm::Intrinsic::cos, scalar, scalar); - register_generic ("exp", matrix, matrix); - - casts.resize (next_id + 1); - jit_function any_id = create_identity (any); - jit_function release_any = get_release (any); - std::vector args; - args.resize (1); - - for (std::map::iterator iter = builtins.begin (); - iter != builtins.end (); ++iter) - { - jit_type *btype = iter->second; - args[0] = btype; - - release_fn.add_overload (jit_function (release_any, 0, args)); - casts[any->type_id ()].add_overload (jit_function (any_id, any, args)); - - args[0] = any; - casts[btype->type_id ()].add_overload (jit_function (any_id, btype, - args)); - } -} - -void -jit_typeinfo::add_print (jit_type *ty, void *fptr) -{ - std::stringstream name; - name << "octave_jit_print_" << ty->name (); - jit_function fn = create_function (jit_convention::external, name.str (), 0, - intN (8), ty); - fn.add_mapping (engine, fptr); - print_fn.add_overload (fn); -} - -// FIXME: cp between add_binary_op, add_binary_icmp, and add_binary_fcmp -void -jit_typeinfo::add_binary_op (jit_type *ty, int op, int llvm_op) -{ - std::stringstream fname; - octave_value::binary_op ov_op = static_cast(op); - fname << "octave_jit_" << octave_value::binary_op_as_string (ov_op) - << "_" << ty->name (); - - jit_function fn = create_function (jit_convention::internal, fname.str (), - ty, ty, ty); - llvm::BasicBlock *block = fn.new_block (); - builder.SetInsertPoint (block); - llvm::Instruction::BinaryOps temp - = static_cast(llvm_op); - - llvm::Value *ret = builder.CreateBinOp (temp, fn.argument (builder, 0), - fn.argument (builder, 1)); - fn.do_return (builder, ret); - binary_ops[op].add_overload (fn); -} - -void -jit_typeinfo::add_binary_icmp (jit_type *ty, int op, int llvm_op) -{ - std::stringstream fname; - octave_value::binary_op ov_op = static_cast(op); - fname << "octave_jit" << octave_value::binary_op_as_string (ov_op) - << "_" << ty->name (); - - jit_function fn = create_function (jit_convention::internal, fname.str (), - boolean, ty, ty); - llvm::BasicBlock *block = fn.new_block (); - builder.SetInsertPoint (block); - llvm::CmpInst::Predicate temp - = static_cast(llvm_op); - llvm::Value *ret = builder.CreateICmp (temp, fn.argument (builder, 0), - fn.argument (builder, 1)); - fn.do_return (builder, ret); - binary_ops[op].add_overload (fn); -} - -void -jit_typeinfo::add_binary_fcmp (jit_type *ty, int op, int llvm_op) -{ - std::stringstream fname; - octave_value::binary_op ov_op = static_cast(op); - fname << "octave_jit" << octave_value::binary_op_as_string (ov_op) - << "_" << ty->name (); - - jit_function fn = create_function (jit_convention::internal, fname.str (), - boolean, ty, ty); - llvm::BasicBlock *block = fn.new_block (); - builder.SetInsertPoint (block); - llvm::CmpInst::Predicate temp - = static_cast(llvm_op); - llvm::Value *ret = builder.CreateFCmp (temp, fn.argument (builder, 0), - fn.argument (builder, 1)); - fn.do_return (builder, ret); - binary_ops[op].add_overload (fn); -} - -jit_function -jit_typeinfo::create_function (jit_convention::type cc, const llvm::Twine& name, - jit_type *ret, - const std::vector& args) -{ - jit_function result (module, cc, name, ret, args); - return result; -} - -jit_function -jit_typeinfo::create_identity (jit_type *type) -{ - size_t id = type->type_id (); - if (id >= identities.size ()) - identities.resize (id + 1); - - if (! identities[id].valid ()) - { - jit_function fn = create_function (jit_convention::internal, "id", type, - type); - llvm::BasicBlock *body = fn.new_block (); - builder.SetInsertPoint (body); - fn.do_return (builder, fn.argument (builder, 0)); - return identities[id] = fn; - } - - return identities[id]; -} - -llvm::Value * -jit_typeinfo::do_insert_error_check (llvm::IRBuilderD& abuilder) -{ - return abuilder.CreateLoad (lerror_state); -} - -void -jit_typeinfo::add_builtin (const std::string& name) -{ - jit_type *btype = new_type (name, any, any->to_llvm ()); - builtins[name] = btype; - - octave_builtin *ov_builtin = find_builtin (name); - if (ov_builtin) - ov_builtin->stash_jit (*btype); -} - -void -jit_typeinfo::register_intrinsic (const std::string& name, size_t iid, - jit_type *result, - const std::vector& args) -{ - jit_type *builtin_type = builtins[name]; - size_t nargs = args.size (); - llvm::SmallVector llvm_args (nargs); - for (size_t i = 0; i < nargs; ++i) - llvm_args[i] = args[i]->to_llvm (); - - llvm::Intrinsic::ID id = static_cast (iid); - llvm::Function *ifun = llvm::Intrinsic::getDeclaration (module, id, - llvm_args); - std::stringstream fn_name; - fn_name << "octave_jit_" << name; - - std::vector args1 (nargs + 1); - args1[0] = builtin_type; - std::copy (args.begin (), args.end (), args1.begin () + 1); - - // The first argument will be the Octave function, but we already know that - // the function call is the equivalent of the intrinsic, so we ignore it and - // call the intrinsic with the remaining arguments. - jit_function fn = create_function (jit_convention::internal, fn_name.str (), - result, args1); - llvm::BasicBlock *body = fn.new_block (); - builder.SetInsertPoint (body); - - llvm::SmallVector fargs (nargs); - for (size_t i = 0; i < nargs; ++i) - fargs[i] = fn.argument (builder, i + 1); - - llvm::Value *ret = builder.CreateCall (ifun, fargs); - fn.do_return (builder, ret); - paren_subsref_fn.add_overload (fn); -} - -octave_builtin * -jit_typeinfo::find_builtin (const std::string& name) -{ - // FIXME: Finalize what we want to store in octave_builtin, then add functions - // to access these values in octave_value - octave_value ov_builtin = symbol_table::find (name); - return dynamic_cast (ov_builtin.internal_rep ()); -} - -void -jit_typeinfo::register_generic (const std::string&, jit_type *, - const std::vector&) -{ - // FIXME: Implement -} - -jit_function -jit_typeinfo::mirror_binary (const jit_function& fn) -{ - jit_function ret = create_function (jit_convention::internal, - fn.name () + "_reverse", - fn.result (), fn.argument_type (1), - fn.argument_type (0)); - if (fn.can_error ()) - ret.mark_can_error (); - - llvm::BasicBlock *body = ret.new_block (); - builder.SetInsertPoint (body); - llvm::Value *result = fn.call (builder, ret.argument (builder, 1), - ret.argument (builder, 0)); - if (ret.result ()) - ret.do_return (builder, result); - else - ret.do_return (builder); - - return ret; -} - -llvm::Value * -jit_typeinfo::pack_complex (llvm::IRBuilderD& bld, llvm::Value *cplx) -{ - llvm::Type *complex_ret = instance->complex_ret; - llvm::Value *real = bld.CreateExtractElement (cplx, bld.getInt32 (0)); - llvm::Value *imag = bld.CreateExtractElement (cplx, bld.getInt32 (1)); - llvm::Value *ret = llvm::UndefValue::get (complex_ret); - ret = bld.CreateInsertValue (ret, real, 0); - return bld.CreateInsertValue (ret, imag, 1); -} - -llvm::Value * -jit_typeinfo::unpack_complex (llvm::IRBuilderD& bld, llvm::Value *result) -{ - llvm::Type *complex_t = get_complex ()->to_llvm (); - llvm::Value *real = bld.CreateExtractValue (result, 0); - llvm::Value *imag = bld.CreateExtractValue (result, 1); - llvm::Value *ret = llvm::UndefValue::get (complex_t); - ret = bld.CreateInsertElement (ret, real, bld.getInt32 (0)); - return bld.CreateInsertElement (ret, imag, bld.getInt32 (1)); -} - -llvm::Value * -jit_typeinfo::complex_real (llvm::Value *cx) -{ - return builder.CreateExtractElement (cx, builder.getInt32 (0)); -} - -llvm::Value * -jit_typeinfo::complex_real (llvm::Value *cx, llvm::Value *real) -{ - return builder.CreateInsertElement (cx, real, builder.getInt32 (0)); -} - -llvm::Value * -jit_typeinfo::complex_imag (llvm::Value *cx) -{ - return builder.CreateExtractElement (cx, builder.getInt32 (1)); -} - -llvm::Value * -jit_typeinfo::complex_imag (llvm::Value *cx, llvm::Value *imag) -{ - return builder.CreateInsertElement (cx, imag, builder.getInt32 (1)); -} - -llvm::Value * -jit_typeinfo::complex_new (llvm::Value *real, llvm::Value *imag) -{ - llvm::Value *ret = llvm::UndefValue::get (complex->to_llvm ()); - ret = complex_real (ret, real); - return complex_imag (ret, imag); -} - -void -jit_typeinfo::create_int (size_t nbits) -{ - std::stringstream tname; - tname << "int" << nbits; - ints[nbits] = new_type (tname.str (), any, llvm::Type::getIntNTy (context, - nbits)); -} - -jit_type * -jit_typeinfo::intN (size_t nbits) const -{ - std::map::const_iterator iter = ints.find (nbits); - if (iter != ints.end ()) - return iter->second; - - throw jit_fail_exception ("No such integer type"); -} - -jit_type * -jit_typeinfo::do_type_of (const octave_value &ov) const -{ - if (ov.is_function ()) - { - // FIXME: This is ugly, we need to finalize how we want to to this, then - // have octave_value fully support the needed functionality - octave_builtin *builtin - = dynamic_cast (ov.internal_rep ()); - return builtin && builtin->to_jit () ? builtin->to_jit () - : unknown_function; - } - - if (ov.is_range ()) - return get_range (); - - if (ov.is_double_type ()) - { - if (ov.is_real_scalar ()) - return get_scalar (); - - if (ov.is_matrix_type ()) - return get_matrix (); - } - - if (ov.is_complex_scalar ()) - return get_complex (); - - return get_any (); -} - -jit_type* -jit_typeinfo::new_type (const std::string& name, jit_type *parent, - llvm::Type *llvm_type) -{ - jit_type *ret = new jit_type (name, parent, llvm_type, next_id++); - id_to_type.push_back (ret); - return ret; -} - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/jit-typeinfo.h --- a/src/jit-typeinfo.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,753 +0,0 @@ -/* - -Copyright (C) 2012 Max Brister - -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 (octave_jit_typeinfo_h) -#define octave_jit_typeinfo_h 1 - -#ifdef HAVE_LLVM - -#include -#include - -#include "Range.h" -#include "jit-util.h" - -// Defines the type system used by jit and a singleton class, jit_typeinfo, to -// manage the types. -// -// FIXME: -// Operations are defined and implemented in jit_typeinfo. Eventually they -// should be moved elsewhere. (just like with octave_typeinfo) - -// jit_range is compatable with the llvm range structure -struct -jit_range -{ - jit_range (const Range& from) : base (from.base ()), limit (from.limit ()), - inc (from.inc ()), nelem (from.nelem ()) - {} - - operator Range () const - { - return Range (base, limit, inc); - } - - bool all_elements_are_ints () const; - - double base; - double limit; - double inc; - octave_idx_type nelem; -}; - -std::ostream& operator<< (std::ostream& os, const jit_range& rng); - -// jit_array is compatable with the llvm array/matrix structures -template -struct -jit_array -{ - jit_array (T& from) : array (new T (from)) - { - update (); - } - - void update (void) - { - ref_count = array->jit_ref_count (); - slice_data = array->jit_slice_data () - 1; - slice_len = array->capacity (); - dimensions = array->jit_dimensions (); - } - - void update (T *aarray) - { - array = aarray; - update (); - } - - operator T () const - { - return *array; - } - - int *ref_count; - - U *slice_data; - octave_idx_type slice_len; - octave_idx_type *dimensions; - - T *array; -}; - -typedef jit_array jit_matrix; - -std::ostream& operator<< (std::ostream& os, const jit_matrix& mat); - -// calling convention -namespace -jit_convention -{ - enum - type - { - // internal to jit - internal, - - // an external C call - external, - - length - }; -} - -// Used to keep track of estimated (infered) types during JIT. This is a -// hierarchical type system which includes both concrete and abstract types. -// -// The types form a lattice. Currently we only allow for one parent type, but -// eventually we may allow for multiple predecessors. -class -jit_type -{ -public: - typedef llvm::Value *(*convert_fn) (llvm::IRBuilderD&, llvm::Value *); - - jit_type (const std::string& aname, jit_type *aparent, llvm::Type *allvm_type, - int aid); - - // a user readable type name - const std::string& name (void) const { return mname; } - - // a unique id for the type - int type_id (void) const { return mid; } - - // An abstract base type, may be null - jit_type *parent (void) const { return mparent; } - - // convert to an llvm type - llvm::Type *to_llvm (void) const { return llvm_type; } - - // how this type gets passed as a function argument - llvm::Type *to_llvm_arg (void) const; - - size_t depth (void) const { return mdepth; } - - // -------------------- Calling Convention information -------------------- - - // A function declared like: mytype foo (int arg0, int arg1); - // Will be converted to: void foo (mytype *retval, int arg0, int arg1) - // if mytype is sret. The caller is responsible for allocating space for - // retval. (on the stack) - bool sret (jit_convention::type cc) const { return msret[cc]; } - - void mark_sret (jit_convention::type cc = jit_convention::external) - { msret[cc] = true; } - - // A function like: void foo (mytype arg0) - // Will be converted to: void foo (mytype *arg0) - // Basically just pass by reference. - bool pointer_arg (jit_convention::type cc) const { return mpointer_arg[cc]; } - - void mark_pointer_arg (jit_convention::type cc = jit_convention::external) - { mpointer_arg[cc] = true; } - - // Convert into an equivalent form before calling. For example, complex is - // represented as two values llvm vector, but we need to pass it as a two - // valued llvm structure to C functions. - convert_fn pack (jit_convention::type cc) { return mpack[cc]; } - - void set_pack (jit_convention::type cc, convert_fn fn) { mpack[cc] = fn; } - - // The inverse operation of pack. - convert_fn unpack (jit_convention::type cc) { return munpack[cc]; } - - void set_unpack (jit_convention::type cc, convert_fn fn) - { munpack[cc] = fn; } - - // The resulting type after pack is called. - llvm::Type *packed_type (jit_convention::type cc) - { return mpacked_type[cc]; } - - void set_packed_type (jit_convention::type cc, llvm::Type *ty) - { mpacked_type[cc] = ty; } -private: - std::string mname; - jit_type *mparent; - llvm::Type *llvm_type; - int mid; - size_t mdepth; - - bool msret[jit_convention::length]; - bool mpointer_arg[jit_convention::length]; - - convert_fn mpack[jit_convention::length]; - convert_fn munpack[jit_convention::length]; - - llvm::Type *mpacked_type[jit_convention::length]; -}; - -// seperate print function to allow easy printing if type is null -std::ostream& jit_print (std::ostream& os, jit_type *atype); - -class jit_value; - -// An abstraction for calling llvm functions with jit_values. Deals with calling -// convention details. -class -jit_function -{ - friend std::ostream& operator<< (std::ostream& os, const jit_function& fn); -public: - // create a function in an invalid state - jit_function (); - - jit_function (llvm::Module *amodule, jit_convention::type acall_conv, - const llvm::Twine& aname, jit_type *aresult, - const std::vector& aargs); - - // Use an existing function, but change the argument types. The new argument - // types must behave the same for the current calling convention. - jit_function (const jit_function& fn, jit_type *aresult, - const std::vector& aargs); - - jit_function (const jit_function& fn); - - template - void add_mapping (llvm::ExecutionEngine *engine, T fn) - { - do_add_mapping (engine, reinterpret_cast (fn)); - } - - bool valid (void) const { return llvm_function; } - - std::string name (void) const; - - llvm::BasicBlock *new_block (const std::string& aname = "body", - llvm::BasicBlock *insert_before = 0); - - llvm::Value *call (llvm::IRBuilderD& builder, - const std::vector& in_args) const; - - llvm::Value *call (llvm::IRBuilderD& builder, - const std::vector& in_args - = std::vector ()) const; - -#define JIT_PARAM_ARGS llvm::IRBuilderD& builder, -#define JIT_PARAMS builder, -#define JIT_CALL(N) JIT_EXPAND (llvm::Value *, call, llvm::Value *, const, N) - - JIT_CALL (1) - JIT_CALL (2) - JIT_CALL (3) - JIT_CALL (4) - JIT_CALL (5) - -#undef JIT_CALL - -#define JIT_CALL(N) JIT_EXPAND (llvm::Value *, call, jit_value *, const, N) - - JIT_CALL (1); - JIT_CALL (2); - -#undef JIT_CALL -#undef JIT_PARAMS -#undef JIT_PARAM_ARGS - - llvm::Value *argument (llvm::IRBuilderD& builder, size_t idx) const; - - void do_return (llvm::IRBuilderD& builder, llvm::Value *rval = 0); - - llvm::Function *to_llvm (void) const { return llvm_function; } - - // If true, then the return value is passed as a pointer in the first argument - bool sret (void) const { return mresult && mresult->sret (call_conv); } - - bool can_error (void) const { return mcan_error; } - - void mark_can_error (void) { mcan_error = true; } - - jit_type *result (void) const { return mresult; } - - jit_type *argument_type (size_t idx) const - { - assert (idx < args.size ()); - return args[idx]; - } - - const std::vector& arguments (void) const { return args; } -private: - void do_add_mapping (llvm::ExecutionEngine *engine, void *fn); - - llvm::Module *module; - llvm::Function *llvm_function; - jit_type *mresult; - std::vector args; - jit_convention::type call_conv; - bool mcan_error; -}; - -std::ostream& operator<< (std::ostream& os, const jit_function& fn); - - -// Keeps track of information about how to implement operations (+, -, *, ect) -// and their resulting types. -class -jit_operation -{ -public: - // type signature vector - typedef std::vector signature_vec; - - virtual ~jit_operation (void); - - void add_overload (const jit_function& func) - { - add_overload (func, func.arguments ()); - } - - void add_overload (const jit_function& func, - const signature_vec& args); - - const jit_function& overload (const signature_vec& types) const; - - jit_type *result (const signature_vec& types) const - { - const jit_function& temp = overload (types); - return temp.result (); - } - -#define JIT_PARAMS -#define JIT_PARAM_ARGS -#define JIT_OVERLOAD(N) \ - JIT_EXPAND (const jit_function&, overload, jit_type *, const, N) \ - JIT_EXPAND (jit_type *, result, jit_type *, const, N) - - JIT_OVERLOAD (1); - JIT_OVERLOAD (2); - JIT_OVERLOAD (3); - -#undef JIT_PARAMS -#undef JIT_PARAM_ARGS - - const std::string& name (void) const { return mname; } - - void stash_name (const std::string& aname) { mname = aname; } -protected: - virtual jit_function *generate (const signature_vec& types) const; -private: - Array to_idx (const signature_vec& types) const; - - const jit_function& do_generate (const signature_vec& types) const; - - struct signature_cmp - { - bool operator() (const signature_vec *lhs, const signature_vec *rhs); - }; - - typedef std::map - generated_map; - - mutable generated_map generated; - - std::vector > overloads; - - std::string mname; -}; - -class -jit_index_operation : public jit_operation -{ -public: - jit_index_operation (void) : module (0), engine (0) {} - - void initialize (llvm::Module *amodule, llvm::ExecutionEngine *aengine) - { - module = amodule; - engine = aengine; - do_initialize (); - } -protected: - virtual jit_function *generate (const signature_vec& types) const; - - virtual jit_function *generate_matrix (const signature_vec& types) const = 0; - - virtual void do_initialize (void) = 0; - - // helper functions - // [start_idx, end_idx). - llvm::Value *create_arg_array (llvm::IRBuilderD& builder, - const jit_function &fn, size_t start_idx, - size_t end_idx) const; - - llvm::Module *module; - llvm::ExecutionEngine *engine; -}; - -class -jit_paren_subsref : public jit_index_operation -{ -protected: - virtual jit_function *generate_matrix (const signature_vec& types) const; - - virtual void do_initialize (void); -private: - jit_function paren_scalar; -}; - -class -jit_paren_subsasgn : public jit_index_operation -{ -protected: - jit_function *generate_matrix (const signature_vec& types) const; - - virtual void do_initialize (void); -private: - jit_function paren_scalar; -}; - -// A singleton class which handles the construction of jit_types and -// jit_operations. -class -jit_typeinfo -{ -public: - static void initialize (llvm::Module *m, llvm::ExecutionEngine *e); - - static jit_type *join (jit_type *lhs, jit_type *rhs) - { - return instance->do_join (lhs, rhs); - } - - static jit_type *get_any (void) { return instance->any; } - - static jit_type *get_matrix (void) { return instance->matrix; } - - static jit_type *get_scalar (void) { return instance->scalar; } - - static llvm::Type *get_scalar_llvm (void) - { return instance->scalar->to_llvm (); } - - static jit_type *get_scalar_ptr (void) { return instance->scalar_ptr; } - - static jit_type *get_range (void) { return instance->range; } - - static jit_type *get_string (void) { return instance->string; } - - static jit_type *get_bool (void) { return instance->boolean; } - - static jit_type *get_index (void) { return instance->index; } - - static llvm::Type *get_index_llvm (void) - { return instance->index->to_llvm (); } - - static jit_type *get_complex (void) { return instance->complex; } - - // Get the jit_type of an octave_value - static jit_type *type_of (const octave_value& ov) - { - return instance->do_type_of (ov); - } - - static const jit_operation& binary_op (int op) - { - return instance->do_binary_op (op); - } - - static const jit_operation& grab (void) { return instance->grab_fn; } - - static const jit_function& get_grab (jit_type *type) - { - return instance->grab_fn.overload (type); - } - - static const jit_operation& release (void) - { - return instance->release_fn; - } - - static const jit_function& get_release (jit_type *type) - { - return instance->release_fn.overload (type); - } - - static const jit_operation& print_value (void) - { - return instance->print_fn; - } - - static const jit_operation& for_init (void) - { - return instance->for_init_fn; - } - - static const jit_operation& for_check (void) - { - return instance->for_check_fn; - } - - static const jit_operation& for_index (void) - { - return instance->for_index_fn; - } - - static const jit_operation& make_range (void) - { - return instance->make_range_fn; - } - - static const jit_operation& paren_subsref (void) - { - return instance->paren_subsref_fn; - } - - static const jit_operation& paren_subsasgn (void) - { - return instance->paren_subsasgn_fn; - } - - static const jit_operation& logically_true (void) - { - return instance->logically_true_fn; - } - - static const jit_operation& cast (jit_type *result) - { - return instance->do_cast (result); - } - - static const jit_function& cast (jit_type *to, jit_type *from) - { - return instance->do_cast (to, from); - } - - static llvm::Value *insert_error_check (llvm::IRBuilderD& bld) - { - return instance->do_insert_error_check (bld); - } - - static const jit_operation& end (void) - { - return instance->end_fn; - } - - static const jit_function& end (jit_type *ty) - { - return instance->end_fn.overload (ty); - } -private: - jit_typeinfo (llvm::Module *m, llvm::ExecutionEngine *e); - - // FIXME: Do these methods really need to be in jit_typeinfo? - jit_type *do_join (jit_type *lhs, jit_type *rhs) - { - // empty case - if (! lhs) - return rhs; - - if (! rhs) - return lhs; - - // check for a shared parent - while (lhs != rhs) - { - if (lhs->depth () > rhs->depth ()) - lhs = lhs->parent (); - else if (lhs->depth () < rhs->depth ()) - rhs = rhs->parent (); - else - { - // we MUST have depth > 0 as any is the base type of everything - do - { - lhs = lhs->parent (); - rhs = rhs->parent (); - } - while (lhs != rhs); - } - } - - return lhs; - } - - jit_type *do_difference (jit_type *lhs, jit_type *) - { - // FIXME: Maybe we can do something smarter? - return lhs; - } - - jit_type *do_type_of (const octave_value &ov) const; - - const jit_operation& do_binary_op (int op) const - { - assert (static_cast(op) < binary_ops.size ()); - return binary_ops[op]; - } - - const jit_operation& do_cast (jit_type *to) - { - static jit_operation null_function; - if (! to) - return null_function; - - size_t id = to->type_id (); - if (id >= casts.size ()) - return null_function; - return casts[id]; - } - - const jit_function& do_cast (jit_type *to, jit_type *from) - { - return do_cast (to).overload (from); - } - - jit_type *new_type (const std::string& name, jit_type *parent, - llvm::Type *llvm_type); - - - void add_print (jit_type *ty, void *fptr); - - void add_binary_op (jit_type *ty, int op, int llvm_op); - - void add_binary_icmp (jit_type *ty, int op, int llvm_op); - - void add_binary_fcmp (jit_type *ty, int op, int llvm_op); - - jit_function create_function (jit_convention::type cc, - const llvm::Twine& name, jit_type *ret, - const std::vector& args - = std::vector ()); - -#define JIT_PARAM_ARGS jit_convention::type cc, const llvm::Twine& name, \ - jit_type *ret, -#define JIT_PARAMS cc, name, ret, -#define CREATE_FUNCTION(N) JIT_EXPAND(jit_function, create_function, \ - jit_type *, /* empty */, N) - - CREATE_FUNCTION(1); - CREATE_FUNCTION(2); - CREATE_FUNCTION(3); - CREATE_FUNCTION(4); - -#undef JIT_PARAM_ARGS -#undef JIT_PARAMS -#undef CREATE_FUNCTION - - jit_function create_identity (jit_type *type); - - llvm::Value *do_insert_error_check (llvm::IRBuilderD& bld); - - void add_builtin (const std::string& name); - - void register_intrinsic (const std::string& name, size_t id, - jit_type *result, jit_type *arg0) - { - std::vector args (1, arg0); - register_intrinsic (name, id, result, args); - } - - void register_intrinsic (const std::string& name, size_t id, jit_type *result, - const std::vector& args); - - void register_generic (const std::string& name, jit_type *result, - jit_type *arg0) - { - std::vector args (1, arg0); - register_generic (name, result, args); - } - - void register_generic (const std::string& name, jit_type *result, - const std::vector& args); - - octave_builtin *find_builtin (const std::string& name); - - jit_function mirror_binary (const jit_function& fn); - - llvm::Function *wrap_complex (llvm::Function *wrap); - - static llvm::Value *pack_complex (llvm::IRBuilderD& bld, - llvm::Value *cplx); - - static llvm::Value *unpack_complex (llvm::IRBuilderD& bld, - llvm::Value *result); - - llvm::Value *complex_real (llvm::Value *cx); - - llvm::Value *complex_real (llvm::Value *cx, llvm::Value *real); - - llvm::Value *complex_imag (llvm::Value *cx); - - llvm::Value *complex_imag (llvm::Value *cx, llvm::Value *imag); - - llvm::Value *complex_new (llvm::Value *real, llvm::Value *imag); - - void create_int (size_t nbits); - - jit_type *intN (size_t nbits) const; - - static jit_typeinfo *instance; - - llvm::Module *module; - llvm::ExecutionEngine *engine; - int next_id; - - llvm::GlobalVariable *lerror_state; - - std::vector id_to_type; - jit_type *any; - jit_type *matrix; - jit_type *scalar; - jit_type *scalar_ptr; // a fake type for interfacing with C++ - jit_type *range; - jit_type *string; - jit_type *boolean; - jit_type *index; - jit_type *complex; - jit_type *unknown_function; - std::map ints; - std::map builtins; - - llvm::StructType *complex_ret; - - std::vector binary_ops; - jit_operation grab_fn; - jit_operation release_fn; - jit_operation print_fn; - jit_operation for_init_fn; - jit_operation for_check_fn; - jit_operation for_index_fn; - jit_operation logically_true_fn; - jit_operation make_range_fn; - jit_paren_subsref paren_subsref_fn; - jit_paren_subsasgn paren_subsasgn_fn; - jit_operation end_fn; - - // type id -> cast function TO that type - std::vector casts; - - // type id -> identity function - std::vector identities; - - llvm::IRBuilderD& builder; -}; - -#endif -#endif diff -r a132d206a36a -r b9b6a310ad97 src/jit-util.cc --- a/src/jit-util.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,44 +0,0 @@ -/* - -Copyright (C) 2012 Max Brister - -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 -. - -*/ - -// defines required by llvm -#define __STDC_LIMIT_MACROS -#define __STDC_CONSTANT_MACROS - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef HAVE_LLVM - -#include -#include - -std::ostream& -operator<< (std::ostream& os, const llvm::Value& v) -{ - llvm::raw_os_ostream llvm_out (os); - v.print (llvm_out); - return os; -} - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/jit-util.h --- a/src/jit-util.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,203 +0,0 @@ -/* - -Copyright (C) 2012 Max Brister - -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 -. - -*/ - -// Some utility classes and functions used throughout jit - -#if !defined (octave_jit_util_h) -#define octave_jit_util_h 1 - -#ifdef HAVE_LLVM - -#include - -// we don't want to include llvm headers here, as they require -// __STDC_LIMIT_MACROS and __STDC_CONSTANT_MACROS be defined in the entire -// compilation unit -namespace llvm -{ - class Value; - class Module; - class FunctionPassManager; - class PassManager; - class ExecutionEngine; - class Function; - class BasicBlock; - class LLVMContext; - class Type; - class StructType; - class Twine; - class GlobalVariable; - class TerminatorInst; - class PHINode; - - class ConstantFolder; - - template - class IRBuilderDefaultInserter; - - template - class IRBuilder; - -typedef IRBuilder > -IRBuilderD; -} - -class octave_base_value; -class octave_builtin; -class octave_value; -class tree; -class tree_expression; - -// thrown when we should give up on JIT and interpret -class jit_fail_exception : public std::runtime_error -{ -public: - jit_fail_exception (void) : std::runtime_error ("unknown"), mknown (false) {} - jit_fail_exception (const std::string& reason) : std::runtime_error (reason), - mknown (true) - {} - - bool known (void) const { return mknown; } -private: - bool mknown; -}; - -// llvm doesn't provide this, and it's really useful for debugging -std::ostream& operator<< (std::ostream& os, const llvm::Value& v); - -template -class jit_internal_node; - -// jit_internal_list and jit_internal_node implement generic embedded doubly -// linked lists. List items extend from jit_internal_list, and can be placed -// in nodes of type jit_internal_node. We use CRTP twice. -template -class -jit_internal_list -{ - friend class jit_internal_node; -public: - jit_internal_list (void) : use_head (0), use_tail (0), muse_count (0) {} - - virtual ~jit_internal_list (void) - { - while (use_head) - use_head->stash_value (0); - } - - NODE_T *first_use (void) const { return use_head; } - - size_t use_count (void) const { return muse_count; } -private: - NODE_T *use_head; - NODE_T *use_tail; - size_t muse_count; -}; - -// a node for internal linked lists -template -class -jit_internal_node -{ -public: - typedef jit_internal_list jit_ilist; - - jit_internal_node (void) : mvalue (0), mnext (0), mprev (0) {} - - ~jit_internal_node (void) { remove (); } - - LIST_T *value (void) const { return mvalue; } - - void stash_value (LIST_T *avalue) - { - remove (); - - mvalue = avalue; - - if (mvalue) - { - jit_ilist *ilist = mvalue; - NODE_T *sthis = static_cast (this); - if (ilist->use_head) - { - ilist->use_tail->mnext = sthis; - mprev = ilist->use_tail; - } - else - ilist->use_head = sthis; - - ilist->use_tail = sthis; - ++ilist->muse_count; - } - } - - NODE_T *next (void) const { return mnext; } - - NODE_T *prev (void) const { return mprev; } -private: - void remove () - { - if (mvalue) - { - jit_ilist *ilist = mvalue; - if (mprev) - mprev->mnext = mnext; - else - // we are the use_head - ilist->use_head = mnext; - - if (mnext) - mnext->mprev = mprev; - else - // we are the use tail - ilist->use_tail = mprev; - - mnext = mprev = 0; - --ilist->muse_count; - mvalue = 0; - } - } - - LIST_T *mvalue; - NODE_T *mnext; - NODE_T *mprev; -}; - -// Use like: isa (value) -// basically just a short cut type typing dyanmic_cast. -template -bool isa (U *value) -{ - return dynamic_cast (value); -} - -#define JIT_ASSIGN_ARG(i) the_args[i] = arg ## i; -#define JIT_EXPAND(ret, fname, type, isconst, N) \ - ret fname (JIT_PARAM_ARGS OCT_MAKE_DECL_LIST (type, arg, N)) isconst \ - { \ - std::vector the_args (N); \ - OCT_ITERATE_MACRO (JIT_ASSIGN_ARG, N); \ - return fname (JIT_PARAMS the_args); \ - } - -#endif -#endif diff -r a132d206a36a -r b9b6a310ad97 src/ls-ascii-helper.cc --- a/src/ls-ascii-helper.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,175 +0,0 @@ -/* - -Copyright (C) 2009-2012 Benjamin Lindner - -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 -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "ls-ascii-helper.h" - -#include -#include - -// Helper functions when reading from ascii files. - -// These function take care of CR/LF issues when files are opened in -// text-mode for reading. - -// Skip characters from stream IS until a newline is reached. -// Depending on KEEP_NEWLINE, either eat newline from stream or -// keep it unread. - -void -skip_until_newline (std::istream& is, bool keep_newline) -{ - if (! is) - return; - - while (is) - { - char c = is.peek (); - - if (c == '\n' || c == '\r') - { - // Reached newline. - if (! keep_newline) - { - // Eat the CR or LF character. - char d; - is.get (d); - - // Make sure that for binary-mode opened ascii files - // containing CRLF line endings we skip the LF after CR. - if (c == '\r' && is.peek () == '\n') - { - // Yes, LF following CR, eat it. - is.get (d); - } - } - - // Newline was found, and read from stream if - // keep_newline == true, so exit loop. - break; - } - else - { - // No newline charater peeked, so read it and proceed to next - // character. - char d; - is.get (d); - } - } -} - - -// If stream IS currently points to a newline (a leftover from a -// previous read) then eat newline(s) until a non-newline character is -// found. - -void -skip_preceeding_newline (std::istream& is) -{ - if (! is) - return; - - // Check whether IS currently points to newline character. - char c = is.peek (); - - if (c == '\n' || c == '\r') - { - // Yes, at newline. - do - { - // Eat the CR or LF character. - char d; - is.get (d); - - // Make sure that for binary-mode opened ascii files - // containing CRLF line endings we skip the LF after CR. - if (c == '\r' && is.peek () == '\n') - { - // Yes, LF following CR, eat it. - is.get (d); - } - - // Peek into next character. - c = is.peek (); - - // Loop while still a newline ahead. - } - while (c == '\n' || c == '\r'); - } -} - -// Read charaters from stream IS until a newline is reached. -// Depending on KEEP_NEWLINE, either eat newline from stream or keep -// it unread. Characters read are stored and returned as -// std::string. - -std::string -read_until_newline (std::istream& is, bool keep_newline) -{ - if (! is) - return std::string (); - - std::ostringstream buf; - - while (is) - { - char c = is.peek (); - - if (c == '\n' || c == '\r') - { - // Reached newline. - if (! keep_newline) - { - // Eat the CR or LF character. - char d; - is.get (d); - - // Make sure that for binary-mode opened ascii files - // containing CRLF line endings we skip the LF after - // CR. - - if (c == '\r' && is.peek () == '\n') - { - // Yes, LF following CR, eat it. - is.get (d); - } - } - - // Newline was found, and read from stream if - // keep_newline == true, so exit loop. - break; - } - else - { - // No newline charater peeked, so read it, store it, and - // proceed to next. - char d; - is.get (d); - buf << d; - } - } - - return buf.str (); -} diff -r a132d206a36a -r b9b6a310ad97 src/ls-ascii-helper.h --- a/src/ls-ascii-helper.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -/* - -Copyright (C) 2009-2012 Benjamin Lindner - -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 (octave_ls_ascii_helper_h) -#define octave_ls_ascii_helper_h 1 - -#include -#include - -extern OCTINTERP_API void -skip_until_newline (std::istream& is, bool keep_newline = false); - -extern OCTINTERP_API void -skip_preceeding_newline (std::istream& is); - -extern OCTINTERP_API std::string -read_until_newline (std::istream& is, bool keep_newline = false); - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/ls-hdf5.cc --- a/src/ls-hdf5.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,921 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -// Author: Steven G. Johnson - -#ifdef HAVE_CONFIG_H -#include -#endif - -#if defined (HAVE_HDF5) - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "byte-swap.h" -#include "data-conv.h" -#include "file-ops.h" -#include "glob-match.h" -#include "lo-mappers.h" -#include "mach-info.h" -#include "oct-env.h" -#include "oct-time.h" -#include "quit.h" -#include "str-vec.h" -#include "oct-locbuf.h" - -#include "Cell.h" -#include "defun.h" -#include "error.h" -#include "gripes.h" -#include "load-save.h" -#include "oct-obj.h" -#include "oct-map.h" -#include "ov-cell.h" -#include "pager.h" -#include "pt-exp.h" -#include "sysdep.h" -#include "unwind-prot.h" -#include "utils.h" -#include "variables.h" -#include "version.h" -#include "dMatrix.h" -#include "ov-lazy-idx.h" - -#include "ls-utils.h" -#include "ls-hdf5.h" - -static std::string -make_valid_identifier (const std::string& nm) -{ - std::string retval; - - size_t nm_len = nm.length (); - - if (nm_len > 0) - { - if (! isalpha (nm[0])) - retval += '_'; - - for (size_t i = 0; i < nm_len; i++) - { - char c = nm[i]; - retval += (isalnum (c) || c == '_') ? c : '_'; - } - } - - return retval; -} - -// Define this to 1 if/when HDF5 supports automatic conversion between -// integer and floating-point binary data: -#define HAVE_HDF5_INT2FLOAT_CONVERSIONS 0 - -// Given two compound types t1 and t2, determine whether they -// are compatible for reading/writing. This function only -// works for non-nested types composed of simple elements (ints, floats...), -// which is all we need it for - -bool -hdf5_types_compatible (hid_t t1, hid_t t2) -{ - int n; - if ((n = H5Tget_nmembers (t1)) != H5Tget_nmembers (t2)) - return false; - - for (int i = 0; i < n; ++i) - { - hid_t mt1 = H5Tget_member_type (t1, i); - hid_t mt2 = H5Tget_member_type (t2, i); - - if (H5Tget_class (mt1) != H5Tget_class (mt2)) - return false; - - H5Tclose (mt2); - H5Tclose (mt1); - } - - return true; -} - -// Return true if loc_id has the attribute named attr_name, and false -// otherwise. - -bool -hdf5_check_attr (hid_t loc_id, const char *attr_name) -{ - bool retval = false; - - // we have to pull some shenanigans here to make sure - // HDF5 doesn't print out all sorts of error messages if we - // call H5Aopen for a non-existing attribute - - H5E_auto_t err_func; - void *err_func_data; - - // turn off error reporting temporarily, but save the error - // reporting function: - -#if HAVE_HDF5_18 - H5Eget_auto (H5E_DEFAULT, &err_func, &err_func_data); - H5Eset_auto (H5E_DEFAULT, 0, 0); -#else - H5Eget_auto (&err_func, &err_func_data); - H5Eset_auto (0, 0); -#endif - - hid_t attr_id = H5Aopen_name (loc_id, attr_name); - - if (attr_id >= 0) - { - // successful - retval = true; - H5Aclose (attr_id); - } - - // restore error reporting: -#if HAVE_HDF5_18 - H5Eset_auto (H5E_DEFAULT, err_func, err_func_data); -#else - H5Eset_auto (err_func, err_func_data); -#endif - return retval; -} - -bool -hdf5_get_scalar_attr (hid_t loc_id, hid_t type_id, - const char *attr_name, void *buf) -{ - bool retval = false; - - // we have to pull some shenanigans here to make sure - // HDF5 doesn't print out all sorts of error messages if we - // call H5Aopen for a non-existing attribute - - H5E_auto_t err_func; - void *err_func_data; - - // turn off error reporting temporarily, but save the error - // reporting function: - -#if HAVE_HDF5_18 - H5Eget_auto (H5E_DEFAULT, &err_func, &err_func_data); - H5Eset_auto (H5E_DEFAULT, 0, 0); -#else - H5Eget_auto (&err_func, &err_func_data); - H5Eset_auto (0, 0); -#endif - - hid_t attr_id = H5Aopen_name (loc_id, attr_name); - - if (attr_id >= 0) - { - hid_t space_id = H5Aget_space (attr_id); - - hsize_t rank = H5Sget_simple_extent_ndims (space_id); - - if (rank == 0) - retval = H5Aread (attr_id, type_id, buf) >= 0; - H5Aclose (attr_id); - } - - // restore error reporting: -#if HAVE_HDF5_18 - H5Eset_auto (H5E_DEFAULT, err_func, err_func_data); -#else - H5Eset_auto (err_func, err_func_data); -#endif - return retval; -} - - - - -// The following subroutines creates an HDF5 representations of the way -// we will store Octave complex types (pairs of floating-point numbers). -// NUM_TYPE is the HDF5 numeric type to use for storage (e.g. -// H5T_NATIVE_DOUBLE to save as 'double'). Note that any necessary -// conversions are handled automatically by HDF5. - -hid_t -hdf5_make_complex_type (hid_t num_type) -{ - hid_t type_id = H5Tcreate (H5T_COMPOUND, sizeof (double) * 2); - - H5Tinsert (type_id, "real", 0 * sizeof (double), num_type); - H5Tinsert (type_id, "imag", 1 * sizeof (double), num_type); - - return type_id; -} - -// This function is designed to be passed to H5Giterate, which calls it -// on each data item in an HDF5 file. For the item whose name is NAME in -// the group GROUP_ID, this function sets dv->tc to an Octave representation -// of that item. (dv must be a pointer to hdf5_callback_data.) (It also -// sets the other fields of dv). -// -// It returns 1 on success (in which case H5Giterate stops and returns), -// -1 on error, and 0 to tell H5Giterate to continue on to the next item -// (e.g. if NAME was a data type we don't recognize). - -herr_t -hdf5_read_next_data (hid_t group_id, const char *name, void *dv) -{ - hdf5_callback_data *d = static_cast (dv); - hid_t type_id = -1, type_class_id = -1, data_id = -1, subgroup_id = -1, - space_id = -1; - - H5G_stat_t info; - herr_t retval = 0; - bool ident_valid = valid_identifier (name); - - std::string vname = name; - - // Allow identifiers as all digits so we can load lists saved by - // earlier versions of Octave. - - if (! ident_valid ) - { - // fix the identifier, replacing invalid chars with underscores - vname = make_valid_identifier (vname); - - // check again (in case vname was null, empty, or some such thing): - ident_valid = valid_identifier (vname); - } - - H5Gget_objinfo (group_id, name, 1, &info); - - if (info.type == H5G_GROUP && ident_valid) - { -#if HAVE_HDF5_18 - subgroup_id = H5Gopen (group_id, name, H5P_DEFAULT); -#else - subgroup_id = H5Gopen (group_id, name); -#endif - - if (subgroup_id < 0) - { - retval = subgroup_id; - goto done; - } - - if (hdf5_check_attr (subgroup_id, "OCTAVE_NEW_FORMAT")) - { -#if HAVE_HDF5_18 - data_id = H5Dopen (subgroup_id, "type", H5P_DEFAULT); -#else - data_id = H5Dopen (subgroup_id, "type"); -#endif - - if (data_id < 0) - { - retval = data_id; - goto done; - } - - type_id = H5Dget_type (data_id); - - type_class_id = H5Tget_class (type_id); - - if (type_class_id != H5T_STRING) - goto done; - - space_id = H5Dget_space (data_id); - hsize_t rank = H5Sget_simple_extent_ndims (space_id); - - if (rank != 0) - goto done; - - int slen = H5Tget_size (type_id); - if (slen < 0) - goto done; - - OCTAVE_LOCAL_BUFFER (char, typ, slen); - - // create datatype for (null-terminated) string to read into: - hid_t st_id = H5Tcopy (H5T_C_S1); - H5Tset_size (st_id, slen); - - if (H5Dread (data_id, st_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, - typ) < 0) - goto done; - - H5Tclose (st_id); - H5Dclose (data_id); - - d->tc = octave_value_typeinfo::lookup_type (typ); - - retval = (d->tc.load_hdf5 (subgroup_id, "value") ? 1 : -1); - - // check for OCTAVE_GLOBAL attribute: - d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL"); - - H5Gclose (subgroup_id); - } - else - { - // an HDF5 group is treated as an octave structure by - // default (since that preserves name information), and an - // octave list otherwise. - - if (hdf5_check_attr (subgroup_id, "OCTAVE_LIST")) - d->tc = octave_value_typeinfo::lookup_type ("list"); - else - d->tc = octave_value_typeinfo::lookup_type ("struct"); - - // check for OCTAVE_GLOBAL attribute: - d->global = hdf5_check_attr (subgroup_id, "OCTAVE_GLOBAL"); - - H5Gclose (subgroup_id); - - retval = (d->tc.load_hdf5 (group_id, name) ? 1 : -1); - } - - } - else if (info.type == H5G_DATASET && ident_valid) - { - // For backwards compatiability. -#if HAVE_HDF5_18 - data_id = H5Dopen (group_id, name, H5P_DEFAULT); -#else - data_id = H5Dopen (group_id, name); -#endif - - if (data_id < 0) - { - retval = data_id; - goto done; - } - - type_id = H5Dget_type (data_id); - - type_class_id = H5Tget_class (type_id); - - if (type_class_id == H5T_FLOAT) - { - space_id = H5Dget_space (data_id); - - hsize_t rank = H5Sget_simple_extent_ndims (space_id); - - if (rank == 0) - d->tc = octave_value_typeinfo::lookup_type ("scalar"); - else - d->tc = octave_value_typeinfo::lookup_type ("matrix"); - - H5Sclose (space_id); - } - else if (type_class_id == H5T_INTEGER) - { - // What integer type do we really have.. - std::string int_typ; -#ifdef HAVE_H5T_GET_NATIVE_TYPE - // FIXME test this code and activated with an autoconf - // test!! It is also incorrect for 64-bit indexing!! - - switch (H5Tget_native_type (type_id, H5T_DIR_ASCEND)) - { - case H5T_NATIVE_CHAR: - int_typ = "int8 "; - break; - - case H5T_NATIVE_SHORT: - int_typ = "int16 "; - break; - - case H5T_NATIVE_INT: - case H5T_NATIVE_LONG: - int_typ = "int32 "; - break; - - case H5T_NATIVE_LLONG: - int_typ = "int64 "; - break; - - case H5T_NATIVE_UCHAR: - int_typ = "uint8 "; - break; - - case H5T_NATIVE_USHORT: - int_typ = "uint16 "; - break; - - case H5T_NATIVE_UINT: - case H5T_NATIVE_ULONG: - int_typ = "uint32 "; - break; - - case H5T_NATIVE_ULLONG: - int_typ = "uint64 "; - break; - } -#else - hid_t int_sign = H5Tget_sign (type_id); - - if (int_sign == H5T_SGN_ERROR) - warning ("load: can't read `%s' (unknown datatype)", name); - else - { - if (int_sign == H5T_SGN_NONE) - int_typ.append ("u"); - int_typ.append ("int"); - - int slen = H5Tget_size (type_id); - if (slen < 0) - warning ("load: can't read `%s' (unknown datatype)", name); - else - { - switch (slen) - { - case 1: - int_typ.append ("8 "); - break; - - case 2: - int_typ.append ("16 "); - break; - - case 4: - int_typ.append ("32 "); - break; - - case 8: - int_typ.append ("64 "); - break; - - default: - warning ("load: can't read `%s' (unknown datatype)", - name); - int_typ = ""; - break; - } - } - } -#endif - if (int_typ == "") - warning ("load: can't read `%s' (unknown datatype)", name); - else - { - // Matrix or scalar? - space_id = H5Dget_space (data_id); - - hsize_t rank = H5Sget_simple_extent_ndims (space_id); - - if (rank == 0) - int_typ.append ("scalar"); - else - int_typ.append ("matrix"); - - d->tc = octave_value_typeinfo::lookup_type (int_typ); - H5Sclose (space_id); - } - } - else if (type_class_id == H5T_STRING) - d->tc = octave_value_typeinfo::lookup_type ("string"); - else if (type_class_id == H5T_COMPOUND) - { - hid_t complex_type = hdf5_make_complex_type (H5T_NATIVE_DOUBLE); - - if (hdf5_types_compatible (type_id, complex_type)) - { - // read complex matrix or scalar variable - space_id = H5Dget_space (data_id); - hsize_t rank = H5Sget_simple_extent_ndims (space_id); - - if (rank == 0) - d->tc = octave_value_typeinfo::lookup_type ("complex scalar"); - else - d->tc = octave_value_typeinfo::lookup_type ("complex matrix"); - - H5Sclose (space_id); - } - else - // Assume that if its not complex its a range. If its not - // it'll be rejected later in the range code - d->tc = octave_value_typeinfo::lookup_type ("range"); - - H5Tclose (complex_type); - } - else - { - warning ("load: can't read `%s' (unknown datatype)", name); - retval = 0; // unknown datatype; skip - } - - // check for OCTAVE_GLOBAL attribute: - d->global = hdf5_check_attr (data_id, "OCTAVE_GLOBAL"); - - H5Tclose (type_id); - H5Dclose (data_id); - - retval = (d->tc.load_hdf5 (group_id, name) ? 1 : -1); - } - - if (!ident_valid) - { - // should we attempt to handle invalid identifiers by converting - // bad characters to '_', say? - warning ("load: skipping invalid identifier `%s' in hdf5 file", - name); - } - - done: - if (retval < 0) - error ("load: error while reading hdf5 item %s", name); - - if (retval > 0) - { - // get documentation string, if any: - int comment_length = H5Gget_comment (group_id, name, 0, 0); - - if (comment_length > 1) - { - OCTAVE_LOCAL_BUFFER (char, tdoc, comment_length); - H5Gget_comment (group_id, name, comment_length, tdoc); - d->doc = tdoc; - } - else if (vname != name) - { - // the name was changed; store the original name - // as the documentation string: - d->doc = name; - } - - // copy name (actually, vname): - d->name = vname; - } - - return retval; -} - -// Read the next Octave variable from the stream IS, which must really be -// an hdf5_ifstream. Return the variable value in tc, its doc string -// in doc, and whether it is global in global. The return value is -// the name of the variable, or NULL if none were found or there was -// and error. -std::string -read_hdf5_data (std::istream& is, const std::string& /* filename */, - bool& global, octave_value& tc, std::string& doc) -{ - std::string retval; - - doc.resize (0); - - hdf5_ifstream& hs = dynamic_cast (is); - hdf5_callback_data d; - - herr_t H5Giterate_retval = -1; - - hsize_t num_obj = 0; -#if HAVE_HDF5_18 - hid_t group_id = H5Gopen (hs.file_id, "/", H5P_DEFAULT); -#else - hid_t group_id = H5Gopen (hs.file_id, "/"); -#endif - H5Gget_num_objs (group_id, &num_obj); - H5Gclose (group_id); - if (hs.current_item < static_cast (num_obj)) - H5Giterate_retval = H5Giterate (hs.file_id, "/", &hs.current_item, - hdf5_read_next_data, &d); - - if (H5Giterate_retval > 0) - { - global = d.global; - tc = d.tc; - doc = d.doc; - } - else - { - // an error occurred (H5Giterate_retval < 0) or there are no - // more datasets print an error message if retval < 0? - // hdf5_read_next_data already printed one, probably. - } - - if (! d.name.empty ()) - retval = d.name; - - return retval; -} - -// Add an attribute named attr_name to loc_id (a simple scalar -// attribute with value 1). Return value is >= 0 on success. -herr_t -hdf5_add_attr (hid_t loc_id, const char *attr_name) -{ - herr_t retval = 0; - - hid_t as_id = H5Screate (H5S_SCALAR); - - if (as_id >= 0) - { -#if HAVE_HDF5_18 - hid_t a_id = H5Acreate (loc_id, attr_name, H5T_NATIVE_UCHAR, - as_id, H5P_DEFAULT, H5P_DEFAULT); -#else - hid_t a_id = H5Acreate (loc_id, attr_name, - H5T_NATIVE_UCHAR, as_id, H5P_DEFAULT); -#endif - if (a_id >= 0) - { - unsigned char attr_val = 1; - - retval = H5Awrite (a_id, H5T_NATIVE_UCHAR, &attr_val); - - H5Aclose (a_id); - } - else - retval = a_id; - - H5Sclose (as_id); - } - else - retval = as_id; - - return retval; -} - -herr_t -hdf5_add_scalar_attr (hid_t loc_id, hid_t type_id, - const char *attr_name, void *buf) -{ - herr_t retval = 0; - - hid_t as_id = H5Screate (H5S_SCALAR); - - if (as_id >= 0) - { -#if HAVE_HDF5_18 - hid_t a_id = H5Acreate (loc_id, attr_name, type_id, - as_id, H5P_DEFAULT, H5P_DEFAULT); -#else - hid_t a_id = H5Acreate (loc_id, attr_name, - type_id, as_id, H5P_DEFAULT); -#endif - if (a_id >= 0) - { - retval = H5Awrite (a_id, type_id, buf); - - H5Aclose (a_id); - } - else - retval = a_id; - - H5Sclose (as_id); - } - else - retval = as_id; - - return retval; -} - -// Save an empty matrix, if needed. Returns -// > 0 Saved empty matrix -// = 0 Not an empty matrix; did nothing -// < 0 Error condition -int -save_hdf5_empty (hid_t loc_id, const char *name, const dim_vector d) -{ - hsize_t sz = d.length (); - OCTAVE_LOCAL_BUFFER (octave_idx_type, dims, sz); - bool empty = false; - hid_t space_hid = -1, data_hid = -1; - int retval; - for (hsize_t i = 0; i < sz; i++) - { - dims[i] = d(i); - if (dims[i] < 1) - empty = true; - } - - if (!empty) - return 0; - - space_hid = H5Screate_simple (1, &sz, 0); - if (space_hid < 0) return space_hid; -#if HAVE_HDF5_18 - data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_IDX, space_hid, - H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); -#else - data_hid = H5Dcreate (loc_id, name, H5T_NATIVE_IDX, space_hid, - H5P_DEFAULT); -#endif - if (data_hid < 0) - { - H5Sclose (space_hid); - return data_hid; - } - - retval = H5Dwrite (data_hid, H5T_NATIVE_IDX, H5S_ALL, H5S_ALL, - H5P_DEFAULT, dims) >= 0; - - H5Dclose (data_hid); - H5Sclose (space_hid); - - if (retval >= 0) - retval = hdf5_add_attr (loc_id, "OCTAVE_EMPTY_MATRIX"); - - return (retval == 0 ? 1 : retval); -} - -// Load an empty matrix, if needed. Returns -// > 0 loaded empty matrix, dimensions returned -// = 0 Not an empty matrix; did nothing -// < 0 Error condition -int -load_hdf5_empty (hid_t loc_id, const char *name, dim_vector &d) -{ - if (! hdf5_check_attr (loc_id, "OCTAVE_EMPTY_MATRIX")) - return 0; - - hsize_t hdims, maxdims; -#if HAVE_HDF5_18 - hid_t data_hid = H5Dopen (loc_id, name, H5P_DEFAULT); -#else - hid_t data_hid = H5Dopen (loc_id, name); -#endif - hid_t space_id = H5Dget_space (data_hid); - H5Sget_simple_extent_dims (space_id, &hdims, &maxdims); - int retval; - - OCTAVE_LOCAL_BUFFER (octave_idx_type, dims, hdims); - - retval = H5Dread (data_hid, H5T_NATIVE_IDX, H5S_ALL, H5S_ALL, - H5P_DEFAULT, dims); - if (retval >= 0) - { - d.resize (hdims); - for (hsize_t i = 0; i < hdims; i++) - d(i) = dims[i]; - } - - H5Sclose (space_id); - H5Dclose (data_hid); - - return (retval == 0 ? hdims : retval); -} - -// save_type_to_hdf5 is not currently used, since hdf5 doesn't yet support -// automatic float<->integer conversions: - -#if HAVE_HDF5_INT2FLOAT_CONVERSIONS - -// return the HDF5 type id corresponding to the Octave save_type - -hid_t -save_type_to_hdf5 (save_type st) -{ - switch (st) - { - case LS_U_CHAR: - return H5T_NATIVE_UCHAR; - - case LS_U_SHORT: - return H5T_NATIVE_USHORT; - - case LS_U_INT: - return H5T_NATIVE_UINT; - - case LS_CHAR: - return H5T_NATIVE_CHAR; - - case LS_SHORT: - return H5T_NATIVE_SHORT; - - case LS_INT: - return H5T_NATIVE_INT; - - case LS_FLOAT: - return H5T_NATIVE_FLOAT; - - case LS_DOUBLE: - default: - return H5T_NATIVE_DOUBLE; - } -} -#endif /* HAVE_HDF5_INT2FLOAT_CONVERSIONS */ - -// Add the data from TC to the HDF5 location loc_id, which could -// be either a file or a group within a file. Return true if -// successful. This function calls itself recursively for lists -// (stored as HDF5 groups). - -bool -add_hdf5_data (hid_t loc_id, const octave_value& tc, - const std::string& name, const std::string& doc, - bool mark_as_global, bool save_as_floats) -{ - hsize_t dims[3]; - hid_t type_id = -1, space_id = -1, data_id = -1, data_type_id = -1; - bool retval = false; - octave_value val = tc; - // FIXME: diagonal & permutation matrices currently don't know how to save - // themselves, so we convert them first to normal matrices using A = A(:,:). - // This is a temporary hack. - if (val.is_diag_matrix () || val.is_perm_matrix () - || val.type_id () == octave_lazy_index::static_type_id ()) - val = val.full_value (); - - std::string t = val.type_name (); -#if HAVE_HDF5_18 - data_id = H5Gcreate (loc_id, name.c_str (), H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); -#else - data_id = H5Gcreate (loc_id, name.c_str (), 0); -#endif - if (data_id < 0) - goto error_cleanup; - - // attach the type of the variable - type_id = H5Tcopy (H5T_C_S1); H5Tset_size (type_id, t.length () + 1); - if (type_id < 0) - goto error_cleanup; - - dims[0] = 0; - space_id = H5Screate_simple (0 , dims, 0); - if (space_id < 0) - goto error_cleanup; -#if HAVE_HDF5_18 - data_type_id = H5Dcreate (data_id, "type", type_id, space_id, - H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); -#else - data_type_id = H5Dcreate (data_id, "type", type_id, space_id, H5P_DEFAULT); -#endif - if (data_type_id < 0 || H5Dwrite (data_type_id, type_id, H5S_ALL, H5S_ALL, - H5P_DEFAULT, t.c_str ()) < 0) - goto error_cleanup; - - // Now call the real function to save the variable - retval = val.save_hdf5 (data_id, "value", save_as_floats); - - // attach doc string as comment: - if (retval && doc.length () > 0 - && H5Gset_comment (loc_id, name.c_str (), doc.c_str ()) < 0) - retval = false; - - // if it's global, add an attribute "OCTAVE_GLOBAL" with value 1 - if (retval && mark_as_global) - retval = hdf5_add_attr (data_id, "OCTAVE_GLOBAL") >= 0; - - // We are saving in the new variable format, so mark it - if (retval) - retval = hdf5_add_attr (data_id, "OCTAVE_NEW_FORMAT") >= 0; - - error_cleanup: - - if (data_type_id >= 0) - H5Dclose (data_type_id); - - if (type_id >= 0) - H5Tclose (type_id); - - if (space_id >= 0) - H5Sclose (space_id); - - if (data_id >= 0) - H5Gclose (data_id); - - if (! retval) - error ("save: error while writing `%s' to hdf5 file", name.c_str ()); - - return retval; -} - -// Write data from TC in HDF5 (binary) format to the stream OS, -// which must be an hdf5_ofstream, returning true on success. - -bool -save_hdf5_data (std::ostream& os, const octave_value& tc, - const std::string& name, const std::string& doc, - bool mark_as_global, bool save_as_floats) -{ - hdf5_ofstream& hs = dynamic_cast (os); - - return add_hdf5_data (hs.file_id, tc, name, doc, - mark_as_global, save_as_floats); -} - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/ls-hdf5.h --- a/src/ls-hdf5.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,213 +0,0 @@ -/* - -Copyright (C) 2003-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_ls_hdf5_h) -#define octave_ls_hdf5_h 1 - -#if defined (HAVE_HDF5) - -#include "oct-hdf5.h" - -// first, we need to define our own dummy stream subclass, since -// HDF5 needs to do its own file i/o - -// hdf5_fstreambase is used for both input and output streams, modeled -// on the fstreambase class in - -class hdf5_fstreambase : virtual public std::ios -{ -public: - - // HDF5 uses an "id" to refer to an open file - hid_t file_id; - - // keep track of current item index in the file - int current_item; - - hdf5_fstreambase () : file_id (-1), current_item () { } - - ~hdf5_fstreambase () { close (); } - - hdf5_fstreambase (const char *name, int mode, int /* prot */ = 0) - : file_id (-1), current_item (-1) - { - if (mode & std::ios::in) - file_id = H5Fopen (name, H5F_ACC_RDONLY, H5P_DEFAULT); - else if (mode & std::ios::out) - { - if (mode & std::ios::app && H5Fis_hdf5 (name) > 0) - file_id = H5Fopen (name, H5F_ACC_RDWR, H5P_DEFAULT); - else - file_id = H5Fcreate (name, H5F_ACC_TRUNC, H5P_DEFAULT, - H5P_DEFAULT); - } - if (file_id < 0) - std::ios::setstate (std::ios::badbit); - - current_item = 0; - } - - void close () - { - if (file_id >= 0) - { - if (H5Fclose (file_id) < 0) - std::ios::setstate (std::ios::badbit); - file_id = -1; - } - } - - void open (const char *name, int mode, int) - { - clear (); - - if (mode & std::ios::in) - file_id = H5Fopen (name, H5F_ACC_RDONLY, H5P_DEFAULT); - else if (mode & std::ios::out) - { - if (mode & std::ios::app && H5Fis_hdf5 (name) > 0) - file_id = H5Fopen (name, H5F_ACC_RDWR, H5P_DEFAULT); - else - file_id = H5Fcreate (name, H5F_ACC_TRUNC, H5P_DEFAULT, - H5P_DEFAULT); - } - if (file_id < 0) - std::ios::setstate (std::ios::badbit); - - current_item = 0; - } -}; - -// input and output streams, subclassing istream and ostream -// so that we can pass them for stream parameters in the functions below. - -class hdf5_ifstream : public hdf5_fstreambase, public std::istream -{ -public: - - hdf5_ifstream () : hdf5_fstreambase (), std::istream (0) { } - - hdf5_ifstream (const char *name, int mode = std::ios::in|std::ios::binary, - int prot = 0) - : hdf5_fstreambase (name, mode, prot), std::istream (0) { } - - void open (const char *name, int mode = std::ios::in|std::ios::binary, - int prot = 0) - { hdf5_fstreambase::open (name, mode, prot); } -}; - -class hdf5_ofstream : public hdf5_fstreambase, public std::ostream -{ -public: - - hdf5_ofstream () : hdf5_fstreambase (), std::ostream (0) { } - - hdf5_ofstream (const char *name, int mode = std::ios::out|std::ios::binary, - int prot = 0) - : hdf5_fstreambase (name, mode, prot), std::ostream (0) { } - - void open (const char *name, int mode = std::ios::out|std::ios::binary, - int prot = 0) - { hdf5_fstreambase::open (name, mode, prot); } -}; - -// Callback data structure for passing data to hdf5_read_next_data, below. - -struct -hdf5_callback_data -{ - hdf5_callback_data (void) - : name (), global (false), tc (), doc () { } - - // the following fields are set by hdf5_read_data on successful return: - - // the name of the variable - std::string name; - - // whether it is global - bool global; - - // the value of the variable, in Octave form - octave_value tc; - - // a documentation string (NULL if none) - std::string doc; -}; - -#if HAVE_HDF5_INT2FLOAT_CONVERSIONS -extern OCTINTERP_API hid_t -save_type_to_hdf5 (save_type st) -#endif - -extern OCTINTERP_API hid_t -hdf5_make_complex_type (hid_t num_type); - -extern OCTINTERP_API bool -hdf5_types_compatible (hid_t t1, hid_t t2); - -extern OCTINTERP_API herr_t -hdf5_read_next_data (hid_t group_id, const char *name, void *dv); - -extern OCTINTERP_API bool -add_hdf5_data (hid_t loc_id, const octave_value& tc, - const std::string& name, const std::string& doc, - bool mark_as_global, bool save_as_floats); - -extern OCTINTERP_API int -save_hdf5_empty (hid_t loc_id, const char *name, const dim_vector d); - -extern OCTINTERP_API int -load_hdf5_empty (hid_t loc_id, const char *name, dim_vector &d); - -extern OCTINTERP_API std::string -read_hdf5_data (std::istream& is, const std::string& filename, bool& global, - octave_value& tc, std::string& doc); - -extern OCTINTERP_API bool -save_hdf5_data (std::ostream& os, const octave_value& tc, - const std::string& name, const std::string& doc, - bool mark_as_global, bool save_as_floats); - -extern OCTINTERP_API bool -hdf5_check_attr (hid_t loc_id, const char *attr_name); - -extern OCTINTERP_API bool -hdf5_get_scalar_attr (hid_t loc_id, hid_t type_id, const char *attr_name, - void *buf); - -extern OCTINTERP_API herr_t -hdf5_add_attr (hid_t loc_id, const char *attr_name); - - -extern OCTINTERP_API herr_t -hdf5_add_scalar_attr (hid_t loc_id, hid_t type_id, - const char *attr_name, void *buf); - -#ifdef IDX_TYPE_LONG -#define H5T_NATIVE_IDX H5T_NATIVE_LONG -#else -#define H5T_NATIVE_IDX H5T_NATIVE_INT -#endif - -#endif - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/ls-mat-ascii.cc --- a/src/ls-mat-ascii.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,378 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "byte-swap.h" -#include "data-conv.h" -#include "file-ops.h" -#include "glob-match.h" -#include "lo-mappers.h" -#include "mach-info.h" -#include "oct-env.h" -#include "oct-time.h" -#include "quit.h" -#include "str-vec.h" - -#include "Cell.h" -#include "defun.h" -#include "error.h" -#include "gripes.h" -#include "lex.h" -#include "load-save.h" -#include "ls-ascii-helper.h" -#include "ls-mat-ascii.h" -#include "oct-obj.h" -#include "oct-map.h" -#include "ov-cell.h" -#include "pager.h" -#include "pt-exp.h" -#include "sysdep.h" -#include "unwind-prot.h" -#include "utils.h" -#include "variables.h" -#include "version.h" -#include "dMatrix.h" - -static std::string -get_mat_data_input_line (std::istream& is) -{ - std::string retval; - - bool have_data = false; - - do - { - retval = ""; - - char c; - while (is.get (c)) - { - if (c == '\n' || c == '\r') - { - is.putback (c); - skip_preceeding_newline (is); - break; - } - - if (c == '%' || c == '#') - { - skip_until_newline (is, false); - break; - } - - if (! is.eof ()) - { - if (! have_data && c != ' ' && c != '\t') - have_data = true; - - retval += c; - } - } - } - while (! (have_data || is.eof ())); - - return retval; -} - -static void -get_lines_and_columns (std::istream& is, const std::string& filename, octave_idx_type& nr, octave_idx_type& nc) -{ - std::streampos pos = is.tellg (); - - int file_line_number = 0; - - nr = 0; - nc = 0; - - while (is && ! error_state) - { - octave_quit (); - - std::string buf = get_mat_data_input_line (is); - - file_line_number++; - - size_t beg = buf.find_first_not_of (", \t"); - - // If we see a CR as the last character in the buffer, we had a - // CRLF pair as the line separator. Any other CR in the text - // will not be considered as whitespace. - - if (beg != std::string::npos && buf[beg] == '\r' && beg == buf.length () - 1) - { - // We had a blank line ending with a CRLF. Handle it the - // same as an empty line. - beg = std::string::npos; - } - - octave_idx_type tmp_nc = 0; - - while (beg != std::string::npos) - { - tmp_nc++; - - size_t end = buf.find_first_of (", \t", beg); - - if (end != std::string::npos) - { - beg = buf.find_first_not_of (", \t", end); - - if (beg == std::string::npos || (buf[beg] == '\r' && - beg == buf.length () - 1)) - { - // We had a line with trailing spaces and - // ending with a CRLF, so this should look like EOL, - // not a new colum. - break; - } - } - else - break; - } - - if (tmp_nc > 0) - { - if (nc == 0) - { - nc = tmp_nc; - nr++; - } - else if (nc == tmp_nc) - nr++; - else - error ("load: %s: inconsistent number of columns near line %d", - filename.c_str (), file_line_number); - } - } - - if (nr == 0 || nc == 0) - error ("load: file `%s' seems to be empty!", filename.c_str ()); - - is.clear (); - is.seekg (pos); -} - -// Extract a matrix from a file of numbers only. -// -// Comments are not allowed. The file should only have numeric values. -// -// Reads the file twice. Once to find the number of rows and columns, -// and once to extract the matrix. -// -// FILENAME is used for error messages. -// -// This format provides no way to tag the data as global. - -std::string -read_mat_ascii_data (std::istream& is, const std::string& filename, - octave_value& tc) -{ - std::string retval; - - std::string varname; - - size_t pos = filename.rfind ('/'); - - if (pos != std::string::npos) - varname = filename.substr (pos+1); - else - varname = filename; - - pos = varname.rfind ('.'); - - if (pos != std::string::npos) - varname = varname.substr (0, pos); - - size_t len = varname.length (); - for (size_t i = 0; i < len; i++) - { - char c = varname[i]; - if (! (isalnum (c) || c == '_')) - varname[i] = '_'; - } - - if (is_keyword (varname) || ! isalpha (varname[0])) - varname.insert (0, "X"); - - if (valid_identifier (varname)) - { - octave_idx_type nr = 0; - octave_idx_type nc = 0; - - int total_count = 0; - - get_lines_and_columns (is, filename, nr, nc); - - octave_quit (); - - if (! error_state && nr > 0 && nc > 0) - { - Matrix tmp (nr, nc); - - if (nr < 1 || nc < 1) - is.clear (std::ios::badbit); - else - { - double d; - for (octave_idx_type i = 0; i < nr; i++) - { - std::string buf = get_mat_data_input_line (is); - - std::istringstream tmp_stream (buf); - - for (octave_idx_type j = 0; j < nc; j++) - { - octave_quit (); - - d = octave_read_value (tmp_stream); - - if (tmp_stream || tmp_stream.eof ()) - { - tmp.elem (i, j) = d; - total_count++; - - // Skip whitespace and commas. - char c; - while (1) - { - tmp_stream >> c; - - if (! tmp_stream) - break; - - if (! (c == ' ' || c == '\t' || c == ',')) - { - tmp_stream.putback (c); - break; - } - } - - if (tmp_stream.eof ()) - break; - } - else - { - error ("load: failed to read matrix from file `%s'", - filename.c_str ()); - - return retval; - } - - } - } - } - - if (is || is.eof ()) - { - // FIXME -- not sure this is best, but it works. - - if (is.eof ()) - is.clear (); - - octave_idx_type expected = nr * nc; - - if (expected == total_count) - { - tc = tmp; - retval = varname; - } - else - error ("load: expected %d elements, found %d", - expected, total_count); - } - else - error ("load: failed to read matrix from file `%s'", - filename.c_str ()); - } - else - error ("load: unable to extract matrix size from file `%s'", - filename.c_str ()); - } - else - error ("load: unable to convert filename `%s' to valid identifier", - filename.c_str ()); - - return retval; -} - -bool -save_mat_ascii_data (std::ostream& os, const octave_value& val, - int precision, bool tabs) -{ - bool success = true; - - if (val.is_complex_type ()) - warning ("save: omitting imaginary part for ASCII file"); - - Matrix m = val.matrix_value (true); - - if (error_state) - { - success = false; - - error_state = 0; - } - else - { - long old_precision = os.precision (); - - os.precision (precision); - - std::ios::fmtflags oflags - = os.flags (static_cast (std::ios::scientific)); - - if (tabs) - { - for (octave_idx_type i = 0; i < m.rows (); i++) - { - for (octave_idx_type j = 0; j < m.cols (); j++) - { - // Omit leading tabs. - if (j != 0) os << '\t'; - octave_write_double (os, m (i, j)); - } - os << "\n"; - } - } - else - os << m; - - os.flags (oflags); - - os.precision (old_precision); - } - - return (os && success); -} diff -r a132d206a36a -r b9b6a310ad97 src/ls-mat-ascii.h --- a/src/ls-mat-ascii.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/* - -Copyright (C) 2003-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_ls_mat_ascii_h) -#define octave_ls_mat_ascii_h 1 - -extern std::string -read_mat_ascii_data (std::istream& is, const std::string& filename, - octave_value& tc); - -extern bool -save_mat_ascii_data (std::ostream& os, const octave_value& val_arg, - int precision, bool tabs = false); - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/ls-mat4.cc --- a/src/ls-mat4.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,609 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "byte-swap.h" -#include "data-conv.h" -#include "file-ops.h" -#include "glob-match.h" -#include "lo-mappers.h" -#include "mach-info.h" -#include "oct-env.h" -#include "oct-time.h" -#include "quit.h" -#include "str-vec.h" -#include "oct-locbuf.h" - -#include "Cell.h" -#include "defun.h" -#include "error.h" -#include "gripes.h" -#include "load-save.h" -#include "oct-obj.h" -#include "oct-map.h" -#include "ov-cell.h" -#include "pager.h" -#include "pt-exp.h" -#include "sysdep.h" -#include "unwind-prot.h" -#include "utils.h" -#include "variables.h" -#include "version.h" -#include "dMatrix.h" -#include "dSparse.h" - -#include "ls-mat4.h" - -// Read LEN elements of data from IS in the format specified by -// PRECISION, placing the result in DATA. If SWAP is TRUE, swap -// the bytes of each element before copying to DATA. FLT_FMT -// specifies the format of the data if we are reading floating point -// numbers. - -static void -read_mat_binary_data (std::istream& is, double *data, int precision, - int len, bool swap, - oct_mach_info::float_format flt_fmt) -{ - switch (precision) - { - case 0: - read_doubles (is, data, LS_DOUBLE, len, swap, flt_fmt); - break; - - case 1: - read_doubles (is, data, LS_FLOAT, len, swap, flt_fmt); - break; - - case 2: - read_doubles (is, data, LS_INT, len, swap, flt_fmt); - break; - - case 3: - read_doubles (is, data, LS_SHORT, len, swap, flt_fmt); - break; - - case 4: - read_doubles (is, data, LS_U_SHORT, len, swap, flt_fmt); - break; - - case 5: - read_doubles (is, data, LS_U_CHAR, len, swap, flt_fmt); - break; - - default: - break; - } -} - -int -read_mat_file_header (std::istream& is, bool& swap, int32_t& mopt, - int32_t& nr, int32_t& nc, - int32_t& imag, int32_t& len, - int quiet) -{ - swap = false; - - // We expect to fail here, at the beginning of a record, so not - // being able to read another mopt value should not result in an - // error. - - is.read (reinterpret_cast (&mopt), 4); - if (! is) - return 1; - - if (! is.read (reinterpret_cast (&nr), 4)) - goto data_read_error; - - if (! is.read (reinterpret_cast (&nc), 4)) - goto data_read_error; - - if (! is.read (reinterpret_cast (&imag), 4)) - goto data_read_error; - - if (! is.read (reinterpret_cast (&len), 4)) - goto data_read_error; - -// If mopt is nonzero and the byte order is swapped, mopt will be -// bigger than we expect, so we swap bytes. -// -// If mopt is zero, it means the file was written on a little endian -// machine, and we only need to swap if we are running on a big endian -// machine. -// -// Gag me. - - if (oct_mach_info::words_big_endian () && mopt == 0) - swap = true; - - // mopt is signed, therefore byte swap may result in negative value. - - if (mopt > 9999 || mopt < 0) - swap = true; - - if (swap) - { - swap_bytes<4> (&mopt); - swap_bytes<4> (&nr); - swap_bytes<4> (&nc); - swap_bytes<4> (&imag); - swap_bytes<4> (&len); - } - - if (mopt > 9999 || mopt < 0 || imag > 1 || imag < 0) - { - if (! quiet) - error ("load: can't read binary file"); - return -1; - } - - return 0; - - data_read_error: - return -1; -} - -// We don't just use a cast here, because we need to be able to detect -// possible errors. - -oct_mach_info::float_format -mopt_digit_to_float_format (int mach) -{ - oct_mach_info::float_format flt_fmt = oct_mach_info::flt_fmt_unknown; - - switch (mach) - { - case 0: - flt_fmt = oct_mach_info::flt_fmt_ieee_little_endian; - break; - - case 1: - flt_fmt = oct_mach_info::flt_fmt_ieee_big_endian; - break; - - case 2: - flt_fmt = oct_mach_info::flt_fmt_vax_d; - break; - - case 3: - flt_fmt = oct_mach_info::flt_fmt_vax_g; - break; - - case 4: - flt_fmt = oct_mach_info::flt_fmt_cray; - break; - - default: - flt_fmt = oct_mach_info::flt_fmt_unknown; - break; - } - - return flt_fmt; -} - -int -float_format_to_mopt_digit (oct_mach_info::float_format flt_fmt) -{ - int retval = -1; - - switch (flt_fmt) - { - case oct_mach_info::flt_fmt_ieee_little_endian: - retval = 0; - break; - - case oct_mach_info::flt_fmt_ieee_big_endian: - retval = 1; - break; - - case oct_mach_info::flt_fmt_vax_d: - retval = 2; - break; - - case oct_mach_info::flt_fmt_vax_g: - retval = 3; - break; - - case oct_mach_info::flt_fmt_cray: - retval = 4; - break; - - default: - break; - } - - return retval; -} - -// Extract one value (scalar, matrix, string, etc.) from stream IS and -// place it in TC, returning the name of the variable. -// -// The data is expected to be in Matlab version 4 .mat format, though -// not all the features of that format are supported. -// -// FILENAME is used for error messages. -// -// This format provides no way to tag the data as global. - -std::string -read_mat_binary_data (std::istream& is, const std::string& filename, - octave_value& tc) -{ - std::string retval; - - // These are initialized here instead of closer to where they are - // first used to avoid errors from gcc about goto crossing - // initialization of variable. - - Matrix re; - oct_mach_info::float_format flt_fmt = oct_mach_info::flt_fmt_unknown; - bool swap = false; - int type = 0; - int prec = 0; - int order = 0; - int mach = 0; - int dlen = 0; - - int32_t mopt, nr, nc, imag, len; - - int err = read_mat_file_header (is, swap, mopt, nr, nc, imag, len); - if (err) - { - if (err < 0) - goto data_read_error; - else - return retval; - } - - type = mopt % 10; // Full, sparse, etc. - mopt /= 10; // Eliminate first digit. - prec = mopt % 10; // double, float, int, etc. - mopt /= 10; // Eliminate second digit. - order = mopt % 10; // Row or column major ordering. - mopt /= 10; // Eliminate third digit. - mach = mopt % 10; // IEEE, VAX, etc. - - flt_fmt = mopt_digit_to_float_format (mach); - - if (flt_fmt == oct_mach_info::flt_fmt_unknown) - { - error ("load: unrecognized binary format!"); - return retval; - } - - if (imag && type == 1) - { - error ("load: encountered complex matrix with string flag set!"); - return retval; - } - - // LEN includes the terminating character, and the file is also - // supposed to include it, but apparently not all files do. Either - // way, I think this should work. - - { - OCTAVE_LOCAL_BUFFER (char, name, len+1); - name[len] = '\0'; - if (! is.read (name, len)) - goto data_read_error; - retval = name; - - dlen = nr * nc; - if (dlen < 0) - goto data_read_error; - - if (order) - { - octave_idx_type tmp = nr; - nr = nc; - nc = tmp; - } - - if (type == 2) - { - if (nc == 4) - { - octave_idx_type nr_new, nc_new; - Array data (dim_vector (1, nr - 1)); - Array c (dim_vector (1, nr - 1)); - Array r (dim_vector (1, nr - 1)); - OCTAVE_LOCAL_BUFFER (double, dtmp, nr); - OCTAVE_LOCAL_BUFFER (double, ctmp, nr); - - read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt); - for (octave_idx_type i = 0; i < nr - 1; i++) - r.xelem (i) = dtmp[i] - 1; - nr_new = dtmp[nr - 1]; - read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt); - for (octave_idx_type i = 0; i < nr - 1; i++) - c.xelem (i) = dtmp[i] - 1; - nc_new = dtmp[nr - 1]; - read_mat_binary_data (is, dtmp, prec, nr - 1, swap, flt_fmt); - read_mat_binary_data (is, ctmp, prec, 1, swap, flt_fmt); - read_mat_binary_data (is, ctmp, prec, nr - 1, swap, flt_fmt); - - for (octave_idx_type i = 0; i < nr - 1; i++) - data.xelem (i) = Complex (dtmp[i], ctmp[i]); - read_mat_binary_data (is, ctmp, prec, 1, swap, flt_fmt); - - SparseComplexMatrix smc = SparseComplexMatrix (data, r, c, - nr_new, nc_new); - - tc = order ? smc.transpose () : smc; - } - else - { - octave_idx_type nr_new, nc_new; - Array data (dim_vector (1, nr - 1)); - Array c (dim_vector (1, nr - 1)); - Array r (dim_vector (1, nr - 1)); - OCTAVE_LOCAL_BUFFER (double, dtmp, nr); - - read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt); - for (octave_idx_type i = 0; i < nr - 1; i++) - r.xelem (i) = dtmp[i] - 1; - nr_new = dtmp[nr - 1]; - read_mat_binary_data (is, dtmp, prec, nr, swap, flt_fmt); - for (octave_idx_type i = 0; i < nr - 1; i++) - c.xelem (i) = dtmp[i] - 1; - nc_new = dtmp[nr - 1]; - read_mat_binary_data (is, data.fortran_vec (), prec, nr - 1, swap, flt_fmt); - read_mat_binary_data (is, dtmp, prec, 1, swap, flt_fmt); - - SparseMatrix sm = SparseMatrix (data, r, c, nr_new, nc_new); - - tc = order ? sm.transpose () : sm; - } - } - else - { - re.resize (nr, nc); - - read_mat_binary_data (is, re.fortran_vec (), prec, dlen, swap, flt_fmt); - - if (! is || error_state) - { - error ("load: reading matrix data for `%s'", name); - goto data_read_error; - } - - if (imag) - { - Matrix im (nr, nc); - - read_mat_binary_data (is, im.fortran_vec (), prec, dlen, swap, - flt_fmt); - - if (! is || error_state) - { - error ("load: reading imaginary matrix data for `%s'", name); - goto data_read_error; - } - - ComplexMatrix ctmp (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - ctmp (i, j) = Complex (re (i, j), im (i, j)); - - tc = order ? ctmp.transpose () : ctmp; - } - else - tc = order ? re.transpose () : re; - - if (type == 1) - tc = tc.convert_to_str (false, true, '\''); - } - - return retval; - } - - data_read_error: - error ("load: trouble reading binary file `%s'", filename.c_str ()); - return retval; -} - -// Save the data from TC along with the corresponding NAME on stream OS -// in the MatLab version 4 binary format. - -bool -save_mat_binary_data (std::ostream& os, const octave_value& tc, - const std::string& name) -{ - int32_t mopt = 0; - - mopt += tc.is_sparse_type () ? 2 : tc.is_string () ? 1 : 0; - - oct_mach_info::float_format flt_fmt = - oct_mach_info::native_float_format ();; - - mopt += 1000 * float_format_to_mopt_digit (flt_fmt); - - os.write (reinterpret_cast (&mopt), 4); - - octave_idx_type len; - int32_t nr = tc.rows (); - - int32_t nc = tc.columns (); - - if (tc.is_sparse_type ()) - { - len = tc.nnz (); - uint32_t nnz = len + 1; - os.write (reinterpret_cast (&nnz), 4); - - uint32_t iscmplx = tc.is_complex_type () ? 4 : 3; - os.write (reinterpret_cast (&iscmplx), 4); - - uint32_t tmp = 0; - os.write (reinterpret_cast (&tmp), 4); - } - else - { - os.write (reinterpret_cast (&nr), 4); - os.write (reinterpret_cast (&nc), 4); - - int32_t imag = tc.is_complex_type () ? 1 : 0; - os.write (reinterpret_cast (&imag), 4); - - len = nr * nc; - } - - - // LEN includes the terminating character, and the file is also - // supposed to include it. - - int32_t name_len = name.length () + 1; - - os.write (reinterpret_cast (&name_len), 4); - os << name << '\0'; - - if (tc.is_string ()) - { - unwind_protect frame; - - charMatrix chm = tc.char_matrix_value (); - - octave_idx_type nrow = chm.rows (); - octave_idx_type ncol = chm.cols (); - - OCTAVE_LOCAL_BUFFER (double, buf, ncol*nrow); - - for (octave_idx_type i = 0; i < nrow; i++) - { - std::string tstr = chm.row_as_string (i); - const char *s = tstr.data (); - - for (octave_idx_type j = 0; j < ncol; j++) - buf[j*nrow+i] = static_cast (*s++ & 0x00FF); - } - os.write (reinterpret_cast (buf), nrow*ncol*sizeof (double)); - } - else if (tc.is_range ()) - { - Range r = tc.range_value (); - double base = r.base (); - double inc = r.inc (); - octave_idx_type nel = r.nelem (); - for (octave_idx_type i = 0; i < nel; i++) - { - double x = base + i * inc; - os.write (reinterpret_cast (&x), 8); - } - } - else if (tc.is_real_scalar ()) - { - double tmp = tc.double_value (); - os.write (reinterpret_cast (&tmp), 8); - } - else if (tc.is_sparse_type ()) - { - double ds; - OCTAVE_LOCAL_BUFFER (double, dtmp, len); - if (tc.is_complex_matrix ()) - { - SparseComplexMatrix m = tc.sparse_complex_matrix_value (); - - for (octave_idx_type i = 0; i < len; i++) - dtmp[i] = m.ridx (i) + 1; - os.write (reinterpret_cast (dtmp), 8 * len); - ds = nr; - os.write (reinterpret_cast (&ds), 8); - - octave_idx_type ii = 0; - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) - dtmp[ii++] = j + 1; - os.write (reinterpret_cast (dtmp), 8 * len); - ds = nc; - os.write (reinterpret_cast (&ds), 8); - - for (octave_idx_type i = 0; i < len; i++) - dtmp[i] = std::real (m.data (i)); - os.write (reinterpret_cast (dtmp), 8 * len); - ds = 0.; - os.write (reinterpret_cast (&ds), 8); - - for (octave_idx_type i = 0; i < len; i++) - dtmp[i] = std::imag (m.data (i)); - os.write (reinterpret_cast (dtmp), 8 * len); - os.write (reinterpret_cast (&ds), 8); - } - else - { - SparseMatrix m = tc.sparse_matrix_value (); - - for (octave_idx_type i = 0; i < len; i++) - dtmp[i] = m.ridx (i) + 1; - os.write (reinterpret_cast (dtmp), 8 * len); - ds = nr; - os.write (reinterpret_cast (&ds), 8); - - octave_idx_type ii = 0; - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = m.cidx (j); i < m.cidx (j+1); i++) - dtmp[ii++] = j + 1; - os.write (reinterpret_cast (dtmp), 8 * len); - ds = nc; - os.write (reinterpret_cast (&ds), 8); - - os.write (reinterpret_cast (m.data ()), 8 * len); - ds = 0.; - os.write (reinterpret_cast (&ds), 8); - } - } - else if (tc.is_real_matrix ()) - { - Matrix m = tc.matrix_value (); - os.write (reinterpret_cast (m.data ()), 8 * len); - } - else if (tc.is_complex_scalar ()) - { - Complex tmp = tc.complex_value (); - os.write (reinterpret_cast (&tmp), 16); - } - else if (tc.is_complex_matrix ()) - { - ComplexMatrix m_cmplx = tc.complex_matrix_value (); - Matrix m = ::real (m_cmplx); - os.write (reinterpret_cast (m.data ()), 8 * len); - m = ::imag (m_cmplx); - os.write (reinterpret_cast (m.data ()), 8 * len); - } - else - gripe_wrong_type_arg ("save", tc, false); - - return os; -} diff -r a132d206a36a -r b9b6a310ad97 src/ls-mat4.h --- a/src/ls-mat4.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - -Copyright (C) 2003-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_ls_mat4_h) -#define octave_ls_mat4_h 1 - -extern oct_mach_info::float_format -mopt_digit_to_float_format (int mach); - -extern int -float_format_to_mopt_digit (oct_mach_info::float_format flt_fmt); - -extern int -read_mat_file_header (std::istream& is, bool& swap, int32_t& mopt, - int32_t& nr, int32_t& nc, int32_t& imag, - int32_t& len, int quiet = 0); - -extern std::string -read_mat_binary_data (std::istream& is, const std::string& filename, - octave_value& tc); - -extern bool -save_mat_binary_data (std::ostream& os, const octave_value& tc, - const std::string& name) ; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/ls-mat5.cc --- a/src/ls-mat5.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2719 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -// Author: James R. Van Zandt - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "byte-swap.h" -#include "data-conv.h" -#include "file-ops.h" -#include "glob-match.h" -#include "lo-mappers.h" -#include "mach-info.h" -#include "oct-env.h" -#include "oct-time.h" -#include "quit.h" -#include "str-vec.h" -#include "file-stat.h" -#include "oct-locbuf.h" - -#include "Cell.h" -#include "defun.h" -#include "error.h" -#include "gripes.h" -#include "load-save.h" -#include "load-path.h" -#include "oct-obj.h" -#include "oct-map.h" -#include "ov-cell.h" -#include "ov-class.h" -#include "ov-fcn-inline.h" -#include "pager.h" -#include "pt-exp.h" -#include "sysdep.h" -#include "toplev.h" -#include "unwind-prot.h" -#include "utils.h" -#include "variables.h" -#include "version.h" -#include "dMatrix.h" - -#include "ls-utils.h" -#include "ls-mat5.h" - -#include "parse.h" -#include "defaults.h" - -#ifdef HAVE_ZLIB -#include -#endif - -#define PAD(l) (((l) > 0 && (l) <= 4) ? 4 : (((l)+7)/8)*8) - - -// The subsystem data block -static octave_value subsys_ov; - -// FIXME -- the following enum values should be the same as the -// mxClassID values in mexproto.h, but it seems they have also changed -// over time. What is the correct way to handle this and maintain -// backward compatibility with old MAT files? For now, use -// "MAT_FILE_" instead of "mx" as the prefix for these names to avoid -// conflict with the mxClassID enum in mexproto.h. - -enum arrayclasstype - { - MAT_FILE_CELL_CLASS=1, // cell array - MAT_FILE_STRUCT_CLASS, // structure - MAT_FILE_OBJECT_CLASS, // object - MAT_FILE_CHAR_CLASS, // character array - MAT_FILE_SPARSE_CLASS, // sparse array - MAT_FILE_DOUBLE_CLASS, // double precision array - MAT_FILE_SINGLE_CLASS, // single precision floating point - MAT_FILE_INT8_CLASS, // 8 bit signed integer - MAT_FILE_UINT8_CLASS, // 8 bit unsigned integer - MAT_FILE_INT16_CLASS, // 16 bit signed integer - MAT_FILE_UINT16_CLASS, // 16 bit unsigned integer - MAT_FILE_INT32_CLASS, // 32 bit signed integer - MAT_FILE_UINT32_CLASS, // 32 bit unsigned integer - MAT_FILE_INT64_CLASS, // 64 bit signed integer - MAT_FILE_UINT64_CLASS, // 64 bit unsigned integer - MAT_FILE_FUNCTION_CLASS, // Function handle - MAT_FILE_WORKSPACE_CLASS // Workspace (undocumented) - }; - -// Read COUNT elements of data from IS in the format specified by TYPE, -// placing the result in DATA. If SWAP is TRUE, swap the bytes of -// each element before copying to DATA. FLT_FMT specifies the format -// of the data if we are reading floating point numbers. - -static void -read_mat5_binary_data (std::istream& is, double *data, - octave_idx_type count, bool swap, mat5_data_type type, - oct_mach_info::float_format flt_fmt) -{ - - switch (type) - { - case miINT8: - read_doubles (is, data, LS_CHAR, count, swap, flt_fmt); - break; - - case miUTF8: - case miUINT8: - read_doubles (is, data, LS_U_CHAR, count, swap, flt_fmt); - break; - - case miINT16: - read_doubles (is, data, LS_SHORT, count, swap, flt_fmt); - break; - - case miUTF16: - case miUINT16: - read_doubles (is, data, LS_U_SHORT, count, swap, flt_fmt); - break; - - case miINT32: - read_doubles (is, data, LS_INT, count, swap, flt_fmt); - break; - - case miUTF32: - case miUINT32: - read_doubles (is, data, LS_U_INT, count, swap, flt_fmt); - break; - - case miSINGLE: - read_doubles (is, data, LS_FLOAT, count, swap, flt_fmt); - break; - - case miRESERVE1: - break; - - case miDOUBLE: - read_doubles (is, data, LS_DOUBLE, count, swap, flt_fmt); - break; - - case miRESERVE2: - case miRESERVE3: - break; - - // FIXME -- how are the 64-bit cases supposed to work here? - case miINT64: - read_doubles (is, data, LS_LONG, count, swap, flt_fmt); - break; - - case miUINT64: - read_doubles (is, data, LS_U_LONG, count, swap, flt_fmt); - break; - - case miMATRIX: - default: - break; - } -} - -static void -read_mat5_binary_data (std::istream& is, float *data, - octave_idx_type count, bool swap, mat5_data_type type, - oct_mach_info::float_format flt_fmt) -{ - - switch (type) - { - case miINT8: - read_floats (is, data, LS_CHAR, count, swap, flt_fmt); - break; - - case miUTF8: - case miUINT8: - read_floats (is, data, LS_U_CHAR, count, swap, flt_fmt); - break; - - case miINT16: - read_floats (is, data, LS_SHORT, count, swap, flt_fmt); - break; - - case miUTF16: - case miUINT16: - read_floats (is, data, LS_U_SHORT, count, swap, flt_fmt); - break; - - case miINT32: - read_floats (is, data, LS_INT, count, swap, flt_fmt); - break; - - case miUTF32: - case miUINT32: - read_floats (is, data, LS_U_INT, count, swap, flt_fmt); - break; - - case miSINGLE: - read_floats (is, data, LS_FLOAT, count, swap, flt_fmt); - break; - - case miRESERVE1: - break; - - case miDOUBLE: - read_floats (is, data, LS_DOUBLE, count, swap, flt_fmt); - break; - - case miRESERVE2: - case miRESERVE3: - break; - - // FIXME -- how are the 64-bit cases supposed to work here? - case miINT64: - read_floats (is, data, LS_LONG, count, swap, flt_fmt); - break; - - case miUINT64: - read_floats (is, data, LS_U_LONG, count, swap, flt_fmt); - break; - - case miMATRIX: - default: - break; - } -} - -template -void -read_mat5_integer_data (std::istream& is, T *m, octave_idx_type count, - bool swap, mat5_data_type type) -{ - -#define READ_INTEGER_DATA(TYPE, swap, data, size, len, stream) \ - do \ - { \ - if (len > 0) \ - { \ - OCTAVE_LOCAL_BUFFER (TYPE, ptr, len); \ - stream.read (reinterpret_cast (ptr), size * len); \ - if (swap) \ - swap_bytes< size > (ptr, len); \ - for (octave_idx_type i = 0; i < len; i++) \ - data[i] = ptr[i]; \ - } \ - } \ - while (0) - - switch (type) - { - case miINT8: - READ_INTEGER_DATA (int8_t, swap, m, 1, count, is); - break; - - case miUINT8: - READ_INTEGER_DATA (uint8_t, swap, m, 1, count, is); - break; - - case miINT16: - READ_INTEGER_DATA (int16_t, swap, m, 2, count, is); - break; - - case miUINT16: - READ_INTEGER_DATA (uint16_t, swap, m, 2, count, is); - break; - - case miINT32: - READ_INTEGER_DATA (int32_t, swap, m, 4, count, is); - break; - - case miUINT32: - READ_INTEGER_DATA (uint32_t, swap, m, 4, count, is); - break; - - case miSINGLE: - case miRESERVE1: - case miDOUBLE: - case miRESERVE2: - case miRESERVE3: - break; - - case miINT64: - READ_INTEGER_DATA (int64_t, swap, m, 8, count, is); - break; - - case miUINT64: - READ_INTEGER_DATA (uint64_t, swap, m, 8, count, is); - break; - - case miMATRIX: - default: - break; - } - -#undef READ_INTEGER_DATA - -} - -template void -read_mat5_integer_data (std::istream& is, octave_int8 *m, - octave_idx_type count, bool swap, - mat5_data_type type); - -template void -read_mat5_integer_data (std::istream& is, octave_int16 *m, - octave_idx_type count, bool swap, - mat5_data_type type); - -template void -read_mat5_integer_data (std::istream& is, octave_int32 *m, - octave_idx_type count, bool swap, - mat5_data_type type); - -template void -read_mat5_integer_data (std::istream& is, octave_int64 *m, - octave_idx_type count, bool swap, - mat5_data_type type); - -template void -read_mat5_integer_data (std::istream& is, octave_uint8 *m, - octave_idx_type count, bool swap, - mat5_data_type type); - -template void -read_mat5_integer_data (std::istream& is, octave_uint16 *m, - octave_idx_type count, bool swap, - mat5_data_type type); - -template void -read_mat5_integer_data (std::istream& is, octave_uint32 *m, - octave_idx_type count, bool swap, - mat5_data_type type); - -template void -read_mat5_integer_data (std::istream& is, octave_uint64 *m, - octave_idx_type count, bool swap, - mat5_data_type type); - -template void -read_mat5_integer_data (std::istream& is, int *m, - octave_idx_type count, bool swap, - mat5_data_type type); - -#define OCTAVE_MAT5_INTEGER_READ(TYP) \ - { \ - TYP re (dims); \ - \ - std::streampos tmp_pos; \ - \ - if (read_mat5_tag (is, swap, type, len)) \ - { \ - error ("load: reading matrix data for `%s'", retval.c_str ()); \ - goto data_read_error; \ - } \ - \ - octave_idx_type n = re.numel (); \ - tmp_pos = is.tellg (); \ - read_mat5_integer_data (is, re.fortran_vec (), n, swap, \ - static_cast (type)); \ - \ - if (! is || error_state) \ - { \ - error ("load: reading matrix data for `%s'", retval.c_str ()); \ - goto data_read_error; \ - } \ - \ - is.seekg (tmp_pos + static_cast (PAD (len))); \ - \ - if (imag) \ - { \ - /* We don't handle imag integer types, convert to an array */ \ - NDArray im (dims); \ - \ - if (read_mat5_tag (is, swap, type, len)) \ - { \ - error ("load: reading matrix data for `%s'", \ - retval.c_str ()); \ - goto data_read_error; \ - } \ - \ - n = im.numel (); \ - read_mat5_binary_data (is, im.fortran_vec (), n, swap, \ - static_cast (type), flt_fmt); \ - \ - if (! is || error_state) \ - { \ - error ("load: reading imaginary matrix data for `%s'", \ - retval.c_str ()); \ - goto data_read_error; \ - } \ - \ - ComplexNDArray ctmp (dims); \ - \ - for (octave_idx_type i = 0; i < n; i++) \ - ctmp(i) = Complex (re(i).double_value (), im(i)); \ - \ - tc = ctmp; \ - } \ - else \ - tc = re; \ - } - -// Read one element tag from stream IS, -// place the type code in TYPE and the byte count in BYTES -// return nonzero on error -static int -read_mat5_tag (std::istream& is, bool swap, int32_t& type, int32_t& bytes) -{ - unsigned int upper; - int32_t temp; - - if (! is.read (reinterpret_cast (&temp), 4 )) - goto data_read_error; - - if (swap) - swap_bytes<4> (&temp); - - upper = (temp >> 16) & 0xffff; - type = temp & 0xffff; - - if (upper) - { - // "compressed" format - bytes = upper; - } - else - { - if (! is.read (reinterpret_cast (&temp), 4 )) - goto data_read_error; - if (swap) - swap_bytes<4> (&temp); - bytes = temp; - } - - return 0; - - data_read_error: - return 1; -} - -static void -read_int (std::istream& is, bool swap, int32_t& val) -{ - is.read (reinterpret_cast (&val), 4); - - if (swap) - swap_bytes<4> (&val); -} - -// Extract one data element (scalar, matrix, string, etc.) from stream -// IS and place it in TC, returning the name of the variable. -// -// The data is expected to be in Matlab's "Version 5" .mat format, -// though not all the features of that format are supported. -// -// FILENAME is used for error messages. - -std::string -read_mat5_binary_element (std::istream& is, const std::string& filename, - bool swap, bool& global, octave_value& tc) -{ - std::string retval; - - global = false; - - // NOTE: these are initialized here instead of closer to where they - // are first used to avoid errors from gcc about goto crossing - // initialization of variable. - - bool imag; - bool isclass = false; - bool logicalvar; - dim_vector dims; - enum arrayclasstype arrayclass; - int16_t number = *(reinterpret_cast("\x00\x01")); - octave_idx_type nzmax; - std::string classname; - - // MAT files always use IEEE floating point - oct_mach_info::float_format flt_fmt = oct_mach_info::flt_fmt_unknown; - if ((number == 1) ^ swap) - flt_fmt = oct_mach_info::flt_fmt_ieee_big_endian; - else - flt_fmt = oct_mach_info::flt_fmt_ieee_little_endian; - - // element type and length - int32_t type = 0; - int32_t element_length; - if (read_mat5_tag (is, swap, type, element_length)) - return retval; // EOF - -#ifdef HAVE_ZLIB - if (type == miCOMPRESSED) - { - // If C++ allowed us direct access to the file descriptor of an - // ifstream in a uniform way, the code below could be vastly - // simplified, and additional copies of the data in memory - // wouldn't be needed. - - OCTAVE_LOCAL_BUFFER (char, inbuf, element_length); - is.read (inbuf, element_length); - - // We uncompress the first 8 bytes of the header to get the buffer length - // This will fail with an error Z_MEM_ERROR - uLongf destLen = 8; - OCTAVE_LOCAL_BUFFER (unsigned int, tmp, 2); - if (uncompress (reinterpret_cast (tmp), &destLen, - reinterpret_cast (inbuf), element_length) - != Z_MEM_ERROR) - { - // Why should I have to initialize outbuf as I'll just overwrite!! - if (swap) - swap_bytes<4> (tmp, 2); - - destLen = tmp[1] + 8; - std::string outbuf (destLen, ' '); - - // FIXME -- find a way to avoid casting away const here! - - int err = uncompress (reinterpret_cast (const_cast (outbuf.c_str ())), - &destLen, reinterpret_cast (inbuf), - element_length); - - if (err != Z_OK) - { - std::string msg; - switch (err) - { - case Z_STREAM_END: - msg = "stream end"; - break; - - case Z_NEED_DICT: - msg = "need dict"; - break; - - case Z_ERRNO: - msg = "errno case"; - break; - - case Z_STREAM_ERROR: - msg = "stream error"; - break; - - case Z_DATA_ERROR: - msg = "data error"; - break; - - case Z_MEM_ERROR: - msg = "mem error"; - break; - - case Z_BUF_ERROR: - msg = "buf error"; - break; - - case Z_VERSION_ERROR: - msg = "version error"; - break; - } - - error ("load: error uncompressing data element (%s from zlib)", - msg.c_str ()); - } - else - { - std::istringstream gz_is (outbuf); - retval = read_mat5_binary_element (gz_is, filename, - swap, global, tc); - } - } - else - error ("load: error probing size of compressed data element"); - - return retval; - } -#endif - - std::streampos pos; - - if (type != miMATRIX) - { - pos = is.tellg (); - error ("load: invalid element type = %d", type); - goto early_read_error; - } - - if (element_length == 0) - { - tc = Matrix (); - return retval; - } - - pos = is.tellg (); - - // array flags subelement - int32_t len; - if (read_mat5_tag (is, swap, type, len) || type != miUINT32 || len != 8) - { - error ("load: invalid array flags subelement"); - goto early_read_error; - } - - int32_t flags; - read_int (is, swap, flags); - - imag = (flags & 0x0800) != 0; // has an imaginary part? - - global = (flags & 0x0400) != 0; // global variable? - - logicalvar = (flags & 0x0200) != 0; // boolean ? - - arrayclass = static_cast (flags & 0xff); - - int32_t tmp_nzmax; - read_int (is, swap, tmp_nzmax); // max number of non-zero in sparse - nzmax = tmp_nzmax; - - // dimensions array subelement - if (arrayclass != MAT_FILE_WORKSPACE_CLASS) - { - int32_t dim_len; - - if (read_mat5_tag (is, swap, type, dim_len) || type != miINT32) - { - error ("load: invalid dimensions array subelement"); - goto early_read_error; - } - - int ndims = dim_len / 4; - dims.resize (ndims); - for (int i = 0; i < ndims; i++) - { - int32_t n; - read_int (is, swap, n); - dims(i) = n; - } - - std::streampos tmp_pos = is.tellg (); - is.seekg (tmp_pos + static_cast (PAD (dim_len) - dim_len)); - } - else - { - // Why did mathworks decide to not have dims for a workspace!!! - dims.resize (2); - dims(0) = 1; - dims(1) = 1; - } - - if (read_mat5_tag (is, swap, type, len) || type != miINT8) - { - error ("load: invalid array name subelement"); - goto early_read_error; - } - - { - OCTAVE_LOCAL_BUFFER (char, name, len+1); - - // Structure field subelements have zero-length array name subelements. - - std::streampos tmp_pos = is.tellg (); - - if (len) - { - if (! is.read (name, len )) - goto data_read_error; - - is.seekg (tmp_pos + static_cast (PAD (len))); - } - - name[len] = '\0'; - retval = name; - } - - switch (arrayclass) - { - case MAT_FILE_CELL_CLASS: - { - Cell cell_array (dims); - - octave_idx_type n = cell_array.numel (); - - for (octave_idx_type i = 0; i < n; i++) - { - octave_value tc2; - - std::string nm - = read_mat5_binary_element (is, filename, swap, global, tc2); - - if (! is || error_state) - { - error ("load: reading cell data for `%s'", nm.c_str ()); - goto data_read_error; - } - - cell_array(i) = tc2; - } - - tc = cell_array; - } - break; - - case MAT_FILE_SPARSE_CLASS: - { - octave_idx_type nr = dims(0); - octave_idx_type nc = dims(1); - SparseMatrix sm; - SparseComplexMatrix scm; - octave_idx_type *ridx; - octave_idx_type *cidx; - double *data; - - // Setup return value - if (imag) - { - scm = SparseComplexMatrix (nr, nc, nzmax); - ridx = scm.ridx (); - cidx = scm.cidx (); - data = 0; - } - else - { - sm = SparseMatrix (nr, nc, nzmax); - ridx = sm.ridx (); - cidx = sm.cidx (); - data = sm.data (); - } - - // row indices - std::streampos tmp_pos; - - if (read_mat5_tag (is, swap, type, len)) - { - error ("load: reading sparse row data for `%s'", retval.c_str ()); - goto data_read_error; - } - - tmp_pos = is.tellg (); - - read_mat5_integer_data (is, ridx, nzmax, swap, - static_cast (type)); - - if (! is || error_state) - { - error ("load: reading sparse row data for `%s'", retval.c_str ()); - goto data_read_error; - } - - is.seekg (tmp_pos + static_cast (PAD (len))); - - // col indices - if (read_mat5_tag (is, swap, type, len)) - { - error ("load: reading sparse column data for `%s'", retval.c_str ()); - goto data_read_error; - } - - tmp_pos = is.tellg (); - - read_mat5_integer_data (is, cidx, nc + 1, swap, - static_cast (type)); - - if (! is || error_state) - { - error ("load: reading sparse column data for `%s'", retval.c_str ()); - goto data_read_error; - } - - is.seekg (tmp_pos + static_cast (PAD (len))); - - // real data subelement - if (read_mat5_tag (is, swap, type, len)) - { - error ("load: reading sparse matrix data for `%s'", retval.c_str ()); - goto data_read_error; - } - - octave_idx_type nnz = cidx[nc]; - NDArray re; - if (imag) - { - re = NDArray (dim_vector (nnz, 1)); - data = re.fortran_vec (); - } - - tmp_pos = is.tellg (); - read_mat5_binary_data (is, data, nnz, swap, - static_cast (type), flt_fmt); - - if (! is || error_state) - { - error ("load: reading sparse matrix data for `%s'", retval.c_str ()); - goto data_read_error; - } - - is.seekg (tmp_pos + static_cast (PAD (len))); - - // imaginary data subelement - if (imag) - { - NDArray im (dim_vector (static_cast (nnz), 1)); - - if (read_mat5_tag (is, swap, type, len)) - { - error ("load: reading sparse matrix data for `%s'", retval.c_str ()); - goto data_read_error; - } - - read_mat5_binary_data (is, im.fortran_vec (), nnz, swap, - static_cast (type), flt_fmt); - - if (! is || error_state) - { - error ("load: reading imaginary sparse matrix data for `%s'", - retval.c_str ()); - goto data_read_error; - } - - for (octave_idx_type i = 0; i < nnz; i++) - scm.xdata (i) = Complex (re (i), im (i)); - - tc = scm; - } - else - tc = sm; - } - break; - - case MAT_FILE_FUNCTION_CLASS: - { - octave_value tc2; - std::string nm - = read_mat5_binary_element (is, filename, swap, global, tc2); - - if (! is || error_state) - goto data_read_error; - - // Octave can handle both "/" and "\" as a directry seperator - // and so can ignore the seperator field of m0. I think the - // sentinel field is also save to ignore. - Octave_map m0 = tc2.map_value (); - Octave_map m1 = m0.contents ("function_handle")(0).map_value (); - std::string ftype = m1.contents ("type")(0).string_value (); - std::string fname = m1.contents ("function")(0).string_value (); - std::string fpath = m1.contents ("file")(0).string_value (); - - if (ftype == "simple" || ftype == "scopedfunction") - { - if (fpath.length () == 0) - // We have a builtin function - tc = make_fcn_handle (fname); - else - { - std::string mroot = - m0.contents ("matlabroot")(0).string_value (); - - if ((fpath.length () >= mroot.length ()) && - fpath.substr (0, mroot.length ()) == mroot && - OCTAVE_EXEC_PREFIX != mroot) - { - // If fpath starts with matlabroot, and matlabroot - // doesn't equal octave_config_info ("exec_prefix") - // then the function points to a version of Octave - // or Matlab other than the running version. In that - // case we replace with the same function in the - // running version of Octave? - - // First check if just replacing matlabroot is enough - std::string str = OCTAVE_EXEC_PREFIX + - fpath.substr (mroot.length ()); - file_stat fs (str); - - if (fs.exists ()) - { - size_t xpos - = str.find_last_of (file_ops::dir_sep_chars ()); - - std::string dir_name = str.substr (0, xpos); - - octave_function *fcn - = load_fcn_from_file (str, dir_name, "", fname); - - if (fcn) - { - octave_value tmp (fcn); - - tc = octave_value (new octave_fcn_handle (tmp, fname)); - } - } - else - { - // Next just search for it anywhere in the - // system path - string_vector names(3); - names(0) = fname + ".oct"; - names(1) = fname + ".mex"; - names(2) = fname + ".m"; - - dir_path p (load_path::system_path ()); - - str = octave_env::make_absolute (p.find_first_of (names)); - - size_t xpos - = str.find_last_of (file_ops::dir_sep_chars ()); - - std::string dir_name = str.substr (0, xpos); - - octave_function *fcn - = load_fcn_from_file (str, dir_name, "", fname); - - if (fcn) - { - octave_value tmp (fcn); - - tc = octave_value (new octave_fcn_handle (tmp, fname)); - } - else - { - warning ("load: can't find the file %s", - fpath.c_str ()); - goto skip_ahead; - } - } - } - else - { - size_t xpos - = fpath.find_last_of (file_ops::dir_sep_chars ()); - - std::string dir_name = fpath.substr (0, xpos); - - octave_function *fcn - = load_fcn_from_file (fpath, dir_name, "", fname); - - if (fcn) - { - octave_value tmp (fcn); - - tc = octave_value (new octave_fcn_handle (tmp, fname)); - } - else - { - warning ("load: can't find the file %s", - fpath.c_str ()); - goto skip_ahead; - } - } - } - } - else if (ftype == "nested") - { - warning ("load: can't load nested function"); - goto skip_ahead; - } - else if (ftype == "anonymous") - { - Octave_map m2 = m1.contents ("workspace")(0).map_value (); - uint32NDArray MCOS = m2.contents ("MCOS")(0).uint32_array_value (); - octave_idx_type off = static_cast(MCOS(4).double_value ()); - m2 = subsys_ov.map_value (); - m2 = m2.contents ("MCOS")(0).map_value (); - tc2 = m2.contents ("MCOS")(0).cell_value ()(1 + off).cell_value ()(1); - m2 = tc2.map_value (); - - unwind_protect_safe frame; - - // Set up temporary scope to use for evaluating the text - // that defines the anonymous function. - - symbol_table::scope_id local_scope = symbol_table::alloc_scope (); - frame.add_fcn (symbol_table::erase_scope, local_scope); - - symbol_table::set_scope (local_scope); - - octave_call_stack::push (local_scope, 0); - frame.add_fcn (octave_call_stack::pop); - - if (m2.nfields () > 0) - { - octave_value tmp; - - for (Octave_map::iterator p0 = m2.begin () ; - p0 != m2.end (); p0++) - { - std::string key = m2.key (p0); - octave_value val = m2.contents (p0)(0); - - symbol_table::varref (key, local_scope, 0) = val; - } - } - - int parse_status; - octave_value anon_fcn_handle = - eval_string (fname.substr (4), true, parse_status); - - if (parse_status == 0) - { - octave_fcn_handle *fh = - anon_fcn_handle.fcn_handle_value (); - - if (fh) - tc = new octave_fcn_handle (fh->fcn_val (), "@"); - else - { - error ("load: failed to load anonymous function handle"); - goto skip_ahead; - } - } - else - { - error ("load: failed to load anonymous function handle"); - goto skip_ahead; - } - - frame.run (); - } - else - { - error ("load: invalid function handle type"); - goto skip_ahead; - } - } - break; - - case MAT_FILE_WORKSPACE_CLASS: - { - Octave_map m (dim_vector (1, 1)); - int n_fields = 2; - string_vector field (n_fields); - - for (int i = 0; i < n_fields; i++) - { - int32_t fn_type; - int32_t fn_len; - if (read_mat5_tag (is, swap, fn_type, fn_len) || fn_type != miINT8) - { - error ("load: invalid field name subelement"); - goto data_read_error; - } - - OCTAVE_LOCAL_BUFFER (char, elname, fn_len + 1); - - std::streampos tmp_pos = is.tellg (); - - if (fn_len) - { - if (! is.read (elname, fn_len)) - goto data_read_error; - - is.seekg (tmp_pos + - static_cast (PAD (fn_len))); - } - - elname[fn_len] = '\0'; - - field(i) = elname; - } - - std::vector elt (n_fields); - - for (octave_idx_type i = 0; i < n_fields; i++) - elt[i] = Cell (dims); - - octave_idx_type n = dims.numel (); - - // fields subelements - for (octave_idx_type j = 0; j < n; j++) - { - for (octave_idx_type i = 0; i < n_fields; i++) - { - if (field(i) == "MCOS") - { - octave_value fieldtc; - read_mat5_binary_element (is, filename, swap, global, - fieldtc); - if (! is || error_state) - goto data_read_error; - - elt[i](j) = fieldtc; - } - else - elt[i](j) = octave_value (); - } - } - - for (octave_idx_type i = 0; i < n_fields; i++) - m.assign (field (i), elt[i]); - tc = m; - } - break; - - case MAT_FILE_OBJECT_CLASS: - { - isclass = true; - - if (read_mat5_tag (is, swap, type, len) || type != miINT8) - { - error ("load: invalid class name"); - goto skip_ahead; - } - - { - OCTAVE_LOCAL_BUFFER (char, name, len+1); - - std::streampos tmp_pos = is.tellg (); - - if (len) - { - if (! is.read (name, len )) - goto data_read_error; - - is.seekg (tmp_pos + static_cast (PAD (len))); - } - - name[len] = '\0'; - classname = name; - } - } - // Fall-through - case MAT_FILE_STRUCT_CLASS: - { - Octave_map m (dim_vector (1, 1)); - int32_t fn_type; - int32_t fn_len; - int32_t field_name_length; - - // field name length subelement -- actually the maximum length - // of a field name. The Matlab docs promise this will always - // be 32. We read and use the actual value, on the theory - // that eventually someone will recognize that's a waste of - // space. - if (read_mat5_tag (is, swap, fn_type, fn_len) || fn_type != miINT32) - { - error ("load: invalid field name length subelement"); - goto data_read_error; - } - - if (! is.read (reinterpret_cast (&field_name_length), fn_len )) - goto data_read_error; - - if (swap) - swap_bytes<4> (&field_name_length); - - // field name subelement. The length of this subelement tells - // us how many fields there are. - if (read_mat5_tag (is, swap, fn_type, fn_len) || fn_type != miINT8) - { - error ("load: invalid field name subelement"); - goto data_read_error; - } - - octave_idx_type n_fields = fn_len/field_name_length; - - if (n_fields > 0) - { - fn_len = PAD (fn_len); - - OCTAVE_LOCAL_BUFFER (char, elname, fn_len); - - if (! is.read (elname, fn_len)) - goto data_read_error; - - std::vector elt (n_fields); - - for (octave_idx_type i = 0; i < n_fields; i++) - elt[i] = Cell (dims); - - octave_idx_type n = dims.numel (); - - // fields subelements - for (octave_idx_type j = 0; j < n; j++) - { - for (octave_idx_type i = 0; i < n_fields; i++) - { - octave_value fieldtc; - read_mat5_binary_element (is, filename, swap, global, - fieldtc); - elt[i](j) = fieldtc; - } - } - - for (octave_idx_type i = 0; i < n_fields; i++) - { - const char *key = elname + i*field_name_length; - - m.assign (key, elt[i]); - } - } - - if (isclass) - { - if (classname == "inline") - { - // inline is not an object in Octave but rather an - // overload of a function handle. Special case. - tc = - new octave_fcn_inline (m.contents ("expr")(0).string_value (), - m.contents ("args")(0).string_value ()); - } - else - { - octave_class* cls - = new octave_class (m, classname, - std::list ()); - - if (cls->reconstruct_exemplar ()) - { - - if (! cls->reconstruct_parents ()) - warning ("load: unable to reconstruct object inheritance"); - - tc = cls; - if (load_path::find_method (classname, "loadobj") != - std::string ()) - { - octave_value_list tmp = feval ("loadobj", tc, 1); - - if (! error_state) - tc = tmp(0); - else - goto data_read_error; - } - } - else - { - tc = m; - warning ("load: element has been converted to a structure"); - } - } - } - else - tc = m; - } - break; - - case MAT_FILE_INT8_CLASS: - OCTAVE_MAT5_INTEGER_READ (int8NDArray); - break; - - case MAT_FILE_UINT8_CLASS: - { - OCTAVE_MAT5_INTEGER_READ (uint8NDArray); - - // Logical variables can either be MAT_FILE_UINT8_CLASS or - // MAT_FILE_DOUBLE_CLASS, so check if we have a logical - // variable and convert it. - - if (logicalvar) - { - uint8NDArray in = tc.uint8_array_value (); - octave_idx_type nel = in.numel (); - boolNDArray out (dims); - - for (octave_idx_type i = 0; i < nel; i++) - out(i) = in(i).bool_value (); - - tc = out; - } - } - break; - - case MAT_FILE_INT16_CLASS: - OCTAVE_MAT5_INTEGER_READ (int16NDArray); - break; - - case MAT_FILE_UINT16_CLASS: - OCTAVE_MAT5_INTEGER_READ (uint16NDArray); - break; - - case MAT_FILE_INT32_CLASS: - OCTAVE_MAT5_INTEGER_READ (int32NDArray); - break; - - case MAT_FILE_UINT32_CLASS: - OCTAVE_MAT5_INTEGER_READ (uint32NDArray); - break; - - case MAT_FILE_INT64_CLASS: - OCTAVE_MAT5_INTEGER_READ (int64NDArray); - break; - - case MAT_FILE_UINT64_CLASS: - OCTAVE_MAT5_INTEGER_READ (uint64NDArray); - break; - - - case MAT_FILE_SINGLE_CLASS: - { - FloatNDArray re (dims); - - // real data subelement - - std::streampos tmp_pos; - - if (read_mat5_tag (is, swap, type, len)) - { - error ("load: reading matrix data for `%s'", retval.c_str ()); - goto data_read_error; - } - - octave_idx_type n = re.numel (); - tmp_pos = is.tellg (); - read_mat5_binary_data (is, re.fortran_vec (), n, swap, - static_cast (type), flt_fmt); - - if (! is || error_state) - { - error ("load: reading matrix data for `%s'", retval.c_str ()); - goto data_read_error; - } - - is.seekg (tmp_pos + static_cast (PAD (len))); - - if (imag) - { - // imaginary data subelement - - FloatNDArray im (dims); - - if (read_mat5_tag (is, swap, type, len)) - { - error ("load: reading matrix data for `%s'", retval.c_str ()); - goto data_read_error; - } - - n = im.numel (); - read_mat5_binary_data (is, im.fortran_vec (), n, swap, - static_cast (type), flt_fmt); - - if (! is || error_state) - { - error ("load: reading imaginary matrix data for `%s'", - retval.c_str ()); - goto data_read_error; - } - - FloatComplexNDArray ctmp (dims); - - for (octave_idx_type i = 0; i < n; i++) - ctmp(i) = FloatComplex (re(i), im(i)); - - tc = ctmp; - } - else - tc = re; - } - break; - - case MAT_FILE_CHAR_CLASS: - // handle as a numerical array to start with - - case MAT_FILE_DOUBLE_CLASS: - default: - { - NDArray re (dims); - - // real data subelement - - std::streampos tmp_pos; - - if (read_mat5_tag (is, swap, type, len)) - { - error ("load: reading matrix data for `%s'", retval.c_str ()); - goto data_read_error; - } - - octave_idx_type n = re.numel (); - tmp_pos = is.tellg (); - read_mat5_binary_data (is, re.fortran_vec (), n, swap, - static_cast (type), flt_fmt); - - if (! is || error_state) - { - error ("load: reading matrix data for `%s'", retval.c_str ()); - goto data_read_error; - } - - is.seekg (tmp_pos + static_cast (PAD (len))); - - if (logicalvar) - { - // Logical variables can either be MAT_FILE_UINT8_CLASS or - // MAT_FILE_DOUBLE_CLASS, so check if we have a logical - // variable and convert it. - - boolNDArray out (dims); - - for (octave_idx_type i = 0; i < n; i++) - out (i) = static_cast (re (i)); - - tc = out; - } - else if (imag) - { - // imaginary data subelement - - NDArray im (dims); - - if (read_mat5_tag (is, swap, type, len)) - { - error ("load: reading matrix data for `%s'", retval.c_str ()); - goto data_read_error; - } - - n = im.numel (); - read_mat5_binary_data (is, im.fortran_vec (), n, swap, - static_cast (type), flt_fmt); - - if (! is || error_state) - { - error ("load: reading imaginary matrix data for `%s'", - retval.c_str ()); - goto data_read_error; - } - - ComplexNDArray ctmp (dims); - - for (octave_idx_type i = 0; i < n; i++) - ctmp(i) = Complex (re(i), im(i)); - - tc = ctmp; - } - else - { - if (arrayclass == MAT_FILE_CHAR_CLASS) - { - if (type == miUTF16 || type == miUTF32) - { - bool found_big_char = false; - for (octave_idx_type i = 0; i < n; i++) - { - if (re(i) > 127) { - re(i) = '?'; - found_big_char = true; - } - } - - if (found_big_char) - warning ("load: can not read non-ASCII portions of UTF characters; replacing unreadable characters with '?'"); - } - else if (type == miUTF8) - { - // Search for multi-byte encoded UTF8 characters and - // replace with 0x3F for '?'... Give the user a warning - - bool utf8_multi_byte = false; - for (octave_idx_type i = 0; i < n; i++) - { - unsigned char a = static_cast (re(i)); - if (a > 0x7f) - utf8_multi_byte = true; - } - - if (utf8_multi_byte) - { - warning ("load: can not read multi-byte encoded UTF8 characters; replacing unreadable characters with '?'"); - for (octave_idx_type i = 0; i < n; i++) - { - unsigned char a = static_cast (re(i)); - if (a > 0x7f) - re(i) = '?'; - } - } - } - tc = re; - tc = tc.convert_to_str (false, true, '\''); - } - else - tc = re; - } - } - } - - is.seekg (pos + static_cast (element_length)); - - if (is.eof ()) - is.clear (); - - return retval; - - data_read_error: - early_read_error: - error ("load: trouble reading binary file `%s'", filename.c_str ()); - return std::string (); - - skip_ahead: - warning ("skipping over `%s'", retval.c_str ()); - is.seekg (pos + static_cast (element_length)); - return read_mat5_binary_element (is, filename, swap, global, tc); -} - -int -read_mat5_binary_file_header (std::istream& is, bool& swap, bool quiet, - const std::string& filename) -{ - int16_t version=0, magic=0; - uint64_t subsys_offset; - - is.seekg (116, std::ios::beg); - is.read (reinterpret_cast (&subsys_offset), 8); - - is.seekg (124, std::ios::beg); - is.read (reinterpret_cast (&version), 2); - is.read (reinterpret_cast (&magic), 2); - - if (magic == 0x4d49) - swap = 0; - else if (magic == 0x494d) - swap = 1; - else - { - if (! quiet) - error ("load: can't read binary file"); - return -1; - } - - if (! swap) // version number is inverse swapped! - version = ((version >> 8) & 0xff) + ((version & 0xff) << 8); - - if (version != 1 && !quiet) - warning ("load: found version %d binary MAT file, " - "but only prepared for version 1", version); - - if (swap) - swap_bytes<8> (&subsys_offset, 1); - - if (subsys_offset != 0x2020202020202020ULL && subsys_offset != 0ULL) - { - // Read the subsystem data block - is.seekg (subsys_offset, std::ios::beg); - - octave_value tc; - bool global; - read_mat5_binary_element (is, filename, swap, global, tc); - - if (!is || error_state) - return -1; - - if (tc.is_uint8_type ()) - { - const uint8NDArray itmp = tc.uint8_array_value (); - octave_idx_type ilen = itmp.numel (); - - // Why should I have to initialize outbuf as just overwrite - std::string outbuf (ilen - 7, ' '); - - // FIXME -- find a way to avoid casting away const here - char *ctmp = const_cast (outbuf.c_str ()); - for (octave_idx_type j = 8; j < ilen; j++) - ctmp[j-8] = itmp(j).char_value (); - - std::istringstream fh_ws (outbuf); - - read_mat5_binary_element (fh_ws, filename, swap, global, subsys_ov); - - if (error_state) - return -1; - } - else - return -1; - - // Reposition to just after the header - is.seekg (128, std::ios::beg); - } - - return 0; -} - -static int -write_mat5_tag (std::ostream& is, int type, octave_idx_type bytes) -{ - int32_t temp; - - if (bytes > 0 && bytes <= 4) - temp = (bytes << 16) + type; - else - { - temp = type; - if (! is.write (reinterpret_cast (&temp), 4)) - goto data_write_error; - temp = bytes; - } - - if (! is.write (reinterpret_cast (&temp), 4)) - goto data_write_error; - - return 0; - - data_write_error: - return 1; -} - -// Have to use copy here to avoid writing over data accessed via -// Matrix::data(). - -#define MAT5_DO_WRITE(TYPE, data, count, stream) \ - do \ - { \ - OCTAVE_LOCAL_BUFFER (TYPE, ptr, count); \ - for (octave_idx_type i = 0; i < count; i++) \ - ptr[i] = static_cast (data[i]); \ - stream.write (reinterpret_cast (ptr), count * sizeof (TYPE)); \ - } \ - while (0) - -// write out the numeric values in M to OS, -// preceded by the appropriate tag. -static void -write_mat5_array (std::ostream& os, const NDArray& m, bool save_as_floats) -{ - save_type st = LS_DOUBLE; - const double *data = m.data (); - - if (save_as_floats) - { - if (m.too_large_for_float ()) - { - warning ("save: some values too large to save as floats --"); - warning ("save: saving as doubles instead"); - } - else - st = LS_FLOAT; - } - - double max_val, min_val; - if (m.all_integers (max_val, min_val)) - st = get_save_type (max_val, min_val); - - mat5_data_type mst; - int size; - switch (st) - { - default: - case LS_DOUBLE: mst = miDOUBLE; size = 8; break; - case LS_FLOAT: mst = miSINGLE; size = 4; break; - case LS_U_CHAR: mst = miUINT8; size = 1; break; - case LS_U_SHORT: mst = miUINT16; size = 2; break; - case LS_U_INT: mst = miUINT32; size = 4; break; - case LS_CHAR: mst = miINT8; size = 1; break; - case LS_SHORT: mst = miINT16; size = 2; break; - case LS_INT: mst = miINT32; size = 4; break; - } - - octave_idx_type nel = m.numel (); - octave_idx_type len = nel*size; - - write_mat5_tag (os, mst, len); - - { - switch (st) - { - case LS_U_CHAR: - MAT5_DO_WRITE (uint8_t, data, nel, os); - break; - - case LS_U_SHORT: - MAT5_DO_WRITE (uint16_t, data, nel, os); - break; - - case LS_U_INT: - MAT5_DO_WRITE (uint32_t, data, nel, os); - break; - - case LS_U_LONG: - MAT5_DO_WRITE (uint64_t, data, nel, os); - break; - - case LS_CHAR: - MAT5_DO_WRITE (int8_t, data, nel, os); - break; - - case LS_SHORT: - MAT5_DO_WRITE (int16_t, data, nel, os); - break; - - case LS_INT: - MAT5_DO_WRITE (int32_t, data, nel, os); - break; - - case LS_LONG: - MAT5_DO_WRITE (int64_t, data, nel, os); - break; - - case LS_FLOAT: - MAT5_DO_WRITE (float, data, nel, os); - break; - - case LS_DOUBLE: // No conversion necessary. - os.write (reinterpret_cast (data), len); - break; - - default: - (*current_liboctave_error_handler) - ("unrecognized data format requested"); - break; - } - } - if (PAD (len) > len) - { - static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00"; - os.write (buf, PAD (len) - len); - } -} - -static void -write_mat5_array (std::ostream& os, const FloatNDArray& m, bool) -{ - save_type st = LS_FLOAT; - const float *data = m.data (); - - float max_val, min_val; - if (m.all_integers (max_val, min_val)) - st = get_save_type (max_val, min_val); - - mat5_data_type mst; - int size; - switch (st) - { - default: - case LS_DOUBLE: mst = miDOUBLE; size = 8; break; - case LS_FLOAT: mst = miSINGLE; size = 4; break; - case LS_U_CHAR: mst = miUINT8; size = 1; break; - case LS_U_SHORT: mst = miUINT16; size = 2; break; - case LS_U_INT: mst = miUINT32; size = 4; break; - case LS_CHAR: mst = miINT8; size = 1; break; - case LS_SHORT: mst = miINT16; size = 2; break; - case LS_INT: mst = miINT32; size = 4; break; - } - - octave_idx_type nel = m.numel (); - octave_idx_type len = nel*size; - - write_mat5_tag (os, mst, len); - - { - switch (st) - { - case LS_U_CHAR: - MAT5_DO_WRITE (uint8_t, data, nel, os); - break; - - case LS_U_SHORT: - MAT5_DO_WRITE (uint16_t, data, nel, os); - break; - - case LS_U_INT: - MAT5_DO_WRITE (uint32_t, data, nel, os); - break; - - case LS_U_LONG: - MAT5_DO_WRITE (uint64_t, data, nel, os); - break; - - case LS_CHAR: - MAT5_DO_WRITE (int8_t, data, nel, os); - break; - - case LS_SHORT: - MAT5_DO_WRITE (int16_t, data, nel, os); - break; - - case LS_INT: - MAT5_DO_WRITE (int32_t, data, nel, os); - break; - - case LS_LONG: - MAT5_DO_WRITE (int64_t, data, nel, os); - break; - - case LS_FLOAT: // No conversion necessary. - os.write (reinterpret_cast (data), len); - break; - - case LS_DOUBLE: - MAT5_DO_WRITE (double, data, nel, os); - break; - - default: - (*current_liboctave_error_handler) - ("unrecognized data format requested"); - break; - } - } - if (PAD (len) > len) - { - static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00"; - os.write (buf, PAD (len) - len); - } -} - -template -void -write_mat5_integer_data (std::ostream& os, const T *m, int size, - octave_idx_type nel) -{ - mat5_data_type mst; - unsigned len; - - switch (size) - { - case 1: - mst = miUINT8; - break; - case 2: - mst = miUINT16; - break; - case 4: - mst = miUINT32; - break; - case 8: - mst = miUINT64; - break; - case -1: - mst = miINT8; - size = - size; - break; - case -2: - mst = miINT16; - size = - size; - break; - case -4: - mst = miINT32; - size = - size; - break; - case -8: - default: - mst = miINT64; - size = - size; - break; - } - - len = nel*size; - write_mat5_tag (os, mst, len); - - os.write (reinterpret_cast (m), len); - - if (PAD (len) > len) - { - static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00"; - os.write (buf, PAD (len) - len); - } -} - -template void -write_mat5_integer_data (std::ostream& os, const octave_int8 *m, - int size, octave_idx_type nel); - -template void -write_mat5_integer_data (std::ostream& os, const octave_int16 *m, - int size, octave_idx_type nel); - -template void -write_mat5_integer_data (std::ostream& os, const octave_int32 *m, - int size, octave_idx_type nel); - -template void -write_mat5_integer_data (std::ostream& os, const octave_int64 *m, - int size, octave_idx_type nel); - -template void -write_mat5_integer_data (std::ostream& os, const octave_uint8 *m, - int size, octave_idx_type nel); - -template void -write_mat5_integer_data (std::ostream& os, const octave_uint16 *m, - int size, octave_idx_type nel); - -template void -write_mat5_integer_data (std::ostream& os, const octave_uint32 *m, - int size, octave_idx_type nel); - -template void -write_mat5_integer_data (std::ostream& os, const octave_uint64 *m, - int size, octave_idx_type nel); - -template void -write_mat5_integer_data (std::ostream& os, const int *m, - int size, octave_idx_type nel); - -// Write out cell element values in the cell array to OS, preceded by -// the appropriate tag. - -static bool -write_mat5_cell_array (std::ostream& os, const Cell& cell, - bool mark_as_global, bool save_as_floats) -{ - octave_idx_type nel = cell.numel (); - - for (octave_idx_type i = 0; i < nel; i++) - { - octave_value ov = cell(i); - - if (! save_mat5_binary_element (os, ov, "", mark_as_global, - false, save_as_floats)) - return false; - } - - return true; -} - -int -save_mat5_array_length (const double* val, octave_idx_type nel, - bool save_as_floats) -{ - if (nel > 0) - { - int size = 8; - - if (save_as_floats) - { - bool too_large_for_float = false; - for (octave_idx_type i = 0; i < nel; i++) - { - double tmp = val[i]; - - if (! (xisnan (tmp) || xisinf (tmp)) - && fabs (tmp) > FLT_MAX) - { - too_large_for_float = true; - break; - } - } - - if (!too_large_for_float) - size = 4; - } - - // The code below is disabled since get_save_type currently doesn't - // deal with integer types. This will need to be activated if get_save_type - // is changed. - - // double max_val = val[0]; - // double min_val = val[0]; - // bool all_integers = true; - // - // for (int i = 0; i < nel; i++) - // { - // double val = val[i]; - // - // if (val > max_val) - // max_val = val; - // - // if (val < min_val) - // min_val = val; - // - // if (D_NINT (val) != val) - // { - // all_integers = false; - // break; - // } - // } - // - // if (all_integers) - // { - // if (max_val < 256 && min_val > -1) - // size = 1; - // else if (max_val < 65536 && min_val > -1) - // size = 2; - // else if (max_val < 4294967295UL && min_val > -1) - // size = 4; - // else if (max_val < 128 && min_val >= -128) - // size = 1; - // else if (max_val < 32768 && min_val >= -32768) - // size = 2; - // else if (max_val <= 2147483647L && min_val >= -2147483647L) - // size = 4; - // } - - return 8 + nel * size; - } - else - return 8; -} - -int -save_mat5_array_length (const float* /* val */, octave_idx_type nel, bool) -{ - if (nel > 0) - { - int size = 4; - - - // The code below is disabled since get_save_type currently doesn't - // deal with integer types. This will need to be activated if get_save_type - // is changed. - - // float max_val = val[0]; - // float min_val = val[0]; - // bool all_integers = true; - // - // for (int i = 0; i < nel; i++) - // { - // float val = val[i]; - // - // if (val > max_val) - // max_val = val; - // - // if (val < min_val) - // min_val = val; - // - // if (D_NINT (val) != val) - // { - // all_integers = false; - // break; - // } - // } - // - // if (all_integers) - // { - // if (max_val < 256 && min_val > -1) - // size = 1; - // else if (max_val < 65536 && min_val > -1) - // size = 2; - // else if (max_val < 4294967295UL && min_val > -1) - // size = 4; - // else if (max_val < 128 && min_val >= -128) - // size = 1; - // else if (max_val < 32768 && min_val >= -32768) - // size = 2; - // else if (max_val <= 2147483647L && min_val >= -2147483647L) - // size = 4; - // } - - // Round nel up to nearest even number of elements. Take into account - // Short tags for 4 byte elements. - return PAD ((nel > 0 && nel * size <= 4 ? 4 : 8) + nel * size); - } - else - return 8; -} - -int -save_mat5_array_length (const Complex* val, octave_idx_type nel, - bool save_as_floats) -{ - int ret; - - OCTAVE_LOCAL_BUFFER (double, tmp, nel); - - for (octave_idx_type i = 1; i < nel; i++) - tmp[i] = std::real (val[i]); - - ret = save_mat5_array_length (tmp, nel, save_as_floats); - - for (octave_idx_type i = 1; i < nel; i++) - tmp[i] = std::imag (val[i]); - - ret += save_mat5_array_length (tmp, nel, save_as_floats); - - return ret; -} - -int -save_mat5_array_length (const FloatComplex* val, octave_idx_type nel, - bool save_as_floats) -{ - int ret; - - OCTAVE_LOCAL_BUFFER (float, tmp, nel); - - for (octave_idx_type i = 1; i < nel; i++) - tmp[i] = std::real (val[i]); - - ret = save_mat5_array_length (tmp, nel, save_as_floats); - - for (octave_idx_type i = 1; i < nel; i++) - tmp[i] = std::imag (val[i]); - - ret += save_mat5_array_length (tmp, nel, save_as_floats); - - return ret; -} - -int -save_mat5_element_length (const octave_value& tc, const std::string& name, - bool save_as_floats, bool mat7_format) -{ - size_t max_namelen = (mat7_format ? 63 : 31); - size_t len = name.length (); - std::string cname = tc.class_name (); - int ret = 32; - - if (len > 4) - ret += PAD (len > max_namelen ? max_namelen : len); - - ret += PAD (4 * tc.ndims ()); - - if (tc.is_string ()) - { - charNDArray chm = tc.char_array_value (); - ret += 8; - if (chm.numel () > 2) - ret += PAD (2 * chm.numel ()); - } - else if (tc.is_sparse_type ()) - { - if (tc.is_complex_type ()) - { - const SparseComplexMatrix m = tc.sparse_complex_matrix_value (); - octave_idx_type nc = m.cols (); - octave_idx_type nnz = m.nnz (); - - ret += 16 + save_mat5_array_length (m.data (), nnz, save_as_floats); - if (nnz > 1) - ret += PAD (nnz * sizeof (int32_t)); - if (nc > 0) - ret += PAD ((nc + 1) * sizeof (int32_t)); - } - else - { - const SparseMatrix m = tc.sparse_matrix_value (); - octave_idx_type nc = m.cols (); - octave_idx_type nnz = m.nnz (); - - ret += 16 + save_mat5_array_length (m.data (), nnz, save_as_floats); - if (nnz > 1) - ret += PAD (nnz * sizeof (int32_t)); - if (nc > 0) - ret += PAD ((nc + 1) * sizeof (int32_t)); - } - } - -#define INT_LEN(nel, size) \ - { \ - ret += 8; \ - octave_idx_type sz = nel * size; \ - if (sz > 4) \ - ret += PAD (sz); \ - } - - else if (cname == "int8") - INT_LEN (tc.int8_array_value ().numel (), 1) - else if (cname == "int16") - INT_LEN (tc.int16_array_value ().numel (), 2) - else if (cname == "int32") - INT_LEN (tc.int32_array_value ().numel (), 4) - else if (cname == "int64") - INT_LEN (tc.int64_array_value ().numel (), 8) - else if (cname == "uint8") - INT_LEN (tc.uint8_array_value ().numel (), 1) - else if (cname == "uint16") - INT_LEN (tc.uint16_array_value ().numel (), 2) - else if (cname == "uint32") - INT_LEN (tc.uint32_array_value ().numel (), 4) - else if (cname == "uint64") - INT_LEN (tc.uint64_array_value ().numel (), 8) - else if (tc.is_bool_type ()) - INT_LEN (tc.bool_array_value ().numel (), 1) - else if (tc.is_real_scalar () || tc.is_real_matrix () || tc.is_range ()) - { - if (tc.is_single_type ()) - { - const FloatNDArray m = tc.float_array_value (); - ret += save_mat5_array_length (m.fortran_vec (), m.numel (), - save_as_floats); - } - else - { - const NDArray m = tc.array_value (); - ret += save_mat5_array_length (m.fortran_vec (), m.numel (), - save_as_floats); - } - } - else if (tc.is_cell ()) - { - Cell cell = tc.cell_value (); - octave_idx_type nel = cell.numel (); - - for (int i = 0; i < nel; i++) - ret += 8 + - save_mat5_element_length (cell (i), "", save_as_floats, mat7_format); - } - else if (tc.is_complex_scalar () || tc.is_complex_matrix ()) - { - if (tc.is_single_type ()) - { - const FloatComplexNDArray m = tc.float_complex_array_value (); - ret += save_mat5_array_length (m.fortran_vec (), m.numel (), - save_as_floats); - } - else - { - const ComplexNDArray m = tc.complex_array_value (); - ret += save_mat5_array_length (m.fortran_vec (), m.numel (), - save_as_floats); - } - } - else if (tc.is_map () || tc.is_inline_function () || tc.is_object ()) - { - int fieldcnt = 0; - const Octave_map m = tc.map_value (); - octave_idx_type nel = m.numel (); - - if (tc.is_inline_function ()) - // length of "inline" is 6 - ret += 8 + PAD (6 > max_namelen ? max_namelen : 6); - else if (tc.is_object ()) - { - size_t classlen = tc.class_name (). length (); - - ret += 8 + PAD (classlen > max_namelen ? max_namelen : classlen); - } - - for (Octave_map::const_iterator i = m.begin (); i != m.end (); i++) - fieldcnt++; - - ret += 16 + fieldcnt * (max_namelen + 1); - - - for (octave_idx_type j = 0; j < nel; j++) - { - - for (Octave_map::const_iterator i = m.begin (); i != m.end (); i++) - { - const Cell elts = m.contents (i); - - ret += 8 + save_mat5_element_length (elts(j), "", - save_as_floats, mat7_format); - } - } - } - else - ret = -1; - - return ret; -} - -static void -write_mat5_sparse_index_vector (std::ostream& os, - const octave_idx_type *idx, - octave_idx_type nel) -{ - int tmp = sizeof (int32_t); - - OCTAVE_LOCAL_BUFFER (int32_t, tmp_idx, nel); - - for (octave_idx_type i = 0; i < nel; i++) - tmp_idx[i] = idx[i]; - - write_mat5_integer_data (os, tmp_idx, -tmp, nel); -} - -static void -gripe_dim_too_large (const std::string& name) -{ - warning ("save: skipping %s: dimension too large for MAT format", - name.c_str ()); -} - -// save the data from TC along with the corresponding NAME on stream -// OS in the MatLab version 5 binary format. Return true on success. - -bool -save_mat5_binary_element (std::ostream& os, - const octave_value& tc, const std::string& name, - bool mark_as_global, bool mat7_format, - bool save_as_floats, bool compressing) -{ - int32_t flags = 0; - int32_t nnz_32 = 0; - std::string cname = tc.class_name (); - size_t max_namelen = (mat7_format ? 63 : 31); - - dim_vector dv = tc.dims (); - int nd = tc.ndims (); - int dim_len = 4*nd; - - static octave_idx_type max_dim_val = std::numeric_limits::max (); - - for (int i = 0; i < nd; i++) - { - if (dv(i) > max_dim_val) - { - gripe_dim_too_large (name); - goto skip_to_next; - } - } - - if (tc.is_sparse_type ()) - { - octave_idx_type nnz; - octave_idx_type nc; - - if (tc.is_complex_type ()) - { - SparseComplexMatrix scm = tc.sparse_complex_matrix_value (); - nnz = scm.nzmax (); - nc = scm.cols (); - } - else - { - SparseMatrix sm = tc.sparse_matrix_value (); - nnz = sm.nzmax (); - nc = sm.cols (); - } - - if (nnz > max_dim_val || nc + 1 > max_dim_val) - { - gripe_dim_too_large (name); - goto skip_to_next; - } - - nnz_32 = nnz; - } - else if (dv.numel () > max_dim_val) - { - gripe_dim_too_large (name); - goto skip_to_next; - } - -#ifdef HAVE_ZLIB - if (mat7_format && !compressing) - { - bool ret = false; - - std::ostringstream buf; - - // The code seeks backwards in the stream to fix the header. Can't - // do this with zlib, so use a stringstream. - ret = save_mat5_binary_element (buf, tc, name, mark_as_global, true, - save_as_floats, true); - - if (ret) - { - // destLen must be at least 0.1% larger than source buffer - // + 12 bytes. Reality is it must be larger again than that. - std::string buf_str = buf.str (); - uLongf srcLen = buf_str.length (); - uLongf destLen = srcLen * 101 / 100 + 12; - OCTAVE_LOCAL_BUFFER (char, out_buf, destLen); - - if (compress (reinterpret_cast (out_buf), &destLen, - reinterpret_cast (buf_str.c_str ()), srcLen) == Z_OK) - { - write_mat5_tag (os, miCOMPRESSED, - static_cast (destLen)); - - os.write (out_buf, destLen); - } - else - { - error ("save: error compressing data element"); - ret = false; - } - } - - return ret; - } -#endif - - write_mat5_tag (os, miMATRIX, save_mat5_element_length - (tc, name, save_as_floats, mat7_format)); - - // array flags subelement - write_mat5_tag (os, miUINT32, 8); - - if (tc.is_bool_type ()) - flags |= 0x0200; - - if (mark_as_global) - flags |= 0x0400; - - if (tc.is_complex_scalar () || tc.is_complex_matrix ()) - flags |= 0x0800; - - if (tc.is_string ()) - flags |= MAT_FILE_CHAR_CLASS; - else if (cname == "int8") - flags |= MAT_FILE_INT8_CLASS; - else if (cname == "int16") - flags |= MAT_FILE_INT16_CLASS; - else if (cname == "int32") - flags |= MAT_FILE_INT32_CLASS; - else if (cname == "int64") - flags |= MAT_FILE_INT64_CLASS; - else if (cname == "uint8" || tc.is_bool_type ()) - flags |= MAT_FILE_UINT8_CLASS; - else if (cname == "uint16") - flags |= MAT_FILE_UINT16_CLASS; - else if (cname == "uint32") - flags |= MAT_FILE_UINT32_CLASS; - else if (cname == "uint64") - flags |= MAT_FILE_UINT64_CLASS; - else if (tc.is_sparse_type ()) - flags |= MAT_FILE_SPARSE_CLASS; - else if (tc.is_real_scalar () || tc.is_real_matrix () || tc.is_range () - || tc.is_complex_scalar () || tc.is_complex_matrix ()) - { - if (tc.is_single_type ()) - flags |= MAT_FILE_SINGLE_CLASS; - else - flags |= MAT_FILE_DOUBLE_CLASS; - } - else if (tc.is_map ()) - flags |= MAT_FILE_STRUCT_CLASS; - else if (tc.is_cell ()) - flags |= MAT_FILE_CELL_CLASS; - else if (tc.is_inline_function () || tc.is_object ()) - flags |= MAT_FILE_OBJECT_CLASS; - else - { - gripe_wrong_type_arg ("save", tc, false); - goto error_cleanup; - } - - os.write (reinterpret_cast (&flags), 4); - os.write (reinterpret_cast (&nnz_32), 4); - - write_mat5_tag (os, miINT32, dim_len); - - for (int i = 0; i < nd; i++) - { - int32_t n = dv(i); - os.write (reinterpret_cast (&n), 4); - } - - if (PAD (dim_len) > dim_len) - { - static char buf[9]="\x00\x00\x00\x00\x00\x00\x00\x00"; - os.write (buf, PAD (dim_len) - dim_len); - } - - // array name subelement - { - size_t namelen = name.length (); - - if (namelen > max_namelen) - namelen = max_namelen; // only 31 or 63 char names permitted in mat file - - int paddedlength = PAD (namelen); - - write_mat5_tag (os, miINT8, namelen); - OCTAVE_LOCAL_BUFFER (char, paddedname, paddedlength); - memset (paddedname, 0, paddedlength); - strncpy (paddedname, name.c_str (), namelen); - os.write (paddedname, paddedlength); - } - - // data element - if (tc.is_string ()) - { - charNDArray chm = tc.char_array_value (); - octave_idx_type nel = chm.numel (); - octave_idx_type len = nel*2; - octave_idx_type paddedlength = PAD (len); - - OCTAVE_LOCAL_BUFFER (int16_t, buf, nel+3); - write_mat5_tag (os, miUINT16, len); - - const char *s = chm.data (); - - for (octave_idx_type i = 0; i < nel; i++) - buf[i] = *s++ & 0x00FF; - - os.write (reinterpret_cast (buf), len); - - if (paddedlength > len) - { - static char padbuf[9]="\x00\x00\x00\x00\x00\x00\x00\x00"; - os.write (padbuf, paddedlength - len); - } - } - else if (tc.is_sparse_type ()) - { - if (tc.is_complex_type ()) - { - const SparseComplexMatrix m = tc.sparse_complex_matrix_value (); - octave_idx_type nnz = m.nnz (); - octave_idx_type nc = m.cols (); - - write_mat5_sparse_index_vector (os, m.ridx (), nnz); - write_mat5_sparse_index_vector (os, m.cidx (), nc + 1); - - NDArray buf (dim_vector (nnz, 1)); - - for (octave_idx_type i = 0; i < nnz; i++) - buf (i) = std::real (m.data (i)); - - write_mat5_array (os, buf, save_as_floats); - - for (octave_idx_type i = 0; i < nnz; i++) - buf (i) = std::imag (m.data (i)); - - write_mat5_array (os, buf, save_as_floats); - } - else - { - const SparseMatrix m = tc.sparse_matrix_value (); - octave_idx_type nnz = m.nnz (); - octave_idx_type nc = m.cols (); - - write_mat5_sparse_index_vector (os, m.ridx (), nnz); - write_mat5_sparse_index_vector (os, m.cidx (), nc + 1); - - // FIXME - // Is there a way to easily do without this buffer - NDArray buf (dim_vector (nnz, 1)); - - for (int i = 0; i < nnz; i++) - buf (i) = m.data (i); - - write_mat5_array (os, buf, save_as_floats); - } - } - else if (cname == "int8") - { - int8NDArray m = tc.int8_array_value (); - - write_mat5_integer_data (os, m.fortran_vec (), -1, m.numel ()); - } - else if (cname == "int16") - { - int16NDArray m = tc.int16_array_value (); - - write_mat5_integer_data (os, m.fortran_vec (), -2, m.numel ()); - } - else if (cname == "int32") - { - int32NDArray m = tc.int32_array_value (); - - write_mat5_integer_data (os, m.fortran_vec (), -4, m.numel ()); - } - else if (cname == "int64") - { - int64NDArray m = tc.int64_array_value (); - - write_mat5_integer_data (os, m.fortran_vec (), -8, m.numel ()); - } - else if (cname == "uint8") - { - uint8NDArray m = tc.uint8_array_value (); - - write_mat5_integer_data (os, m.fortran_vec (), 1, m.numel ()); - } - else if (cname == "uint16") - { - uint16NDArray m = tc.uint16_array_value (); - - write_mat5_integer_data (os, m.fortran_vec (), 2, m.numel ()); - } - else if (cname == "uint32") - { - uint32NDArray m = tc.uint32_array_value (); - - write_mat5_integer_data (os, m.fortran_vec (), 4, m.numel ()); - } - else if (cname == "uint64") - { - uint64NDArray m = tc.uint64_array_value (); - - write_mat5_integer_data (os, m.fortran_vec (), 8, m.numel ()); - } - else if (tc.is_bool_type ()) - { - uint8NDArray m (tc.bool_array_value ()); - - write_mat5_integer_data (os, m.fortran_vec (), 1, m.numel ()); - } - else if (tc.is_real_scalar () || tc.is_real_matrix () || tc.is_range ()) - { - if (tc.is_single_type ()) - { - FloatNDArray m = tc.float_array_value (); - - write_mat5_array (os, m, save_as_floats); - } - else - { - NDArray m = tc.array_value (); - - write_mat5_array (os, m, save_as_floats); - } - } - else if (tc.is_cell ()) - { - Cell cell = tc.cell_value (); - - if (! write_mat5_cell_array (os, cell, mark_as_global, save_as_floats)) - goto error_cleanup; - } - else if (tc.is_complex_scalar () || tc.is_complex_matrix ()) - { - if (tc.is_single_type ()) - { - FloatComplexNDArray m_cmplx = tc.float_complex_array_value (); - - write_mat5_array (os, ::real (m_cmplx), save_as_floats); - write_mat5_array (os, ::imag (m_cmplx), save_as_floats); - } - else - { - ComplexNDArray m_cmplx = tc.complex_array_value (); - - write_mat5_array (os, ::real (m_cmplx), save_as_floats); - write_mat5_array (os, ::imag (m_cmplx), save_as_floats); - } - } - else if (tc.is_map () || tc.is_inline_function () || tc.is_object ()) - { - if (tc.is_inline_function () || tc.is_object ()) - { - std::string classname = tc.is_object () ? tc.class_name () : "inline"; - size_t namelen = classname.length (); - - if (namelen > max_namelen) - namelen = max_namelen; // only 31 or 63 char names permitted - - int paddedlength = PAD (namelen); - - write_mat5_tag (os, miINT8, namelen); - OCTAVE_LOCAL_BUFFER (char, paddedname, paddedlength); - memset (paddedname, 0, paddedlength); - strncpy (paddedname, classname.c_str (), namelen); - os.write (paddedname, paddedlength); - } - - Octave_map m; - - if (tc.is_object () && - load_path::find_method (tc.class_name (), "saveobj") != std::string ()) - { - octave_value_list tmp = feval ("saveobj", tc, 1); - if (! error_state) - m = tmp(0).map_value (); - else - goto error_cleanup; - } - else - m = tc.map_value (); - - // an Octave structure */ - // recursively write each element of the structure - { - char buf[64]; - int32_t maxfieldnamelength = max_namelen + 1; - - octave_idx_type nf = m.nfields (); - - write_mat5_tag (os, miINT32, 4); - os.write (reinterpret_cast (&maxfieldnamelength), 4); - write_mat5_tag (os, miINT8, nf*maxfieldnamelength); - - // Iterating over the list of keys will preserve the order of - // the fields. - string_vector keys = m.keys (); - - for (octave_idx_type i = 0; i < nf; i++) - { - std::string key = keys(i); - - // write the name of each element - memset (buf, 0, max_namelen + 1); - // only 31 or 63 char names permitted - strncpy (buf, key.c_str (), max_namelen); - os.write (buf, max_namelen + 1); - } - - octave_idx_type len = m.numel (); - - // Create temporary copy of structure contents to avoid - // multiple calls of the contents method. - std::vector elts (nf); - for (octave_idx_type i = 0; i < nf; i++) - elts[i] = m.contents (keys(i)).data (); - - for (octave_idx_type j = 0; j < len; j++) - { - // write the data of each element - - // Iterating over the list of keys will preserve the order - // of the fields. - for (octave_idx_type i = 0; i < nf; i++) - { - bool retval2 = save_mat5_binary_element (os, elts[i][j], "", - mark_as_global, - false, - save_as_floats); - if (! retval2) - goto error_cleanup; - } - } - } - } - else - gripe_wrong_type_arg ("save", tc, false); - - skip_to_next: - return true; - - error_cleanup: - error ("save: error while writing `%s' to MAT file", name.c_str ()); - - return false; -} diff -r a132d206a36a -r b9b6a310ad97 src/ls-mat5.h --- a/src/ls-mat5.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - -Copyright (C) 2003-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_ls_mat5_h) -#define octave_ls_mat5_h 1 - -enum mat5_data_type - { - miINT8 = 1, // 8 bit signed - miUINT8, // 8 bit unsigned - miINT16, // 16 bit signed - miUINT16, // 16 bit unsigned - miINT32, // 32 bit signed - miUINT32, // 32 bit unsigned - miSINGLE, // IEEE 754 single precision float - miRESERVE1, - miDOUBLE, // IEEE 754 double precision float - miRESERVE2, - miRESERVE3, - miINT64, // 64 bit signed - miUINT64, // 64 bit unsigned - miMATRIX, // MATLAB array - miCOMPRESSED, // Compressed data - miUTF8, // Unicode UTF-8 Encoded Character Data - miUTF16, // Unicode UTF-16 Encoded Character Data - miUTF32 // Unicode UTF-32 Encoded Character Data - }; - -extern int -read_mat5_binary_file_header (std::istream& is, bool& swap, - bool quiet = false, - const std::string& filename = std::string ()); -extern std::string -read_mat5_binary_element (std::istream& is, const std::string& filename, - bool swap, bool& global, octave_value& tc); -extern bool -save_mat5_binary_element (std::ostream& os, - const octave_value& tc, const std::string& name, - bool mark_as_global, bool mat7_format, - bool save_as_floats, bool compressing = false); - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/ls-oct-binary.cc --- a/src/ls-oct-binary.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,307 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "byte-swap.h" -#include "data-conv.h" -#include "file-ops.h" -#include "glob-match.h" -#include "lo-mappers.h" -#include "mach-info.h" -#include "oct-env.h" -#include "oct-time.h" -#include "quit.h" -#include "str-vec.h" -#include "oct-locbuf.h" - -#include "Cell.h" -#include "defun.h" -#include "error.h" -#include "gripes.h" -#include "load-save.h" -#include "oct-obj.h" -#include "oct-map.h" -#include "ov-cell.h" -#include "pager.h" -#include "pt-exp.h" -#include "sysdep.h" -#include "unwind-prot.h" -#include "utils.h" -#include "variables.h" -#include "version.h" -#include "dMatrix.h" - -#include "ls-utils.h" -#include "ls-oct-binary.h" - -// Extract one value (scalar, matrix, string, etc.) from stream IS and -// place it in TC, returning the name of the variable. If the value -// is tagged as global in the file, return TRUE in GLOBAL. If SWAP -// is TRUE, swap bytes after reading. -// -// The data is expected to be in the following format: -// -// Header (one per file): -// ===================== -// -// object type bytes -// ------ ---- ----- -// magic number string 10 -// -// float format integer 1 -// -// -// Data (one set for each item): -// ============================ -// -// object type bytes -// ------ ---- ----- -// name_length integer 4 -// -// name string name_length -// -// doc_length integer 4 -// -// doc string doc_length -// -// global flag integer 1 -// -// data type char 1 -// -// In general "data type" is 255, and in that case the next arguments -// in the data set are -// -// object type bytes -// ------ ---- ----- -// type_length integer 4 -// -// type string type_length -// -// The string "type" is then used with octave_value_typeinfo::lookup_type -// to create an octave_value of the correct type. The specific load/save -// function is then called. -// -// For backward compatiablity "data type" can also be a value between 1 -// and 7, where this defines a hardcoded octave_value of the type -// -// data type octave_value -// --------- ------------ -// 1 scalar -// 2 matrix -// 3 complex scalar -// 4 complex matrix -// 5 string (old style storage) -// 6 range -// 7 string -// -// Except for "data type" equal 5 that requires special treatment, these -// old style "data type" value also cause the specific load/save functions -// to be called. FILENAME is used for error messages. - -std::string -read_binary_data (std::istream& is, bool swap, - oct_mach_info::float_format fmt, - const std::string& filename, bool& global, - octave_value& tc, std::string& doc) -{ - std::string retval; - - unsigned char tmp = 0; - - int32_t name_len = 0; - int32_t doc_len = 0; - - doc.resize (0); - - // We expect to fail here, at the beginning of a record, so not - // being able to read another name should not result in an error. - - is.read (reinterpret_cast (&name_len), 4); - if (! is) - return retval; - if (swap) - swap_bytes<4> (&name_len); - - { - OCTAVE_LOCAL_BUFFER (char, name, name_len+1); - name[name_len] = '\0'; - if (! is.read (reinterpret_cast (name), name_len)) - goto data_read_error; - retval = name; - } - - is.read (reinterpret_cast (&doc_len), 4); - if (! is) - goto data_read_error; - if (swap) - swap_bytes<4> (&doc_len); - - { - OCTAVE_LOCAL_BUFFER (char, tdoc, doc_len+1); - tdoc[doc_len] = '\0'; - if (! is.read (reinterpret_cast (tdoc), doc_len)) - goto data_read_error; - doc = tdoc; - } - - if (! is.read (reinterpret_cast (&tmp), 1)) - goto data_read_error; - global = tmp ? 1 : 0; - - tmp = 0; - if (! is.read (reinterpret_cast (&tmp), 1)) - goto data_read_error; - - // All cases except 255 kept for backwards compatibility - switch (tmp) - { - case 1: - tc = octave_value_typeinfo::lookup_type ("scalar"); - break; - - case 2: - tc = octave_value_typeinfo::lookup_type ("matrix"); - break; - - case 3: - tc = octave_value_typeinfo::lookup_type ("complex scalar"); - break; - - case 4: - tc = octave_value_typeinfo::lookup_type ("complex matrix"); - break; - - case 5: - { - // FIXMEX - // This is cruft, since its for a save type that is old. Maybe - // this is taking backward compatability too far!! - int32_t len; - if (! is.read (reinterpret_cast (&len), 4)) - goto data_read_error; - if (swap) - swap_bytes<4> (&len); - OCTAVE_LOCAL_BUFFER (char, s, len+1); - if (! is.read (reinterpret_cast (s), len)) - goto data_read_error; - s[len] = '\0'; - tc = s; - - // Early return, since don't want rest of this function - return retval; - } - break; - - case 6: - tc = octave_value_typeinfo::lookup_type ("range"); - break; - - case 7: - tc = octave_value_typeinfo::lookup_type ("string"); - break; - - case 255: - { - // Read the saved variable type - int32_t len; - if (! is.read (reinterpret_cast (&len), 4)) - goto data_read_error; - if (swap) - swap_bytes<4> (&len); - OCTAVE_LOCAL_BUFFER (char, s, len+1); - if (! is.read (s, len)) - goto data_read_error; - s[len] = '\0'; - std::string typ = s; - tc = octave_value_typeinfo::lookup_type (typ); - } - break; - default: - goto data_read_error; - break; - } - - if (!tc.load_binary (is, swap, fmt)) - { - data_read_error: - error ("load: trouble reading binary file `%s'", filename.c_str ()); - } - - return retval; -} - -// Save the data from TC along with the corresponding NAME, help -// string DOC, and global flag MARK_AS_GLOBAL on stream OS in the -// binary format described above for read_binary_data. - -bool -save_binary_data (std::ostream& os, const octave_value& tc, - const std::string& name, const std::string& doc, - bool mark_as_global, bool save_as_floats) -{ - int32_t name_len = name.length (); - - os.write (reinterpret_cast (&name_len), 4); - os << name; - - int32_t doc_len = doc.length (); - - os.write (reinterpret_cast (&doc_len), 4); - os << doc; - - unsigned char tmp; - - tmp = mark_as_global; - os.write (reinterpret_cast (&tmp), 1); - - // 255 flags the new binary format - tmp = 255; - os.write (reinterpret_cast (&tmp), 1); - - // Write the string corresponding to the octave_value type - std::string typ = tc.type_name (); - int32_t len = typ.length (); - os.write (reinterpret_cast (&len), 4); - const char *btmp = typ.data (); - os.write (btmp, len); - - // The octave_value of tc is const. Make a copy... - octave_value val = tc; - - // Call specific save function - bool success = val.save_binary (os, save_as_floats); - - return (os && success); -} diff -r a132d206a36a -r b9b6a310ad97 src/ls-oct-binary.h --- a/src/ls-oct-binary.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - -Copyright (C) 2003-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_ls_oct_binary_h) -#define octave_ls_oct_binary_h 1 - -extern OCTINTERP_API bool -save_binary_data (std::ostream& os, const octave_value& tc, - const std::string& name, const std::string& doc, - bool mark_as_global, bool save_as_floats); - -extern OCTINTERP_API std::string -read_binary_data (std::istream& is, bool swap, - oct_mach_info::float_format fmt, - const std::string& filename, bool& global, - octave_value& tc, std::string& doc); - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/ls-utils.cc --- a/src/ls-utils.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - -Copyright (C) 2003-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "data-conv.h" - -#include "ls-utils.h" - -// MAX_VAL and MIN_VAL are assumed to have integral values even though -// they are stored in doubles. - -save_type -get_save_type (double /* max_val */, double /* min_val */) -{ - save_type st = LS_DOUBLE; - - // Matlab doesn't seem to load the UINT32 type correctly, so let's - // avoid it (and the other unsigned types, even though they may not - // have the same problem. And apparently, there are problems with - // other smaller types as well. If we avoid them all, then maybe we - // will avoid problems. Unfortunately, we won't be able to save - // space... - - // if (max_val < 256 && min_val > -1) - // st = LS_U_CHAR; - // else if (max_val < 65536 && min_val > -1) - // st = LS_U_SHORT; - // else if (max_val < 4294967295UL && min_val > -1) - // st = LS_U_INT; - // else if (max_val < 128 && min_val >= -128) - // st = LS_CHAR; - // else if (max_val < 32768 && min_val >= -32768) - // st = LS_SHORT; - // else if (max_val <= 2147483647L && min_val >= -2147483647L) - // st = LS_INT; - - return st; -} - -save_type -get_save_type (float /* max_val */, float /* min_val */) -{ - save_type st = LS_FLOAT; - - // Matlab doesn't seem to load the UINT32 type correctly, so let's - // avoid it (and the other unsigned types, even though they may not - // have the same problem. And apparently, there are problems with - // other smaller types as well. If we avoid them all, then maybe we - // will avoid problems. Unfortunately, we won't be able to save - // space... - - // if (max_val < 256 && min_val > -1) - // st = LS_U_CHAR; - // else if (max_val < 65536 && min_val > -1) - // st = LS_U_SHORT; - // else if (max_val < 4294967295UL && min_val > -1) - // st = LS_U_INT; - // else if (max_val < 128 && min_val >= -128) - // st = LS_CHAR; - // else if (max_val < 32768 && min_val >= -32768) - // st = LS_SHORT; - // else if (max_val <= 2147483647L && min_val >= -2147483647L) - // st = LS_INT; - - return st; -} diff -r a132d206a36a -r b9b6a310ad97 src/ls-utils.h --- a/src/ls-utils.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,32 +0,0 @@ -/* - -Copyright (C) 2003-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_ls_utils_h) -#define octave_ls_utils 1 - -extern save_type -get_save_type (double max_val, double min_val); - -extern save_type -get_save_type (float max_val, float min_val); - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/matherr.c --- a/src/matherr.c Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ -/* - -Copyright (C) 1997-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#if defined (EXCEPTION_IN_MATH) - -#include "lo-math.h" - -int -matherr (struct exception *x) -{ - /* Possibly print our own message someday. Should probably be - user-switchable. */ - - switch (x->type) - { - case DOMAIN: - case SING: - case OVERFLOW: - case UNDERFLOW: - case TLOSS: - case PLOSS: - default: - break; - } - - /* But don't print the system message. */ - - return 1; -} -#endif diff -r a132d206a36a -r b9b6a310ad97 src/mex.cc --- a/src/mex.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,3540 +0,0 @@ -/* - -Copyright (C) 2006-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include "f77-fcn.h" -#include "lo-ieee.h" -#include "oct-locbuf.h" - -// mxArray must be declared as a class before including mexproto.h. -class mxArray; -#include "Cell.h" -#include "mexproto.h" -#include "oct-map.h" -#include "oct-obj.h" -#include "ov.h" -#include "ov-mex-fcn.h" -#include "ov-usr-fcn.h" -#include "pager.h" -#include "parse.h" -#include "toplev.h" -#include "unwind-prot.h" -#include "utils.h" -#include "variables.h" -#include "graphics.h" - -// #define DEBUG 1 - -static void -xfree (void *ptr) -{ - ::free (ptr); -} - -static mwSize -max_str_len (mwSize m, const char **str) -{ - int max_len = 0; - - for (mwSize i = 0; i < m; i++) - { - mwSize tmp = strlen (str[i]); - - if (tmp > max_len) - max_len = tmp; - } - - return max_len; -} - -static int -valid_key (const char *key) -{ - int retval = 0; - - int nel = strlen (key); - - if (nel > 0) - { - if (isalpha (key[0])) - { - for (int i = 1; i < nel; i++) - { - if (! (isalnum (key[i]) || key[i] == '_')) - goto done; - } - - retval = 1; - } - } - - done: - - return retval; -} - -// ------------------------------------------------------------------ - -// A class to provide the default implemenation of some of the virtual -// functions declared in the mxArray class. - -class mxArray_base : public mxArray -{ -protected: - - mxArray_base (void) : mxArray (xmxArray ()) { } - -public: - - mxArray *dup (void) const = 0; - - ~mxArray_base (void) { } - - bool is_octave_value (void) const { return false; } - - int is_cell (void) const = 0; - - int is_char (void) const = 0; - - int is_class (const char *name_arg) const - { - int retval = 0; - - const char *cname = get_class_name (); - - if (cname && name_arg) - retval = ! strcmp (cname, name_arg); - - return retval; - } - - int is_complex (void) const = 0; - - int is_double (void) const = 0; - - int is_function_handle (void) const = 0; - - int is_int16 (void) const = 0; - - int is_int32 (void) const = 0; - - int is_int64 (void) const = 0; - - int is_int8 (void) const = 0; - - int is_logical (void) const = 0; - - int is_numeric (void) const = 0; - - int is_single (void) const = 0; - - int is_sparse (void) const = 0; - - int is_struct (void) const = 0; - - int is_uint16 (void) const = 0; - - int is_uint32 (void) const = 0; - - int is_uint64 (void) const = 0; - - int is_uint8 (void) const = 0; - - int is_logical_scalar (void) const - { - return is_logical () && get_number_of_elements () == 1; - } - - int is_logical_scalar_true (void) const = 0; - - mwSize get_m (void) const = 0; - - mwSize get_n (void) const = 0; - - mwSize *get_dimensions (void) const = 0; - - mwSize get_number_of_dimensions (void) const = 0; - - void set_m (mwSize m) = 0; - - void set_n (mwSize n) = 0; - - void set_dimensions (mwSize *dims_arg, mwSize ndims_arg) = 0; - - mwSize get_number_of_elements (void) const = 0; - - int is_empty (void) const = 0; - - mxClassID get_class_id (void) const = 0; - - const char *get_class_name (void) const = 0; - - void set_class_name (const char *name_arg) = 0; - - mxArray *get_cell (mwIndex /*idx*/) const - { - invalid_type_error (); - return 0; - } - - void set_cell (mwIndex idx, mxArray *val) = 0; - - double get_scalar (void) const = 0; - - void *get_data (void) const = 0; - - void *get_imag_data (void) const = 0; - - void set_data (void *pr) = 0; - - void set_imag_data (void *pi) = 0; - - mwIndex *get_ir (void) const = 0; - - mwIndex *get_jc (void) const = 0; - - mwSize get_nzmax (void) const = 0; - - void set_ir (mwIndex *ir) = 0; - - void set_jc (mwIndex *jc) = 0; - - void set_nzmax (mwSize nzmax) = 0; - - int add_field (const char *key) = 0; - - void remove_field (int key_num) = 0; - - mxArray *get_field_by_number (mwIndex index, int key_num) const = 0; - - void set_field_by_number (mwIndex index, int key_num, mxArray *val) = 0; - - int get_number_of_fields (void) const = 0; - - const char *get_field_name_by_number (int key_num) const = 0; - - int get_field_number (const char *key) const = 0; - - int get_string (char *buf, mwSize buflen) const = 0; - - char *array_to_string (void) const = 0; - - mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const = 0; - - size_t get_element_size (void) const = 0; - - bool mutation_needed (void) const { return false; } - - mxArray *mutate (void) const { return 0; } - -protected: - - octave_value as_octave_value (void) const = 0; - - mxArray_base (const mxArray_base&) : mxArray (xmxArray ()) { } - - void invalid_type_error (void) const - { - error ("invalid type for operation"); - } - - void error (const char *msg) const - { - // FIXME - ::error ("%s", msg); - } -}; - -static mwIndex -calc_single_subscript_internal (mwSize ndims, const mwSize *dims, - mwSize nsubs, const mwIndex *subs) -{ - mwIndex retval = 0; - - switch (nsubs) - { - case 0: - break; - - case 1: - retval = subs[0]; - break; - - default: - { - // Both nsubs and ndims should be at least 2 here. - - mwSize n = nsubs <= ndims ? nsubs : ndims; - - retval = subs[--n]; - - while (--n >= 0) - retval = dims[n] * retval + subs[n]; - } - break; - } - - return retval; -} - -// The object that handles values pass to MEX files from Octave. Some -// methods in this class may set mutate_flag to TRUE to tell the -// mxArray class to convert to the Matlab-style representation and -// then invoke the method on that object instead (for example, getting -// a pointer to real or imaginary data from a complex object requires -// a mutation but getting a pointer to real data from a real object -// does not). Changing the representation causes a copy so we try to -// avoid it unless it is really necessary. Once the conversion -// happens, we delete this representation, so the conversion can only -// happen once per call to a MEX file. - -static inline void *maybe_mark_foreign (void *ptr); - -class mxArray_octave_value : public mxArray_base -{ -public: - - mxArray_octave_value (const octave_value& ov) - : mxArray_base (), val (ov), mutate_flag (false), - id (mxUNKNOWN_CLASS), class_name (0), ndims (-1), dims (0) { } - - mxArray *dup (void) const - { - mxArray *retval = val.as_mxArray (); - - if (! retval) - retval = new mxArray_octave_value (*this); - - return retval; - } - - ~mxArray_octave_value (void) - { - mxFree (class_name); - mxFree (dims); - } - - bool is_octave_value (void) const { return true; } - - int is_cell (void) const { return val.is_cell (); } - - int is_char (void) const { return val.is_string (); } - - int is_complex (void) const { return val.is_complex_type (); } - - int is_double (void) const { return val.is_double_type (); } - - int is_function_handle (void) const { return val.is_function_handle (); } - - int is_int16 (void) const { return val.is_int16_type (); } - - int is_int32 (void) const { return val.is_int32_type (); } - - int is_int64 (void) const { return val.is_int64_type (); } - - int is_int8 (void) const { return val.is_int8_type (); } - - int is_logical (void) const { return val.is_bool_type (); } - - int is_numeric (void) const { return val.is_numeric_type (); } - - int is_single (void) const { return val.is_single_type (); } - - int is_sparse (void) const { return val.is_sparse_type (); } - - int is_struct (void) const { return val.is_map (); } - - int is_uint16 (void) const { return val.is_uint16_type (); } - - int is_uint32 (void) const { return val.is_uint32_type (); } - - int is_uint64 (void) const { return val.is_uint64_type (); } - - int is_uint8 (void) const { return val.is_uint8_type (); } - - int is_range (void) const { return val.is_range (); } - - int is_real_type (void) const { return val.is_real_type (); } - - int is_logical_scalar_true (void) const - { - return (is_logical_scalar () && val.is_true ()); - } - - mwSize get_m (void) const { return val.rows (); } - - mwSize get_n (void) const - { - mwSize n = 1; - - // Force dims and ndims to be cached. - get_dimensions (); - - for (mwIndex i = ndims - 1; i > 0; i--) - n *= dims[i]; - - return n; - } - - mwSize *get_dimensions (void) const - { - if (! dims) - { - ndims = val.ndims (); - - dims = static_cast (malloc (ndims * sizeof (mwSize))); - - dim_vector dv = val.dims (); - - for (mwIndex i = 0; i < ndims; i++) - dims[i] = dv(i); - } - - return dims; - } - - mwSize get_number_of_dimensions (void) const - { - // Force dims and ndims to be cached. - get_dimensions (); - - return ndims; - } - - void set_m (mwSize /*m*/) { request_mutation (); } - - void set_n (mwSize /*n*/) { request_mutation (); } - - void set_dimensions (mwSize */*dims_arg*/, mwSize /*ndims_arg*/) - { - request_mutation (); - } - - mwSize get_number_of_elements (void) const { return val.numel (); } - - int is_empty (void) const { return val.is_empty (); } - - mxClassID get_class_id (void) const - { - id = mxUNKNOWN_CLASS; - - std::string cn = val.class_name (); - - if (cn == "cell") - id = mxCELL_CLASS; - else if (cn == "struct") - id = mxSTRUCT_CLASS; - else if (cn == "logical") - id = mxLOGICAL_CLASS; - else if (cn == "char") - id = mxCHAR_CLASS; - else if (cn == "double") - id = mxDOUBLE_CLASS; - else if (cn == "single") - id = mxSINGLE_CLASS; - else if (cn == "int8") - id = mxINT8_CLASS; - else if (cn == "uint8") - id = mxUINT8_CLASS; - else if (cn == "int16") - id = mxINT16_CLASS; - else if (cn == "uint16") - id = mxUINT16_CLASS; - else if (cn == "int32") - id = mxINT32_CLASS; - else if (cn == "uint32") - id = mxUINT32_CLASS; - else if (cn == "int64") - id = mxINT64_CLASS; - else if (cn == "uint64") - id = mxUINT64_CLASS; - else if (cn == "function_handle") - id = mxFUNCTION_CLASS; - - return id; - } - - const char *get_class_name (void) const - { - if (! class_name) - { - std::string s = val.class_name (); - class_name = strsave (s.c_str ()); - } - - return class_name; - } - - // Not allowed. - void set_class_name (const char */*name_arg*/) { request_mutation (); } - - mxArray *get_cell (mwIndex /*idx*/) const - { - request_mutation (); - return 0; - } - - // Not allowed. - void set_cell (mwIndex /*idx*/, mxArray */*val*/) { request_mutation (); } - - double get_scalar (void) const { return val.scalar_value (true); } - - void *get_data (void) const - { - void *retval = val.mex_get_data (); - - if (retval) - maybe_mark_foreign (retval); - else - request_mutation (); - - return retval; - } - - void *get_imag_data (void) const - { - void *retval = 0; - - if (is_numeric () && is_real_type ()) - retval = 0; - else - request_mutation (); - - return retval; - } - - // Not allowed. - void set_data (void */*pr*/) { request_mutation (); } - - // Not allowed. - void set_imag_data (void */*pi*/) { request_mutation (); } - - mwIndex *get_ir (void) const - { - return static_cast (maybe_mark_foreign (val.mex_get_ir ())); - } - - mwIndex *get_jc (void) const - { - return static_cast (maybe_mark_foreign (val.mex_get_jc ())); - } - - mwSize get_nzmax (void) const { return val.nzmax (); } - - // Not allowed. - void set_ir (mwIndex */*ir*/) { request_mutation (); } - - // Not allowed. - void set_jc (mwIndex */*jc*/) { request_mutation (); } - - // Not allowed. - void set_nzmax (mwSize /*nzmax*/) { request_mutation (); } - - // Not allowed. - int add_field (const char */*key*/) - { - request_mutation (); - return 0; - } - - // Not allowed. - void remove_field (int /*key_num*/) { request_mutation (); } - - mxArray *get_field_by_number (mwIndex /*index*/, int /*key_num*/) const - { - request_mutation (); - return 0; - } - - // Not allowed. - void set_field_by_number (mwIndex /*index*/, int /*key_num*/, mxArray */*val*/) - { - request_mutation (); - } - - int get_number_of_fields (void) const { return val.nfields (); } - - const char *get_field_name_by_number (int /*key_num*/) const - { - request_mutation (); - return 0; - } - - int get_field_number (const char */*key*/) const - { - request_mutation (); - return 0; - } - - int get_string (char *buf, mwSize buflen) const - { - int retval = 1; - - mwSize nel = get_number_of_elements (); - - if (val.is_string () && nel < buflen) - { - charNDArray tmp = val.char_array_value (); - - const char *p = tmp.data (); - - for (mwIndex i = 0; i < nel; i++) - buf[i] = p[i]; - - buf[nel] = 0; - - retval = 0; - } - - return retval; - } - - char *array_to_string (void) const - { - // FIXME -- this is suposed to handle multi-byte character - // strings. - - char *buf = 0; - - if (val.is_string ()) - { - mwSize nel = get_number_of_elements (); - - buf = static_cast (malloc (nel + 1)); - - if (buf) - { - charNDArray tmp = val.char_array_value (); - - const char *p = tmp.data (); - - for (mwIndex i = 0; i < nel; i++) - buf[i] = p[i]; - - buf[nel] = '\0'; - } - } - - return buf; - } - - mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const - { - // Force ndims, dims to be cached. - get_dimensions (); - - return calc_single_subscript_internal (ndims, dims, nsubs, subs); - } - - size_t get_element_size (void) const - { - // Force id to be cached. - get_class_id (); - - switch (id) - { - case mxCELL_CLASS: return sizeof (mxArray *); - case mxSTRUCT_CLASS: return sizeof (mxArray *); - case mxLOGICAL_CLASS: return sizeof (mxLogical); - case mxCHAR_CLASS: return sizeof (mxChar); - case mxDOUBLE_CLASS: return sizeof (double); - case mxSINGLE_CLASS: return sizeof (float); - case mxINT8_CLASS: return 1; - case mxUINT8_CLASS: return 1; - case mxINT16_CLASS: return 2; - case mxUINT16_CLASS: return 2; - case mxINT32_CLASS: return 4; - case mxUINT32_CLASS: return 4; - case mxINT64_CLASS: return 8; - case mxUINT64_CLASS: return 8; - case mxFUNCTION_CLASS: return 0; - default: return 0; - } - } - - bool mutation_needed (void) const { return mutate_flag; } - - void request_mutation (void) const - { - if (mutate_flag) - panic_impossible (); - - mutate_flag = true; - } - - mxArray *mutate (void) const { return val.as_mxArray (); } - -protected: - - octave_value as_octave_value (void) const { return val; } - - mxArray_octave_value (const mxArray_octave_value& arg) - : mxArray_base (arg), val (arg.val), mutate_flag (arg.mutate_flag), - id (arg.id), class_name (strsave (arg.class_name)), ndims (arg.ndims), - dims (ndims > 0 ? static_cast (malloc (ndims * sizeof (mwSize))) : 0) - { - if (dims) - { - for (mwIndex i = 0; i < ndims; i++) - dims[i] = arg.dims[i]; - } - } - -private: - - octave_value val; - - mutable bool mutate_flag; - - // Caching these does not cost much or lead to much duplicated - // code. For other things, we just request mutation to a - // Matlab-style mxArray object. - - mutable mxClassID id; - mutable char *class_name; - mutable mwSize ndims; - mutable mwSize *dims; - - // No assignment! FIXME -- should this be implemented? Note that we - // do have a copy constructor. - - mxArray_octave_value& operator = (const mxArray_octave_value&); -}; - -// The base class for the Matlab-style representation, used to handle -// things that are common to all Matlab-style objects. - -class mxArray_matlab : public mxArray_base -{ -protected: - - mxArray_matlab (mxClassID id_arg = mxUNKNOWN_CLASS) - : mxArray_base (), class_name (0), id (id_arg), ndims (0), dims (0) { } - - mxArray_matlab (mxClassID id_arg, mwSize ndims_arg, const mwSize *dims_arg) - : mxArray_base (), class_name (0), id (id_arg), - ndims (ndims_arg < 2 ? 2 : ndims_arg), - dims (static_cast (malloc (ndims * sizeof (mwSize)))) - { - if (ndims_arg < 2) - { - dims[0] = 1; - dims[1] = 1; - } - - for (mwIndex i = 0; i < ndims_arg; i++) - dims[i] = dims_arg[i]; - - for (mwIndex i = ndims - 1; i > 1; i--) - { - if (dims[i] == 1) - ndims--; - else - break; - } - } - - mxArray_matlab (mxClassID id_arg, const dim_vector& dv) - : mxArray_base (), class_name (0), id (id_arg), - ndims (dv.length ()), - dims (static_cast (malloc (ndims * sizeof (mwSize)))) - { - for (mwIndex i = 0; i < ndims; i++) - dims[i] = dv(i); - - for (mwIndex i = ndims - 1; i > 1; i--) - { - if (dims[i] == 1) - ndims--; - else - break; - } - } - - mxArray_matlab (mxClassID id_arg, mwSize m, mwSize n) - : mxArray_base (), class_name (0), id (id_arg), ndims (2), - dims (static_cast (malloc (ndims * sizeof (mwSize)))) - { - dims[0] = m; - dims[1] = n; - } - -public: - - ~mxArray_matlab (void) - { - mxFree (class_name); - mxFree (dims); - } - - int is_cell (void) const { return id == mxCELL_CLASS; } - - int is_char (void) const { return id == mxCHAR_CLASS; } - - int is_complex (void) const { return 0; } - - int is_double (void) const { return id == mxDOUBLE_CLASS; } - - int is_function_handle (void) const { return id == mxFUNCTION_CLASS; } - - int is_int16 (void) const { return id == mxINT16_CLASS; } - - int is_int32 (void) const { return id == mxINT32_CLASS; } - - int is_int64 (void) const { return id == mxINT64_CLASS; } - - int is_int8 (void) const { return id == mxINT8_CLASS; } - - int is_logical (void) const { return id == mxLOGICAL_CLASS; } - - int is_numeric (void) const - { - return (id == mxDOUBLE_CLASS || id == mxSINGLE_CLASS - || id == mxINT8_CLASS || id == mxUINT8_CLASS - || id == mxINT16_CLASS || id == mxUINT16_CLASS - || id == mxINT32_CLASS || id == mxUINT32_CLASS - || id == mxINT64_CLASS || id == mxUINT64_CLASS); - } - - int is_single (void) const { return id == mxSINGLE_CLASS; } - - int is_sparse (void) const { return 0; } - - int is_struct (void) const { return id == mxSTRUCT_CLASS; } - - int is_uint16 (void) const { return id == mxUINT16_CLASS; } - - int is_uint32 (void) const { return id == mxUINT32_CLASS; } - - int is_uint64 (void) const { return id == mxUINT64_CLASS; } - - int is_uint8 (void) const { return id == mxUINT8_CLASS; } - - int is_logical_scalar_true (void) const - { - return (is_logical_scalar () - && static_cast (get_data ())[0] != 0); - } - - mwSize get_m (void) const { return dims[0]; } - - mwSize get_n (void) const - { - mwSize n = 1; - - for (mwSize i = ndims - 1 ; i > 0 ; i--) - n *= dims[i]; - - return n; - } - - mwSize *get_dimensions (void) const { return dims; } - - mwSize get_number_of_dimensions (void) const { return ndims; } - - void set_m (mwSize m) { dims[0] = m; } - - void set_n (mwSize n) { dims[1] = n; } - - void set_dimensions (mwSize *dims_arg, mwSize ndims_arg) - { - dims = dims_arg; - ndims = ndims_arg; - } - - mwSize get_number_of_elements (void) const - { - mwSize retval = dims[0]; - - for (mwIndex i = 1; i < ndims; i++) - retval *= dims[i]; - - return retval; - } - - int is_empty (void) const { return get_number_of_elements () == 0; } - - mxClassID get_class_id (void) const { return id; } - - const char *get_class_name (void) const - { - switch (id) - { - case mxCELL_CLASS: return "cell"; - case mxSTRUCT_CLASS: return "struct"; - case mxLOGICAL_CLASS: return "logical"; - case mxCHAR_CLASS: return "char"; - case mxDOUBLE_CLASS: return "double"; - case mxSINGLE_CLASS: return "single"; - case mxINT8_CLASS: return "int8"; - case mxUINT8_CLASS: return "uint8"; - case mxINT16_CLASS: return "int16"; - case mxUINT16_CLASS: return "uint16"; - case mxINT32_CLASS: return "int32"; - case mxUINT32_CLASS: return "uint32"; - case mxINT64_CLASS: return "int64"; - case mxUINT64_CLASS: return "uint64"; - case mxFUNCTION_CLASS: return "function_handle"; - default: return "unknown"; - } - } - - void set_class_name (const char *name_arg) - { - mxFree (class_name); - class_name = static_cast (malloc (strlen (name_arg) + 1)); - strcpy (class_name, name_arg); - } - - mxArray *get_cell (mwIndex /*idx*/) const - { - invalid_type_error (); - return 0; - } - - void set_cell (mwIndex /*idx*/, mxArray */*val*/) - { - invalid_type_error (); - } - - double get_scalar (void) const - { - invalid_type_error (); - return 0; - } - - void *get_data (void) const - { - invalid_type_error (); - return 0; - } - - void *get_imag_data (void) const - { - invalid_type_error (); - return 0; - } - - void set_data (void */*pr*/) - { - invalid_type_error (); - } - - void set_imag_data (void */*pi*/) - { - invalid_type_error (); - } - - mwIndex *get_ir (void) const - { - invalid_type_error (); - return 0; - } - - mwIndex *get_jc (void) const - { - invalid_type_error (); - return 0; - } - - mwSize get_nzmax (void) const - { - invalid_type_error (); - return 0; - } - - void set_ir (mwIndex */*ir*/) - { - invalid_type_error (); - } - - void set_jc (mwIndex */*jc*/) - { - invalid_type_error (); - } - - void set_nzmax (mwSize /*nzmax*/) - { - invalid_type_error (); - } - - int add_field (const char */*key*/) - { - invalid_type_error (); - return -1; - } - - void remove_field (int /*key_num*/) - { - invalid_type_error (); - } - - mxArray *get_field_by_number (mwIndex /*index*/, int /*key_num*/) const - { - invalid_type_error (); - return 0; - } - - void set_field_by_number (mwIndex /*index*/, int /*key_num*/, mxArray */*val*/) - { - invalid_type_error (); - } - - int get_number_of_fields (void) const - { - invalid_type_error (); - return 0; - } - - const char *get_field_name_by_number (int /*key_num*/) const - { - invalid_type_error (); - return 0; - } - - int get_field_number (const char */*key*/) const - { - return -1; - } - - int get_string (char */*buf*/, mwSize /*buflen*/) const - { - invalid_type_error (); - return 0; - } - - char *array_to_string (void) const - { - invalid_type_error (); - return 0; - } - - mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const - { - return calc_single_subscript_internal (ndims, dims, nsubs, subs); - } - - size_t get_element_size (void) const - { - switch (id) - { - case mxCELL_CLASS: return sizeof (mxArray *); - case mxSTRUCT_CLASS: return sizeof (mxArray *); - case mxLOGICAL_CLASS: return sizeof (mxLogical); - case mxCHAR_CLASS: return sizeof (mxChar); - case mxDOUBLE_CLASS: return sizeof (double); - case mxSINGLE_CLASS: return sizeof (float); - case mxINT8_CLASS: return 1; - case mxUINT8_CLASS: return 1; - case mxINT16_CLASS: return 2; - case mxUINT16_CLASS: return 2; - case mxINT32_CLASS: return 4; - case mxUINT32_CLASS: return 4; - case mxINT64_CLASS: return 8; - case mxUINT64_CLASS: return 8; - case mxFUNCTION_CLASS: return 0; - default: return 0; - } - } - -protected: - - mxArray_matlab (const mxArray_matlab& val) - : mxArray_base (val), class_name (strsave (val.class_name)), - id (val.id), ndims (val.ndims), - dims (static_cast (malloc (ndims * sizeof (mwSize)))) - { - for (mwIndex i = 0; i < ndims; i++) - dims[i] = val.dims[i]; - } - - dim_vector - dims_to_dim_vector (void) const - { - mwSize nd = get_number_of_dimensions (); - - mwSize *d = get_dimensions (); - - dim_vector dv; - dv.resize (nd); - - for (mwIndex i = 0; i < nd; i++) - dv(i) = d[i]; - - return dv; - } - -private: - - char *class_name; - - mxClassID id; - - mwSize ndims; - mwSize *dims; - - void invalid_type_error (void) const - { - error ("invalid type for operation"); - } - - // No assignment! FIXME -- should this be implemented? Note that we - // do have a copy constructor. - - mxArray_matlab& operator = (const mxArray_matlab&); -}; - -// Matlab-style numeric, character, and logical data. - -class mxArray_number : public mxArray_matlab -{ -public: - - mxArray_number (mxClassID id_arg, mwSize ndims_arg, const mwSize *dims_arg, - mxComplexity flag = mxREAL) - : mxArray_matlab (id_arg, ndims_arg, dims_arg), - pr (calloc (get_number_of_elements (), get_element_size ())), - pi (flag == mxCOMPLEX ? calloc (get_number_of_elements (), get_element_size ()) : 0) { } - - mxArray_number (mxClassID id_arg, const dim_vector& dv, - mxComplexity flag = mxREAL) - : mxArray_matlab (id_arg, dv), - pr (calloc (get_number_of_elements (), get_element_size ())), - pi (flag == mxCOMPLEX ? calloc (get_number_of_elements (), get_element_size ()) : 0) { } - - mxArray_number (mxClassID id_arg, mwSize m, mwSize n, mxComplexity flag = mxREAL) - : mxArray_matlab (id_arg, m, n), - pr (calloc (get_number_of_elements (), get_element_size ())), - pi (flag == mxCOMPLEX ? calloc (get_number_of_elements (), get_element_size ()) : 0) { } - - mxArray_number (mxClassID id_arg, double val) - : mxArray_matlab (id_arg, 1, 1), - pr (calloc (get_number_of_elements (), get_element_size ())), - pi (0) - { - double *dpr = static_cast (pr); - dpr[0] = val; - } - - mxArray_number (mxClassID id_arg, mxLogical val) - : mxArray_matlab (id_arg, 1, 1), - pr (calloc (get_number_of_elements (), get_element_size ())), - pi (0) - { - mxLogical *lpr = static_cast (pr); - lpr[0] = val; - } - - mxArray_number (const char *str) - : mxArray_matlab (mxCHAR_CLASS, - str ? (strlen (str) ? 1 : 0) : 0, - str ? strlen (str) : 0), - pr (calloc (get_number_of_elements (), get_element_size ())), - pi (0) - { - mxChar *cpr = static_cast (pr); - mwSize nel = get_number_of_elements (); - for (mwIndex i = 0; i < nel; i++) - cpr[i] = str[i]; - } - - // FIXME?? - mxArray_number (mwSize m, const char **str) - : mxArray_matlab (mxCHAR_CLASS, m, max_str_len (m, str)), - pr (calloc (get_number_of_elements (), get_element_size ())), - pi (0) - { - mxChar *cpr = static_cast (pr); - - mwSize *dv = get_dimensions (); - - mwSize nc = dv[1]; - - for (mwIndex j = 0; j < m; j++) - { - const char *ptr = str[j]; - - size_t tmp_len = strlen (ptr); - - for (size_t i = 0; i < tmp_len; i++) - cpr[m*i+j] = static_cast (ptr[i]); - - for (size_t i = tmp_len; i < static_cast(nc); i++) - cpr[m*i+j] = static_cast (' '); - } - } - - mxArray_number *dup (void) const { return new mxArray_number (*this); } - - ~mxArray_number (void) - { - mxFree (pr); - mxFree (pi); - } - - int is_complex (void) const { return pi != 0; } - - double get_scalar (void) const - { - double retval = 0; - - switch (get_class_id ()) - { - case mxLOGICAL_CLASS: - retval = *(static_cast (pr)); - break; - - case mxCHAR_CLASS: - retval = *(static_cast (pr)); - break; - - case mxSINGLE_CLASS: - retval = *(static_cast (pr)); - break; - - case mxDOUBLE_CLASS: - retval = *(static_cast (pr)); - break; - - case mxINT8_CLASS: - retval = *(static_cast (pr)); - break; - - case mxUINT8_CLASS: - retval = *(static_cast (pr)); - break; - - case mxINT16_CLASS: - retval = *(static_cast (pr)); - break; - - case mxUINT16_CLASS: - retval = *(static_cast (pr)); - break; - - case mxINT32_CLASS: - retval = *(static_cast (pr)); - break; - - case mxUINT32_CLASS: - retval = *(static_cast (pr)); - break; - - case mxINT64_CLASS: - retval = *(static_cast (pr)); - break; - - case mxUINT64_CLASS: - retval = *(static_cast (pr)); - break; - - default: - panic_impossible (); - } - - return retval; - } - - void *get_data (void) const { return pr; } - - void *get_imag_data (void) const { return pi; } - - void set_data (void *pr_arg) { pr = pr_arg; } - - void set_imag_data (void *pi_arg) { pi = pi_arg; } - - int get_string (char *buf, mwSize buflen) const - { - int retval = 0; - - mwSize nel = get_number_of_elements (); - - if (! (nel < buflen)) - { - retval = 1; - if (buflen > 0) - nel = buflen-1; - } - - if (nel < buflen) - { - mxChar *ptr = static_cast (pr); - - for (mwIndex i = 0; i < nel; i++) - buf[i] = static_cast (ptr[i]); - - buf[nel] = 0; - } - - return retval; - } - - char *array_to_string (void) const - { - // FIXME -- this is suposed to handle multi-byte character - // strings. - - mwSize nel = get_number_of_elements (); - - char *buf = static_cast (malloc (nel + 1)); - - if (buf) - { - mxChar *ptr = static_cast (pr); - - for (mwIndex i = 0; i < nel; i++) - buf[i] = static_cast (ptr[i]); - - buf[nel] = '\0'; - } - - return buf; - } - -protected: - - template - octave_value - int_to_ov (const dim_vector& dv) const - { - octave_value retval; - - mwSize nel = get_number_of_elements (); - - ELT_T *ppr = static_cast (pr); - - if (pi) - error ("complex integer types are not supported"); - else - { - ARRAY_T val (dv); - - ARRAY_ELT_T *ptr = val.fortran_vec (); - - for (mwIndex i = 0; i < nel; i++) - ptr[i] = ppr[i]; - - retval = val; - } - - return retval; - } - - octave_value as_octave_value (void) const - { - octave_value retval; - - dim_vector dv = dims_to_dim_vector (); - - switch (get_class_id ()) - { - case mxLOGICAL_CLASS: - retval = int_to_ov (dv); - break; - - case mxCHAR_CLASS: - { - mwSize nel = get_number_of_elements (); - - mxChar *ppr = static_cast (pr); - - charNDArray val (dv); - - char *ptr = val.fortran_vec (); - - for (mwIndex i = 0; i < nel; i++) - ptr[i] = static_cast (ppr[i]); - - retval = val; - } - break; - - case mxSINGLE_CLASS: - { - mwSize nel = get_number_of_elements (); - - float *ppr = static_cast (pr); - - if (pi) - { - FloatComplexNDArray val (dv); - - FloatComplex *ptr = val.fortran_vec (); - - float *ppi = static_cast (pi); - - for (mwIndex i = 0; i < nel; i++) - ptr[i] = FloatComplex (ppr[i], ppi[i]); - - retval = val; - } - else - { - FloatNDArray val (dv); - - float *ptr = val.fortran_vec (); - - for (mwIndex i = 0; i < nel; i++) - ptr[i] = ppr[i]; - - retval = val; - } - } - break; - - case mxDOUBLE_CLASS: - { - mwSize nel = get_number_of_elements (); - - double *ppr = static_cast (pr); - - if (pi) - { - ComplexNDArray val (dv); - - Complex *ptr = val.fortran_vec (); - - double *ppi = static_cast (pi); - - for (mwIndex i = 0; i < nel; i++) - ptr[i] = Complex (ppr[i], ppi[i]); - - retval = val; - } - else - { - NDArray val (dv); - - double *ptr = val.fortran_vec (); - - for (mwIndex i = 0; i < nel; i++) - ptr[i] = ppr[i]; - - retval = val; - } - } - break; - - case mxINT8_CLASS: - retval = int_to_ov (dv); - break; - - case mxUINT8_CLASS: - retval = int_to_ov (dv); - break; - - case mxINT16_CLASS: - retval = int_to_ov (dv); - break; - - case mxUINT16_CLASS: - retval = int_to_ov (dv); - break; - - case mxINT32_CLASS: - retval = int_to_ov (dv); - break; - - case mxUINT32_CLASS: - retval = int_to_ov (dv); - break; - - case mxINT64_CLASS: - retval = int_to_ov (dv); - break; - - case mxUINT64_CLASS: - retval = int_to_ov (dv); - break; - - default: - panic_impossible (); - } - - return retval; - } - - mxArray_number (const mxArray_number& val) - : mxArray_matlab (val), - pr (malloc (get_number_of_elements () * get_element_size ())), - pi (val.pi ? malloc (get_number_of_elements () * get_element_size ()) : 0) - { - size_t nbytes = get_number_of_elements () * get_element_size (); - - if (pr) - memcpy (pr, val.pr, nbytes); - - if (pi) - memcpy (pi, val.pi, nbytes); - } - -private: - - void *pr; - void *pi; - - // No assignment! FIXME -- should this be implemented? Note that we - // do have a copy constructor. - - mxArray_number& operator = (const mxArray_number&); -}; - -// Matlab-style sparse arrays. - -class mxArray_sparse : public mxArray_matlab -{ -public: - - mxArray_sparse (mxClassID id_arg, mwSize m, mwSize n, mwSize nzmax_arg, - mxComplexity flag = mxREAL) - : mxArray_matlab (id_arg, m, n), nzmax (nzmax_arg), - pr (calloc (nzmax, get_element_size ())), - pi (flag == mxCOMPLEX ? calloc (nzmax, get_element_size ()) : 0), - ir (static_cast (calloc (nzmax, sizeof (mwIndex)))), - jc (static_cast (calloc (n + 1, sizeof (mwIndex)))) - { } - - mxArray_sparse *dup (void) const { return new mxArray_sparse (*this); } - - ~mxArray_sparse (void) - { - mxFree (pr); - mxFree (pi); - mxFree (ir); - mxFree (jc); - } - - int is_complex (void) const { return pi != 0; } - - int is_sparse (void) const { return 1; } - - void *get_data (void) const { return pr; } - - void *get_imag_data (void) const { return pi; } - - void set_data (void *pr_arg) { pr = pr_arg; } - - void set_imag_data (void *pi_arg) { pi = pi_arg; } - - mwIndex *get_ir (void) const { return ir; } - - mwIndex *get_jc (void) const { return jc; } - - mwSize get_nzmax (void) const { return nzmax; } - - void set_ir (mwIndex *ir_arg) { ir = ir_arg; } - - void set_jc (mwIndex *jc_arg) { jc = jc_arg; } - - void set_nzmax (mwSize nzmax_arg) { nzmax = nzmax_arg; } - -protected: - - octave_value as_octave_value (void) const - { - octave_value retval; - - dim_vector dv = dims_to_dim_vector (); - - switch (get_class_id ()) - { - case mxLOGICAL_CLASS: - { - bool *ppr = static_cast (pr); - - SparseBoolMatrix val (get_m (), get_n (), - static_cast (nzmax)); - - for (mwIndex i = 0; i < nzmax; i++) - { - val.xdata (i) = ppr[i]; - val.xridx (i) = ir[i]; - } - - for (mwIndex i = 0; i < get_n () + 1; i++) - val.xcidx (i) = jc[i]; - - retval = val; - } - break; - - case mxSINGLE_CLASS: - error ("single precision sparse data type not supported"); - break; - - case mxDOUBLE_CLASS: - { - if (pi) - { - double *ppr = static_cast (pr); - double *ppi = static_cast (pi); - - SparseComplexMatrix val (get_m (), get_n (), - static_cast (nzmax)); - - for (mwIndex i = 0; i < nzmax; i++) - { - val.xdata (i) = Complex (ppr[i], ppi[i]); - val.xridx (i) = ir[i]; - } - - for (mwIndex i = 0; i < get_n () + 1; i++) - val.xcidx (i) = jc[i]; - - retval = val; - } - else - { - double *ppr = static_cast (pr); - - SparseMatrix val (get_m (), get_n (), - static_cast (nzmax)); - - for (mwIndex i = 0; i < nzmax; i++) - { - val.xdata (i) = ppr[i]; - val.xridx (i) = ir[i]; - } - - for (mwIndex i = 0; i < get_n () + 1; i++) - val.xcidx (i) = jc[i]; - - retval = val; - } - } - break; - - default: - panic_impossible (); - } - - return retval; - } - -private: - - mwSize nzmax; - - void *pr; - void *pi; - mwIndex *ir; - mwIndex *jc; - - mxArray_sparse (const mxArray_sparse& val) - : mxArray_matlab (val), nzmax (val.nzmax), - pr (malloc (nzmax * get_element_size ())), - pi (val.pi ? malloc (nzmax * get_element_size ()) : 0), - ir (static_cast (malloc (nzmax * sizeof (mwIndex)))), - jc (static_cast (malloc (nzmax * sizeof (mwIndex)))) - { - size_t nbytes = nzmax * get_element_size (); - - if (pr) - memcpy (pr, val.pr, nbytes); - - if (pi) - memcpy (pi, val.pi, nbytes); - - if (ir) - memcpy (ir, val.ir, nzmax * sizeof (mwIndex)); - - if (jc) - memcpy (jc, val.jc, (val.get_n () + 1) * sizeof (mwIndex)); - } - - // No assignment! FIXME -- should this be implemented? Note that we - // do have a copy constructor. - - mxArray_sparse& operator = (const mxArray_sparse&); -}; - -// Matlab-style struct arrays. - -class mxArray_struct : public mxArray_matlab -{ -public: - - mxArray_struct (mwSize ndims_arg, const mwSize *dims_arg, int num_keys_arg, - const char **keys) - : mxArray_matlab (mxSTRUCT_CLASS, ndims_arg, dims_arg), nfields (num_keys_arg), - fields (static_cast (calloc (nfields, sizeof (char *)))), - data (static_cast (calloc (nfields * get_number_of_elements (), sizeof (mxArray *)))) - { - init (keys); - } - - mxArray_struct (const dim_vector& dv, int num_keys_arg, const char **keys) - : mxArray_matlab (mxSTRUCT_CLASS, dv), nfields (num_keys_arg), - fields (static_cast (calloc (nfields, sizeof (char *)))), - data (static_cast (calloc (nfields * get_number_of_elements (), sizeof (mxArray *)))) - { - init (keys); - } - - mxArray_struct (mwSize m, mwSize n, int num_keys_arg, const char **keys) - : mxArray_matlab (mxSTRUCT_CLASS, m, n), nfields (num_keys_arg), - fields (static_cast (calloc (nfields, sizeof (char *)))), - data (static_cast (calloc (nfields * get_number_of_elements (), sizeof (mxArray *)))) - { - init (keys); - } - - void init (const char **keys) - { - for (int i = 0; i < nfields; i++) - fields[i] = strsave (keys[i]); - } - - mxArray_struct *dup (void) const { return new mxArray_struct (*this); } - - ~mxArray_struct (void) - { - for (int i = 0; i < nfields; i++) - mxFree (fields[i]); - - mxFree (fields); - - mwSize ntot = nfields * get_number_of_elements (); - - for (mwIndex i = 0; i < ntot; i++) - delete data[i]; - - mxFree (data); - } - - int add_field (const char *key) - { - int retval = -1; - - if (valid_key (key)) - { - nfields++; - - fields = static_cast (mxRealloc (fields, nfields * sizeof (char *))); - - if (fields) - { - fields[nfields-1] = strsave (key); - - mwSize nel = get_number_of_elements (); - - mwSize ntot = nfields * nel; - - mxArray **new_data = static_cast (malloc (ntot * sizeof (mxArray *))); - - if (new_data) - { - mwIndex j = 0; - mwIndex k = 0; - mwIndex n = 0; - - for (mwIndex i = 0; i < ntot; i++) - { - if (++n == nfields) - { - new_data[j++] = 0; - n = 0; - } - else - new_data[j++] = data[k++]; - } - - mxFree (data); - - data = new_data; - - retval = nfields - 1; - } - } - } - - return retval; - } - - void remove_field (int key_num) - { - if (key_num >= 0 && key_num < nfields) - { - mwSize nel = get_number_of_elements (); - - mwSize ntot = nfields * nel; - - int new_nfields = nfields - 1; - - char **new_fields = static_cast (malloc (new_nfields * sizeof (char *))); - - mxArray **new_data = static_cast (malloc (new_nfields * nel * sizeof (mxArray *))); - - for (int i = 0; i < key_num; i++) - new_fields[i] = fields[i]; - - for (int i = key_num + 1; i < nfields; i++) - new_fields[i-1] = fields[i]; - - if (new_nfields > 0) - { - mwIndex j = 0; - mwIndex k = 0; - mwIndex n = 0; - - for (mwIndex i = 0; i < ntot; i++) - { - if (n == key_num) - k++; - else - new_data[j++] = data[k++]; - - if (++n == nfields) - n = 0; - } - } - - nfields = new_nfields; - - mxFree (fields); - mxFree (data); - - fields = new_fields; - data = new_data; - } - } - - mxArray *get_field_by_number (mwIndex index, int key_num) const - { - return key_num >= 0 && key_num < nfields - ? data[nfields * index + key_num] : 0; - } - - void set_field_by_number (mwIndex index, int key_num, mxArray *val); - - int get_number_of_fields (void) const { return nfields; } - - const char *get_field_name_by_number (int key_num) const - { - return key_num >= 0 && key_num < nfields ? fields[key_num] : 0; - } - - int get_field_number (const char *key) const - { - int retval = -1; - - for (int i = 0; i < nfields; i++) - { - if (! strcmp (key, fields[i])) - { - retval = i; - break; - } - } - - return retval; - } - - void *get_data (void) const { return data; } - - void set_data (void *data_arg) { data = static_cast (data_arg); } - -protected: - - octave_value as_octave_value (void) const - { - dim_vector dv = dims_to_dim_vector (); - - string_vector keys (fields, nfields); - - octave_map m; - - mwSize ntot = nfields * get_number_of_elements (); - - for (int i = 0; i < nfields; i++) - { - Cell c (dv); - - octave_value *p = c.fortran_vec (); - - mwIndex k = 0; - for (mwIndex j = i; j < ntot; j += nfields) - p[k++] = mxArray::as_octave_value (data[j]); - - m.assign (keys[i], c); - } - - return m; - } - -private: - - int nfields; - - char **fields; - - mxArray **data; - - mxArray_struct (const mxArray_struct& val) - : mxArray_matlab (val), nfields (val.nfields), - fields (static_cast (malloc (nfields * sizeof (char *)))), - data (static_cast (malloc (nfields * get_number_of_elements () * sizeof (mxArray *)))) - { - for (int i = 0; i < nfields; i++) - fields[i] = strsave (val.fields[i]); - - mwSize nel = get_number_of_elements (); - - for (mwIndex i = 0; i < nel * nfields; i++) - { - mxArray *ptr = val.data[i]; - data[i] = ptr ? ptr->dup () : 0; - } - } - - // No assignment! FIXME -- should this be implemented? Note that we - // do have a copy constructor. - - mxArray_struct& operator = (const mxArray_struct& val); -}; - -// Matlab-style cell arrays. - -class mxArray_cell : public mxArray_matlab -{ -public: - - mxArray_cell (mwSize ndims_arg, const mwSize *dims_arg) - : mxArray_matlab (mxCELL_CLASS, ndims_arg, dims_arg), - data (static_cast (calloc (get_number_of_elements (), sizeof (mxArray *)))) { } - - mxArray_cell (const dim_vector& dv) - : mxArray_matlab (mxCELL_CLASS, dv), - data (static_cast (calloc (get_number_of_elements (), sizeof (mxArray *)))) { } - - mxArray_cell (mwSize m, mwSize n) - : mxArray_matlab (mxCELL_CLASS, m, n), - data (static_cast (calloc (get_number_of_elements (), sizeof (mxArray *)))) { } - - mxArray_cell *dup (void) const { return new mxArray_cell (*this); } - - ~mxArray_cell (void) - { - mwSize nel = get_number_of_elements (); - - for (mwIndex i = 0; i < nel; i++) - delete data[i]; - - mxFree (data); - } - - mxArray *get_cell (mwIndex idx) const - { - return idx >= 0 && idx < get_number_of_elements () ? data[idx] : 0; - } - - void set_cell (mwIndex idx, mxArray *val); - - void *get_data (void) const { return data; } - - void set_data (void *data_arg) { data = static_cast (data_arg); } - -protected: - - octave_value as_octave_value (void) const - { - dim_vector dv = dims_to_dim_vector (); - - Cell c (dv); - - mwSize nel = get_number_of_elements (); - - octave_value *p = c.fortran_vec (); - - for (mwIndex i = 0; i < nel; i++) - p[i] = mxArray::as_octave_value (data[i]); - - return c; - } - -private: - - mxArray **data; - - mxArray_cell (const mxArray_cell& val) - : mxArray_matlab (val), - data (static_cast (malloc (get_number_of_elements () * sizeof (mxArray *)))) - { - mwSize nel = get_number_of_elements (); - - for (mwIndex i = 0; i < nel; i++) - { - mxArray *ptr = val.data[i]; - data[i] = ptr ? ptr->dup () : 0; - } - } - - // No assignment! FIXME -- should this be implemented? Note that we - // do have a copy constructor. - - mxArray_cell& operator = (const mxArray_cell&); -}; - -// ------------------------------------------------------------------ - -mxArray::mxArray (const octave_value& ov) - : rep (new mxArray_octave_value (ov)), name (0) { } - -mxArray::mxArray (mxClassID id, mwSize ndims, const mwSize *dims, mxComplexity flag) - : rep (new mxArray_number (id, ndims, dims, flag)), name (0) { } - -mxArray::mxArray (mxClassID id, const dim_vector& dv, mxComplexity flag) - : rep (new mxArray_number (id, dv, flag)), name (0) { } - -mxArray::mxArray (mxClassID id, mwSize m, mwSize n, mxComplexity flag) - : rep (new mxArray_number (id, m, n, flag)), name (0) { } - -mxArray::mxArray (mxClassID id, double val) - : rep (new mxArray_number (id, val)), name (0) { } - -mxArray::mxArray (mxClassID id, mxLogical val) - : rep (new mxArray_number (id, val)), name (0) { } - -mxArray::mxArray (const char *str) - : rep (new mxArray_number (str)), name (0) { } - -mxArray::mxArray (mwSize m, const char **str) - : rep (new mxArray_number (m, str)), name (0) { } - -mxArray::mxArray (mxClassID id, mwSize m, mwSize n, mwSize nzmax, mxComplexity flag) - : rep (new mxArray_sparse (id, m, n, nzmax, flag)), name (0) { } - -mxArray::mxArray (mwSize ndims, const mwSize *dims, int num_keys, const char **keys) - : rep (new mxArray_struct (ndims, dims, num_keys, keys)), name (0) { } - -mxArray::mxArray (const dim_vector& dv, int num_keys, const char **keys) - : rep (new mxArray_struct (dv, num_keys, keys)), name (0) { } - -mxArray::mxArray (mwSize m, mwSize n, int num_keys, const char **keys) - : rep (new mxArray_struct (m, n, num_keys, keys)), name (0) { } - -mxArray::mxArray (mwSize ndims, const mwSize *dims) - : rep (new mxArray_cell (ndims, dims)), name (0) { } - -mxArray::mxArray (const dim_vector& dv) - : rep (new mxArray_cell (dv)), name (0) { } - -mxArray::mxArray (mwSize m, mwSize n) - : rep (new mxArray_cell (m, n)), name (0) { } - -mxArray::~mxArray (void) -{ - mxFree (name); - - delete rep; -} - -void -mxArray::set_name (const char *name_arg) -{ - mxFree (name); - name = strsave (name_arg); -} - -octave_value -mxArray::as_octave_value (mxArray *ptr) -{ - return ptr ? ptr->as_octave_value () : octave_value (Matrix ()); -} - -octave_value -mxArray::as_octave_value (void) const -{ - return rep->as_octave_value (); -} - -void -mxArray::maybe_mutate (void) const -{ - if (rep->is_octave_value ()) - { - // The mutate function returns a pointer to a complete new - // mxArray object (or 0, if no mutation happened). We just want - // to replace the existing rep with the rep from the new object. - - mxArray *new_val = rep->mutate (); - - if (new_val) - { - delete rep; - rep = new_val->rep; - new_val->rep = 0; - delete new_val; - } - } -} - -// ------------------------------------------------------------------ - -// A class to manage calls to MEX functions. Mostly deals with memory -// management. - -class mex -{ -public: - - mex (octave_mex_function *f) - : curr_mex_fcn (f), memlist (), arraylist (), fname (0) { } - - ~mex (void) - { - if (! memlist.empty ()) - error ("mex: %s: cleanup failed", function_name ()); - - mxFree (fname); - } - - const char *function_name (void) const - { - if (! fname) - { - octave_function *fcn = octave_call_stack::current (); - - if (fcn) - { - std::string nm = fcn->name (); - fname = mxArray::strsave (nm.c_str ()); - } - else - fname = mxArray::strsave ("unknown"); - } - - return fname; - } - - // Free all unmarked pointers obtained from malloc and calloc. - static void cleanup (void *ptr) - { - mex *context = static_cast (ptr); - - // We can't use mex::free here because it modifies memlist. - for (std::set::iterator p = context->memlist.begin (); - p != context->memlist.end (); p++) - xfree (*p); - - context->memlist.clear (); - - // We can't use mex::free_value here because it modifies arraylist. - for (std::set::iterator p = context->arraylist.begin (); - p != context->arraylist.end (); p++) - delete *p; - - context->arraylist.clear (); - } - - // Allocate memory. - void *malloc_unmarked (size_t n) - { - void *ptr = gnulib::malloc (n); - - if (! ptr) - { - // FIXME -- could use "octave_new_handler();" instead - - error ("%s: failed to allocate %d bytes of memory", - function_name (), n); - - abort (); - } - - global_mark (ptr); - - return ptr; - } - - // Allocate memory to be freed on exit. - void *malloc (size_t n) - { - void *ptr = malloc_unmarked (n); - - mark (ptr); - - return ptr; - } - - // Allocate memory and initialize to 0. - void *calloc_unmarked (size_t n, size_t t) - { - void *ptr = malloc_unmarked (n*t); - - memset (ptr, 0, n*t); - - return ptr; - } - - // Allocate memory to be freed on exit and initialize to 0. - void *calloc (size_t n, size_t t) - { - void *ptr = calloc_unmarked (n, t); - - mark (ptr); - - return ptr; - } - - // Reallocate a pointer obtained from malloc or calloc. If the - // pointer is NULL, allocate using malloc. We don't need an - // "unmarked" version of this. - void *realloc (void *ptr, size_t n) - { - void *v; - - if (ptr) - { - v = gnulib::realloc (ptr, n); - - std::set::iterator p = memlist.find (ptr); - - if (v && p != memlist.end ()) - { - memlist.erase (p); - memlist.insert (v); - } - - p = global_memlist.find (ptr); - - if (v && p != global_memlist.end ()) - { - global_memlist.erase (p); - global_memlist.insert (v); - } - } - else - v = malloc (n); - - return v; - } - - // Free a pointer obtained from malloc or calloc. - void free (void *ptr) - { - if (ptr) - { - unmark (ptr); - - std::set::iterator p = global_memlist.find (ptr); - - if (p != global_memlist.end ()) - { - global_memlist.erase (p); - - xfree (ptr); - } - else - { - p = foreign_memlist.find (ptr); - - if (p != foreign_memlist.end ()) - foreign_memlist.erase (p); -#ifdef DEBUG - else - warning ("mxFree: skipping memory not allocated by mxMalloc, mxCalloc, or mxRealloc"); -#endif - } - } - } - - // Mark a pointer to be freed on exit. - void mark (void *ptr) - { -#ifdef DEBUG - if (memlist.find (ptr) != memlist.end ()) - warning ("%s: double registration ignored", function_name ()); -#endif - - memlist.insert (ptr); - } - - // Unmark a pointer to be freed on exit, either because it was - // made persistent, or because it was already freed. - void unmark (void *ptr) - { - std::set::iterator p = memlist.find (ptr); - - if (p != memlist.end ()) - memlist.erase (p); -#ifdef DEBUG - else - warning ("%s: value not marked", function_name ()); -#endif - } - - mxArray *mark_array (mxArray *ptr) - { - arraylist.insert (ptr); - return ptr; - } - - void unmark_array (mxArray *ptr) - { - std::set::iterator p = arraylist.find (ptr); - - if (p != arraylist.end ()) - arraylist.erase (p); - } - - // Mark a pointer as one we allocated. - void mark_foreign (void *ptr) - { -#ifdef DEBUG - if (foreign_memlist.find (ptr) != foreign_memlist.end ()) - warning ("%s: double registration ignored", function_name ()); -#endif - - foreign_memlist.insert (ptr); - } - - // Unmark a pointer as one we allocated. - void unmark_foreign (void *ptr) - { - std::set::iterator p = foreign_memlist.find (ptr); - - if (p != foreign_memlist.end ()) - foreign_memlist.erase (p); -#ifdef DEBUG - else - warning ("%s: value not marked", function_name ()); -#endif - - } - - // Make a new array value and initialize from an octave value; it will be - // freed on exit unless marked as persistent. - mxArray *make_value (const octave_value& ov) - { - return mark_array (new mxArray (ov)); - } - - // Free an array and its contents. - bool free_value (mxArray *ptr) - { - bool inlist = false; - - std::set::iterator p = arraylist.find (ptr); - - if (p != arraylist.end ()) - { - inlist = true; - arraylist.erase (p); - delete ptr; - } -#ifdef DEBUG - else - warning ("mex::free_value: skipping memory not allocated by mex::make_value"); -#endif - - return inlist; - } - - octave_mex_function *current_mex_function (void) const - { - return curr_mex_fcn; - } - - // 1 if error should be returned to MEX file, 0 if abort. - int trap_feval_error; - - // longjmp return point if mexErrMsgTxt or error. - jmp_buf jump; - - // Trigger a long jump back to the mex calling function. - void abort (void) { longjmp (jump, 1); } - -private: - - // Pointer to the mex function that corresponds to this mex context. - octave_mex_function *curr_mex_fcn; - - // List of memory resources that need to be freed upon exit. - std::set memlist; - - // List of mxArray objects that need to be freed upon exit. - std::set arraylist; - - // List of memory resources we know about, but that were allocated - // elsewhere. - std::set foreign_memlist; - - // The name of the currently executing function. - mutable char *fname; - - // List of memory resources we allocated. - static std::set global_memlist; - - // Mark a pointer as one we allocated. - void global_mark (void *ptr) - { -#ifdef DEBUG - if (global_memlist.find (ptr) != global_memlist.end ()) - warning ("%s: double registration ignored", function_name ()); -#endif - - global_memlist.insert (ptr); - } - - // Unmark a pointer as one we allocated. - void global_unmark (void *ptr) - { - std::set::iterator p = global_memlist.find (ptr); - - if (p != global_memlist.end ()) - global_memlist.erase (p); -#ifdef DEBUG - else - warning ("%s: value not marked", function_name ()); -#endif - - } - - // No copying! - - mex (const mex&); - - mex& operator = (const mex&); -}; - -// List of memory resources we allocated. -std::set mex::global_memlist; - -// Current context. -mex *mex_context = 0; - -void * -mxArray::malloc (size_t n) -{ - return mex_context ? mex_context->malloc_unmarked (n) : gnulib::malloc (n); -} - -void * -mxArray::calloc (size_t n, size_t t) -{ - return mex_context ? mex_context->calloc_unmarked (n, t) : ::calloc (n, t); -} - -static inline void * -maybe_mark_foreign (void *ptr) -{ - if (mex_context) - mex_context->mark_foreign (ptr); - - return ptr; -} - -static inline mxArray * -maybe_unmark_array (mxArray *ptr) -{ - if (mex_context) - mex_context->unmark_array (ptr); - - return ptr; -} - -static inline void * -maybe_unmark (void *ptr) -{ - if (mex_context) - mex_context->unmark (ptr); - - return ptr; -} - -void -mxArray_struct::set_field_by_number (mwIndex index, int key_num, mxArray *val) -{ - if (key_num >= 0 && key_num < nfields) - data[nfields * index + key_num] = maybe_unmark_array (val); -} - -void -mxArray_cell::set_cell (mwIndex idx, mxArray *val) -{ - if (idx >= 0 && idx < get_number_of_elements ()) - data[idx] = maybe_unmark_array (val); -} - -// ------------------------------------------------------------------ - -// C interface to mxArray objects: - -// Floating point predicates. - -int -mxIsFinite (const double v) -{ - return lo_ieee_finite (v) != 0; -} - -int -mxIsInf (const double v) -{ - return lo_ieee_isinf (v) != 0; -} - -int -mxIsNaN (const double v) -{ - return lo_ieee_isnan (v) != 0; -} - -double -mxGetEps (void) -{ - return DBL_EPSILON; -} - -double -mxGetInf (void) -{ - return lo_ieee_inf_value (); -} - -double -mxGetNaN (void) -{ - return lo_ieee_nan_value (); -} - -// Memory management. -void * -mxCalloc (size_t n, size_t size) -{ - return mex_context ? mex_context->calloc (n, size) : calloc (n, size); -} - -void * -mxMalloc (size_t n) -{ - return mex_context ? mex_context->malloc (n) : gnulib::malloc (n); -} - -void * -mxRealloc (void *ptr, size_t size) -{ - return mex_context ? mex_context->realloc (ptr, size) : gnulib::realloc (ptr, size); -} - -void -mxFree (void *ptr) -{ - if (mex_context) - mex_context->free (ptr); - else - xfree (ptr); -} - -static inline mxArray * -maybe_mark_array (mxArray *ptr) -{ - return mex_context ? mex_context->mark_array (ptr) : ptr; -} - -// Constructors. -mxArray * -mxCreateCellArray (mwSize ndims, const mwSize *dims) -{ - return maybe_mark_array (new mxArray (ndims, dims)); -} - -mxArray * -mxCreateCellMatrix (mwSize m, mwSize n) -{ - return maybe_mark_array (new mxArray (m, n)); -} - -mxArray * -mxCreateCharArray (mwSize ndims, const mwSize *dims) -{ - return maybe_mark_array (new mxArray (mxCHAR_CLASS, ndims, dims)); -} - -mxArray * -mxCreateCharMatrixFromStrings (mwSize m, const char **str) -{ - return maybe_mark_array (new mxArray (m, str)); -} - -mxArray * -mxCreateDoubleMatrix (mwSize m, mwSize n, mxComplexity flag) -{ - return maybe_mark_array (new mxArray (mxDOUBLE_CLASS, m, n, flag)); -} - -mxArray * -mxCreateDoubleScalar (double val) -{ - return maybe_mark_array (new mxArray (mxDOUBLE_CLASS, val)); -} - -mxArray * -mxCreateLogicalArray (mwSize ndims, const mwSize *dims) -{ - return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, ndims, dims)); -} - -mxArray * -mxCreateLogicalMatrix (mwSize m, mwSize n) -{ - return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, m, n)); -} - -mxArray * -mxCreateLogicalScalar (mxLogical val) -{ - return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, val)); -} - -mxArray * -mxCreateNumericArray (mwSize ndims, const mwSize *dims, mxClassID class_id, - mxComplexity flag) -{ - return maybe_mark_array (new mxArray (class_id, ndims, dims, flag)); -} - -mxArray * -mxCreateNumericMatrix (mwSize m, mwSize n, mxClassID class_id, mxComplexity flag) -{ - return maybe_mark_array (new mxArray (class_id, m, n, flag)); -} - -mxArray * -mxCreateSparse (mwSize m, mwSize n, mwSize nzmax, mxComplexity flag) -{ - return maybe_mark_array (new mxArray (mxDOUBLE_CLASS, m, n, nzmax, flag)); -} - -mxArray * -mxCreateSparseLogicalMatrix (mwSize m, mwSize n, mwSize nzmax) -{ - return maybe_mark_array (new mxArray (mxLOGICAL_CLASS, m, n, nzmax)); -} - -mxArray * -mxCreateString (const char *str) -{ - return maybe_mark_array (new mxArray (str)); -} - -mxArray * -mxCreateStructArray (mwSize ndims, const mwSize *dims, int num_keys, const char **keys) -{ - return maybe_mark_array (new mxArray (ndims, dims, num_keys, keys)); -} - -mxArray * -mxCreateStructMatrix (mwSize m, mwSize n, int num_keys, const char **keys) -{ - return maybe_mark_array (new mxArray (m, n, num_keys, keys)); -} - -// Copy constructor. -mxArray * -mxDuplicateArray (const mxArray *ptr) -{ - return maybe_mark_array (ptr->dup ()); -} - -// Destructor. -void -mxDestroyArray (mxArray *ptr) -{ - if (! (mex_context && mex_context->free_value (ptr))) - delete ptr; -} - -// Type Predicates. -int -mxIsCell (const mxArray *ptr) -{ - return ptr->is_cell (); -} - -int -mxIsChar (const mxArray *ptr) -{ - return ptr->is_char (); -} - -int -mxIsClass (const mxArray *ptr, const char *name) -{ - return ptr->is_class (name); -} - -int -mxIsComplex (const mxArray *ptr) -{ - return ptr->is_complex (); -} - -int -mxIsDouble (const mxArray *ptr) -{ - return ptr->is_double (); -} - -int -mxIsFunctionHandle (const mxArray *ptr) -{ - return ptr->is_function_handle (); -} - -int -mxIsInt16 (const mxArray *ptr) -{ - return ptr->is_int16 (); -} - -int -mxIsInt32 (const mxArray *ptr) -{ - return ptr->is_int32 (); -} - -int -mxIsInt64 (const mxArray *ptr) -{ - return ptr->is_int64 (); -} - -int -mxIsInt8 (const mxArray *ptr) -{ - return ptr->is_int8 (); -} - -int -mxIsLogical (const mxArray *ptr) -{ - return ptr->is_logical (); -} - -int -mxIsNumeric (const mxArray *ptr) -{ - return ptr->is_numeric (); -} - -int -mxIsSingle (const mxArray *ptr) -{ - return ptr->is_single (); -} - -int -mxIsSparse (const mxArray *ptr) -{ - return ptr->is_sparse (); -} - -int -mxIsStruct (const mxArray *ptr) -{ - return ptr->is_struct (); -} - -int -mxIsUint16 (const mxArray *ptr) -{ - return ptr->is_uint16 (); -} - -int -mxIsUint32 (const mxArray *ptr) -{ - return ptr->is_uint32 (); -} - -int -mxIsUint64 (const mxArray *ptr) -{ - return ptr->is_uint64 (); -} - -int -mxIsUint8 (const mxArray *ptr) -{ - return ptr->is_uint8 (); -} - -// Odd type+size predicate. -int -mxIsLogicalScalar (const mxArray *ptr) -{ - return ptr->is_logical_scalar (); -} - -// Odd type+size+value predicate. -int -mxIsLogicalScalarTrue (const mxArray *ptr) -{ - return ptr->is_logical_scalar_true (); -} - -// Size predicate. -int -mxIsEmpty (const mxArray *ptr) -{ - return ptr->is_empty (); -} - -// Just plain odd thing to ask of a value. -int -mxIsFromGlobalWS (const mxArray */*ptr*/) -{ - // FIXME - abort (); - return 0; -} - -// Dimension extractors. -size_t -mxGetM (const mxArray *ptr) -{ - return ptr->get_m (); -} - -size_t -mxGetN (const mxArray *ptr) -{ - return ptr->get_n (); -} - -mwSize * -mxGetDimensions (const mxArray *ptr) -{ - return ptr->get_dimensions (); -} - -mwSize -mxGetNumberOfDimensions (const mxArray *ptr) -{ - return ptr->get_number_of_dimensions (); -} - -size_t -mxGetNumberOfElements (const mxArray *ptr) -{ - return ptr->get_number_of_elements (); -} - -// Dimension setters. -void -mxSetM (mxArray *ptr, mwSize m) -{ - ptr->set_m (m); -} - -void -mxSetN (mxArray *ptr, mwSize n) -{ - ptr->set_n (n); -} - -void -mxSetDimensions (mxArray *ptr, const mwSize *dims, mwSize ndims) -{ - ptr->set_dimensions (static_cast ( - maybe_unmark (const_cast (dims))), - ndims); -} - -// Data extractors. -double * -mxGetPr (const mxArray *ptr) -{ - return static_cast (ptr->get_data ()); -} - -double * -mxGetPi (const mxArray *ptr) -{ - return static_cast (ptr->get_imag_data ()); -} - -double -mxGetScalar (const mxArray *ptr) -{ - return ptr->get_scalar (); -} - -mxChar * -mxGetChars (const mxArray *ptr) -{ - return static_cast (ptr->get_data ()); -} - -mxLogical * -mxGetLogicals (const mxArray *ptr) -{ - return static_cast (ptr->get_data ()); -} - -void * -mxGetData (const mxArray *ptr) -{ - return ptr->get_data (); -} - -void * -mxGetImagData (const mxArray *ptr) -{ - return ptr->get_imag_data (); -} - -// Data setters. -void -mxSetPr (mxArray *ptr, double *pr) -{ - ptr->set_data (maybe_unmark (pr)); -} - -void -mxSetPi (mxArray *ptr, double *pi) -{ - ptr->set_imag_data (maybe_unmark (pi)); -} - -void -mxSetData (mxArray *ptr, void *pr) -{ - ptr->set_data (maybe_unmark (pr)); -} - -void -mxSetImagData (mxArray *ptr, void *pi) -{ - ptr->set_imag_data (maybe_unmark (pi)); -} - -// Classes. -mxClassID -mxGetClassID (const mxArray *ptr) -{ - return ptr->get_class_id (); -} - -const char * -mxGetClassName (const mxArray *ptr) -{ - return ptr->get_class_name (); -} - -void -mxSetClassName (mxArray *ptr, const char *name) -{ - ptr->set_class_name (name); -} - -// Cell support. -mxArray * -mxGetCell (const mxArray *ptr, mwIndex idx) -{ - return ptr->get_cell (idx); -} - -void -mxSetCell (mxArray *ptr, mwIndex idx, mxArray *val) -{ - ptr->set_cell (idx, val); -} - -// Sparse support. -mwIndex * -mxGetIr (const mxArray *ptr) -{ - return ptr->get_ir (); -} - -mwIndex * -mxGetJc (const mxArray *ptr) -{ - return ptr->get_jc (); -} - -mwSize -mxGetNzmax (const mxArray *ptr) -{ - return ptr->get_nzmax (); -} - -void -mxSetIr (mxArray *ptr, mwIndex *ir) -{ - ptr->set_ir (static_cast (maybe_unmark (ir))); -} - -void -mxSetJc (mxArray *ptr, mwIndex *jc) -{ - ptr->set_jc (static_cast (maybe_unmark (jc))); -} - -void -mxSetNzmax (mxArray *ptr, mwSize nzmax) -{ - ptr->set_nzmax (nzmax); -} - -// Structure support. -int -mxAddField (mxArray *ptr, const char *key) -{ - return ptr->add_field (key); -} - -void -mxRemoveField (mxArray *ptr, int key_num) -{ - ptr->remove_field (key_num); -} - -mxArray * -mxGetField (const mxArray *ptr, mwIndex index, const char *key) -{ - int key_num = mxGetFieldNumber (ptr, key); - return mxGetFieldByNumber (ptr, index, key_num); -} - -mxArray * -mxGetFieldByNumber (const mxArray *ptr, mwIndex index, int key_num) -{ - return ptr->get_field_by_number (index, key_num); -} - -void -mxSetField (mxArray *ptr, mwIndex index, const char *key, mxArray *val) -{ - int key_num = mxGetFieldNumber (ptr, key); - mxSetFieldByNumber (ptr, index, key_num, val); -} - -void -mxSetFieldByNumber (mxArray *ptr, mwIndex index, int key_num, mxArray *val) -{ - ptr->set_field_by_number (index, key_num, val); -} - -int -mxGetNumberOfFields (const mxArray *ptr) -{ - return ptr->get_number_of_fields (); -} - -const char * -mxGetFieldNameByNumber (const mxArray *ptr, int key_num) -{ - return ptr->get_field_name_by_number (key_num); -} - -int -mxGetFieldNumber (const mxArray *ptr, const char *key) -{ - return ptr->get_field_number (key); -} - -int -mxGetString (const mxArray *ptr, char *buf, mwSize buflen) -{ - return ptr->get_string (buf, buflen); -} - -char * -mxArrayToString (const mxArray *ptr) -{ - return ptr->array_to_string (); -} - -mwIndex -mxCalcSingleSubscript (const mxArray *ptr, mwSize nsubs, mwIndex *subs) -{ - return ptr->calc_single_subscript (nsubs, subs); -} - -size_t -mxGetElementSize (const mxArray *ptr) -{ - return ptr->get_element_size (); -} - -// ------------------------------------------------------------------ - -typedef void (*cmex_fptr) (int nlhs, mxArray **plhs, int nrhs, mxArray **prhs); -typedef F77_RET_T (*fmex_fptr) (int& nlhs, mxArray **plhs, int& nrhs, mxArray **prhs); - -octave_value_list -call_mex (bool have_fmex, void *f, const octave_value_list& args, - int nargout_arg, octave_mex_function *curr_mex_fcn) -{ - // Use at least 1 for nargout since even for zero specified args, - // still want to be able to return an ans. - - volatile int nargout = nargout_arg; - - int nargin = args.length (); - OCTAVE_LOCAL_BUFFER (mxArray *, argin, nargin); - for (int i = 0; i < nargin; i++) - argin[i] = 0; - - int nout = nargout == 0 ? 1 : nargout; - OCTAVE_LOCAL_BUFFER (mxArray *, argout, nout); - for (int i = 0; i < nout; i++) - argout[i] = 0; - - unwind_protect_safe frame; - - // Save old mex pointer. - frame.protect_var (mex_context); - - mex context (curr_mex_fcn); - - frame.add (mex::cleanup, static_cast (&context)); - - for (int i = 0; i < nargin; i++) - argin[i] = context.make_value (args(i)); - - if (setjmp (context.jump) == 0) - { - mex_context = &context; - - if (have_fmex) - { - fmex_fptr fcn = FCN_PTR_CAST (fmex_fptr, f); - - int tmp_nargout = nargout; - int tmp_nargin = nargin; - - fcn (tmp_nargout, argout, tmp_nargin, argin); - } - else - { - cmex_fptr fcn = FCN_PTR_CAST (cmex_fptr, f); - - fcn (nargout, argout, nargin, argin); - } - } - - // Convert returned array entries back into octave values. - - octave_value_list retval; - - if (! error_state) - { - if (nargout == 0 && argout[0]) - { - // We have something for ans. - nargout = 1; - } - - retval.resize (nargout); - - for (int i = 0; i < nargout; i++) - retval(i) = mxArray::as_octave_value (argout[i]); - } - - // Clean up mex resources. - frame.run (); - - return retval; -} - -// C interface to mex functions: - -const char * -mexFunctionName (void) -{ - return mex_context ? mex_context->function_name () : "unknown"; -} - -int -mexCallMATLAB (int nargout, mxArray *argout[], int nargin, mxArray *argin[], - const char *fname) -{ - octave_value_list args; - - // FIXME -- do we need unwind protect to clean up args? Off hand, I - // would say that this problem is endemic to Octave and we will - // continue to have memory leaks after Ctrl-C until proper exception - // handling is implemented. longjmp() only clears the stack, so any - // class which allocates data on the heap is going to leak. - - args.resize (nargin); - - for (int i = 0; i < nargin; i++) - args(i) = mxArray::as_octave_value (argin[i]); - - octave_value_list retval = feval (fname, args, nargout); - - if (error_state && mex_context->trap_feval_error == 0) - { - // FIXME -- is this the correct way to clean up? abort() is - // going to trigger a long jump, so the normal class destructors - // will not be called. Hopefully this will reduce things to a - // tiny leak. Maybe create a new octave memory tracer type - // which prints a friendly message every time it is - // created/copied/deleted to check this. - - args.resize (0); - retval.resize (0); - mex_context->abort (); - } - - int num_to_copy = retval.length (); - - if (nargout < retval.length ()) - num_to_copy = nargout; - - for (int i = 0; i < num_to_copy; i++) - { - // FIXME -- it would be nice to avoid copying the value here, - // but there is no way to steal memory from a matrix, never mind - // that matrix memory is allocated by new[] and mxArray memory - // is allocated by malloc(). - argout[i] = mex_context->make_value (retval (i)); - } - - while (num_to_copy < nargout) - argout[num_to_copy++] = 0; - - if (error_state) - { - error_state = 0; - return 1; - } - else - return 0; -} - -void -mexSetTrapFlag (int flag) -{ - if (mex_context) - mex_context->trap_feval_error = flag; -} - -int -mexEvalString (const char *s) -{ - int retval = 0; - - int parse_status; - - octave_value_list ret; - - ret = eval_string (s, false, parse_status, 0); - - if (parse_status || error_state) - { - error_state = 0; - - retval = 1; - } - - return retval; -} - -void -mexErrMsgTxt (const char *s) -{ - if (s && strlen (s) > 0) - error ("%s: %s", mexFunctionName (), s); - else - // Just set the error state; don't print msg. - error (""); - - mex_context->abort (); -} - -void -mexErrMsgIdAndTxt (const char *id, const char *fmt, ...) -{ - if (fmt && strlen (fmt) > 0) - { - const char *fname = mexFunctionName (); - size_t len = strlen (fname) + 2 + strlen (fmt) + 1; - OCTAVE_LOCAL_BUFFER (char, tmpfmt, len); - sprintf (tmpfmt, "%s: %s", fname, fmt); - va_list args; - va_start (args, fmt); - verror_with_id (id, tmpfmt, args); - va_end (args); - } - else - // Just set the error state; don't print msg. - error (""); - - mex_context->abort (); -} - -void -mexWarnMsgTxt (const char *s) -{ - warning ("%s", s); -} - -void -mexWarnMsgIdAndTxt (const char *id, const char *fmt, ...) -{ - // FIXME -- is this right? What does Matlab do if fmt is NULL or - // an empty string? - - if (fmt && strlen (fmt) > 0) - { - const char *fname = mexFunctionName (); - size_t len = strlen (fname) + 2 + strlen (fmt) + 1; - OCTAVE_LOCAL_BUFFER (char, tmpfmt, len); - sprintf (tmpfmt, "%s: %s", fname, fmt); - va_list args; - va_start (args, fmt); - vwarning_with_id (id, tmpfmt, args); - va_end (args); - } -} - -int -mexPrintf (const char *fmt, ...) -{ - int retval; - va_list args; - va_start (args, fmt); - retval = octave_vformat (octave_stdout, fmt, args); - va_end (args); - return retval; -} - -mxArray * -mexGetVariable (const char *space, const char *name) -{ - mxArray *retval = 0; - - octave_value val; - - if (! strcmp (space, "global")) - val = get_global_value (name); - else - { - // FIXME -- should this be in variables.cc? - - unwind_protect frame; - - bool caller = ! strcmp (space, "caller"); - bool base = ! strcmp (space, "base"); - - if (caller || base) - { - if (caller) - octave_call_stack::goto_caller_frame (); - else - octave_call_stack::goto_base_frame (); - - if (! error_state) - frame.add_fcn (octave_call_stack::pop); - - val = symbol_table::varval (name); - } - else - mexErrMsgTxt ("mexGetVariable: symbol table does not exist"); - } - - if (val.is_defined ()) - { - retval = mex_context->make_value (val); - - retval->set_name (name); - } - - return retval; -} - -const mxArray * -mexGetVariablePtr (const char *space, const char *name) -{ - return mexGetVariable (space, name); -} - -int -mexPutVariable (const char *space, const char *name, mxArray *ptr) -{ - if (! ptr) - return 1; - - if (! name) - return 1; - - if (name[0] == '\0') - name = ptr->get_name (); - - if (! name || name[0] == '\0') - return 1; - - if (! strcmp (space, "global")) - set_global_value (name, mxArray::as_octave_value (ptr)); - else - { - // FIXME -- should this be in variables.cc? - - unwind_protect frame; - - bool caller = ! strcmp (space, "caller"); - bool base = ! strcmp (space, "base"); - - if (caller || base) - { - if (caller) - octave_call_stack::goto_caller_frame (); - else - octave_call_stack::goto_base_frame (); - - if (! error_state) - frame.add_fcn (octave_call_stack::pop); - - symbol_table::varref (name) = mxArray::as_octave_value (ptr); - } - else - mexErrMsgTxt ("mexPutVariable: symbol table does not exist"); - } - - return 0; -} - -void -mexMakeArrayPersistent (mxArray *ptr) -{ - maybe_unmark_array (ptr); -} - -void -mexMakeMemoryPersistent (void *ptr) -{ - maybe_unmark (ptr); -} - -int -mexAtExit (void (*f) (void)) -{ - if (mex_context) - { - octave_mex_function *curr_mex_fcn = mex_context->current_mex_function (); - - assert (curr_mex_fcn); - - curr_mex_fcn->atexit (f); - } - - return 0; -} - -const mxArray * -mexGet (double handle, const char *property) -{ - mxArray *m = 0; - octave_value ret = get_property_from_handle (handle, property, "mexGet"); - - if (!error_state && ret.is_defined ()) - m = ret.as_mxArray (); - return m; -} - -int -mexIsGlobal (const mxArray *ptr) -{ - return mxIsFromGlobalWS (ptr); -} - -int -mexIsLocked (void) -{ - int retval = 0; - - if (mex_context) - { - const char *fname = mexFunctionName (); - - retval = mislocked (fname); - } - - return retval; -} - -std::map mex_lock_count; - -void -mexLock (void) -{ - if (mex_context) - { - const char *fname = mexFunctionName (); - - if (mex_lock_count.find (fname) == mex_lock_count.end ()) - mex_lock_count[fname] = 1; - else - mex_lock_count[fname]++; - - mlock (); - } -} - -int -mexSet (double handle, const char *property, mxArray *val) -{ - bool ret = - set_property_in_handle (handle, property, mxArray::as_octave_value (val), - "mexSet"); - return (ret ? 0 : 1); -} - -void -mexUnlock (void) -{ - if (mex_context) - { - const char *fname = mexFunctionName (); - - std::map::iterator p = mex_lock_count.find (fname); - - if (p != mex_lock_count.end ()) - { - int count = --mex_lock_count[fname]; - - if (count == 0) - { - munlock (fname); - - mex_lock_count.erase (p); - } - } - } -} diff -r a132d206a36a -r b9b6a310ad97 src/mex.h --- a/src/mex.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,175 +0,0 @@ -/* - -Copyright (C) 2001-2012 Paul Kienzle - -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 -. - -*/ - -/* - -This code was originally distributed as part of Octave Forge under -the following terms: - -Author: Paul Kienzle -I grant this code to the public domain. -2001-03-22 - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - -*/ - -/* mex.h is for use in C-programs only; do NOT include it in mex.cc */ - -#if ! defined (MEX_H) -#define MEX_H - -#define HAVE_OCTAVE - -typedef void mxArray; - -#if ! defined (__cplusplus) -typedef int bool; -#endif - -/* -V4 stuff */ -#if defined (V4) -#define Matrix mxArray -#define REAL mxREAL -#endif - -#define mxMAXNAME 64 - -#if defined (__cplusplus) -extern "C" { -#endif - -#if defined (V4) -void mexFunction (int nlhs, mxArray* plhs[], int nrhs, mxArray *prhs[]); -#else -void mexFunction (int nlhs, mxArray* plhs[], int nrhs, const mxArray *prhs[]); -#endif - -#include "mexproto.h" - -/* V4 floating point routines renamed in V5. */ -#define mexIsNaN mxIsNaN -#define mexIsFinite mxIsFinite -#define mexIsInf mxIsInf -#define mexGetEps mxGetEps -#define mexGetInf mxGetInf -#define mexGetNaN mxGetNan - -#define mexGetGlobal(nm) mexGetArray (nm, "global") -#define mexGetMatrix(nm) mexGetArray (nm, "caller") -#define mexGetMatrixPtr(nm) mexGetArrayPtr (nm, "caller") - -#define mexGetArray(nm, space) mexGetVariable (space, nm) -#define mexGetArrayPtr(nm, space) mexGetVariablePtr (space, nm) - -#define mexPutMatrix(ptr) mexPutVariable ("caller", "", ptr) -#define mexPutArray(ptr, space) mexPutVariable (space, "", ptr) - -#define mxCreateFull mxCreateDoubleMatrix - -#define mxCreateScalarDouble mxCreateDoubleScalar - -#define mxFreeMatrix mxDestroyArray - -#define mxIsString mxIsChar - -/* Apparently these are also defined. */ - -#ifndef UINT64_T -#define UINT64_T uint64_t -#endif - -#ifndef uint64_T -#define uint64_T uint64_t -#endif - -#ifndef INT64_T -#define INT64_T int64_t -#endif - -#ifndef int64_T -#define int64_T int64_t -#endif - -#ifndef UINT32_T -#define UINT32_T uint32_t -#endif - -#ifndef uint32_T -#define uint32_T uint32_t -#endif - -#ifndef INT32_T -#define INT32_T int32_t -#endif - -#ifndef int32_T -#define int32_T int32_t -#endif - -#ifndef UINT16_T -#define UINT16_T uint16_t -#endif - -#ifndef uint16_T -#define uint16_T uint16_t -#endif - -#ifndef INT16_T -#define INT16_T int16_t -#endif - -#ifndef int16_T -#define int16_T int16_t -#endif - -#ifndef UINT8_T -#define UINT8_T uint8_t -#endif - -#ifndef uint8_T -#define uint8_T uint8_t -#endif - -#ifndef INT8_T -#define INT8_T int8_t -#endif - -#ifndef int8_T -#define int8_T int8_t -#endif - -#if defined (__cplusplus) -} -#endif - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/mexproto.h --- a/src/mexproto.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,279 +0,0 @@ -/* - -Copyright (C) 2006-2012 Paul Kienzle - -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 -. - -*/ - -/* - -This code was originally distributed as part of Octave Forge under -the following terms: - -Author: Paul Kienzle -I grant this code to the public domain. -2001-03-22 - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - -*/ - -/* mex.h is for use in C-programs only; do NOT include it in mex.cc */ - -#if ! defined (MEXPROTO_H) -#define MEXPROTO_H - -#if defined (__cplusplus) -#include -extern "C" { -#else -#include -#endif - -/* The definition of OCTINTERP_API is normally provided by Octave's - config.h file. This is provided for the case of mex.h included by - user programs that don't use Octave's config.h. */ -#if ! defined (OCTINTERP_API) -#if defined (_MSC_VER) -#define OCTINTERP_API __declspec(dllimport) -#else -/* All other compilers, at least for now. */ -#define OCTINTERP_API -#endif -#endif - -#define MXARRAY_TYPEDEFS_ONLY -#include "mxarray.h" -#undef MXARRAY_TYPEDEFS_ONLY - -/* Interface to the interpreter. */ -extern OCTINTERP_API const char *mexFunctionName (void); - -extern OCTINTERP_API int mexCallMATLAB (int nargout, mxArray *argout[], int nargin, mxArray *argin[], const char *fname); - -extern OCTINTERP_API void mexSetTrapFlag (int flag); -extern OCTINTERP_API int mexEvalString (const char *s); -extern OCTINTERP_API void mexErrMsgTxt (const char *s); -extern OCTINTERP_API void mexErrMsgIdAndTxt (const char *id, const char *s, ...); -extern OCTINTERP_API void mexWarnMsgTxt (const char *s); -extern OCTINTERP_API void mexWarnMsgIdAndTxt (const char *id, const char *s, ...); -extern OCTINTERP_API int mexPrintf (const char *fmt, ...); - -extern OCTINTERP_API mxArray *mexGetVariable (const char *space, const char *name); -extern OCTINTERP_API const mxArray *mexGetVariablePtr (const char *space, const char *name); - -extern OCTINTERP_API int mexPutVariable (const char *space, const char *name, mxArray *ptr); - -extern OCTINTERP_API void mexMakeArrayPersistent (mxArray *ptr); -extern OCTINTERP_API void mexMakeMemoryPersistent (void *ptr); - -extern OCTINTERP_API int mexAtExit (void (*f) (void)); -extern OCTINTERP_API const mxArray *mexGet (double handle, const char *property); -extern OCTINTERP_API int mexIsGlobal (const mxArray *ptr); -extern OCTINTERP_API int mexIsLocked (void); -extern OCTINTERP_API void mexLock (void); -extern OCTINTERP_API int mexSet (double handle, const char *property, mxArray *val); -extern OCTINTERP_API void mexUnlock (void); - -/* Floating point predicates. */ -extern OCTINTERP_API int mxIsFinite (double v); -extern OCTINTERP_API int mxIsInf (double v); -extern OCTINTERP_API int mxIsNaN (double v); - -/* Floating point values. */ -extern OCTINTERP_API double mxGetEps (void); -extern OCTINTERP_API double mxGetInf (void); -extern OCTINTERP_API double mxGetNaN (void); - -/* Memory management. */ -extern OCTINTERP_API void *mxCalloc (size_t n, size_t size); -extern OCTINTERP_API void *mxMalloc (size_t n); -extern OCTINTERP_API void *mxRealloc (void *ptr, size_t size); -extern OCTINTERP_API void mxFree (void *ptr); - -/* Constructors. */ -extern OCTINTERP_API mxArray *mxCreateCellArray (mwSize ndims, const mwSize *dims); -extern OCTINTERP_API mxArray *mxCreateCellMatrix (mwSize m, mwSize n); -extern OCTINTERP_API mxArray *mxCreateCharArray (mwSize ndims, const mwSize *dims); -extern OCTINTERP_API mxArray *mxCreateCharMatrixFromStrings (mwSize m, const char **str); -extern OCTINTERP_API mxArray *mxCreateDoubleMatrix (mwSize nr, mwSize nc, mxComplexity flag); -extern OCTINTERP_API mxArray *mxCreateDoubleScalar (double val); -extern OCTINTERP_API mxArray *mxCreateLogicalArray (mwSize ndims, const mwSize *dims); -extern OCTINTERP_API mxArray *mxCreateLogicalMatrix (mwSize m, mwSize n); -extern OCTINTERP_API mxArray *mxCreateLogicalScalar (mxLogical val); -extern OCTINTERP_API mxArray *mxCreateNumericArray (mwSize ndims, const mwSize *dims, mxClassID class_id, mxComplexity flag); -extern OCTINTERP_API mxArray *mxCreateNumericMatrix (mwSize m, mwSize n, mxClassID class_id, mxComplexity flag); -extern OCTINTERP_API mxArray *mxCreateSparse (mwSize m, mwSize n, mwSize nzmax, mxComplexity flag); -extern OCTINTERP_API mxArray *mxCreateSparseLogicalMatrix (mwSize m, mwSize n, mwSize nzmax); -extern OCTINTERP_API mxArray *mxCreateString (const char *str); -extern OCTINTERP_API mxArray *mxCreateStructArray (mwSize ndims, const mwSize *dims, int num_keys, const char **keys); -extern OCTINTERP_API mxArray *mxCreateStructMatrix (mwSize rows, mwSize cols, int num_keys, const char **keys); - -/* Copy constructor. */ -extern OCTINTERP_API mxArray *mxDuplicateArray (const mxArray *v); - -/* Destructor. */ -extern OCTINTERP_API void mxDestroyArray (mxArray *v); - -/* Type Predicates. */ -extern OCTINTERP_API int mxIsCell (const mxArray *ptr); -extern OCTINTERP_API int mxIsChar (const mxArray *ptr); -extern OCTINTERP_API int mxIsClass (const mxArray *ptr, const char *name); -extern OCTINTERP_API int mxIsComplex (const mxArray *ptr); -extern OCTINTERP_API int mxIsDouble (const mxArray *ptr); -extern OCTINTERP_API int mxIsFunctionHandle (const mxArray *ptr); -extern OCTINTERP_API int mxIsInt16 (const mxArray *ptr); -extern OCTINTERP_API int mxIsInt32 (const mxArray *ptr); -extern OCTINTERP_API int mxIsInt64 (const mxArray *ptr); -extern OCTINTERP_API int mxIsInt8 (const mxArray *ptr); -extern OCTINTERP_API int mxIsLogical (const mxArray *ptr); -extern OCTINTERP_API int mxIsNumeric (const mxArray *ptr); -extern OCTINTERP_API int mxIsSingle (const mxArray *ptr); -extern OCTINTERP_API int mxIsSparse (const mxArray *ptr); -extern OCTINTERP_API int mxIsStruct (const mxArray *ptr); -extern OCTINTERP_API int mxIsUint16 (const mxArray *ptr); -extern OCTINTERP_API int mxIsUint32 (const mxArray *ptr); -extern OCTINTERP_API int mxIsUint64 (const mxArray *ptr); -extern OCTINTERP_API int mxIsUint8 (const mxArray *ptr); - -/* Odd type+size predicate. */ -extern OCTINTERP_API int mxIsLogicalScalar (const mxArray *ptr); - -/* Odd type+size+value predicate. */ -extern OCTINTERP_API int mxIsLogicalScalarTrue (const mxArray *ptr); - -/* Size predicate. */ -extern OCTINTERP_API int mxIsEmpty (const mxArray *ptr); - -/* Just plain odd thing to ask of a value. */ -extern OCTINTERP_API int mxIsFromGlobalWS (const mxArray *ptr); - -/* Dimension extractors. */ -extern OCTINTERP_API size_t mxGetM (const mxArray *ptr); -extern OCTINTERP_API size_t mxGetN (const mxArray *ptr); -extern OCTINTERP_API mwSize *mxGetDimensions (const mxArray *ptr); -extern OCTINTERP_API mwSize mxGetNumberOfDimensions (const mxArray *ptr); -extern OCTINTERP_API size_t mxGetNumberOfElements (const mxArray *ptr); - -/* Dimension setters. */ -extern OCTINTERP_API void mxSetM (mxArray *ptr, mwSize M); -extern OCTINTERP_API void mxSetN (mxArray *ptr, mwSize N); -extern OCTINTERP_API void mxSetDimensions (mxArray *ptr, const mwSize *dims, mwSize ndims); - -/* Data extractors. */ -extern OCTINTERP_API double *mxGetPi (const mxArray *ptr); -extern OCTINTERP_API double *mxGetPr (const mxArray *ptr); -extern OCTINTERP_API double mxGetScalar (const mxArray *ptr); -extern OCTINTERP_API mxChar *mxGetChars (const mxArray *ptr); -extern OCTINTERP_API mxLogical *mxGetLogicals (const mxArray *ptr); -extern OCTINTERP_API void *mxGetData (const mxArray *ptr); -extern OCTINTERP_API void *mxGetImagData (const mxArray *ptr); - -/* Data setters. */ -extern OCTINTERP_API void mxSetPr (mxArray *ptr, double *pr); -extern OCTINTERP_API void mxSetPi (mxArray *ptr, double *pi); -extern OCTINTERP_API void mxSetData (mxArray *ptr, void *data); -extern OCTINTERP_API void mxSetImagData (mxArray *ptr, void *pi); - -/* Classes. */ -extern OCTINTERP_API mxClassID mxGetClassID (const mxArray *ptr); -extern OCTINTERP_API const char *mxGetClassName (const mxArray *ptr); - -extern OCTINTERP_API void mxSetClassName (mxArray *ptr, const char *name); - -/* Cell support. */ -extern OCTINTERP_API mxArray *mxGetCell (const mxArray *ptr, mwIndex idx); - -extern OCTINTERP_API void mxSetCell (mxArray *ptr, mwIndex idx, mxArray *val); - -/* Sparse support. */ -extern OCTINTERP_API mwIndex *mxGetIr (const mxArray *ptr); -extern OCTINTERP_API mwIndex *mxGetJc (const mxArray *ptr); -extern OCTINTERP_API mwSize mxGetNzmax (const mxArray *ptr); - -extern OCTINTERP_API void mxSetIr (mxArray *ptr, mwIndex *ir); -extern OCTINTERP_API void mxSetJc (mxArray *ptr, mwIndex *jc); -extern OCTINTERP_API void mxSetNzmax (mxArray *ptr, mwSize nzmax); - -/* Structure support. */ -extern OCTINTERP_API int mxAddField (mxArray *ptr, const char *key); - -extern OCTINTERP_API void mxRemoveField (mxArray *ptr, int key_num); - -extern OCTINTERP_API mxArray *mxGetField (const mxArray *ptr, mwIndex index, const char *key); -extern OCTINTERP_API mxArray *mxGetFieldByNumber (const mxArray *ptr, mwIndex index, int key_num); - -extern OCTINTERP_API void mxSetField (mxArray *ptr, mwIndex index, const char *key, mxArray *val); -extern OCTINTERP_API void mxSetFieldByNumber (mxArray *ptr, mwIndex index, int key_num, mxArray *val); - -extern OCTINTERP_API int mxGetNumberOfFields (const mxArray *ptr); - -extern OCTINTERP_API const char *mxGetFieldNameByNumber (const mxArray *ptr, int key_num); -extern OCTINTERP_API int mxGetFieldNumber (const mxArray *ptr, const char *key); - -extern OCTINTERP_API int mxGetString (const mxArray *ptr, char *buf, mwSize buflen); -extern OCTINTERP_API char *mxArrayToString (const mxArray *ptr); - -/* Miscellaneous. */ -#ifdef NDEBUG -#define mxAssert(expr, msg) \ - do \ - { \ - if (! expr) \ - { \ - mexPrintf ("Assertion failed: %s, at line %d of file \"%s\".\n%s\n", \ - #expr, __LINE__, __FILE__, msg); \ - } \ - } \ - while (0) - -#define mxAssertS(expr, msg) \ - do \ - { \ - if (! expr) \ - { \ - mexPrintf ("Assertion failed at line %d of file \"%s\".\n%s\n", \ - __LINE__, __FILE__, msg); \ - abort (); \ - } \ - } \ - while (0) -#else -#define mxAssert(expr, msg) -#define mxAssertS(expr, msg) -#endif - -extern OCTINTERP_API mwIndex mxCalcSingleSubscript (const mxArray *ptr, mwSize nsubs, mwIndex *subs); - -extern OCTINTERP_API size_t mxGetElementSize (const mxArray *ptr); - -#if defined (__cplusplus) -} -#endif - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/mxarray.in.h --- a/src/mxarray.in.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,348 +0,0 @@ -// DO NOT EDIT! Generated automatically from mxarray.in.h by configure -/* - -Copyright (C) 2001-2012 Paul Kienzle - -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 -. - -*/ - -/* - -Part of this code was originally distributed as part of Octave Forge under -the following terms: - -Author: Paul Kienzle -I grant this code to the public domain. -2001-03-22 - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS -OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. - -*/ - -#if ! defined (MXARRAY_H) -#define MXARRAY_H - -typedef enum - { - mxREAL = 0, - mxCOMPLEX = 1 - } - mxComplexity; - -typedef enum - { - mxUNKNOWN_CLASS = 0, - mxCELL_CLASS, - mxSTRUCT_CLASS, - mxLOGICAL_CLASS, - mxCHAR_CLASS, - mxUNUSED_CLASS, - mxDOUBLE_CLASS, - mxSINGLE_CLASS, - mxINT8_CLASS, - mxUINT8_CLASS, - mxINT16_CLASS, - mxUINT16_CLASS, - mxINT32_CLASS, - mxUINT32_CLASS, - mxINT64_CLASS, - mxUINT64_CLASS, - mxFUNCTION_CLASS - } - mxClassID; - -typedef unsigned char mxLogical; - -/* typedef Uint16 mxChar; */ -typedef char mxChar; - -/* - * FIXME? Mathworks says these should be size_t on 64-bit system and when - * mex is used with the -largearraydims flag, but why do that? Its better - * to conform to the same indexing as the rest of Octave - */ -typedef %OCTAVE_IDX_TYPE% mwSize; -typedef %OCTAVE_IDX_TYPE% mwIndex; - -#if ! defined (MXARRAY_TYPEDEFS_ONLY) - -#include - -class octave_value; - -#define DO_MUTABLE_METHOD(RET_T, METHOD_CALL) \ - RET_T retval = rep->METHOD_CALL; \ - \ - if (rep->mutation_needed ()) \ - { \ - maybe_mutate (); \ - retval = rep->METHOD_CALL; \ - } \ - \ - return retval - -#define DO_VOID_MUTABLE_METHOD(METHOD_CALL) \ - rep->METHOD_CALL; \ - \ - if (rep->mutation_needed ()) \ - { \ - maybe_mutate (); \ - rep->METHOD_CALL; \ - } - -// This just provides a way to avoid infinite recursion when building -// mxArray objects. - -struct -xmxArray -{ - xmxArray (void) { } -}; - -// The main interface class. The representation can be based on an -// octave_value object or a separate object that tries to reproduce -// the semantics of mxArray objects in Matlab more directly. - -class mxArray -{ -public: - - mxArray (const octave_value& ov); - - mxArray (mxClassID id, mwSize ndims, const mwSize *dims, - mxComplexity flag = mxREAL); - - mxArray (mxClassID id, const dim_vector& dv, mxComplexity flag = mxREAL); - - mxArray (mxClassID id, mwSize m, mwSize n, mxComplexity flag = mxREAL); - - mxArray (mxClassID id, double val); - - mxArray (mxClassID id, mxLogical val); - - mxArray (const char *str); - - mxArray (mwSize m, const char **str); - - mxArray (mxClassID id, mwSize m, mwSize n, mwSize nzmax, - mxComplexity flag = mxREAL); - - mxArray (mwSize ndims, const mwSize *dims, int num_keys, const char **keys); - - mxArray (const dim_vector& dv, int num_keys, const char **keys); - - mxArray (mwSize m, mwSize n, int num_keys, const char **keys); - - mxArray (mwSize ndims, const mwSize *dims); - - mxArray (const dim_vector& dv); - - mxArray (mwSize m, mwSize n); - - virtual mxArray *dup (void) const - { - mxArray *new_rep = rep->dup (); - - return new mxArray (new_rep, name); - } - - virtual ~mxArray (void); - - virtual bool is_octave_value (void) const { return rep->is_octave_value (); } - - virtual int is_cell (void) const { return rep->is_cell (); } - - virtual int is_char (void) const { return rep->is_char (); } - - virtual int is_class (const char *name_arg) const { return rep->is_class (name_arg); } - - virtual int is_complex (void) const { return rep->is_complex (); } - - virtual int is_double (void) const { return rep->is_double (); } - - virtual int is_function_handle (void) const { return rep->is_function_handle (); } - - virtual int is_int16 (void) const { return rep->is_int16 (); } - - virtual int is_int32 (void) const { return rep->is_int32 (); } - - virtual int is_int64 (void) const { return rep->is_int64 (); } - - virtual int is_int8 (void) const { return rep->is_int8 (); } - - virtual int is_logical (void) const { return rep->is_logical (); } - - virtual int is_numeric (void) const { return rep->is_numeric (); } - - virtual int is_single (void) const { return rep->is_single (); } - - virtual int is_sparse (void) const { return rep->is_sparse (); } - - virtual int is_struct (void) const { return rep->is_struct (); } - - virtual int is_uint16 (void) const { return rep->is_uint16 (); } - - virtual int is_uint32 (void) const { return rep->is_uint32 (); } - - virtual int is_uint64 (void) const { return rep->is_uint64 (); } - - virtual int is_uint8 (void) const { return rep->is_uint8 (); } - - virtual int is_logical_scalar (void) const { return rep->is_logical_scalar (); } - - virtual int is_logical_scalar_true (void) const { return rep->is_logical_scalar_true (); } - - virtual mwSize get_m (void) const { return rep->get_m (); } - - virtual mwSize get_n (void) const { return rep->get_n (); } - - virtual mwSize *get_dimensions (void) const { return rep->get_dimensions (); } - - virtual mwSize get_number_of_dimensions (void) const { return rep->get_number_of_dimensions (); } - - virtual void set_m (mwSize m) { DO_VOID_MUTABLE_METHOD (set_m (m)); } - - virtual void set_n (mwSize n) { DO_VOID_MUTABLE_METHOD (set_n (n)); } - - virtual void set_dimensions (mwSize *dims_arg, mwSize ndims_arg) { DO_VOID_MUTABLE_METHOD (set_dimensions (dims_arg, ndims_arg)); } - - virtual mwSize get_number_of_elements (void) const { return rep->get_number_of_elements (); } - - virtual int is_empty (void) const { return get_number_of_elements () == 0; } - - const char *get_name (void) const { return name; } - - void set_name (const char *name_arg); - - virtual mxClassID get_class_id (void) const { return rep->get_class_id (); } - - virtual const char *get_class_name (void) const { return rep->get_class_name (); } - - virtual void set_class_name (const char *name_arg) { DO_VOID_MUTABLE_METHOD (set_class_name (name_arg)); } - - virtual mxArray *get_cell (mwIndex idx) const { DO_MUTABLE_METHOD (mxArray *, get_cell (idx)); } - - virtual void set_cell (mwIndex idx, mxArray *val) { DO_VOID_MUTABLE_METHOD (set_cell (idx, val)); } - - virtual double get_scalar (void) const { return rep->get_scalar (); } - - virtual void *get_data (void) const { DO_MUTABLE_METHOD (void *, get_data ()); } - - virtual void *get_imag_data (void) const { DO_MUTABLE_METHOD (void *, get_imag_data ()); } - - virtual void set_data (void *pr) { DO_VOID_MUTABLE_METHOD (set_data (pr)); } - - virtual void set_imag_data (void *pi) { DO_VOID_MUTABLE_METHOD (set_imag_data (pi)); } - - virtual mwIndex *get_ir (void) const { DO_MUTABLE_METHOD (mwIndex *, get_ir ()); } - - virtual mwIndex *get_jc (void) const { DO_MUTABLE_METHOD (mwIndex *, get_jc ()); } - - virtual mwSize get_nzmax (void) const { return rep->get_nzmax (); } - - virtual void set_ir (mwIndex *ir) { DO_VOID_MUTABLE_METHOD (set_ir (ir)); } - - virtual void set_jc (mwIndex *jc) { DO_VOID_MUTABLE_METHOD (set_jc (jc)); } - - virtual void set_nzmax (mwSize nzmax) { DO_VOID_MUTABLE_METHOD (set_nzmax (nzmax)); } - - virtual int add_field (const char *key) { DO_MUTABLE_METHOD (int, add_field (key)); } - - virtual void remove_field (int key_num) { DO_VOID_MUTABLE_METHOD (remove_field (key_num)); } - - virtual mxArray *get_field_by_number (mwIndex index, int key_num) const { DO_MUTABLE_METHOD (mxArray *, get_field_by_number (index, key_num)); } - - virtual void set_field_by_number (mwIndex index, int key_num, mxArray *val) { DO_VOID_MUTABLE_METHOD (set_field_by_number (index, key_num, val)); } - - virtual int get_number_of_fields (void) const { return rep->get_number_of_fields (); } - - virtual const char *get_field_name_by_number (int key_num) const { DO_MUTABLE_METHOD (const char*, get_field_name_by_number (key_num)); } - - virtual int get_field_number (const char *key) const { DO_MUTABLE_METHOD (int, get_field_number (key)); } - - virtual int get_string (char *buf, mwSize buflen) const { return rep->get_string (buf, buflen); } - - virtual char *array_to_string (void) const { return rep->array_to_string (); } - - virtual mwIndex calc_single_subscript (mwSize nsubs, mwIndex *subs) const { return rep->calc_single_subscript (nsubs, subs); } - - virtual size_t get_element_size (void) const { return rep->get_element_size (); } - - virtual bool mutation_needed (void) const { return rep->mutation_needed (); } - - virtual mxArray *mutate (void) const { return rep->mutate (); } - - static void *malloc (size_t n); - - static void *calloc (size_t n, size_t t); - - static char *strsave (const char *str) - { - char *retval = 0; - - if (str) - { - mwSize sz = sizeof (mxChar) * (strlen (str) + 1); - retval = static_cast (mxArray::malloc (sz)); - strcpy (retval, str); - } - - return retval; - } - - static octave_value as_octave_value (mxArray *ptr); - -protected: - - virtual octave_value as_octave_value (void) const; - - mxArray (const xmxArray&) : rep (0), name (0) { } - -private: - - mutable mxArray *rep; - - char *name; - - mxArray (mxArray *r, const char *n) - : rep (r), name (strsave (n)) { } - - void maybe_mutate (void) const; - - // No copying! - - mxArray (const mxArray&); - - mxArray& operator = (const mxArray&); -}; - -#undef DO_MUTABLE_METHOD -#undef DO_VOID_MUTABLE_METHOD - -#endif -#endif diff -r a132d206a36a -r b9b6a310ad97 src/oct-errno.h --- a/src/oct-errno.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,72 +0,0 @@ -// oct-errno.h.in -/* - -Copyright (C) 2005-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_errno_h) -#define octave_errno_h 1 - -#include -#include -#include - -#include "oct-map.h" - -class -octave_errno -{ -protected: - - octave_errno (void); - -public: - - ~octave_errno (void) { } - - static bool instance_ok (void); - - static void cleanup_instance (void) { delete instance; instance = 0; } - - static int lookup (const std::string& name); - - static octave_scalar_map list (void); - - static int get (void) { return errno; } - - static int set (int val) - { - int retval = errno; - errno = val; - return retval; - } - -private: - - std::map errno_tbl; - - static octave_errno *instance; - - int do_lookup (const std::string& name); - - octave_scalar_map do_list (void); -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/oct-errno.in.cc --- a/src/oct-errno.in.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,345 +0,0 @@ -// oct-errno.cc.in -/* - -Copyright (C) 2005-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "singleton-cleanup.h" - -#include "oct-errno.h" -#include "oct-map.h" -#include "error.h" - -octave_errno *octave_errno::instance = 0; - -octave_errno::octave_errno (void) -{ - struct errno_struct - { - const char *name; - int value; - }; - - static errno_struct errno_codes[] = - { - // POSIX. - -#if defined (E2BIG) - { "E2BIG", E2BIG, }, -#endif -#if defined (EACCES) - { "EACCES", EACCES, }, -#endif -#if defined (EADDRINUSE) - { "EADDRINUSE", EADDRINUSE, }, -#endif -#if defined (EADDRNOTAVAIL) - { "EADDRNOTAVAIL", EADDRNOTAVAIL, }, -#endif -#if defined (EAFNOSUPPORT) - { "EAFNOSUPPORT", EAFNOSUPPORT, }, -#endif -#if defined (EAGAIN) - { "EAGAIN", EAGAIN, }, -#endif -#if defined (EALREADY) - { "EALREADY", EALREADY, }, -#endif -#if defined (EBADF) - { "EBADF", EBADF, }, -#endif -#if defined (EBUSY) - { "EBUSY", EBUSY, }, -#endif -#if defined (ECHILD) - { "ECHILD", ECHILD, }, -#endif -#if defined (ECONNABORTED) - { "ECONNABORTED", ECONNABORTED, }, -#endif -#if defined (ECONNREFUSED) - { "ECONNREFUSED", ECONNREFUSED, }, -#endif -#if defined (ECONNRESET) - { "ECONNRESET", ECONNRESET, }, -#endif -#if defined (EDEADLK) - { "EDEADLK", EDEADLK, }, -#endif -#if defined (EDESTADDRREQ) - { "EDESTADDRREQ", EDESTADDRREQ, }, -#endif -#if defined (EDOM) - { "EDOM", EDOM, }, -#endif -#if defined (EDQUOT) - { "EDQUOT", EDQUOT, }, -#endif -#if defined (EEXIST) - { "EEXIST", EEXIST, }, -#endif -#if defined (EFAULT) - { "EFAULT", EFAULT, }, -#endif -#if defined (EFBIG) - { "EFBIG", EFBIG, }, -#endif -#if defined (EHOSTDOWN) - { "EHOSTDOWN", EHOSTDOWN, }, -#endif -#if defined (EHOSTUNREACH) - { "EHOSTUNREACH", EHOSTUNREACH, }, -#endif -#if defined (EINPROGRESS) - { "EINPROGRESS", EINPROGRESS, }, -#endif -#if defined (EINTR) - { "EINTR", EINTR, }, -#endif -#if defined (EINVAL) - { "EINVAL", EINVAL, }, -#endif -#if defined (EIO) - { "EIO", EIO, }, -#endif -#if defined (EISCONN) - { "EISCONN", EISCONN, }, -#endif -#if defined (EISDIR) - { "EISDIR", EISDIR, }, -#endif -#if defined (ELOOP) - { "ELOOP", ELOOP, }, -#endif -#if defined (EMFILE) - { "EMFILE", EMFILE, }, -#endif -#if defined (EMLINK) - { "EMLINK", EMLINK, }, -#endif -#if defined (EMSGSIZE) - { "EMSGSIZE", EMSGSIZE, }, -#endif -#if defined (ENAMETOOLONG) - { "ENAMETOOLONG", ENAMETOOLONG, }, -#endif -#if defined (ENETDOWN) - { "ENETDOWN", ENETDOWN, }, -#endif -#if defined (ENETRESET) - { "ENETRESET", ENETRESET, }, -#endif -#if defined (ENETUNREACH) - { "ENETUNREACH", ENETUNREACH, }, -#endif -#if defined (ENFILE) - { "ENFILE", ENFILE, }, -#endif -#if defined (ENOBUFS) - { "ENOBUFS", ENOBUFS, }, -#endif -#if defined (ENODEV) - { "ENODEV", ENODEV, }, -#endif -#if defined (ENOENT) - { "ENOENT", ENOENT, }, -#endif -#if defined (ENOEXEC) - { "ENOEXEC", ENOEXEC, }, -#endif -#if defined (ENOLCK) - { "ENOLCK", ENOLCK, }, -#endif -#if defined (ENOMEM) - { "ENOMEM", ENOMEM, }, -#endif -#if defined (ENOPROTOOPT) - { "ENOPROTOOPT", ENOPROTOOPT, }, -#endif -#if defined (ENOSPC) - { "ENOSPC", ENOSPC, }, -#endif -#if defined (ENOSYS) - { "ENOSYS", ENOSYS, }, -#endif -#if defined (ENOTBLK) - { "ENOTBLK", ENOTBLK, }, -#endif -#if defined (ENOTCONN) - { "ENOTCONN", ENOTCONN, }, -#endif -#if defined (ENOTDIR) - { "ENOTDIR", ENOTDIR, }, -#endif -#if defined (ENOTEMPTY) - { "ENOTEMPTY", ENOTEMPTY, }, -#endif -#if defined (ENOTSOCK) - { "ENOTSOCK", ENOTSOCK, }, -#endif -#if defined (ENOTTY) - { "ENOTTY", ENOTTY, }, -#endif -#if defined (ENXIO) - { "ENXIO", ENXIO, }, -#endif -#if defined (EOPNOTSUPP) - { "EOPNOTSUPP", EOPNOTSUPP, }, -#endif -#if defined (EPERM) - { "EPERM", EPERM, }, -#endif -#if defined (EPFNOSUPPORT) - { "EPFNOSUPPORT", EPFNOSUPPORT, }, -#endif -#if defined (EPIPE) - { "EPIPE", EPIPE, }, -#endif -#if defined (EPROTONOSUPPORT) - { "EPROTONOSUPPORT", EPROTONOSUPPORT, }, -#endif -#if defined (EPROTOTYPE) - { "EPROTOTYPE", EPROTOTYPE, }, -#endif -#if defined (ERANGE) - { "ERANGE", ERANGE, }, -#endif -#if defined (EREMOTE) - { "EREMOTE", EREMOTE, }, -#endif -#if defined (ERESTART) - { "ERESTART", ERESTART, }, -#endif -#if defined (EROFS) - { "EROFS", EROFS, }, -#endif -#if defined (ESHUTDOWN) - { "ESHUTDOWN", ESHUTDOWN, }, -#endif -#if defined (ESOCKTNOSUPPORT) - { "ESOCKTNOSUPPORT", ESOCKTNOSUPPORT, }, -#endif -#if defined (ESPIPE) - { "ESPIPE", ESPIPE, }, -#endif -#if defined (ESRCH) - { "ESRCH", ESRCH, }, -#endif -#if defined (ESTALE) - { "ESTALE", ESTALE, }, -#endif -#if defined (ETIMEDOUT) - { "ETIMEDOUT", ETIMEDOUT, }, -#endif -#if defined (ETOOMANYREFS) - { "ETOOMANYREFS", ETOOMANYREFS, }, -#endif -#if defined (ETXTBSY) - { "ETXTBSY", ETXTBSY, }, -#endif -#if defined (EUSERS) - { "EUSERS", EUSERS, }, -#endif -#if defined (EWOULDBLOCK) - { "EWOULDBLOCK", EWOULDBLOCK, }, -#endif -#if defined (EXDEV) - { "EXDEV", EXDEV, }, -#endif - - // Others (duplicates are OK). - -@SYSDEP_ERRNO_LIST@ - - { 0, 0, }, - }; - - // Stuff them all in a map for fast access. - - errno_struct *ptr = errno_codes; - - while (ptr->name) - { - errno_tbl[ptr->name] = ptr->value; - ptr++; - } -} - -bool -octave_errno::instance_ok (void) -{ - bool retval = true; - - if (! instance) - { - instance = new octave_errno (); - - if (instance) - singleton_cleanup_list::add (cleanup_instance); - } - - if (! instance) - { - ::error ("unable to create errno object!"); - - retval = false; - } - - return retval; -} - -int -octave_errno::lookup (const std::string& name) -{ - return (instance_ok ()) ? instance->do_lookup (name) : -1; -} - -octave_scalar_map -octave_errno::list (void) -{ - return (instance_ok ()) ? instance->do_list () : octave_scalar_map (); -} - -int -octave_errno::do_lookup (const std::string& name) -{ - return (errno_tbl.find (name) != errno_tbl.end ()) ? errno_tbl[name] : -1; -} - -octave_scalar_map -octave_errno::do_list (void) -{ - octave_scalar_map retval; - - for (std::map::const_iterator p = errno_tbl.begin (); - p != errno_tbl.end (); - p++) - { - retval.assign (p->first, p->second); - } - - return retval; -} diff -r a132d206a36a -r b9b6a310ad97 src/oct-fstrm.cc --- a/src/oct-fstrm.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,114 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "error.h" -#include "oct-fstrm.h" - -octave_stream -octave_fstream::create (const std::string& nm_arg, std::ios::openmode arg_md, - oct_mach_info::float_format ff) -{ - return octave_stream (new octave_fstream (nm_arg, arg_md, ff)); -} - -octave_fstream::octave_fstream (const std::string& nm_arg, - std::ios::openmode arg_md, - oct_mach_info::float_format ff) - : octave_base_stream (arg_md, ff), nm (nm_arg) -{ - -#if CXX_ISO_COMPLIANT_LIBRARY - - fs.open (nm.c_str (), arg_md); - -#else - // Override default protection of 0664 so that umask will appear to - // do the right thing. - - fs.open (nm.c_str (), arg_md, 0666); - -#endif - - if (! fs) - error (gnulib::strerror (errno)); -} - -// Position a stream at OFFSET relative to ORIGIN. - -int -octave_fstream::seek (long, int) -{ - error ("fseek: invalid_operation"); - return -1; -} - -// Return current stream position. - -long -octave_fstream::tell (void) -{ - error ("ftell: invalid_operation"); - return -1; -} - -// Return non-zero if EOF has been reached on this stream. - -bool -octave_fstream::eof (void) const -{ - return fs.eof (); -} - -void -octave_fstream::do_close (void) -{ - fs.close (); -} - -std::istream * -octave_fstream::input_stream (void) -{ - std::istream *retval = 0; - - if (mode () & std::ios::in) - retval = &fs; - - return retval; -} - -std::ostream * -octave_fstream::output_stream (void) -{ - std::ostream *retval = 0; - - if (mode () & std::ios::out) - retval = &fs; - - return retval; -} diff -r a132d206a36a -r b9b6a310ad97 src/oct-fstrm.h --- a/src/oct-fstrm.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,86 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_octave_fstream_h) -#define octave_octave_fstream_h 1 - -#include -#include - -#include "oct-stream.h" - -class -octave_fstream : public octave_base_stream -{ -public: - - octave_fstream (const std::string& nm_arg, - std::ios::openmode arg_md = std::ios::in|std::ios::out, - oct_mach_info::float_format flt_fmt - = oct_mach_info::native_float_format ()); - - static octave_stream - create (const std::string& nm_arg, - std::ios::openmode arg_md = std::ios::in|std::ios::out, - oct_mach_info::float_format flt_fmt - = oct_mach_info::native_float_format ()); - - // Position a stream at OFFSET relative to ORIGIN. - - int seek (long offset, int origin); - - // Return current stream position. - - long tell (void); - - // Return non-zero if EOF has been reached on this stream. - - bool eof (void) const; - - void do_close (void); - - // The name of the file. - - std::string name (void) const { return nm; } - - std::istream *input_stream (void); - - std::ostream *output_stream (void); - -protected: - - ~octave_fstream (void) { } - -private: - - std::string nm; - - std::fstream fs; - - // No copying! - - octave_fstream (const octave_fstream&); - - octave_fstream& operator = (const octave_fstream&); -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/oct-hdf5.h --- a/src/oct-hdf5.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/* - -Copyright (C) 2009-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave__hdf5_h) -#define octave_hdf5_h 1 - -#if defined (HAVE_HDF5) -#include -#endif - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/oct-iostrm.cc --- a/src/oct-iostrm.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,89 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "error.h" -#include "oct-iostrm.h" - -// Position a stream at OFFSET relative to ORIGIN. - -int -octave_base_iostream::seek (long, int) -{ - invalid_operation (); - return -1; -} - -// Return current stream position. - -long -octave_base_iostream::tell (void) -{ - invalid_operation (); - return -1; -} - -// Return non-zero if EOF has been reached on this stream. - -bool -octave_base_iostream::eof (void) const -{ - invalid_operation (); - return false; -} - -void -octave_base_iostream::invalid_operation (void) const -{ - ::error ("%s: invalid operation", stream_type ()); -} - -// Return non-zero if EOF has been reached on this stream. - -bool -octave_istream::eof (void) const -{ - return is && is->eof (); -} - -octave_stream -octave_istream::create (std::istream *arg, const std::string& n) -{ - return octave_stream (new octave_istream (arg, n)); -} - -// Return non-zero if EOF has been reached on this stream. - -bool -octave_ostream::eof (void) const -{ - return os && os->eof (); -} - -octave_stream -octave_ostream::create (std::ostream *arg, const std::string& n) -{ - return octave_stream (new octave_ostream (arg, n)); -} diff -r a132d206a36a -r b9b6a310ad97 src/oct-iostrm.h --- a/src/oct-iostrm.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,154 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_octave_iostream_h) -#define octave_octave_iostream_h 1 - -#include - -#include "oct-stream.h" - -class -octave_base_iostream : public octave_base_stream -{ -public: - - octave_base_iostream (const std::string& n = std::string (), - std::ios::openmode m = std::ios::in|std::ios::out, - oct_mach_info::float_format ff - = oct_mach_info::native_float_format ()) - : octave_base_stream (m, ff), nm (n) { } - - // Position a stream at OFFSET relative to ORIGIN. - - int seek (long offset, int origin); - - // Return current stream position. - - long tell (void); - - // Return non-zero if EOF has been reached on this stream. - - bool eof (void) const; - - // The name of the file. - - std::string name (void) const { return nm; } - -protected: - - ~octave_base_iostream (void) { } - - void invalid_operation (void) const; - -private: - - std::string nm; - - virtual const char *stream_type (void) const = 0; - - // No copying! - - octave_base_iostream (const octave_base_iostream&); - - octave_base_iostream& operator = (const octave_base_iostream&); -}; - -class -octave_istream : public octave_base_iostream -{ -public: - - octave_istream (std::istream *arg = 0, const std::string& n = std::string ()) - : octave_base_iostream (n, std::ios::in, - oct_mach_info::native_float_format ()), - is (arg) - { } - - static octave_stream - create (std::istream *arg = 0, const std::string& n = std::string ()); - - // Return non-zero if EOF has been reached on this stream. - - bool eof (void) const; - - std::istream *input_stream (void) { return is; } - - std::ostream *output_stream (void) { return 0; } - -protected: - - ~octave_istream (void) { } - -private: - - std::istream *is; - - const char *stream_type (void) const { return "octave_istream"; } - - // No copying! - - octave_istream (const octave_istream&); - - octave_istream& operator = (const octave_istream&); -}; - -class -octave_ostream : public octave_base_iostream -{ -public: - - octave_ostream (std::ostream *arg, const std::string& n = std::string ()) - : octave_base_iostream (n, std::ios::out, - oct_mach_info::native_float_format ()), - os (arg) - { } - - static octave_stream - create (std::ostream *arg, const std::string& n = std::string ()); - - // Return non-zero if EOF has been reached on this stream. - - bool eof (void) const; - - std::istream *input_stream (void) { return 0; } - - std::ostream *output_stream (void) { return os; } - -protected: - - ~octave_ostream (void) { } - -private: - - std::ostream *os; - - const char *stream_type (void) const { return "octave_ostream"; } - - // No copying! - - octave_ostream (const octave_ostream&); - - octave_ostream& operator = (const octave_ostream&); -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/oct-lvalue.cc --- a/src/oct-lvalue.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "error.h" -#include "oct-obj.h" -#include "oct-lvalue.h" -#include "ov.h" - -void -octave_lvalue::assign (octave_value::assign_op op, const octave_value& rhs) -{ - if (val) - { - if (idx.empty ()) - val->assign (op, rhs); - else - val->assign (op, type, idx, rhs); - } -} - -void -octave_lvalue::set_index (const std::string& t, - const std::list& i) -{ - if (idx.empty ()) - { - type = t; - idx = i; - } - else - error ("invalid index expression in assignment"); -} - -void -octave_lvalue::do_unary_op (octave_value::unary_op op) -{ - if (val) - { - if (idx.empty ()) - val->do_non_const_unary_op (op); - else - val->do_non_const_unary_op (op, type, idx); - } - else - error ("internal: invalid operation on ~"); -} - -octave_value -octave_lvalue::value (void) -{ - octave_value retval; - - if (val) - { - if (idx.empty ()) - retval = *val; - else - { - if (val->is_constant ()) - retval = val->subsref (type, idx); - else - { - octave_value_list t = val->subsref (type, idx, 1); - if (t.length () > 0) - retval = t(0); - } - } - } - - return retval; -} diff -r a132d206a36a -r b9b6a310ad97 src/oct-lvalue.h --- a/src/oct-lvalue.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,104 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_lvalue_h) -#define octave_lvalue_h 1 - -class octave_value; -class octave_value_list; - -#include - -#include "oct-obj.h" -#include "pt-idx.h" - -class -octave_lvalue -{ -public: - - octave_lvalue (octave_value *v = 0) - : val (v), type (), idx (), nel (1) - { } - - octave_lvalue (const octave_lvalue& vr) - : val (vr.val), type (vr.type), idx (vr.idx), nel (vr.nel) - { - } - - octave_lvalue& operator = (const octave_lvalue& vr) - { - if (this != &vr) - { - val = vr.val; - type = vr.type; - idx = vr.idx; - nel = vr.nel; - } - - return *this; - } - - ~octave_lvalue (void) { } - - bool is_black_hole (void) const { return val == 0; } - - bool is_defined (void) const { return val && val->is_defined (); } - - bool is_undefined (void) const { return ! val || val->is_undefined (); } - - bool is_map (void) const { return val && val->is_map (); } - - void define (const octave_value& v) - { - if (val) - *val = v; - } - - void assign (octave_value::assign_op, const octave_value&); - - void numel (octave_idx_type n) { nel = n; } - - octave_idx_type numel (void) const { return nel; } - - void set_index (const std::string& t, const std::list& i); - - void clear_index (void) { type = std::string (); idx.clear (); } - - void do_unary_op (octave_value::unary_op op); - - octave_value value (void); - - const octave_value *object (void) const { return val; } - -private: - - octave_value *val; - - std::string type; - - std::list idx; - - octave_idx_type nel; -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/oct-map.cc --- a/src/oct-map.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1779 +0,0 @@ -/* - -Copyright (C) 1995-2012 John W. Eaton -Copyright (C) 2010 VZLU Prague - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "error.h" -#include "str-vec.h" - -#include "oct-map.h" -#include "utils.h" - -octave_fields::octave_fields (const string_vector& fields) - : rep (new fields_rep) -{ - octave_idx_type n = fields.numel (); - for (octave_idx_type i = 0; i < n; i++) - (*rep)[fields(i)] = i; -} - -octave_fields::octave_fields (const char * const *fields) - : rep (new fields_rep) -{ - octave_idx_type n = 0; - while (*fields) - (*rep)[std::string (*fields++)] = n++; -} - -bool -octave_fields::isfield (const std::string& field) const -{ - return rep->find (field) != rep->end (); -} - -octave_idx_type -octave_fields::getfield (const std::string& field) const -{ - fields_rep::iterator p = rep->find (field); - return (p != rep->end ()) ? p->second : -1; -} - -octave_idx_type -octave_fields::getfield (const std::string& field) -{ - fields_rep::iterator p = rep->find (field); - if (p != rep->end ()) - return p->second; - else - { - make_unique (); - octave_idx_type n = rep->size (); - return (*rep)[field] = n; - } -} - -octave_idx_type -octave_fields::rmfield (const std::string& field) -{ - fields_rep::iterator p = rep->find (field); - if (p == rep->end ()) - return -1; - else - { - octave_idx_type n = p->second; - make_unique (); - rep->erase (field); - for (fields_rep::iterator q = rep->begin (); q != rep->end (); q++) - { - if (q->second >= n) - q->second--; - } - - return n; - } -} - -void -octave_fields::orderfields (Array& perm) -{ - octave_idx_type n = rep->size (); - perm.clear (n, 1); - - make_unique (); - octave_idx_type i = 0; - for (fields_rep::iterator q = rep->begin (); q != rep->end (); q++) - { - octave_idx_type j = q->second; - q->second = i; - perm(i++) = j; - } -} - -bool -octave_fields::equal_up_to_order (const octave_fields& other, - octave_idx_type* perm) const -{ - bool retval = true; - - iterator p = begin (), q = other.begin (); - for (; p != end () && q != other.end (); p++, q++) - { - if (p->first == q->first) - perm[p->second] = q->second; - else - { - retval = false; - break; - } - } - - retval = (p == end () && q == other.end ()); - - return retval; -} - -bool -octave_fields::equal_up_to_order (const octave_fields& other, - Array& perm) const -{ - octave_idx_type n = nfields (); - if (perm.length () != n) - perm.clear (1, n); - - return equal_up_to_order (other, perm.fortran_vec ()); -} - -string_vector -octave_fields::fieldnames (void) const -{ - octave_idx_type n = nfields (); - string_vector retval(n); - - for (iterator p = begin (); p != end (); p++) - retval.xelem (p->second) = p->first; - - return retval; -} - -octave_value -octave_scalar_map::getfield (const std::string& k) const -{ - octave_idx_type idx = xkeys.getfield (k); - return (idx >= 0) ? xvals[idx] : octave_value (); -} - -void -octave_scalar_map::setfield (const std::string& k, const octave_value& val) -{ - octave_idx_type idx = xkeys.getfield (k); - if (idx < static_cast (xvals.size ())) - xvals[idx] = val; - else - xvals.push_back (val); -} - -void -octave_scalar_map::rmfield (const std::string& k) -{ - octave_idx_type idx = xkeys.rmfield (k); - if (idx >= 0) - xvals.erase (xvals.begin () + idx); -} - -octave_scalar_map -octave_scalar_map::orderfields (void) const -{ - Array perm; - return orderfields (perm); -} - -octave_scalar_map -octave_scalar_map::orderfields (Array& perm) const -{ - octave_scalar_map retval (xkeys); - retval.xkeys.orderfields (perm); - - octave_idx_type nf = nfields (); - for (octave_idx_type i = 0; i < nf; i++) - retval.xvals[i] = xvals[perm.xelem (i)]; - - return retval; -} - -octave_scalar_map -octave_scalar_map::orderfields (const octave_scalar_map& other, - Array& perm) const -{ - if (xkeys.is_same (other.xkeys)) - return *this; - else - { - octave_scalar_map retval (other.xkeys); - if (other.xkeys.equal_up_to_order (xkeys, perm)) - { - octave_idx_type nf = nfields (); - for (octave_idx_type i = 0; i < nf; i++) - retval.xvals[i] = xvals[perm.xelem (i)]; - } - else - error ("orderfields: structs must have same fields up to order"); - - return retval; - } -} - -octave_value -octave_scalar_map::contents (const std::string& k) const -{ - return getfield (k); -} - -octave_value& -octave_scalar_map::contents (const std::string& k) -{ - octave_idx_type idx = xkeys.getfield (k); - if (idx >= static_cast (xvals.size ())) - xvals.resize (idx+1); - return xvals[idx]; -} - -octave_map::octave_map (const octave_scalar_map& m) - : xkeys (m.xkeys), xvals (), dimensions (1, 1) -{ - octave_idx_type nf = m.nfields (); - xvals.reserve (nf); - for (octave_idx_type i = 0; i < nf; i++) - { - xvals.push_back (Cell (dimensions)); - xvals[i].xelem (0) = m.xvals[i]; - } -} - -octave_map::octave_map (const Octave_map& m) - : xkeys (m.keys ()), xvals (m.nfields ()), dimensions (m.dims ()) -{ - for (iterator p = begin (); p != end (); p++) - contents(p) = m.contents (key (p)); - - optimize_dimensions (); -} - -Cell -octave_map::getfield (const std::string& k) const -{ - octave_idx_type idx = xkeys.getfield (k); - return (idx >= 0) ? xvals[idx] : Cell (); -} - -void -octave_map::setfield (const std::string& k, const Cell& val) -{ - if (nfields () == 0) - dimensions = val.dims (); - - if (val.dims () == dimensions) - { - octave_idx_type idx = xkeys.getfield (k); - if (idx < static_cast (xvals.size ())) - xvals[idx] = val; - else - xvals.push_back (val); - } - else - error ("octave_map::setfield: internal error"); -} - -void -octave_map::rmfield (const std::string& k) -{ - octave_idx_type idx = xkeys.rmfield (k); - if (idx >= 0) - xvals.erase (xvals.begin () + idx); -} - -octave_map -octave_map::orderfields (void) const -{ - Array perm; - return orderfields (perm); -} - -octave_map -octave_map::orderfields (Array& perm) const -{ - octave_map retval (xkeys); - retval.xkeys.orderfields (perm); - - octave_idx_type nf = nfields (); - for (octave_idx_type i = 0; i < nf; i++) - retval.xvals[i] = xvals[perm.xelem (i)]; - - return retval; -} - -octave_map -octave_map::orderfields (const octave_map& other, - Array& perm) const -{ - if (xkeys.is_same (other.xkeys)) - return *this; - else - { - octave_map retval (other.xkeys); - if (other.xkeys.equal_up_to_order (xkeys, perm)) - { - octave_idx_type nf = nfields (); - for (octave_idx_type i = 0; i < nf; i++) - retval.xvals[i] = xvals[perm.xelem (i)]; - } - else - error ("orderfields: structs must have same fields up to order"); - - return retval; - } -} - -Cell -octave_map::contents (const std::string& k) const -{ - return getfield (k); -} - -Cell& -octave_map::contents (const std::string& k) -{ - octave_idx_type idx = xkeys.getfield (k); - if (idx >= static_cast (xvals.size ())) - xvals.push_back (Cell (dimensions)); // auto-set correct dims. - return xvals[idx]; -} - -void -octave_map::extract_scalar (octave_scalar_map& dest, - octave_idx_type idx) const -{ - octave_idx_type nf = nfields (); - for (octave_idx_type i = 0; i < nf; i++) - dest.xvals[i] = xvals[i](idx); -} - -octave_scalar_map -octave_map::checkelem (octave_idx_type n) const -{ - octave_scalar_map retval (xkeys); - - // Optimize this so that there is just one check. - extract_scalar (retval, compute_index (n, dimensions)); - - return retval; -} - -octave_scalar_map -octave_map::checkelem (octave_idx_type i, octave_idx_type j) const -{ - octave_scalar_map retval (xkeys); - - // Optimize this so that there is just one check. - extract_scalar (retval, compute_index (i, j, dimensions)); - - return retval; -} - -octave_scalar_map -octave_map::checkelem (const Array& ra_idx) const -{ - octave_scalar_map retval (xkeys); - - // Optimize this so that there is just one check. - extract_scalar (retval, compute_index (ra_idx, dimensions)); - - return retval; -} - -octave_scalar_map -octave_map::fast_elem_extract (octave_idx_type n) const -{ - octave_scalar_map retval (xkeys); - - extract_scalar (retval, n); - - return retval; -} - -bool -octave_map::fast_elem_insert (octave_idx_type n, - const octave_scalar_map& rhs) -{ - bool retval = false; - - octave_idx_type nf = nfields (); - if (rhs.xkeys.is_same (xkeys)) - { - for (octave_idx_type i = 0; i < nf; i++) - xvals[i](n) = rhs.xvals[i]; - - retval = true; - } - else - { - OCTAVE_LOCAL_BUFFER (octave_idx_type, perm, nf); - if (xkeys.equal_up_to_order (rhs.xkeys, perm)) - { - for (octave_idx_type i = 0; i < nf; i++) - xvals[i](n) = rhs.xvals[perm[i]]; - - retval = true; - } - } - - return retval; -} - -octave_map -octave_map::squeeze (void) const -{ - octave_map retval (*this); - octave_idx_type nf = nfields (); - - retval.dimensions = dimensions.squeeze (); - - for (octave_idx_type i = 0; i < nf; i++) - retval.xvals[i] = xvals[i].squeeze (); - - retval.optimize_dimensions (); - - return retval; -} - -/* -## test preservation of xkeys by squeeze -%!test -%! x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27; -%! assert (fieldnames (squeeze (x)), {"d"; "a"; "f"}); -*/ - -octave_map -octave_map::permute (const Array& vec, bool inv) const -{ - octave_map retval (xkeys); - octave_idx_type nf = nfields (); - - for (octave_idx_type i = 0; i < nf; i++) - retval.xvals[i] = xvals[i].permute (vec, inv); - - // FIXME: - // There is no dim_vector::permute for technical reasons. - // We pick the dim vector from results if possible, otherwise use a dummy - // array to get it. Need (?) a better solution to this problem. - if (nf > 0) - retval.dimensions = retval.xvals[0].dims (); - else - { - Array dummy (dimensions); - dummy = dummy.permute (vec, inv); - retval.dimensions = dummy.dims (); - } - - retval.optimize_dimensions (); - - return retval; -} - -/* -## test preservation of key order by permute -%!test -%! x(1,1,1,1).d = 10; x(3,5,1,7).a = "b"; x(2,4,1,7).f = 27; -%! assert (fieldnames (permute (x, [3, 4, 1, 2])), {"d"; "a"; "f"}); -*/ - -octave_map -octave_map::transpose (void) const -{ - assert (ndims () == 2); - - octave_map retval (xkeys); - - retval.dimensions = dim_vector (dimensions (1), dimensions (0)); - - octave_idx_type nf = nfields (); - for (octave_idx_type i = 0; i < nf; i++) - retval.xvals[i] = xvals[i].transpose (); - - retval.optimize_dimensions (); - - return retval; -} - -/* -## test preservation of key order by transpose -%!test -%! x(1,1).d = 10; x(3,5).a = "b"; x(2,4).f = 27; -%! assert (fieldnames (transpose (x)), {"d"; "a"; "f"}); -%! assert (fieldnames (x'), {"d"; "a"; "f"}); -%! assert (fieldnames (x.'), {"d"; "a"; "f"}); -*/ - -octave_map -octave_map::reshape (const dim_vector& dv) const -{ - octave_map retval (xkeys); - retval.dimensions = dv; - - octave_idx_type nf = nfields (); - if (nf > 0) - { - retval.xvals.reserve (nf); - for (octave_idx_type i = 0; i < nf; i++) - retval.xvals[i] = xvals[i].reshape (dv); - } - else - { - // FIXME: Do it with a dummy array, to reuse error message. - // Need (?) a better solution. - Array dummy (dimensions); - dummy.reshape (dv); - } - - retval.optimize_dimensions (); - - return retval; -} - -/* -## test preservation of key order by reshape -%!test -%! x(1,1).d = 10; x(4,6).a = "b"; x(2,4).f = 27; -%! assert (fieldnames (reshape (x, 3, 8)), {"d"; "a"; "f"}); -*/ - -void -octave_map::resize (const dim_vector& dv, bool fill) -{ - octave_idx_type nf = nfields (); - if (nf > 0) - { - for (octave_idx_type i = 0; i < nf; i++) - { - if (fill) - xvals[i].resize (dv, Matrix ()); - else - xvals[i].resize (dv); - } - } - else - { - // FIXME: Do it with a dummy array, to reuse error message. - // Need (?) a better solution. - Array dummy (dimensions); - dummy.resize (dv); - } - - dimensions = dv; - optimize_dimensions (); -} - -void -octave_map::do_cat (int dim, octave_idx_type n, const octave_scalar_map *map_list, - octave_map& retval) -{ - octave_idx_type nf = retval.nfields (); - retval.xvals.reserve (nf); - - dim_vector& rd = retval.dimensions; - rd.resize (dim+1, 1); - rd(0) = rd(1) = 1; - rd(dim) = n; - - for (octave_idx_type j = 0; j < nf; j++) - { - retval.xvals.push_back (Cell (rd)); - assert (retval.xvals[j].numel () == n); - for (octave_idx_type i = 0; i < n; i++) - retval.xvals[j].xelem (i) = map_list[i].xvals[j]; - } -} - -void -octave_map::do_cat (int dim, octave_idx_type n, const octave_map *map_list, - octave_map& retval) -{ - octave_idx_type nf = retval.nfields (); - retval.xvals.reserve (nf); - - OCTAVE_LOCAL_BUFFER (Array, field_list, n); - - for (octave_idx_type j = 0; j < nf; j++) - { - for (octave_idx_type i = 0; i < n; i++) - field_list[i] = map_list[i].xvals[j]; - - retval.xvals.push_back (Array::cat (dim, n, field_list)); - if (j == 0) - retval.dimensions = retval.xvals[j].dims (); - } -} - -// This is just a wrapper. -void permute_to_correct_order1 (const octave_scalar_map& ref, const octave_scalar_map& src, - octave_scalar_map& dest, Array& perm) -{ - dest = src.orderfields (ref, perm); -} - -// In non-scalar case, we also promote empty structs without fields. -void permute_to_correct_order1 (const octave_map& ref, const octave_map& src, - octave_map& dest, Array& perm) -{ - if (src.nfields () == 0 && src.is_empty ()) - dest = octave_map (src.dims (), ref.keys ()); - else - dest = src.orderfields (ref, perm); -} - -template -static void -permute_to_correct_order (octave_idx_type n, octave_idx_type nf, - octave_idx_type idx, const map *map_list, - map *new_map_list) -{ - new_map_list[idx] = map_list[idx]; - - Array perm (dim_vector (1, nf)); - - for (octave_idx_type i = 0; i < n; i++) - { - if (i == idx) - continue; - - permute_to_correct_order1 (map_list[idx], map_list[i], new_map_list[i], perm); - - if (error_state) - { - // Use liboctave exception to be consistent. - (*current_liboctave_error_handler) - ("cat: field names mismatch in concatenating structs"); - break; - } - } -} - - -octave_map -octave_map::cat (int dim, octave_idx_type n, const octave_scalar_map *map_list) -{ - octave_map retval; - - // Allow dim = -1, -2 for compatibility, though it makes no difference here. - if (dim == -1 || dim == -2) - dim = -dim - 1; - else if (dim < 0) - (*current_liboctave_error_handler) - ("cat: invalid dimension"); - - if (n == 1) - retval = map_list[0]; - else if (n > 1) - { - octave_idx_type idx, nf = 0; - for (idx = 0; idx < n; idx++) - { - nf = map_list[idx].nfields (); - if (nf > 0) - { - retval.xkeys = map_list[idx].xkeys; - break; - } - } - - if (nf > 0) - { - // Try the fast case. - bool all_same = true; - for (octave_idx_type i = 0; i < n; i++) - { - all_same = map_list[idx].xkeys.is_same (map_list[i].xkeys); - if (! all_same) - break; - } - - if (all_same) - do_cat (dim, n, map_list, retval); - else - { - // permute all structures to common order. - OCTAVE_LOCAL_BUFFER (octave_scalar_map, new_map_list, n); - - permute_to_correct_order (n, nf, idx, map_list, new_map_list); - - do_cat (dim, n, new_map_list, retval); - } - - } - else - { - dim_vector& rd = retval.dimensions; - rd.resize (dim+1, 1); - rd(0) = rd(1) = 1; - rd(dim) = n; - } - - retval.optimize_dimensions (); - } - - return retval; -} - -octave_map -octave_map::cat (int dim, octave_idx_type n, const octave_map *map_list) -{ - octave_map retval; - - // Allow dim = -1, -2 for compatibility, though it makes no difference here. - if (dim == -1 || dim == -2) - dim = -dim - 1; - else if (dim < 0) - (*current_liboctave_error_handler) - ("cat: invalid dimension"); - - if (n == 1) - retval = map_list[0]; - else if (n > 1) - { - octave_idx_type idx, nf = 0; - - for (idx = 0; idx < n; idx++) - { - nf = map_list[idx].nfields (); - if (nf > 0) - { - retval.xkeys = map_list[idx].xkeys; - break; - } - } - - // Try the fast case. - bool all_same = true; - - if (nf > 0) - { - for (octave_idx_type i = 0; i < n; i++) - { - all_same = map_list[idx].xkeys.is_same (map_list[i].xkeys); - - if (! all_same) - break; - } - } - - if (all_same && nf > 0) - do_cat (dim, n, map_list, retval); - else - { - if (nf > 0) - { - // permute all structures to correct order. - OCTAVE_LOCAL_BUFFER (octave_map, new_map_list, n); - - permute_to_correct_order (n, nf, idx, map_list, new_map_list); - - do_cat (dim, n, new_map_list, retval); - } - else - { - dim_vector dv = map_list[0].dimensions; - - for (octave_idx_type i = 1; i < n; i++) - { - if (! dv.concat (map_list[i].dimensions, dim)) - { - error ("dimension mismatch in struct concatenation"); - return retval; - } - } - - retval.dimensions = dv; - } - } - - retval.optimize_dimensions (); - } - - return retval; -} - -/* -## test preservation of key order by concatenation -%!test -%! x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27; -%! y(1, 6).f = 11; y(1, 6).a = "c"; y(1, 6).d = 33; -%! assert (fieldnames ([x; y]), {"d"; "a"; "f"}); - -%!test -%! s = struct (); -%! sr = [s,s]; -%! sc = [s;s]; -%! sm = [s,s;s,s]; -%! assert (nfields (sr), 0); -%! assert (nfields (sc), 0); -%! assert (nfields (sm), 0); -%! assert (size (sr), [1, 2]); -%! assert (size (sc), [2, 1]); -%! assert (size (sm), [2, 2]); -*/ - -octave_map -octave_map::index (const idx_vector& i, bool resize_ok) const -{ - octave_map retval (xkeys); - octave_idx_type nf = nfields (); - - for (octave_idx_type k = 0; k < nf; k++) - retval.xvals[k] = xvals[k].index (i, resize_ok); - - if (nf > 0) - retval.dimensions = retval.xvals[0].dims (); - else - { - // Use dummy array. FIXME: Need(?) a better solution. - Array dummy (dimensions); - dummy = dummy.index (i, resize_ok); - retval.dimensions = dummy.dims (); - } - - retval.optimize_dimensions (); - - return retval; -} - -octave_map -octave_map::index (const idx_vector& i, const idx_vector& j, - bool resize_ok) const -{ - octave_map retval (xkeys); - octave_idx_type nf = nfields (); - - for (octave_idx_type k = 0; k < nf; k++) - retval.xvals[k] = xvals[k].index (i, j, resize_ok); - - if (nf > 0) - retval.dimensions = retval.xvals[0].dims (); - else - { - // Use dummy array. FIXME: Need(?) a better solution. - Array dummy (dimensions); - dummy = dummy.index (i, j, resize_ok); - retval.dimensions = dummy.dims (); - } - - retval.optimize_dimensions (); - - return retval; -} - -octave_map -octave_map::index (const Array& ia, bool resize_ok) const -{ - octave_map retval (xkeys); - octave_idx_type nf = nfields (); - - for (octave_idx_type k = 0; k < nf; k++) - retval.xvals[k] = xvals[k].index (ia, resize_ok); - - if (nf > 0) - retval.dimensions = retval.xvals[0].dims (); - else - { - // Use dummy array. FIXME: Need(?) a better solution. - Array dummy (dimensions); - dummy = dummy.index (ia, resize_ok); - retval.dimensions = dummy.dims (); - } - - retval.optimize_dimensions (); - - return retval; -} - -octave_map -octave_map::index (const octave_value_list& idx, bool resize_ok) const -{ - octave_idx_type n_idx = idx.length (); - octave_map retval; - - switch (n_idx) - { - case 1: - { - idx_vector i = idx(0).index_vector (); - - if (! error_state) - retval = index (i, resize_ok); - } - break; - - case 2: - { - idx_vector i = idx(0).index_vector (); - - if (! error_state) - { - idx_vector j = idx(1).index_vector (); - - retval = index (i, j, resize_ok); - } - } - break; - - default: - { - Array ia (dim_vector (n_idx, 1)); - - for (octave_idx_type i = 0; i < n_idx; i++) - { - ia(i) = idx(i).index_vector (); - - if (error_state) - break; - } - - if (! error_state) - retval = index (ia, resize_ok); - } - break; - } - - return retval; -} - -// Perhaps one day these will be optimized. Right now, they just call index. -octave_map -octave_map::column (octave_idx_type k) const -{ - return index (idx_vector::colon, k); -} - -octave_map -octave_map::page (octave_idx_type k) const -{ - static Array ia (dim_vector (3, 1), idx_vector::colon); - - ia(2) = k; - return index (ia); -} - -void -octave_map::assign (const idx_vector& i, const octave_map& rhs) -{ - if (rhs.xkeys.is_same (xkeys)) - { - octave_idx_type nf = nfields (); - - for (octave_idx_type k = 0; k < nf; k++) - xvals[k].assign (i, rhs.xvals[k], Matrix ()); - - if (nf > 0) - dimensions = xvals[0].dims (); - else - { - // Use dummy array. FIXME: Need(?) a better solution. - Array dummy (dimensions), rhs_dummy (rhs.dimensions); - dummy.assign (i, rhs_dummy);; - dimensions = dummy.dims (); - } - - optimize_dimensions (); - } - else if (nfields () == 0) - { - octave_map tmp (dimensions, rhs.xkeys); - tmp.assign (i, rhs); - *this = tmp; - } - else - { - Array perm; - octave_map rhs1 = rhs.orderfields (*this, perm); - if (! error_state) - { - assert (rhs1.xkeys.is_same (xkeys)); - assign (i, rhs1); - } - else - error ("incompatible fields in struct assignment"); - } -} - -void -octave_map::assign (const idx_vector& i, const idx_vector& j, - const octave_map& rhs) -{ - if (rhs.xkeys.is_same (xkeys)) - { - octave_idx_type nf = nfields (); - - for (octave_idx_type k = 0; k < nf; k++) - xvals[k].assign (i, j, rhs.xvals[k], Matrix ()); - - if (nf > 0) - dimensions = xvals[0].dims (); - else - { - // Use dummy array. FIXME: Need(?) a better solution. - Array dummy (dimensions), rhs_dummy (rhs.dimensions); - dummy.assign (i, j, rhs_dummy);; - dimensions = dummy.dims (); - } - - optimize_dimensions (); - } - else if (nfields () == 0) - { - octave_map tmp (dimensions, rhs.xkeys); - tmp.assign (i, j, rhs); - *this = tmp; - } - else - { - Array perm; - octave_map rhs1 = rhs.orderfields (*this, perm); - if (! error_state) - { - assert (rhs1.xkeys.is_same (xkeys)); - assign (i, j, rhs1); - } - else - error ("incompatible fields in struct assignment"); - } -} - -void -octave_map::assign (const Array& ia, - const octave_map& rhs) -{ - if (rhs.xkeys.is_same (xkeys)) - { - octave_idx_type nf = nfields (); - - for (octave_idx_type k = 0; k < nf; k++) - xvals[k].assign (ia, rhs.xvals[k], Matrix ()); - - if (nf > 0) - dimensions = xvals[0].dims (); - else - { - // Use dummy array. FIXME: Need(?) a better solution. - Array dummy (dimensions), rhs_dummy (rhs.dimensions); - dummy.assign (ia, rhs_dummy);; - dimensions = dummy.dims (); - } - - optimize_dimensions (); - } - else if (nfields () == 0) - { - octave_map tmp (dimensions, rhs.xkeys); - tmp.assign (ia, rhs); - *this = tmp; - } - else - { - Array perm; - octave_map rhs1 = rhs.orderfields (*this, perm); - if (! error_state) - { - assert (rhs1.xkeys.is_same (xkeys)); - assign (ia, rhs1); - } - else - error ("incompatible fields in struct assignment"); - } -} - -void -octave_map::assign (const octave_value_list& idx, const octave_map& rhs) -{ - octave_idx_type n_idx = idx.length (); - - switch (n_idx) - { - case 1: - { - idx_vector i = idx(0).index_vector (); - - if (! error_state) - assign (i, rhs); - } - break; - - case 2: - { - idx_vector i = idx(0).index_vector (); - - if (! error_state) - { - idx_vector j = idx(1).index_vector (); - - assign (i, j, rhs); - } - } - break; - - default: - { - Array ia (dim_vector (n_idx, 1)); - - for (octave_idx_type i = 0; i < n_idx; i++) - { - ia(i) = idx(i).index_vector (); - - if (error_state) - break; - } - - if (! error_state) - assign (ia, rhs); - } - break; - } -} - -void -octave_map::assign (const octave_value_list& idx, const std::string& k, - const Cell& rhs) -{ - Cell tmp; - iterator p = seek (k); - Cell& ref = p != end () ? contents (p) : tmp; - - if (&ref == &tmp) - ref = Cell (dimensions); - - ref.assign (idx, rhs); - - if (! error_state && ref.dims () != dimensions) - { - dimensions = ref.dims (); - - octave_idx_type nf = nfields (); - for (octave_idx_type i = 0; i < nf; i++) - { - if (&xvals[i] != &ref) - xvals[i].resize (dimensions, Matrix ()); - } - - optimize_dimensions (); - } - - if (! error_state && &ref == &tmp) - setfield (k, tmp); -} - -/* -%!test -%! rhs.b = 1; -%! a(3) = rhs; -%! assert ({a.b}, {[], [], 1}) -*/ - -void -octave_map::delete_elements (const idx_vector& i) -{ - octave_idx_type nf = nfields (); - for (octave_idx_type k = 0; k < nf; k++) - xvals[k].delete_elements (i); - - if (nf > 0) - dimensions = xvals[0].dims (); - else - { - // Use dummy array. FIXME: Need(?) a better solution. - Array dummy (dimensions); - dummy.delete_elements (i); - dimensions = dummy.dims (); - } - - optimize_dimensions (); -} - -void -octave_map::delete_elements (int dim, const idx_vector& i) -{ - octave_idx_type nf = nfields (); - for (octave_idx_type k = 0; k < nf; k++) - xvals[k].delete_elements (dim, i); - - if (nf > 0) - dimensions = xvals[0].dims (); - else - { - // Use dummy array. FIXME: Need(?) a better solution. - Array dummy (dimensions); - dummy.delete_elements (dim, i); - dimensions = dummy.dims (); - } - - optimize_dimensions (); -} - -void -octave_map::delete_elements (const Array& ia) -{ - octave_idx_type nf = nfields (); - for (octave_idx_type k = 0; k < nf; k++) - xvals[k].delete_elements (ia); - - if (nf > 0) - dimensions = xvals[0].dims (); - else - { - // Use dummy array. FIXME: Need(?) a better solution. - Array dummy (dimensions); - dummy.delete_elements (ia); - dimensions = dummy.dims (); - } - - optimize_dimensions (); -} - -void -octave_map::delete_elements (const octave_value_list& idx) -{ - octave_idx_type n_idx = idx.length (); - - Array ia (dim_vector (n_idx, 1)); - - for (octave_idx_type i = 0; i < n_idx; i++) - { - ia(i) = idx(i).index_vector (); - - if (error_state) - break; - } - - if (! error_state) - delete_elements (ia); -} - -/* -## test preservation of key order by indexing -%!test -%! x(1, 1).d = 10; x(4, 6).a = "b"; x(2, 4).f = 27; -%! assert (fieldnames (x([1, 2], [2:5])), {"d"; "a"; "f"}); -*/ - -octave_map -octave_map::concat (const octave_map& rb, const Array& ra_idx) -{ - if (nfields () == rb.nfields ()) - { - for (const_iterator pa = begin (); pa != end (); pa++) - { - const_iterator pb = rb.seek (key(pa)); - - if (pb == rb.end ()) - { - error ("field name mismatch in structure concatenation"); - break; - } - - contents(pa).insert (rb.contents (pb), ra_idx); - } - } - else - { - dim_vector dv = dims (); - - if (dv.all_zero ()) - *this = rb; - else if (! rb.dims ().all_zero ()) - error ("invalid structure concatenation"); - } - - return *this; -} - -void -octave_map::optimize_dimensions (void) -{ - octave_idx_type nf = nfields (); - - for (octave_idx_type i = 0; i < nf; i++) - { - if (! xvals[i].optimize_dimensions (dimensions)) - { - error ("internal error: dimension mismatch across fields in struct"); - break; - } - } - -} - -Octave_map::Octave_map (const dim_vector& dv, const Cell& key_vals) - : map (), key_list (), dimensions (dv) -{ - Cell c (dv); - - if (key_vals.is_cellstr ()) - { - for (octave_idx_type i = 0; i < key_vals.numel (); i++) - { - std::string k = key_vals(i).string_value (); - map[k] = c; - key_list.push_back (k); - } - } - else - error ("Octave_map: expecting keys to be cellstr"); -} - -Octave_map::Octave_map (const octave_map& m) - : map (), key_list (), dimensions (m.dims ()) -{ - for (octave_map::const_iterator p = m.begin (); p != m.end (); p++) - map[m.key (p)] = m.contents (p); - const string_vector mkeys = m.fieldnames (); - for (octave_idx_type i = 0; i < mkeys.numel (); i++) - key_list.push_back (mkeys(i)); -} - -Octave_map -Octave_map::squeeze (void) const -{ - Octave_map retval (dims ().squeeze ()); - - for (const_iterator pa = begin (); pa != end (); pa++) - { - Cell tmp = contents (pa).squeeze (); - - if (error_state) - break; - - retval.assign (key (pa), tmp); - } - - // Preserve order of keys. - retval.key_list = key_list; - - return retval; -} - -Octave_map -Octave_map::permute (const Array& vec, bool inv) const -{ - Octave_map retval (dims ()); - - for (const_iterator pa = begin (); pa != end (); pa++) - { - Cell tmp = contents (pa).permute (vec, inv); - - if (error_state) - break; - - retval.assign (key (pa), tmp); - } - - // Preserve order of keys. - retval.key_list = key_list; - - return retval; -} - -Cell& -Octave_map::contents (const std::string& k) -{ - maybe_add_to_key_list (k); - - return map[k]; -} - -Cell -Octave_map::contents (const std::string& k) const -{ - const_iterator p = seek (k); - - return p != end () ? p->second : Cell (); -} - -int -Octave_map::intfield (const std::string& k, int def_val) const -{ - int retval = def_val; - - Cell c = contents (k); - - if (! c.is_empty ()) - retval = c(0).int_value (); - - return retval; -} - -std::string -Octave_map::stringfield (const std::string& k, - const std::string& def_val) const -{ - std::string retval = def_val; - - Cell c = contents (k); - - if (! c.is_empty ()) - retval = c(0).string_value (); - - return retval; -} - -string_vector -Octave_map::keys (void) const -{ - assert (static_cast(nfields ()) == key_list.size ()); - - return string_vector (key_list); -} - -Octave_map -Octave_map::transpose (void) const -{ - assert (ndims () == 2); - - dim_vector dv = dims (); - - octave_idx_type nr = dv(0); - octave_idx_type nc = dv(1); - - dim_vector new_dims (nc, nr); - - Octave_map retval (new_dims); - - for (const_iterator p = begin (); p != end (); p++) - retval.assign (key(p), Cell (contents(p).transpose ())); - - // Preserve order of keys. - retval.key_list = key_list; - - return retval; -} - -Octave_map -Octave_map::reshape (const dim_vector& new_dims) const -{ - Octave_map retval; - - if (new_dims != dims ()) - { - for (const_iterator p = begin (); p != end (); p++) - retval.assign (key(p), contents(p).reshape (new_dims)); - - retval.dimensions = new_dims; - - // Preserve order of keys. - retval.key_list = key_list; - } - else - retval = *this; - - return retval; -} - -void -Octave_map::resize (const dim_vector& dv, bool fill) -{ - if (dv != dims ()) - { - if (nfields () == 0) - dimensions = dv; - else - { - for (const_iterator p = begin (); p != end (); p++) - { - Cell tmp = contents(p); - - if (fill) - tmp.resize (dv, Matrix ()); - else - tmp.resize (dv); - - dimensions = dv; - - assign (key(p), tmp); - } - } - } -} - -Octave_map -Octave_map::concat (const Octave_map& rb, const Array& ra_idx) -{ - Octave_map retval; - - if (nfields () == rb.nfields ()) - { - for (const_iterator pa = begin (); pa != end (); pa++) - { - const_iterator pb = rb.seek (key(pa)); - - if (pb == rb.end ()) - { - error ("field name mismatch in structure concatenation"); - break; - } - - retval.assign (key(pa), - contents(pa).insert (rb.contents(pb), ra_idx)); - } - - // Preserve order of keys. - retval.key_list = key_list; - } - else - { - dim_vector dv = dims (); - - if (dv.all_zero ()) - retval = rb; - else - { - dv = rb.dims (); - - if (dv.all_zero ()) - retval = *this; - else - error ("invalid structure concatenation"); - } - } - - return retval; -} - -static bool -keys_ok (const Octave_map& a, const Octave_map& b, string_vector& keys) -{ - bool retval = false; - - keys = string_vector (); - - if (a.nfields () == 0) - { - keys = b.keys (); - retval = true; - } - else - { - string_vector a_keys = a.keys ().sort (); - string_vector b_keys = b.keys ().sort (); - - octave_idx_type a_len = a_keys.length (); - octave_idx_type b_len = b_keys.length (); - - if (a_len == b_len) - { - for (octave_idx_type i = 0; i < a_len; i++) - { - if (a_keys[i] != b_keys[i]) - goto done; - } - - keys = a_keys; - retval = true; - } - } - - done: - return retval; -} - -Octave_map& -Octave_map::maybe_delete_elements (const octave_value_list& idx) -{ - string_vector t_keys = keys (); - octave_idx_type len = t_keys.length (); - - if (len > 0) - { - for (octave_idx_type i = 0; i < len; i++) - { - std::string k = t_keys[i]; - - contents(k).delete_elements (idx); - - if (error_state) - break; - } - - if (!error_state) - dimensions = contents(t_keys[0]).dims (); - } - - return *this; -} - -Octave_map& -Octave_map::assign (const octave_value_list& idx, const Octave_map& rhs) -{ - string_vector t_keys; - - if (keys_ok (*this, rhs, t_keys)) - { - octave_idx_type len = t_keys.length (); - - if (len == 0) - { - Cell tmp_lhs (dims ()); - Cell tmp_rhs (rhs.dims ()); - - tmp_lhs.assign (idx, tmp_rhs, Matrix ()); - - if (! error_state) - resize (tmp_lhs.dims ()); - else - error ("size mismatch in structure assignment"); - } - else - { - for (octave_idx_type i = 0; i < len; i++) - { - std::string k = t_keys[i]; - - Cell t_rhs = rhs.contents (k); - - assign (idx, k, t_rhs); - - if (error_state) - break; - } - } - } - else - error ("field name mismatch in structure assignment"); - - return *this; -} - -Octave_map& -Octave_map::assign (const octave_value_list& idx, const std::string& k, - const Cell& rhs) -{ - Cell tmp; - - if (contains (k)) - tmp = map[k]; - else - tmp = Cell (dimensions); - - tmp.assign (idx, rhs); - - if (! error_state) - { - dim_vector tmp_dims = tmp.dims (); - - if (tmp_dims != dimensions) - { - for (iterator p = begin (); p != end (); p++) - contents(p).resize (tmp_dims, Matrix ()); - - dimensions = tmp_dims; - } - - maybe_add_to_key_list (k); - - map[k] = tmp; - } - - return *this; -} - -Octave_map& -Octave_map::assign (const std::string& k, const octave_value& rhs) -{ - if (nfields () == 0) - { - maybe_add_to_key_list (k); - - map[k] = Cell (rhs); - - dimensions = dim_vector (1, 1); - } - else - { - dim_vector dv = dims (); - - if (dv.all_ones ()) - { - maybe_add_to_key_list (k); - - map[k] = Cell (rhs); - } - else - error ("invalid structure assignment"); - } - - return *this; -} - -Octave_map& -Octave_map::assign (const std::string& k, const Cell& rhs) -{ - if (nfields () == 0) - { - maybe_add_to_key_list (k); - - map[k] = rhs; - - dimensions = rhs.dims (); - } - else - { - if (dims () == rhs.dims ()) - { - maybe_add_to_key_list (k); - - map[k] = rhs; - } - else - error ("invalid structure assignment"); - } - - return *this; -} - -Octave_map -Octave_map::index (const octave_value_list& idx, bool resize_ok) const -{ - Octave_map retval; - - octave_idx_type n_idx = idx.length (); - - if (n_idx > 0) - { - Array ra_idx (dim_vector (n_idx, 1)); - - for (octave_idx_type i = 0; i < n_idx; i++) - { - ra_idx(i) = idx(i).index_vector (); - if (error_state) - break; - } - - if (! error_state) - { - for (const_iterator p = begin (); p != end (); p++) - { - Cell tmp = contents (p); - - tmp = tmp.Array::index (ra_idx, resize_ok); - - if (error_state) - break; - - retval.assign (key(p), tmp); - } - - // Preserve order of keys. - retval.key_list = key_list; - } - } - else - retval = *this; - - return retval; -} diff -r a132d206a36a -r b9b6a310ad97 src/oct-map.h --- a/src/oct-map.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,659 +0,0 @@ -/* - -Copyright (C) 1994-2012 John W. Eaton -Copyright (C) 2010 VZLU Prague - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_oct_map_h) -#define octave_oct_map_h 1 - -#include -#include - -#include "Cell.h" -#include "oct-obj.h" - -class string_vector; - -// A class holding a map field->index. Supports reference-counting. -class OCTINTERP_API -octave_fields -{ - class fields_rep : public std::map - { - public: - fields_rep (void) : std::map (), count (1) { } - fields_rep (const fields_rep& other) - : std::map (other), count (1) { } - - octave_refcount count; - - private: - fields_rep& operator = (const fields_rep&); // no assignment! - }; - - fields_rep *rep; - - static fields_rep *nil_rep (void) - { - static fields_rep nr; - return &nr; - } - -public: - - octave_fields (void) : rep (nil_rep ()) { rep->count++; } - octave_fields (const string_vector&); - octave_fields (const char * const *); - - ~octave_fields (void) - { - if (--rep->count == 0) - delete rep; - } - - void make_unique (void) - { - if (rep->count > 1) - { - fields_rep *r = new fields_rep (*rep); - - if (--rep->count == 0) - delete rep; - - rep = r; - } - } - - octave_fields (const octave_fields& o) : rep (o.rep) { rep->count++; } - - octave_fields& - operator = (const octave_fields& o) - { - o.rep->count++; - if (--rep->count == 0) - delete rep; - rep = o.rep; - - return *this; - } - - // constant iteration support. non-const iteration intentionally unsupported. - - typedef std::map::const_iterator const_iterator; - typedef const_iterator iterator; - - const_iterator begin (void) const { return rep->begin (); } - const_iterator end (void) const { return rep->end (); } - - std::string key (const_iterator p) const { return p->first; } - octave_idx_type index (const_iterator p) const { return p->second; } - - const_iterator seek (const std::string& k) const - { return rep->find (k); } - - // high-level methods. - - // number of fields. - octave_idx_type nfields (void) const { return rep->size (); } - - // check whether a field exists. - bool isfield (const std::string& name) const; - - // get index of field. return -1 if not exist - octave_idx_type getfield (const std::string& name) const; - // get index of field. add if not exist - octave_idx_type getfield (const std::string& name); - // remove field and return the index. -1 if didn't exist. - octave_idx_type rmfield (const std::string& name); - - // order the fields of this map. creates a permutation - // used to order the fields. - void orderfields (Array& perm); - - // compares two instances for equality up to order of fields. - // returns a permutation needed to bring the fields of *other* - // into the order of *this*. - bool equal_up_to_order (const octave_fields& other, - octave_idx_type* perm) const; - - bool equal_up_to_order (const octave_fields& other, - Array& perm) const; - - bool is_same (const octave_fields& other) const - { return rep == other.rep; } - - // Returns the fields as a vector of strings. - string_vector fieldnames (void) const; - - void clear (void) - { - *this = octave_fields (); - } -}; - - -class OCTINTERP_API -octave_scalar_map -{ -public: - - octave_scalar_map (const octave_fields& k) - : xkeys (k), xvals (k.nfields ()) { } - - octave_scalar_map (void) : xkeys (), xvals () { } - - octave_scalar_map (const string_vector& k) - : xkeys (k), xvals (k.length ()) { } - - octave_scalar_map (const octave_scalar_map& m) - : xkeys (m.xkeys), xvals(m.xvals) { } - - octave_scalar_map& operator = (const octave_scalar_map& m) - { - xkeys = m.xkeys; - xvals = m.xvals; - - return *this; - } - - // iteration support. note that both const and non-const iterators are the - // same. The const/non-const distinction is made by the key & contents method. - typedef octave_fields::const_iterator const_iterator; - typedef const_iterator iterator; - - const_iterator begin (void) const { return xkeys.begin (); } - const_iterator end (void) const { return xkeys.end (); } - - const_iterator seek (const std::string& k) const { return xkeys.seek (k); } - - std::string key (const_iterator p) const - { return xkeys.key (p); } - octave_idx_type index (const_iterator p) const - { return xkeys.index (p); } - - const octave_value& contents (const_iterator p) const - { return xvals[xkeys.index (p)]; } - - octave_value& contents (iterator p) - { return xvals[xkeys.index (p)]; } - - const octave_value& contents (octave_idx_type i) const - { return xvals[i]; } - - octave_value& contents (octave_idx_type i) - { return xvals[i]; } - - // number of fields. - octave_idx_type nfields (void) const { return xkeys.nfields (); } - - // check whether a field exists. - bool isfield (const std::string& name) const - { return xkeys.isfield (name); } - - bool contains (const std::string& name) const - { return isfield (name); } - - string_vector fieldnames (void) const - { return xkeys.fieldnames (); } - - string_vector keys (void) const - { return fieldnames (); } - - // get contents of a given field. empty value if not exist. - octave_value getfield (const std::string& key) const; - - // set contents of a given field. add if not exist. - void setfield (const std::string& key, const octave_value& val); - void assign (const std::string& k, const octave_value& val) - { setfield (k, val); } - - // remove a given field. do nothing if not exist. - void rmfield (const std::string& key); - void del (const std::string& k) { rmfield (k); } - - // return a copy with fields ordered, optionally along with permutation. - octave_scalar_map orderfields (void) const; - octave_scalar_map orderfields (Array& perm) const; - octave_scalar_map orderfields (const octave_scalar_map& other, - Array& perm) const; - - // aka getfield/setfield, but the latter returns a reference. - octave_value contents (const std::string& k) const; - octave_value& contents (const std::string& k); - - void clear (void) - { - xkeys.clear (); - xvals.clear (); - } - - friend class octave_map; - -private: - - octave_fields xkeys; - std::vector xvals; - -}; - -template<> -inline octave_scalar_map octave_value_extract (const octave_value& v) - { return v.scalar_map_value (); } - -class OCTINTERP_API -octave_map -{ -public: - - octave_map (const octave_fields& k) - : xkeys (k), xvals (k.nfields ()), dimensions () { } - - octave_map (const dim_vector& dv, const octave_fields& k) - : xkeys (k), xvals (k.nfields (), Cell (dv)), dimensions (dv) { } - - typedef octave_scalar_map element_type; - - octave_map (void) : xkeys (), xvals (), dimensions () { } - - octave_map (const dim_vector& dv) : xkeys (), xvals (), dimensions (dv) { } - - octave_map (const string_vector& k) - : xkeys (k), xvals (k.length (), Cell (1, 1)), dimensions (1, 1) { } - - octave_map (const dim_vector& dv, const string_vector& k) - : xkeys (k), xvals (k.length (), Cell (dv)), dimensions (dv) { } - - octave_map (const octave_map& m) - : xkeys (m.xkeys), xvals (m.xvals), dimensions (m.dimensions) { } - - octave_map (const octave_scalar_map& m); - - octave_map (const Octave_map& m); - - octave_map& operator = (const octave_map& m) - { - xkeys = m.xkeys; - xvals = m.xvals; - dimensions = m.dimensions; - - return *this; - } - - // iteration support. note that both const and non-const iterators are the - // same. The const/non-const distinction is made by the key & contents method. - typedef octave_fields::const_iterator const_iterator; - typedef const_iterator iterator; - - const_iterator begin (void) const { return xkeys.begin (); } - const_iterator end (void) const { return xkeys.end (); } - - const_iterator seek (const std::string& k) const { return xkeys.seek (k); } - - std::string key (const_iterator p) const - { return xkeys.key (p); } - octave_idx_type index (const_iterator p) const - { return xkeys.index (p); } - - const Cell& contents (const_iterator p) const - { return xvals[xkeys.index (p)]; } - - Cell& contents (iterator p) - { return xvals[xkeys.index (p)]; } - - const Cell& contents (octave_idx_type i) const - { return xvals[i]; } - - Cell& contents (octave_idx_type i) - { return xvals[i]; } - - // number of fields. - octave_idx_type nfields (void) const { return xkeys.nfields (); } - - // check whether a field exists. - bool isfield (const std::string& name) const - { return xkeys.isfield (name); } - - bool contains (const std::string& name) const - { return isfield (name); } - - string_vector fieldnames (void) const - { return xkeys.fieldnames (); } - - string_vector keys (void) const - { return fieldnames (); } - - // get contents of a given field. empty value if not exist. - Cell getfield (const std::string& key) const; - - // set contents of a given field. add if not exist. checks for - // correct dimensions. - void setfield (const std::string& key, const Cell& val); - void assign (const std::string& k, const Cell& val) - { setfield (k, val); } - - // remove a given field. do nothing if not exist. - void rmfield (const std::string& key); - void del (const std::string& k) { rmfield (k); } - - // return a copy with fields ordered, optionally along with permutation. - octave_map orderfields (void) const; - octave_map orderfields (Array& perm) const; - octave_map orderfields (const octave_map& other, - Array& perm) const; - - // aka getfield/setfield, but the latter returns a reference. - Cell contents (const std::string& k) const; - Cell& contents (const std::string& k); - - void clear (void) - { - xkeys.clear (); - xvals.clear (); - } - - // The Array-like methods. - octave_idx_type numel (void) const { return dimensions.numel (); } - octave_idx_type length (void) const { return numel (); } - bool is_empty (void) const { return dimensions.any_zero (); } - - octave_idx_type rows (void) const { return dimensions(0); } - octave_idx_type cols (void) const { return dimensions(1); } - octave_idx_type columns (void) const { return dimensions(1); } - - // Extract a scalar substructure. - octave_scalar_map checkelem (octave_idx_type n) const; - octave_scalar_map checkelem (octave_idx_type i, octave_idx_type j) const; - - octave_scalar_map - checkelem (const Array& ra_idx) const; - - octave_scalar_map operator () (octave_idx_type n) const - { return checkelem (n); } - octave_scalar_map operator () (octave_idx_type i, octave_idx_type j) const - { return checkelem (i, j); } - - octave_scalar_map - operator () (const Array& ra_idx) const - { return checkelem (ra_idx); } - - octave_map squeeze (void) const; - - octave_map permute (const Array& vec, bool inv = false) const; - - dim_vector dims (void) const { return dimensions; } - - int ndims (void) const { return dimensions.length (); } - - octave_map transpose (void) const; - - octave_map reshape (const dim_vector& dv) const; - - void resize (const dim_vector& dv, bool fill = false); - - static octave_map - cat (int dim, octave_idx_type n, const octave_scalar_map *map_list); - - static octave_map - cat (int dim, octave_idx_type n, const octave_map *map_list); - - octave_map index (const idx_vector& i, bool resize_ok = false) const; - - octave_map index (const idx_vector& i, const idx_vector& j, - bool resize_ok = false) const; - - octave_map index (const Array& ia, - bool resize_ok = false) const; - - octave_map index (const octave_value_list&, bool resize_ok = false) const; - - octave_map column (octave_idx_type k) const; - octave_map page (octave_idx_type k) const; - - void assign (const idx_vector& i, const octave_map& rhs); - - void assign (const idx_vector& i, const idx_vector& j, const octave_map& rhs); - - void assign (const Array& ia, const octave_map& rhs); - - void assign (const octave_value_list&, const octave_map& rhs); - - void assign (const octave_value_list& idx, const std::string& k, - const Cell& rhs); - - void delete_elements (const idx_vector& i); - - void delete_elements (int dim, const idx_vector& i); - - void delete_elements (const Array& ia); - - void delete_elements (const octave_value_list&); - - octave_map concat (const octave_map& rb, const Array& ra_idx); - - // like checkelem, but no check. - octave_scalar_map fast_elem_extract (octave_idx_type n) const; - - // element assignment, no bounds check - bool fast_elem_insert (octave_idx_type n, const octave_scalar_map& rhs); - -private: - - octave_fields xkeys; - std::vector xvals; - dim_vector dimensions; - - void optimize_dimensions (void); - void extract_scalar (octave_scalar_map& dest, - octave_idx_type index) const; - static void do_cat (int dim, octave_idx_type n, - const octave_scalar_map *map_list, octave_map& retval); - static void do_cat (int dim, octave_idx_type n, - const octave_map *map_list, octave_map& retval); -}; - -template<> -inline octave_map octave_value_extract (const octave_value& v) - { return v.map_value (); } - -// The original Octave_map object. Octave_map and octave_map are convertible to -// each other. - -class -OCTINTERP_API -Octave_map -{ - public: - - typedef std::map::iterator iterator; - typedef std::map::const_iterator const_iterator; - - typedef std::list::iterator key_list_iterator; - typedef std::list::const_iterator const_key_list_iterator; - - // Warning! You should always use at least two dimensions. - - Octave_map (const dim_vector& dv = dim_vector (0, 0), - const Cell& key_vals = Cell ()); - - Octave_map (const std::string& k, const octave_value& value) - : map (), key_list (), dimensions (1, 1) - { - map[k] = value; - key_list.push_back (k); - } - - Octave_map (const string_vector& sv, - const dim_vector& dv = dim_vector (0, 0)) - : map (), key_list (), dimensions (dv) - { - for (octave_idx_type i = 0; i < sv.length (); i++) - { - std::string k = sv[i]; - map[k] = Cell (dv); - key_list.push_back (k); - } - } - - Octave_map (const std::string& k, const Cell& vals) - : map (), key_list (), dimensions (vals.dims ()) - { - map[k] = vals; - key_list.push_back (k); - } - - Octave_map (const std::string& k, const octave_value_list& val_list) - : map (), key_list (), dimensions (1, val_list.length ()) - { - map[k] = val_list; - key_list.push_back (k); - } - - Octave_map (const Octave_map& m) - : map (m.map), key_list (m.key_list), dimensions (m.dimensions) { } - - Octave_map (const octave_map& m); - - Octave_map& operator = (const Octave_map& m) - { - if (this != &m) - { - map = m.map; - key_list = m.key_list; - dimensions = m.dimensions; - } - - return *this; - } - - ~Octave_map (void) { } - - Octave_map squeeze (void) const; - - Octave_map permute (const Array& vec, bool inv = false) const; - - // This is the number of keys. - octave_idx_type nfields (void) const { return map.size (); } - - void del (const std::string& k) - { - iterator p = map.find (k); - - if (p != map.end ()) - { - map.erase (p); - - key_list_iterator q - = std::find (key_list.begin (), key_list.end (), k); - - assert (q != key_list.end ()); - - key_list.erase (q); - } - } - - iterator begin (void) { return iterator (map.begin ()); } - const_iterator begin (void) const { return const_iterator (map.begin ()); } - - iterator end (void) { return iterator (map.end ()); } - const_iterator end (void) const { return const_iterator (map.end ()); } - - std::string key (const_iterator p) const { return p->first; } - - Cell& contents (const std::string& k); - Cell contents (const std::string& k) const; - - Cell& contents (iterator p) - { return p->second; } - - Cell contents (const_iterator p) const - { return p->second; } - - int intfield (const std::string& k, int def_val = 0) const; - - std::string stringfield (const std::string& k, - const std::string& def_val = std::string ()) const; - - iterator seek (const std::string& k) { return map.find (k); } - const_iterator seek (const std::string& k) const { return map.find (k); } - - bool contains (const std::string& k) const - { return (seek (k) != map.end ()); } - - void clear (void) - { - map.clear (); - key_list.clear (); - } - - string_vector keys (void) const; - - octave_idx_type rows (void) const { return dimensions(0); } - - octave_idx_type columns (void) const { return dimensions(1); } - - dim_vector dims (void) const { return dimensions; } - - int ndims (void) const { return dimensions.length (); } - - Octave_map transpose (void) const; - - Octave_map reshape (const dim_vector& new_dims) const; - - void resize (const dim_vector& dv, bool fill = false); - - octave_idx_type numel (void) const { return dimensions.numel (); } - - Octave_map concat (const Octave_map& rb, const Array& ra_idx); - - Octave_map& maybe_delete_elements (const octave_value_list& idx); - - Octave_map& assign (const octave_value_list& idx, const Octave_map& rhs); - - Octave_map& assign (const octave_value_list& idx, const std::string& k, - const Cell& rhs); - - Octave_map& assign (const std::string& k, const octave_value& rhs); - - Octave_map& assign (const std::string& k, const Cell& rhs); - - Octave_map index (const octave_value_list& idx, - bool resize_ok = false) const; - -private: - - // The map of names to values. - std::map map; - - // An extra list of keys, so we can keep track of the order the keys - // are added for compatibility with you know what. - std::list key_list; - - // The current size. - mutable dim_vector dimensions; - - void maybe_add_to_key_list (const std::string& k) - { - if (! contains (k)) - key_list.push_back (k); - } -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/oct-obj.cc --- a/src/oct-obj.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,284 +0,0 @@ -/* - -Copyright (C) 1994-2012 John W. Eaton -Copyright (C) 2009 VZLU Prague - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "error.h" -#include "oct-obj.h" -#include "Cell.h" - -// We are likely to have a lot of octave_value_list objects to allocate, -// so make the grow_size large. -DEFINE_OCTAVE_ALLOCATOR2(octave_value_list, 1024); - -octave_value_list::octave_value_list (const std::list& lst) -{ - octave_idx_type n = 0, nel = 0; - - // Determine number. - for (std::list::const_iterator p = lst.begin (); - p != lst.end (); p++) - { - n++; - nel += p->length (); - } - - // Optimize single-element case - if (n == 1) - data = lst.front ().data; - else if (nel > 0) - { - data.resize (dim_vector (1, nel)); - octave_idx_type k = 0; - for (std::list::const_iterator p = lst.begin (); - p != lst.end (); p++) - { - data.assign (idx_vector (k, k + p->length ()), p->data); - k += p->length (); - } - assert (k == nel); - } - -} - -octave_value_list& -octave_value_list::prepend (const octave_value& val) -{ - octave_idx_type n = length (); - - resize (n + 1); - - while (n > 0) - { - elem (n) = elem (n - 1); - n--; - } - - elem (0) = val; - - return *this; -} - -octave_value_list& -octave_value_list::append (const octave_value& val) -{ - octave_idx_type n = length (); - - resize (n + 1); - - elem (n) = val; - - return *this; -} - -octave_value_list& -octave_value_list::append (const octave_value_list& lst) -{ - octave_idx_type len = length (); - octave_idx_type lst_len = lst.length (); - - resize (len + lst_len); - - for (octave_idx_type i = 0; i < lst_len; i++) - elem (len + i) = lst (i); - - return *this; -} - -octave_value_list& -octave_value_list::reverse (void) -{ - octave_idx_type n = length (); - - for (octave_idx_type i = 0; i < n / 2; i++) - { - octave_value tmp = elem (i); - elem (i) = elem (n - i - 1); - elem (n - i - 1) = tmp; - } - - return *this; -} - -octave_value_list -octave_value_list::splice (octave_idx_type offset, octave_idx_type rep_length, - const octave_value_list& lst) const -{ - octave_value_list retval; - - octave_idx_type len = length (); - - if (offset < 0 || offset >= len) - { - if (! (rep_length == 0 && offset == len)) - { - error ("octave_value_list::splice: invalid OFFSET"); - return retval; - } - } - - if (rep_length < 0 || rep_length + offset > len) - { - error ("octave_value_list::splice: invalid LENGTH"); - return retval; - } - - octave_idx_type lst_len = lst.length (); - - octave_idx_type new_len = len - rep_length + lst_len; - - retval.resize (new_len); - - octave_idx_type k = 0; - - for (octave_idx_type i = 0; i < offset; i++) - retval(k++) = elem (i); - - for (octave_idx_type i = 0; i < lst_len; i++) - retval(k++) = lst (i); - - for (octave_idx_type i = offset + rep_length; i < len; i++) - retval(k++) = elem (i); - - return retval; -} - -bool -octave_value_list::all_strings_p (void) const -{ - octave_idx_type n = length (); - - for (octave_idx_type i = 0; i < n; i++) - if (! elem(i).is_string ()) - return false; - - return true; -} - -bool -octave_value_list::all_scalars (void) const -{ - octave_idx_type n = length (); - - for (octave_idx_type i = 0; i < n; i++) - { - dim_vector dv = elem(i).dims (); - if (! dv.all_ones ()) - return false; - } - - return true; -} - -bool -octave_value_list::any_cell (void) const -{ - octave_idx_type n = length (); - - for (octave_idx_type i = 0; i < n; i++) - if (elem (i).is_cell ()) - return true; - - return false; -} - -bool -octave_value_list::has_magic_colon (void) const -{ - octave_idx_type n = length (); - - for (octave_idx_type i = 0; i < n; i++) - if (elem(i).is_magic_colon ()) - return true; - - return false; -} - -string_vector -octave_value_list::make_argv (const std::string& fcn_name) const -{ - string_vector argv; - - if (all_strings_p ()) - { - octave_idx_type len = length (); - - octave_idx_type total_nr = 0; - - for (octave_idx_type i = 0; i < len; i++) - { - // An empty std::string ("") has zero columns and zero rows (a - // change that was made for Matlab contemptibility. - - octave_idx_type n = elem(i).rows (); - - total_nr += n ? n : 1; - } - - octave_idx_type k = 0; - if (! fcn_name.empty ()) - { - argv.resize (total_nr+1); - argv[0] = fcn_name; - k = 1; - } - else - argv.resize (total_nr); - - for (octave_idx_type i = 0; i < len; i++) - { - octave_idx_type nr = elem(i).rows (); - - if (nr < 2) - argv[k++] = elem(i).string_value (); - else - { - string_vector tmp = elem(i).all_strings (); - - for (octave_idx_type j = 0; j < nr; j++) - argv[k++] = tmp[j]; - } - } - } - else - error ("%s: expecting all arguments to be strings", fcn_name.c_str ()); - - return argv; -} - -void -octave_value_list::make_storable_values (void) -{ - octave_idx_type len = length (); - const Array& cdata = data; - - for (octave_idx_type i = 0; i < len; i++) - { - // This is optimized so that we don't force a copy unless necessary. - octave_value tmp = cdata(i).storable_value (); - if (! tmp.is_copy_of (cdata (i))) - data(i) = tmp; - } -} diff -r a132d206a36a -r b9b6a310ad97 src/oct-obj.h --- a/src/oct-obj.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,169 +0,0 @@ -/* - -Copyright (C) 1994-2012 John W. Eaton -Copyright (C) 2009 VZLU Prague - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_oct_obj_h) -#define octave_oct_obj_h 1 - -#include -#include - -#include "oct-alloc.h" -#include "str-vec.h" -#include "Array.h" - -#include "ov.h" -#include "Cell.h" - -class -OCTINTERP_API -octave_value_list -{ -public: - - octave_value_list (void) - : data (), names () { } - - explicit octave_value_list (octave_idx_type n) - : data (dim_vector (1, n)), names () { } - - octave_value_list (octave_idx_type n, const octave_value& val) - : data (dim_vector (1, n), val), names () { } - - octave_value_list (const octave_value& tc) - : data (dim_vector (1, 1), tc), names () { } - - octave_value_list (const Array& d) - : data (d.as_row ()), names () { } - - octave_value_list (const Cell& tc) - : data (tc.as_row ()), names () { } - - octave_value_list (const octave_value_list& obj) - : data (obj.data), names (obj.names) { } - - // Concatenation constructor. - octave_value_list (const std::list&); - - ~octave_value_list (void) { } - - octave_value_list& operator = (const octave_value_list& obj) - { - if (this != &obj) - { - data = obj.data; - names = obj.names; - } - - return *this; - } - - Array array_value (void) const { return data; } - - Cell cell_value (void) const { return array_value (); } - - // Assignment will resize on range errors. - - octave_value& operator () (octave_idx_type n) { return elem (n); } - - const octave_value& operator () (octave_idx_type n) const { return elem (n); } - - octave_idx_type length (void) const { return data.length (); } - - bool empty (void) const { return length () == 0; } - - void resize (octave_idx_type n, const octave_value& rfv = octave_value ()) - { - data.resize (dim_vector (1, n), rfv); - } - - octave_value_list& prepend (const octave_value& val); - - octave_value_list& append (const octave_value& val); - - octave_value_list& append (const octave_value_list& lst); - - octave_value_list& reverse (void); - - octave_value_list - slice (octave_idx_type offset, octave_idx_type len, bool tags = false) const - { - octave_value_list retval (data.linear_slice (offset, offset + len)); - if (tags && len > 0 && names.length () > 0) - retval.names = names.linear_slice (offset, std::min (len, names.length ())); - - return retval; - } - - octave_value_list - splice (octave_idx_type offset, octave_idx_type len, - const octave_value_list& lst = octave_value_list ()) const; - - bool all_strings_p (void) const; - - bool all_scalars (void) const; - - bool any_cell (void) const; - - bool has_magic_colon (void) const; - - string_vector make_argv (const std::string& = std::string ()) const; - - void stash_name_tags (const string_vector& nm) { names = nm; } - - string_vector name_tags (void) const { return names; } - - void make_storable_values (void); - - octave_value& xelem (octave_idx_type i) - { - return data.xelem (i); - } - - void clear (void) - { - data.clear (); - } - -private: - - Array data; - - // This list of strings can be used to tag each element of data with - // a name. By default, it is empty. - string_vector names; - - octave_value& elem (octave_idx_type n) - { - if (n >= length ()) - resize (n + 1); - - return data(n); - } - - const octave_value& elem (octave_idx_type n) const - { return data(n); } - - DECLARE_OCTAVE_ALLOCATOR -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/oct-prcstrm.cc --- a/src/oct-prcstrm.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "oct-prcstrm.h" -#include "sysdep.h" - -octave_stream -octave_iprocstream::create (const std::string& n, std::ios::openmode arg_md, - oct_mach_info::float_format ff) -{ - return octave_stream (new octave_iprocstream (n, arg_md, ff)); -} - -octave_iprocstream::octave_iprocstream (const std::string& n, - std::ios::openmode arg_md, - oct_mach_info::float_format ff) - : octave_stdiostream (n, octave_popen (n.c_str (), "r"), - arg_md, ff, octave_pclose) -{ -} - -octave_iprocstream::~octave_iprocstream (void) -{ - do_close (); -} - -octave_stream -octave_oprocstream::create (const std::string& n, std::ios::openmode arg_md, - oct_mach_info::float_format ff) -{ - return octave_stream (new octave_oprocstream (n, arg_md, ff)); -} - -octave_oprocstream::octave_oprocstream (const std::string& n, - std::ios::openmode arg_md, - oct_mach_info::float_format ff) - : octave_stdiostream (n, octave_popen (n.c_str (), "w"), - arg_md, ff, octave_pclose) -{ -} - -octave_oprocstream::~octave_oprocstream (void) -{ - do_close (); -} diff -r a132d206a36a -r b9b6a310ad97 src/oct-prcstrm.h --- a/src/oct-prcstrm.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_octave_procstream_h) -#define octave_octave_procstream_h 1 - -#include "oct-stdstrm.h" - -// FIXME -- why don't these classes use iprocstream and -// oprocstream, which in turn use the octave_procbuf class? - -class -octave_iprocstream : public octave_stdiostream -{ -public: - - octave_iprocstream (const std::string& n, - std::ios::openmode arg_md = std::ios::in, - oct_mach_info::float_format flt_fmt - = oct_mach_info::native_float_format ()); - - static octave_stream - create (const std::string& n, std::ios::openmode arg_md = std::ios::in, - oct_mach_info::float_format flt_fmt - = oct_mach_info::native_float_format ()); - -protected: - - ~octave_iprocstream (void); - -private: - - // No copying! - - octave_iprocstream (const octave_iprocstream&); - - octave_iprocstream& operator = (const octave_iprocstream&); -}; - -class -octave_oprocstream : public octave_stdiostream -{ -public: - - octave_oprocstream (const std::string& n, - std::ios::openmode arg_md = std::ios::out, - oct_mach_info::float_format flt_fmt - = oct_mach_info::native_float_format ()); - - static octave_stream - create (const std::string& n, std::ios::openmode arg_md = std::ios::out, - oct_mach_info::float_format flt_fmt - = oct_mach_info::native_float_format ()); - -protected: - - ~octave_oprocstream (void); - -private: - - // No copying! - - octave_oprocstream (const octave_oprocstream&); - - octave_oprocstream& operator = (const octave_oprocstream&); -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/oct-procbuf.cc --- a/src/oct-procbuf.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,218 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include - -#include -#include - -#include "lo-mappers.h" -#include "lo-utils.h" -#include "oct-procbuf.h" -#include "oct-syscalls.h" -#include "sysdep.h" -#include "variables.h" - -#include "defun.h" -#include "gripes.h" -#include "utils.h" - -// This class is based on the procbuf class from libg++, written by -// Per Bothner, Copyright (C) 1993 Free Software Foundation. - -static octave_procbuf *octave_procbuf_list = 0; - -#ifndef BUFSIZ -#define BUFSIZ 1024 -#endif - -octave_procbuf * -octave_procbuf::open (const char *command, int mode) -{ -#if defined (__CYGWIN__) || defined (__MINGW32__) || defined (_MSC_VER) - - if (is_open ()) - return 0; - - f = octave_popen (command, (mode & std::ios::in) ? "r" : "w"); - - if (! f) - return 0; - - // Oops... popen doesn't return the associated pid, so fake it for now - - proc_pid = 1; - - open_p = true; - - if (mode & std::ios::out) - ::setvbuf (f, 0, _IOLBF, BUFSIZ); - - return this; - -#elif defined (HAVE_SYS_WAIT_H) - - int pipe_fds[2]; - - volatile int child_std_end = (mode & std::ios::in) ? 1 : 0; - - volatile int parent_end, child_end; - - if (is_open ()) - return 0; - - if (pipe (pipe_fds) < 0) - return 0; - - if (mode & std::ios::in) - { - parent_end = pipe_fds[0]; - child_end = pipe_fds[1]; - } - else - { - parent_end = pipe_fds[1]; - child_end = pipe_fds[0]; - } - - proc_pid = ::fork (); - - if (proc_pid == 0) - { - gnulib::close (parent_end); - - if (child_end != child_std_end) - { - gnulib::dup2 (child_end, child_std_end); - gnulib::close (child_end); - } - - while (octave_procbuf_list) - { - FILE *fp = octave_procbuf_list->f; - - if (fp) - { - gnulib::fclose (fp); - fp = 0; - } - - octave_procbuf_list = octave_procbuf_list->next; - } - - execl ("/bin/sh", "sh", "-c", command, static_cast (0)); - - exit (127); - } - - gnulib::close (child_end); - - if (proc_pid < 0) - { - gnulib::close (parent_end); - return 0; - } - - f = ::fdopen (parent_end, (mode & std::ios::in) ? "r" : "w"); - - if (mode & std::ios::out) - ::setvbuf (f, 0, _IOLBF, BUFSIZ); - - open_p = true; - - next = octave_procbuf_list; - octave_procbuf_list = this; - - return this; - -#else - - return 0; - -#endif -} - -octave_procbuf * -octave_procbuf::close (void) -{ -#if defined (__CYGWIN__) || defined (__MINGW32__) || defined (_MSC_VER) - - if (f) - { - wstatus = octave_pclose (f); - f = 0; - } - - open_p = false; - - return this; - -#elif defined (HAVE_SYS_WAIT_H) - - if (f) - { - pid_t wait_pid; - - int status = -1; - - for (octave_procbuf **ptr = &octave_procbuf_list; - *ptr != 0; - ptr = &(*ptr)->next) - { - if (*ptr == this) - { - *ptr = (*ptr)->next; - status = 0; - break; - } - } - - if (status == 0 && gnulib::fclose (f) == 0) - { - using namespace std; - - do - { - wait_pid = octave_syscalls::waitpid (proc_pid, &wstatus, 0); - } - while (wait_pid == -1 && errno == EINTR); - } - - f = 0; - } - - open_p = false; - - return this; - -#else - - return 0; - -#endif -} diff -r a132d206a36a -r b9b6a310ad97 src/oct-procbuf.h --- a/src/oct-procbuf.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -// This class is based on the procbuf class from libg++, written by -// Per Bothner, Copyright (C) 1993 Free Software Foundation. - -#if !defined (octave_octave_procbuf_h) -#define octave_octave_procbuf_h 1 - -#include - -#include "c-file-ptr-stream.h" - -class -octave_procbuf : public c_file_ptr_buf -{ -public: - - octave_procbuf (void) - : c_file_ptr_buf (0), wstatus (-1), open_p (false), proc_pid (-1), - next (0) { } - - octave_procbuf (const char *command, int mode) - : c_file_ptr_buf (0), wstatus (-1), open_p (false), proc_pid (-1), - next (0) { open (command, mode); } - - ~octave_procbuf (void) { close (); } - - octave_procbuf *open (const char *command, int mode); - - octave_procbuf *close (void); - - int wait_status (void) const { return wstatus; } - - bool is_open (void) const { return open_p; } - - pid_t pid (void) const { return proc_pid; } - -protected: - - int wstatus; - - bool open_p; - - pid_t proc_pid; - - octave_procbuf *next; - -private: - - // No copying! - - octave_procbuf (const octave_procbuf&); - - octave_procbuf& operator = (const octave_procbuf&); -}; - -extern void symbols_of_oct_procbuf (void); - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/oct-stdstrm.h --- a/src/oct-stdstrm.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,175 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_octave_stdiostream_h) -#define octave_octave_stdiostream_h 1 - -#include "oct-stream.h" -#include "c-file-ptr-stream.h" - -template -class -octave_tstdiostream : public octave_base_stream -{ -public: - - octave_tstdiostream (const std::string& n, FILE_T f = 0, int fid = 0, - std::ios::openmode m = std::ios::in|std::ios::out, - oct_mach_info::float_format ff - = oct_mach_info::native_float_format (), - typename BUF_T::close_fcn cf = BUF_T::file_close) - : octave_base_stream (m, ff), nm (n), md (m), - s (f ? new STREAM_T (f, cf) : 0), fnum (fid) - { } - - // Position a stream at OFFSET relative to ORIGIN. - - int seek (long offset, int origin) - { return s ? s->seek (offset, origin) : -1; } - - // Return current stream position. - - long tell (void) { return s ? s->tell () : -1; } - - // Return non-zero if EOF has been reached on this stream. - - bool eof (void) const { return s ? s->eof () : true; } - - // The name of the file. - - std::string name (void) const { return nm; } - - std::istream *input_stream (void) { return (md & std::ios::in) ? s : 0; } - - std::ostream *output_stream (void) { return (md & std::ios::out) ? s : 0; } - - // FIXME -- should not have to cast away const here. - BUF_T *rdbuf (void) const - { return s ? (const_cast (s))->rdbuf () : 0; } - - int file_number (void) const { return fnum; } - - bool bad (void) const { return s ? s->bad () : true; } - - void clear (void) { if (s) s->clear (); } - - void do_close (void) { if (s) s->stream_close (); } - -protected: - - std::string nm; - - std::ios::openmode md; - - STREAM_T *s; - - // The file number associated with this file. - int fnum; - - ~octave_tstdiostream (void) { delete s; } - -private: - - // No copying! - - octave_tstdiostream (const octave_tstdiostream&); - - octave_tstdiostream& operator = (const octave_tstdiostream&); -}; - -class -octave_stdiostream - : public octave_tstdiostream -{ -public: - - octave_stdiostream (const std::string& n, FILE *f = 0, - std::ios::openmode m = std::ios::in|std::ios::out, - oct_mach_info::float_format ff - = oct_mach_info::native_float_format (), - c_file_ptr_buf::close_fcn cf = c_file_ptr_buf::file_close) - : octave_tstdiostream (n, f, f ? fileno (f) : -1, m, ff, cf) { } - - static octave_stream - create (const std::string& n, FILE *f = 0, - std::ios::openmode m = std::ios::in|std::ios::out, - oct_mach_info::float_format ff - = oct_mach_info::native_float_format (), - c_file_ptr_buf::close_fcn cf = c_file_ptr_buf::file_close) - { - return octave_stream (new octave_stdiostream (n, f, m, ff, cf)); - } - -protected: - - ~octave_stdiostream (void) { } - -private: - - // No copying! - - octave_stdiostream (const octave_stdiostream&); - - octave_stdiostream& operator = (const octave_stdiostream&); -}; - -#ifdef HAVE_ZLIB - -class -octave_zstdiostream - : public octave_tstdiostream -{ -public: - - octave_zstdiostream (const std::string& n, gzFile f = 0, int fid = 0, - std::ios::openmode m = std::ios::in|std::ios::out, - oct_mach_info::float_format ff - = oct_mach_info::native_float_format (), - c_zfile_ptr_buf::close_fcn cf = c_zfile_ptr_buf::file_close) - : octave_tstdiostream (n, f, fid, m, ff, cf) { } - - static octave_stream - create (const std::string& n, gzFile f = 0, int fid = 0, - std::ios::openmode m = std::ios::in|std::ios::out, - oct_mach_info::float_format ff - = oct_mach_info::native_float_format (), - c_zfile_ptr_buf::close_fcn cf = c_zfile_ptr_buf::file_close) - { - return octave_stream (new octave_zstdiostream (n, f, fid, m, ff, cf)); - } - -protected: - - ~octave_zstdiostream (void) { } - -private: - - // No copying! - - octave_zstdiostream (const octave_zstdiostream&); - - octave_zstdiostream& operator = (const octave_zstdiostream&); -}; - -#endif - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/oct-stream.cc --- a/src/oct-stream.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4308 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include "byte-swap.h" -#include "lo-ieee.h" -#include "lo-mappers.h" -#include "lo-utils.h" -#include "quit.h" -#include "singleton-cleanup.h" -#include "str-vec.h" - -#include "error.h" -#include "gripes.h" -#include "input.h" -#include "oct-stdstrm.h" -#include "oct-stream.h" -#include "oct-obj.h" -#include "utils.h" - -// Possible values for conv_err: -// -// 1 : not a real scalar -// 2 : value is NaN -// 3 : value is not an integer - -static int -convert_to_valid_int (const octave_value& tc, int& conv_err) -{ - int retval = 0; - - conv_err = 0; - - double dval = tc.double_value (); - - if (! error_state) - { - if (! lo_ieee_isnan (dval)) - { - int ival = NINT (dval); - - if (ival == dval) - retval = ival; - else - conv_err = 3; - } - else - conv_err = 2; - } - else - conv_err = 1; - - return retval; -} - -static int -get_size (double d, const std::string& who) -{ - int retval = -1; - - if (! lo_ieee_isnan (d)) - { - if (! xisinf (d)) - { - if (d >= 0.0) - retval = NINT (d); - else - ::error ("%s: negative value invalid as size specification", - who.c_str ()); - } - else - retval = -1; - } - else - ::error ("%s: NaN is invalid as size specification", who.c_str ()); - - return retval; -} - -static void -get_size (const Array& size, octave_idx_type& nr, octave_idx_type& nc, bool& one_elt_size_spec, - const std::string& who) -{ - nr = -1; - nc = -1; - - one_elt_size_spec = false; - - double dnr = -1.0; - double dnc = -1.0; - - octave_idx_type sz_len = size.length (); - - if (sz_len == 1) - { - one_elt_size_spec = true; - - dnr = size (0); - - dnc = (dnr == 0.0) ? 0.0 : 1.0; - } - else if (sz_len == 2) - { - dnr = size (0); - - if (! xisinf (dnr)) - dnc = size (1); - else - ::error ("%s: invalid size specification", who.c_str ()); - } - else - ::error ("%s: invalid size specification", who.c_str ()); - - if (! error_state) - { - nr = get_size (dnr, who); - - if (! error_state && dnc >= 0.0) - nc = get_size (dnc, who); - } -} - -scanf_format_list::scanf_format_list (const std::string& s) - : nconv (0), curr_idx (0), list (dim_vector (16, 1)), buf (0) -{ - octave_idx_type num_elts = 0; - - size_t n = s.length (); - - size_t i = 0; - - int width = 0; - bool discard = false; - char modifier = '\0'; - char type = '\0'; - - bool have_more = true; - - while (i < n) - { - have_more = true; - - if (! buf) - buf = new std::ostringstream (); - - if (s[i] == '%') - { - // Process percent-escape conversion type. - - process_conversion (s, i, n, width, discard, type, modifier, - num_elts); - - have_more = (buf != 0); - } - else if (isspace (s[i])) - { - type = scanf_format_elt::whitespace_conversion; - - width = 0; - discard = false; - modifier = '\0'; - *buf << " "; - - while (++i < n && isspace (s[i])) - /* skip whitespace */; - - add_elt_to_list (width, discard, type, modifier, num_elts); - - have_more = false; - } - else - { - type = scanf_format_elt::literal_conversion; - - width = 0; - discard = false; - modifier = '\0'; - - while (i < n && ! isspace (s[i]) && s[i] != '%') - *buf << s[i++]; - - add_elt_to_list (width, discard, type, modifier, num_elts); - - have_more = false; - } - - if (nconv < 0) - { - have_more = false; - break; - } - } - - if (have_more) - add_elt_to_list (width, discard, type, modifier, num_elts); - - list.resize (dim_vector (num_elts, 1)); - - delete buf; -} - -scanf_format_list::~scanf_format_list (void) -{ - octave_idx_type n = list.length (); - - for (octave_idx_type i = 0; i < n; i++) - { - scanf_format_elt *elt = list(i); - delete elt; - } -} - -void -scanf_format_list::add_elt_to_list (int width, bool discard, char type, - char modifier, octave_idx_type& num_elts, - const std::string& char_class) -{ - if (buf) - { - std::string text = buf->str (); - - if (! text.empty ()) - { - scanf_format_elt *elt - = new scanf_format_elt (text.c_str (), width, discard, type, - modifier, char_class); - - if (num_elts == list.length ()) - list.resize (dim_vector (2 * num_elts, 1)); - - list(num_elts++) = elt; - } - - delete buf; - buf = 0; - } -} - -static std::string -expand_char_class (const std::string& s) -{ - std::string retval; - - size_t len = s.length (); - - size_t i = 0; - - while (i < len) - { - unsigned char c = s[i++]; - - if (c == '-' && i > 1 && i < len - && static_cast (s[i-2]) <= static_cast (s[i])) - { - // Add all characters from the range except the first (we - // already added it below). - - for (c = s[i-2]+1; c < s[i]; c++) - retval += c; - } - else - { - // Add the character to the class. Only add '-' if it is - // the last character in the class. - - if (c != '-' || i == len) - retval += c; - } - } - - return retval; -} - -void -scanf_format_list::process_conversion (const std::string& s, size_t& i, - size_t n, int& width, bool& discard, - char& type, char& modifier, - octave_idx_type& num_elts) -{ - width = 0; - discard = false; - modifier = '\0'; - type = '\0'; - - *buf << s[i++]; - - bool have_width = false; - - while (i < n) - { - switch (s[i]) - { - case '*': - if (discard) - nconv = -1; - else - { - discard = true; - *buf << s[i++]; - } - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - if (have_width) - nconv = -1; - else - { - char c = s[i++]; - width = width * 10 + c - '0'; - have_width = true; - *buf << c; - while (i < n && isdigit (s[i])) - { - c = s[i++]; - width = width * 10 + c - '0'; - *buf << c; - } - } - break; - - case 'h': case 'l': case 'L': - if (modifier != '\0') - nconv = -1; - else - modifier = s[i++]; - break; - - case 'd': case 'i': case 'o': case 'u': case 'x': - if (modifier == 'L') - { - nconv = -1; - break; - } - goto fini; - - case 'e': case 'f': case 'g': - if (modifier == 'h') - { - nconv = -1; - break; - } - - // No float or long double conversions, thanks. - *buf << 'l'; - - goto fini; - - case 'c': case 's': case 'p': case '%': case '[': - if (modifier != '\0') - { - nconv = -1; - break; - } - goto fini; - - fini: - { - if (finish_conversion (s, i, n, width, discard, type, - modifier, num_elts) == 0) - return; - } - break; - - default: - nconv = -1; - break; - } - - if (nconv < 0) - break; - } - - nconv = -1; -} - -int -scanf_format_list::finish_conversion (const std::string& s, size_t& i, - size_t n, int& width, bool discard, - char& type, char modifier, - octave_idx_type& num_elts) -{ - int retval = 0; - - std::string char_class; - - size_t beg_idx = std::string::npos; - size_t end_idx = std::string::npos; - - if (s[i] == '%') - { - type = '%'; - *buf << s[i++]; - } - else - { - type = s[i]; - - if (s[i] == '[') - { - *buf << s[i++]; - - if (i < n) - { - beg_idx = i; - - if (s[i] == '^') - { - type = '^'; - *buf << s[i++]; - - if (i < n) - { - beg_idx = i; - - if (s[i] == ']') - *buf << s[i++]; - } - } - else if (s[i] == ']') - *buf << s[i++]; - } - - while (i < n && s[i] != ']') - *buf << s[i++]; - - if (i < n && s[i] == ']') - { - end_idx = i-1; - *buf << s[i++]; - } - - if (s[i-1] != ']') - retval = nconv = -1; - } - else - *buf << s[i++]; - - nconv++; - } - - if (nconv >= 0) - { - if (beg_idx != std::string::npos && end_idx != std::string::npos) - char_class = expand_char_class (s.substr (beg_idx, - end_idx - beg_idx + 1)); - - add_elt_to_list (width, discard, type, modifier, num_elts, char_class); - } - - return retval; -} - -void -scanf_format_list::printme (void) const -{ - octave_idx_type n = list.length (); - - for (octave_idx_type i = 0; i < n; i++) - { - scanf_format_elt *elt = list(i); - - std::cerr - << "width: " << elt->width << "\n" - << "discard: " << elt->discard << "\n" - << "type: "; - - if (elt->type == scanf_format_elt::literal_conversion) - std::cerr << "literal text\n"; - else if (elt->type == scanf_format_elt::whitespace_conversion) - std::cerr << "whitespace\n"; - else - std::cerr << elt->type << "\n"; - - std::cerr - << "modifier: " << elt->modifier << "\n" - << "char_class: `" << undo_string_escapes (elt->char_class) << "'\n" - << "text: `" << undo_string_escapes (elt->text) << "'\n\n"; - } -} - -bool -scanf_format_list::all_character_conversions (void) -{ - octave_idx_type n = list.length (); - - if (n > 0) - { - for (octave_idx_type i = 0; i < n; i++) - { - scanf_format_elt *elt = list(i); - - switch (elt->type) - { - case 'c': case 's': case '%': case '[': case '^': - case scanf_format_elt::literal_conversion: - case scanf_format_elt::whitespace_conversion: - break; - - default: - return false; - break; - } - } - - return true; - } - else - return false; -} - -bool -scanf_format_list::all_numeric_conversions (void) -{ - octave_idx_type n = list.length (); - - if (n > 0) - { - for (octave_idx_type i = 0; i < n; i++) - { - scanf_format_elt *elt = list(i); - - switch (elt->type) - { - case 'd': case 'i': case 'o': case 'u': case 'x': - case 'e': case 'f': case 'g': - break; - - default: - return false; - break; - } - } - - return true; - } - else - return false; -} - -// Ugh again. - -printf_format_list::printf_format_list (const std::string& s) - : nconv (0), curr_idx (0), list (dim_vector (16, 1)), buf (0) -{ - octave_idx_type num_elts = 0; - - size_t n = s.length (); - - size_t i = 0; - - int args = 0; - std::string flags; - int fw = 0; - int prec = 0; - char modifier = '\0'; - char type = '\0'; - - bool have_more = true; - bool empty_buf = true; - - if (n == 0) - { - printf_format_elt *elt - = new printf_format_elt ("", args, fw, prec, flags, type, modifier); - - list(num_elts++) = elt; - - list.resize (dim_vector (num_elts, 1)); - } - else - { - while (i < n) - { - have_more = true; - - if (! buf) - { - buf = new std::ostringstream (); - empty_buf = true; - } - - switch (s[i]) - { - case '%': - { - if (empty_buf) - { - process_conversion (s, i, n, args, flags, fw, prec, - type, modifier, num_elts); - - have_more = (buf != 0); - } - else - add_elt_to_list (args, flags, fw, prec, type, modifier, - num_elts); - } - break; - - default: - { - args = 0; - flags = ""; - fw = 0; - prec = 0; - modifier = '\0'; - type = '\0'; - *buf << s[i++]; - empty_buf = false; - } - break; - } - - if (nconv < 0) - { - have_more = false; - break; - } - } - - if (have_more) - add_elt_to_list (args, flags, fw, prec, type, modifier, num_elts); - - list.resize (dim_vector (num_elts, 1)); - - delete buf; - } -} - -printf_format_list::~printf_format_list (void) -{ - octave_idx_type n = list.length (); - - for (octave_idx_type i = 0; i < n; i++) - { - printf_format_elt *elt = list(i); - delete elt; - } -} - -void -printf_format_list::add_elt_to_list (int args, const std::string& flags, - int fw, int prec, char type, - char modifier, octave_idx_type& num_elts) -{ - if (buf) - { - std::string text = buf->str (); - - if (! text.empty ()) - { - printf_format_elt *elt - = new printf_format_elt (text.c_str (), args, fw, prec, flags, - type, modifier); - - if (num_elts == list.length ()) - list.resize (dim_vector (2 * num_elts, 1)); - - list(num_elts++) = elt; - } - - delete buf; - buf = 0; - } -} - -void -printf_format_list::process_conversion - (const std::string& s, size_t& i, size_t n, int& args, std::string& flags, - int& fw, int& prec, char& modifier, char& type, octave_idx_type& num_elts) -{ - args = 0; - flags = ""; - fw = 0; - prec = 0; - modifier = '\0'; - type = '\0'; - - *buf << s[i++]; - - bool nxt = false; - - while (i < n) - { - switch (s[i]) - { - case '-': case '+': case ' ': case '0': case '#': - flags += s[i]; - *buf << s[i++]; - break; - - default: - nxt = true; - break; - } - - if (nxt) - break; - } - - if (i < n) - { - if (s[i] == '*') - { - fw = -1; - args++; - *buf << s[i++]; - } - else - { - if (isdigit (s[i])) - { - int nn = 0; - std::string tmp = s.substr (i); - sscanf (tmp.c_str (), "%d%n", &fw, &nn); - } - - while (i < n && isdigit (s[i])) - *buf << s[i++]; - } - } - - if (i < n && s[i] == '.') - { - *buf << s[i++]; - - if (i < n) - { - if (s[i] == '*') - { - prec = -1; - args++; - *buf << s[i++]; - } - else - { - if (isdigit (s[i])) - { - int nn = 0; - std::string tmp = s.substr (i); - sscanf (tmp.c_str (), "%d%n", &prec, &nn); - } - - while (i < n && isdigit (s[i])) - *buf << s[i++]; - } - } - } - - if (i < n) - { - switch (s[i]) - { - case 'h': case 'l': case 'L': - modifier = s[i]; - *buf << s[i++]; - break; - - default: - break; - } - } - - if (i < n) - finish_conversion (s, i, args, flags, fw, prec, modifier, type, num_elts); - else - nconv = -1; -} - -void -printf_format_list::finish_conversion - (const std::string& s, size_t& i, int args, const std::string& flags, - int fw, int prec, char modifier, char& type, octave_idx_type& num_elts) - -{ - switch (s[i]) - { - case 'd': case 'i': case 'o': case 'x': case 'X': - case 'u': case 'c': - if (modifier == 'L') - { - nconv = -1; - break; - } - goto fini; - - case 'f': case 'e': case 'E': case 'g': case 'G': - if (modifier == 'h' || modifier == 'l') - { - nconv = -1; - break; - } - goto fini; - - case 's': case 'p': case '%': - if (modifier != '\0') - { - nconv = -1; - break; - } - goto fini; - - fini: - - type = s[i]; - - *buf << s[i++]; - - if (type != '%' || args != 0) - nconv++; - - if (type != '%') - args++; - - add_elt_to_list (args, flags, fw, prec, type, modifier, num_elts); - - break; - - default: - nconv = -1; - break; - } -} - -void -printf_format_list::printme (void) const -{ - int n = list.length (); - - for (int i = 0; i < n; i++) - { - printf_format_elt *elt = list(i); - - std::cerr - << "args: " << elt->args << "\n" - << "flags: `" << elt->flags << "'\n" - << "width: " << elt->fw << "\n" - << "prec: " << elt->prec << "\n" - << "type: `" << elt->type << "'\n" - << "modifier: `" << elt->modifier << "'\n" - << "text: `" << undo_string_escapes (elt->text) << "'\n\n"; - } -} - -void -octave_base_stream::error (const std::string& msg) -{ - fail = true; - errmsg = msg; -} - -void -octave_base_stream::error (const std::string& who, const std::string& msg) -{ - fail = true; - errmsg = who + ": " + msg; -} - -void -octave_base_stream::clear (void) -{ - fail = false; - errmsg = ""; -} - -void -octave_base_stream::clearerr (void) -{ - std::istream *is = input_stream (); - std::ostream *os = output_stream (); - - if (is) - is->clear (); - - if (os) - os->clear (); -} - -// Functions that are defined for all input streams (input streams -// are those that define is). - -std::string -octave_base_stream::do_gets (octave_idx_type max_len, bool& err, - bool strip_newline, const std::string& who) -{ - std::string retval; - - if ((interactive || forced_interactive) && file_number () == 0) - { - ::error ("%s: unable to read from stdin while running interactively", - who.c_str ()); - - return retval; - } - - err = false; - - std::istream *isp = input_stream (); - - if (isp) - { - std::istream& is = *isp; - - std::ostringstream buf; - - int c = 0; - int char_count = 0; - - if (max_len != 0) - { - while (is && (c = is.get ()) != EOF) - { - char_count++; - - // Handle CRLF, CR, or LF as line ending. - - if (c == '\r') - { - if (! strip_newline) - buf << static_cast (c); - - c = is.get (); - - if (c != EOF) - { - if (c == '\n') - { - char_count++; - - if (! strip_newline) - buf << static_cast (c); - } - else - is.putback (c); - } - - break; - } - else if (c == '\n') - { - if (! strip_newline) - buf << static_cast (c); - - break; - } - else - buf << static_cast (c); - - if (max_len > 0 && char_count == max_len) - break; - } - } - - if (! is.eof () && char_count > 0) - { - // GAGME. Matlab seems to check for EOF even if the last - // character in a file is a newline character. This is NOT - // what the corresponding C-library functions do. - int disgusting_compatibility_hack = is.get (); - if (! is.eof ()) - is.putback (disgusting_compatibility_hack); - } - - if (is.good () || (is.eof () && char_count > 0)) - retval = buf.str (); - else - { - err = true; - - if (is.eof () && char_count == 0) - error (who, "at end of file"); - else - error (who, "read error"); - } - } - else - { - err = true; - invalid_operation (who, "reading"); - } - - return retval; -} - -std::string -octave_base_stream::getl (octave_idx_type max_len, bool& err, const std::string& who) -{ - return do_gets (max_len, err, true, who); -} - -std::string -octave_base_stream::gets (octave_idx_type max_len, bool& err, const std::string& who) -{ - return do_gets (max_len, err, false, who); -} - -long -octave_base_stream::skipl (long num, bool& err, const std::string& who) -{ - long cnt = -1; - - if ((interactive || forced_interactive) && file_number () == 0) - { - ::error ("%s: unable to read from stdin while running interactively", - who.c_str ()); - - return count; - } - - err = false; - - std::istream *isp = input_stream (); - - if (isp) - { - std::istream& is = *isp; - - int c = 0, lastc = -1; - cnt = 0; - - while (is && (c = is.get ()) != EOF) - { - // Handle CRLF, CR, or LF as line ending. - - if (c == '\r' || (c == '\n' && lastc != '\r')) - { - if (++cnt == num) - break; - } - - lastc = c; - } - - // Maybe eat the following \n if \r was just met. - if (c == '\r' && is.peek () == '\n') - is.get (); - - if (is.bad ()) - { - err = true; - error (who, "read error"); - } - - if (err) - cnt = -1; - } - else - { - err = true; - invalid_operation (who, "reading"); - } - - return cnt; -} - -#define OCTAVE_SCAN(is, fmt, arg) octave_scan (is, fmt, arg) - -template -std::istream& -octave_scan_1 (std::istream& is, const scanf_format_elt& fmt, T* valptr) -{ - T& ref = *valptr; - - switch (fmt.type) - { - case 'o': - is >> std::oct >> ref >> std::dec; - break; - - case 'x': - is >> std::hex >> ref >> std::dec; - break; - - case 'i': - { - int c1 = EOF; - - while (is && (c1 = is.get ()) != EOF && isspace (c1)) - /* skip whitespace */; - - if (c1 != EOF) - { - if (c1 == '0') - { - int c2 = is.peek (); - - if (c2 == 'x' || c2 == 'X') - { - is.ignore (); - if (std::isxdigit (is.peek ())) - is >> std::hex >> ref >> std::dec; - else - ref = 0; - } - else - { - if (c2 == '0' || c2 == '1' || c2 == '2' - || c2 == '3' || c2 == '4' || c2 == '5' - || c2 == '6' || c2 == '7') - is >> std::oct >> ref >> std::dec; - else - ref = 0; - } - } - else - { - is.putback (c1); - - is >> ref; - } - } - } - break; - - default: - is >> ref; - break; - } - - return is; -} - -template -std::istream& -octave_scan (std::istream& is, const scanf_format_elt& fmt, T* valptr) -{ - if (fmt.width) - { - // Limit input to fmt.width characters by reading into a - // temporary stringstream buffer. - - std::string tmp; - - is.width (fmt.width); - is >> tmp; - - std::istringstream ss (tmp); - - octave_scan_1 (ss, fmt, valptr); - } - else - octave_scan_1 (is, fmt, valptr); - - return is; -} - -// Note that this specialization is only used for reading characters, not -// character strings. See BEGIN_S_CONVERSION for details. - -template<> -std::istream& -octave_scan<> (std::istream& is, const scanf_format_elt& /* fmt */, - char* valptr) -{ - return is >> valptr; -} - -template std::istream& -octave_scan (std::istream&, const scanf_format_elt&, int*); - -template std::istream& -octave_scan (std::istream&, const scanf_format_elt&, long int*); - -template std::istream& -octave_scan (std::istream&, const scanf_format_elt&, short int*); - -template std::istream& -octave_scan (std::istream&, const scanf_format_elt&, unsigned int*); - -template std::istream& -octave_scan (std::istream&, const scanf_format_elt&, unsigned long int*); - -template std::istream& -octave_scan (std::istream&, const scanf_format_elt&, unsigned short int*); - -#if 0 -template std::istream& -octave_scan (std::istream&, const scanf_format_elt&, float*); -#endif - -template<> -std::istream& -octave_scan<> (std::istream& is, const scanf_format_elt& fmt, double* valptr) -{ - double& ref = *valptr; - - switch (fmt.type) - { - case 'e': - case 'f': - case 'g': - { - int c1 = EOF; - - while (is && (c1 = is.get ()) != EOF && isspace (c1)) - /* skip whitespace */; - - if (c1 != EOF) - { - is.putback (c1); - - ref = octave_read_value (is); - } - } - break; - - default: - panic_impossible (); - break; - } - - return is; -} - -template -void -do_scanf_conv (std::istream& is, const scanf_format_elt& fmt, - T valptr, Matrix& mval, double *data, octave_idx_type& idx, - octave_idx_type& conversion_count, octave_idx_type nr, octave_idx_type max_size, - bool discard) -{ - OCTAVE_SCAN (is, fmt, valptr); - - if (is) - { - if (idx == max_size && ! discard) - { - max_size *= 2; - - if (nr > 0) - mval.resize (nr, max_size / nr, 0.0); - else - mval.resize (max_size, 1, 0.0); - - data = mval.fortran_vec (); - } - - if (! discard) - { - conversion_count++; - data[idx++] = *(valptr); - } - } -} - -template void -do_scanf_conv (std::istream&, const scanf_format_elt&, int*, - Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); - -template void -do_scanf_conv (std::istream&, const scanf_format_elt&, long int*, - Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); - -template void -do_scanf_conv (std::istream&, const scanf_format_elt&, short int*, - Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); - -template void -do_scanf_conv (std::istream&, const scanf_format_elt&, unsigned int*, - Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); - -template void -do_scanf_conv (std::istream&, const scanf_format_elt&, unsigned long int*, - Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); - -template void -do_scanf_conv (std::istream&, const scanf_format_elt&, unsigned short int*, - Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); - -#if 0 -template void -do_scanf_conv (std::istream&, const scanf_format_elt&, float*, - Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); -#endif - -template void -do_scanf_conv (std::istream&, const scanf_format_elt&, double*, - Matrix&, double*, octave_idx_type&, octave_idx_type&, octave_idx_type, octave_idx_type, bool); - -#define DO_WHITESPACE_CONVERSION() \ - do \ - { \ - int c = EOF; \ - \ - while (is && (c = is.get ()) != EOF && isspace (c)) \ - /* skip whitespace */; \ - \ - if (c != EOF) \ - is.putback (c); \ - } \ - while (0) - -#define DO_LITERAL_CONVERSION() \ - do \ - { \ - int c = EOF; \ - \ - int n = strlen (fmt); \ - int i = 0; \ - \ - while (i < n && is && (c = is.get ()) != EOF) \ - { \ - if (c == static_cast (fmt[i])) \ - { \ - i++; \ - continue; \ - } \ - else \ - { \ - is.putback (c); \ - break; \ - } \ - } \ - \ - if (i != n) \ - is.setstate (std::ios::failbit); \ - } \ - while (0) - -#define DO_PCT_CONVERSION() \ - do \ - { \ - int c = is.get (); \ - \ - if (c != EOF) \ - { \ - if (c != '%') \ - { \ - is.putback (c); \ - is.setstate (std::ios::failbit); \ - } \ - } \ - else \ - is.setstate (std::ios::failbit); \ - } \ - while (0) - -#define BEGIN_C_CONVERSION() \ - is.unsetf (std::ios::skipws); \ - \ - int width = elt->width ? elt->width : 1; \ - \ - std::string tmp (width, '\0'); \ - \ - int c = EOF; \ - int n = 0; \ - \ - while (is && n < width && (c = is.get ()) != EOF) \ - tmp[n++] = static_cast (c); \ - \ - if (n > 0 && c == EOF) \ - 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. -#define BEGIN_S_CONVERSION() \ - int width = elt->width; \ - \ - std::string tmp; \ - \ - do \ - { \ - if (width) \ - { \ - tmp = std::string (width, '\0'); \ - \ - int c = EOF; \ - \ - int n = 0; \ - \ - while (is && (c = is.get ()) != EOF) \ - { \ - if (! isspace (c)) \ - { \ - tmp[n++] = static_cast (c); \ - break; \ - } \ - } \ - \ - while (is && n < width && (c = is.get ()) != EOF) \ - { \ - if (isspace (c)) \ - { \ - is.putback (c); \ - break; \ - } \ - else \ - tmp[n++] = static_cast (c); \ - } \ - \ - if (n > 0 && c == EOF) \ - is.clear (); \ - \ - tmp.resize (n); \ - } \ - else \ - { \ - is >> std::ws >> tmp; \ - } \ - } \ - while (0) - -// This format must match a nonempty sequence of characters. -#define BEGIN_CHAR_CLASS_CONVERSION() \ - int width = elt->width; \ - \ - std::string tmp; \ - \ - do \ - { \ - if (! width) \ - width = INT_MAX; \ - \ - std::ostringstream buf; \ - \ - std::string char_class = elt->char_class; \ - \ - int c = EOF; \ - \ - if (elt->type == '[') \ - { \ - int chars_read = 0; \ - while (is && chars_read++ < width && (c = is.get ()) != EOF \ - && char_class.find (c) != std::string::npos) \ - buf << static_cast (c); \ - } \ - else \ - { \ - int chars_read = 0; \ - while (is && chars_read++ < width && (c = is.get ()) != EOF \ - && char_class.find (c) == std::string::npos) \ - buf << static_cast (c); \ - } \ - \ - if (width == INT_MAX && c != EOF) \ - is.putback (c); \ - \ - tmp = buf.str (); \ - \ - if (tmp.empty ()) \ - is.setstate (std::ios::failbit); \ - else if (c == EOF) \ - is.clear (); \ - \ - } \ - while (0) - -#define FINISH_CHARACTER_CONVERSION() \ - do \ - { \ - width = tmp.length (); \ - \ - if (is) \ - { \ - int i = 0; \ - \ - if (! discard) \ - { \ - conversion_count++; \ - \ - while (i < width) \ - { \ - if (data_index == max_size) \ - { \ - max_size *= 2; \ - \ - if (all_char_conv) \ - { \ - if (one_elt_size_spec) \ - mval.resize (1, max_size, 0.0); \ - else if (nr > 0) \ - mval.resize (nr, max_size / nr, 0.0); \ - else \ - panic_impossible (); \ - } \ - else if (nr > 0) \ - mval.resize (nr, max_size / nr, 0.0); \ - else \ - mval.resize (max_size, 1, 0.0); \ - \ - data = mval.fortran_vec (); \ - } \ - \ - data[data_index++] = tmp[i++]; \ - } \ - } \ - } \ - } \ - while (0) - -octave_value -octave_base_stream::do_scanf (scanf_format_list& fmt_list, - octave_idx_type nr, octave_idx_type nc, bool one_elt_size_spec, - octave_idx_type& conversion_count, const std::string& who) -{ - octave_value retval = Matrix (); - - if ((interactive || forced_interactive) && file_number () == 0) - { - ::error ("%s: unable to read from stdin while running interactively", - who.c_str ()); - - return retval; - } - - conversion_count = 0; - - octave_idx_type nconv = fmt_list.num_conversions (); - - octave_idx_type data_index = 0; - - if (nr == 0 || nc == 0) - { - if (one_elt_size_spec) - nc = 0; - - return Matrix (nr, nc, 0.0); - } - - std::istream *isp = input_stream (); - - bool all_char_conv = fmt_list.all_character_conversions (); - - Matrix mval; - double *data = 0; - octave_idx_type max_size = 0; - octave_idx_type max_conv = 0; - - octave_idx_type final_nr = 0; - octave_idx_type final_nc = 0; - - if (all_char_conv) - { - // Any of these could be resized later (if we have %s - // conversions, we may read more than one element for each - // conversion). - - if (one_elt_size_spec) - { - max_size = 512; - mval.resize (1, max_size, 0.0); - - if (nr > 0) - max_conv = nr; - } - else if (nr > 0) - { - if (nc > 0) - { - mval.resize (nr, nc, 0.0); - max_size = max_conv = nr * nc; - } - else - { - mval.resize (nr, 32, 0.0); - max_size = nr * 32; - } - } - else - panic_impossible (); - } - else if (nr > 0) - { - if (nc > 0) - { - // Will not resize later. - mval.resize (nr, nc, 0.0); - max_size = nr * nc; - max_conv = max_size; - } - else - { - // Maybe resize later. - mval.resize (nr, 32, 0.0); - max_size = nr * 32; - } - } - else - { - // Maybe resize later. - mval.resize (32, 1, 0.0); - max_size = 32; - } - - data = mval.fortran_vec (); - - if (isp) - { - std::istream& is = *isp; - - const scanf_format_elt *elt = fmt_list.first (); - - std::ios::fmtflags flags = is.flags (); - - octave_idx_type trips = 0; - - octave_idx_type num_fmt_elts = fmt_list.length (); - - for (;;) - { - octave_quit (); - - if (elt) - { - if (! (elt->type == scanf_format_elt::whitespace_conversion - || elt->type == scanf_format_elt::literal_conversion - || elt->type == '%') - && max_conv > 0 && conversion_count == max_conv) - { - if (all_char_conv && one_elt_size_spec) - { - final_nr = 1; - final_nc = data_index; - } - else - { - final_nr = nr; - final_nc = (data_index - 1) / nr + 1; - } - - break; - } - else if (data_index == max_size) - { - max_size *= 2; - - if (all_char_conv) - { - if (one_elt_size_spec) - mval.resize (1, max_size, 0.0); - else if (nr > 0) - mval.resize (nr, max_size / nr, 0.0); - else - panic_impossible (); - } - else if (nr > 0) - mval.resize (nr, max_size / nr, 0.0); - else - mval.resize (max_size, 1, 0.0); - - data = mval.fortran_vec (); - } - - const char *fmt = elt->text; - - bool discard = elt->discard; - - switch (elt->type) - { - case scanf_format_elt::whitespace_conversion: - DO_WHITESPACE_CONVERSION (); - break; - - case scanf_format_elt::literal_conversion: - DO_LITERAL_CONVERSION (); - break; - - case '%': - DO_PCT_CONVERSION (); - break; - - case 'd': case 'i': - { - switch (elt->modifier) - { - case 'h': - { - short int tmp; - do_scanf_conv (is, *elt, &tmp, mval, data, - data_index, conversion_count, - nr, max_size, discard); - } - break; - - case 'l': - { - long int tmp; - do_scanf_conv (is, *elt, &tmp, mval, data, - data_index, conversion_count, - nr, max_size, discard); - } - break; - - default: - { - int tmp; - do_scanf_conv (is, *elt, &tmp, mval, data, - data_index, conversion_count, - nr, max_size, discard); - } - break; - } - } - break; - - case 'o': case 'u': case 'x': - { - switch (elt->modifier) - { - case 'h': - { - unsigned short int tmp; - do_scanf_conv (is, *elt, &tmp, mval, data, - data_index, conversion_count, - nr, max_size, discard); - } - break; - - case 'l': - { - unsigned long int tmp; - do_scanf_conv (is, *elt, &tmp, mval, data, - data_index, conversion_count, - nr, max_size, discard); - } - break; - - default: - { - unsigned int tmp; - do_scanf_conv (is, *elt, &tmp, mval, data, - data_index, conversion_count, - nr, max_size, discard); - } - break; - } - } - break; - - case 'e': case 'f': case 'g': - { - double tmp; - - do_scanf_conv (is, *elt, &tmp, mval, data, - data_index, conversion_count, - nr, max_size, discard); - } - break; - - case 'c': - { - BEGIN_C_CONVERSION (); - - FINISH_CHARACTER_CONVERSION (); - - is.setf (flags); - } - break; - - case 's': - { - BEGIN_S_CONVERSION (); - - FINISH_CHARACTER_CONVERSION (); - } - break; - - case '[': case '^': - { - BEGIN_CHAR_CLASS_CONVERSION (); - - FINISH_CHARACTER_CONVERSION (); - } - break; - - case 'p': - error ("%s: unsupported format specifier", who.c_str ()); - break; - - default: - error ("%s: internal format error", who.c_str ()); - break; - } - - if (! ok ()) - { - break; - } - else if (! is) - { - if (all_char_conv) - { - if (one_elt_size_spec) - { - final_nr = 1; - final_nc = data_index; - } - else if (data_index > nr) - { - final_nr = nr; - final_nc = (data_index - 1) / nr + 1; - } - else - { - final_nr = data_index; - final_nc = 1; - } - } - else if (nr > 0) - { - if (data_index > nr) - { - final_nr = nr; - final_nc = (data_index - 1) / nr + 1; - } - else - { - final_nr = data_index; - final_nc = 1; - } - } - else - { - final_nr = data_index; - final_nc = 1; - } - - // If it looks like we have a matching failure, then - // reset the failbit in the stream state. - - if (is.rdstate () & std::ios::failbit) - is.clear (is.rdstate () & (~std::ios::failbit)); - - // FIXME -- is this the right thing to do? - - if (interactive && name () == "stdin") - { - is.clear (); - - // Skip to end of line. - - bool err; - do_gets (-1, err, false, who); - } - - break; - } - } - else - { - error ("%s: internal format error", who.c_str ()); - break; - } - - if (nconv == 0 && ++trips == num_fmt_elts) - { - if (all_char_conv && one_elt_size_spec) - { - final_nr = 1; - final_nc = data_index; - } - else - { - final_nr = nr; - final_nc = (data_index - 1) / nr + 1; - } - - break; - } - else - elt = fmt_list.next (nconv > 0); - } - } - - if (ok ()) - { - mval.resize (final_nr, final_nc, 0.0); - - retval = mval; - - if (all_char_conv) - retval = retval.convert_to_str (false, true); - } - - return retval; -} - -octave_value -octave_base_stream::scanf (const std::string& fmt, const Array& size, - octave_idx_type& conversion_count, const std::string& who) -{ - octave_value retval = Matrix (); - - conversion_count = 0; - - std::istream *isp = input_stream (); - - if (isp) - { - scanf_format_list fmt_list (fmt); - - if (fmt_list.num_conversions () == -1) - ::error ("%s: invalid format specified", who.c_str ()); - else - { - octave_idx_type nr = -1; - octave_idx_type nc = -1; - - bool one_elt_size_spec; - - get_size (size, nr, nc, one_elt_size_spec, who); - - if (! error_state) - retval = do_scanf (fmt_list, nr, nc, one_elt_size_spec, - conversion_count, who); - } - } - else - invalid_operation (who, "reading"); - - return retval; -} - -bool -octave_base_stream::do_oscanf (const scanf_format_elt *elt, - octave_value& retval, const std::string& who) -{ - bool quit = false; - - std::istream *isp = input_stream (); - - if (isp) - { - std::istream& is = *isp; - - std::ios::fmtflags flags = is.flags (); - - if (elt) - { - const char *fmt = elt->text; - - bool discard = elt->discard; - - switch (elt->type) - { - case scanf_format_elt::whitespace_conversion: - DO_WHITESPACE_CONVERSION (); - break; - - case scanf_format_elt::literal_conversion: - DO_LITERAL_CONVERSION (); - break; - - case '%': - { - DO_PCT_CONVERSION (); - - if (! is) - quit = true; - - } - break; - - case 'd': case 'i': - { - int tmp; - - if (OCTAVE_SCAN (is, *elt, &tmp)) - { - if (! discard) - retval = tmp; - } - else - quit = true; - } - break; - - case 'o': case 'u': case 'x': - { - long int tmp; - - if (OCTAVE_SCAN (is, *elt, &tmp)) - { - if (! discard) - retval = tmp; - } - else - quit = true; - } - break; - - case 'e': case 'f': case 'g': - { - double tmp; - - if (OCTAVE_SCAN (is, *elt, &tmp)) - { - if (! discard) - retval = tmp; - } - else - quit = true; - } - break; - - case 'c': - { - BEGIN_C_CONVERSION (); - - if (! discard) - retval = tmp; - - if (! is) - quit = true; - - is.setf (flags); - } - break; - - case 's': - { - BEGIN_S_CONVERSION (); - - if (! discard) - retval = tmp; - - if (! is) - quit = true; - } - break; - - case '[': case '^': - { - BEGIN_CHAR_CLASS_CONVERSION (); - - if (! discard) - retval = tmp; - - if (! is) - quit = true; - } - break; - - case 'p': - error ("%s: unsupported format specifier", who.c_str ()); - break; - - default: - error ("%s: internal format error", who.c_str ()); - break; - } - } - - if (ok () && is.fail ()) - { - error ("%s: read error", who.c_str ()); - - // FIXME -- is this the right thing to do? - - if (interactive && name () == "stdin") - { - // Skip to end of line. - - bool err; - do_gets (-1, err, false, who); - } - } - } - - return quit; -} - -octave_value_list -octave_base_stream::oscanf (const std::string& fmt, const std::string& who) -{ - octave_value_list retval; - - std::istream *isp = input_stream (); - - if (isp) - { - std::istream& is = *isp; - - scanf_format_list fmt_list (fmt); - - octave_idx_type nconv = fmt_list.num_conversions (); - - if (nconv == -1) - ::error ("%s: invalid format specified", who.c_str ()); - else - { - is.clear (); - - octave_idx_type len = fmt_list.length (); - - retval.resize (nconv+2, Matrix ()); - - const scanf_format_elt *elt = fmt_list.first (); - - int num_values = 0; - - bool quit = false; - - for (octave_idx_type i = 0; i < len; i++) - { - octave_value tmp; - - quit = do_oscanf (elt, tmp, who); - - if (quit) - break; - else - { - if (tmp.is_defined ()) - retval(num_values++) = tmp; - - if (! ok ()) - break; - - elt = fmt_list.next (nconv > 0); - } - } - - retval(nconv) = num_values; - - int err_num; - retval(nconv+1) = error (false, err_num); - - if (! quit) - { - // Pick up any trailing stuff. - if (ok () && len > nconv) - { - octave_value tmp; - - elt = fmt_list.next (); - - do_oscanf (elt, tmp, who); - } - } - } - } - else - invalid_operation (who, "reading"); - - return retval; -} - -// Functions that are defined for all output streams (output streams -// are those that define os). - -int -octave_base_stream::flush (void) -{ - int retval = -1; - - std::ostream *os = output_stream (); - - if (os) - { - os->flush (); - - if (os->good ()) - retval = 0; - } - else - invalid_operation ("fflush", "writing"); - - return retval; -} - -class -printf_value_cache -{ -public: - - enum state { ok, conversion_error }; - - printf_value_cache (const octave_value_list& args, const std::string& who) - : values (args), val_idx (0), elt_idx (0), - n_vals (values.length ()), n_elts (0), data (0), - curr_state (ok) - { - for (octave_idx_type i = 0; i < values.length (); i++) - { - octave_value val = values(i); - - if (val.is_map () || val.is_cell () || val.is_object ()) - { - gripe_wrong_type_arg (who, val); - break; - } - } - } - - ~printf_value_cache (void) { } - - // Get the current value as a double and advance the internal pointer. - double double_value (void); - - // Get the current value as an int and advance the internal pointer. - int int_value (void); - - // Get the current value as a string and advance the internal pointer. - std::string string_value (void); - - operator bool () const { return (curr_state == ok); } - - bool exhausted (void) { return (val_idx >= n_vals); } - -private: - - const octave_value_list values; - int val_idx; - int elt_idx; - int n_vals; - int n_elts; - const double *data; - NDArray curr_val; - state curr_state; - - // Must create value cache with values! - - printf_value_cache (void); - - // No copying! - - printf_value_cache (const printf_value_cache&); - - printf_value_cache& operator = (const printf_value_cache&); -}; - -double -printf_value_cache::double_value (void) -{ - double retval = 0.0; - - if (exhausted ()) - curr_state = conversion_error; - - while (! exhausted ()) - { - if (! data) - { - octave_value tmp_val = values (val_idx); - - // Force string conversion here for compatibility. - - curr_val = tmp_val.array_value (true); - - if (! error_state) - { - elt_idx = 0; - n_elts = curr_val.length (); - data = curr_val.data (); - } - else - { - curr_state = conversion_error; - break; - } - } - - if (elt_idx < n_elts) - { - retval = data[elt_idx++]; - - if (elt_idx >= n_elts) - { - elt_idx = 0; - val_idx++; - data = 0; - } - - break; - } - else - { - val_idx++; - data = 0; - - if (n_elts == 0 && exhausted ()) - curr_state = conversion_error; - - continue; - } - } - - return retval; -} - -int -printf_value_cache::int_value (void) -{ - int retval = 0; - - double dval = double_value (); - - if (! error_state) - { - if (D_NINT (dval) == dval) - retval = NINT (dval); - else - curr_state = conversion_error; - } - - return retval; -} - -std::string -printf_value_cache::string_value (void) -{ - std::string retval; - - if (exhausted ()) - curr_state = conversion_error; - else - { - octave_value tval = values (val_idx++); - - if (tval.rows () == 1) - retval = tval.string_value (); - else - { - // In the name of Matlab compatibility. - - charMatrix chm = tval.char_matrix_value (); - - octave_idx_type nr = chm.rows (); - octave_idx_type nc = chm.columns (); - - int k = 0; - - retval.resize (nr * nc, '\0'); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - retval[k++] = chm(i,j); - } - - if (error_state) - curr_state = conversion_error; - } - - return retval; -} - -// Ugh again and again. - -template -int -do_printf_conv (std::ostream& os, const char *fmt, int nsa, int sa_1, - int sa_2, T arg, const std::string& who) -{ - int retval = 0; - - switch (nsa) - { - case 2: - retval = octave_format (os, fmt, sa_1, sa_2, arg); - break; - - case 1: - retval = octave_format (os, fmt, sa_1, arg); - break; - - case 0: - retval = octave_format (os, fmt, arg); - break; - - default: - ::error ("%s: internal error handling format", who.c_str ()); - break; - } - - return retval; -} - -template int -do_printf_conv (std::ostream&, const char*, int, int, int, int, - const std::string&); - -template int -do_printf_conv (std::ostream&, const char*, int, int, int, long, - const std::string&); - -template int -do_printf_conv (std::ostream&, const char*, int, int, int, unsigned int, - const std::string&); - -template int -do_printf_conv (std::ostream&, const char*, int, int, int, unsigned long, - const std::string&); - -template int -do_printf_conv (std::ostream&, const char*, int, int, int, double, - const std::string&); - -template int -do_printf_conv (std::ostream&, const char*, int, int, int, const char*, - const std::string&); - -#define DO_DOUBLE_CONV(TQUAL) \ - do \ - { \ - if (val > std::numeric_limits::max () \ - || val < std::numeric_limits::min ()) \ - { \ - std::string tfmt = fmt; \ - \ - tfmt.replace (tfmt.rfind (elt->type), 1, ".f"); \ - \ - if (elt->modifier == 'l') \ - tfmt.replace (tfmt.rfind (elt->modifier), 1, ""); \ - \ - retval += do_printf_conv (os, tfmt.c_str (), nsa, sa_1, sa_2, \ - val, who); \ - } \ - else \ - retval += do_printf_conv (os, fmt, nsa, sa_1, sa_2, \ - static_cast (val), who); \ - } \ - while (0) - -int -octave_base_stream::do_printf (printf_format_list& fmt_list, - const octave_value_list& args, - const std::string& who) -{ - int retval = 0; - - octave_idx_type nconv = fmt_list.num_conversions (); - - std::ostream *osp = output_stream (); - - if (osp) - { - std::ostream& os = *osp; - - const printf_format_elt *elt = fmt_list.first (); - - printf_value_cache val_cache (args, who); - - if (error_state) - return retval; - - for (;;) - { - octave_quit (); - - if (elt) - { - // NSA is the number of `star' args to convert. - - int nsa = (elt->fw < 0) + (elt->prec < 0); - - int sa_1 = 0; - int sa_2 = 0; - - if (nsa > 0) - { - sa_1 = val_cache.int_value (); - - if (! val_cache) - break; - else - { - if (nsa > 1) - { - sa_2 = val_cache.int_value (); - - if (! val_cache) - break; - } - } - } - - const char *fmt = elt->text; - - if (elt->type == '%') - { - os << "%"; - retval++; - } - else if (elt->args == 0 && elt->text) - { - os << elt->text; - retval += strlen (elt->text); - } - else if (elt->type == 's') - { - std::string val = val_cache.string_value (); - - if (val_cache) - retval += do_printf_conv (os, fmt, nsa, sa_1, - sa_2, val.c_str (), who); - else - break; - } - else - { - double val = val_cache.double_value (); - - if (val_cache) - { - if (lo_ieee_isnan (val) || xisinf (val)) - { - std::string tfmt = fmt; - std::string::size_type i1, i2; - - tfmt.replace ((i1 = tfmt.rfind (elt->type)), - 1, 1, 's'); - - if ((i2 = tfmt.rfind ('.')) != std::string::npos && i2 < i1) - { - tfmt.erase (i2, i1-i2); - if (elt->prec < 0) - nsa--; - } - - const char *tval = xisinf (val) - ? (val < 0 ? "-Inf" : "Inf") - : (lo_ieee_is_NA (val) ? "NA" : "NaN"); - - retval += do_printf_conv (os, tfmt.c_str (), - nsa, sa_1, sa_2, - tval, who); - } - else - { - char type = elt->type; - - switch (type) - { - case 'd': case 'i': case 'c': - DO_DOUBLE_CONV (OCTAVE_EMPTY_CPP_ARG); - break; - - case 'o': case 'x': case 'X': case 'u': - DO_DOUBLE_CONV (unsigned); - break; - - case 'f': case 'e': case 'E': - case 'g': case 'G': - retval - += do_printf_conv (os, fmt, nsa, sa_1, sa_2, - val, who); - break; - - default: - error ("%s: invalid format specifier", - who.c_str ()); - return -1; - break; - } - } - } - else - break; - } - - if (! os) - { - error ("%s: write error", who.c_str ()); - break; - } - } - else - { - ::error ("%s: internal error handling format", who.c_str ()); - retval = -1; - break; - } - - elt = fmt_list.next (nconv > 0 && ! val_cache.exhausted ()); - - if (! elt || (val_cache.exhausted () && elt->args > 0)) - break; - } - } - else - invalid_operation (who, "writing"); - - return retval; -} - -int -octave_base_stream::printf (const std::string& fmt, - const octave_value_list& args, - const std::string& who) -{ - int retval = 0; - - printf_format_list fmt_list (fmt); - - if (fmt_list.num_conversions () == -1) - ::error ("%s: invalid format specified", who.c_str ()); - else - retval = do_printf (fmt_list, args, who); - - return retval; -} - -int -octave_base_stream::puts (const std::string& s, const std::string& who) -{ - int retval = -1; - - std::ostream *osp = output_stream (); - - if (osp) - { - std::ostream& os = *osp; - - os << s; - - if (os) - { - // FIXME -- why does this seem to be necessary? - // Without it, output from a loop like - // - // for i = 1:100, fputs (stdout, "foo\n"); endfor - // - // doesn't seem to go to the pager immediately. - - os.flush (); - - if (os) - retval = 0; - else - error ("%s: write error", who.c_str ()); - } - else - error ("%s: write error", who.c_str ()); - } - else - invalid_operation (who, "writing"); - - return retval; -} - -// Return current error message for this stream. - -std::string -octave_base_stream::error (bool clear_err, int& err_num) -{ - err_num = fail ? -1 : 0; - - std::string tmp = errmsg; - - if (clear_err) - clear (); - - return tmp; -} - -void -octave_base_stream::invalid_operation (const std::string& who, const char *rw) -{ - // Note that this is not ::error () ! - - error (who, std::string ("stream not open for ") + rw); -} - -octave_stream::octave_stream (octave_base_stream *bs) - : rep (bs) -{ - if (rep) - rep->count = 1; -} - -octave_stream::~octave_stream (void) -{ - if (rep && --rep->count == 0) - delete rep; -} - -octave_stream::octave_stream (const octave_stream& s) - : rep (s.rep) -{ - if (rep) - rep->count++; -} - -octave_stream& -octave_stream::operator = (const octave_stream& s) -{ - if (rep != s.rep) - { - if (rep && --rep->count == 0) - delete rep; - - rep = s.rep; - - if (rep) - rep->count++; - } - - return *this; -} - -int -octave_stream::flush (void) -{ - int retval = -1; - - if (stream_ok ()) - retval = rep->flush (); - - return retval; -} - -std::string -octave_stream::getl (octave_idx_type max_len, bool& err, const std::string& who) -{ - std::string retval; - - if (stream_ok ()) - retval = rep->getl (max_len, err, who); - - return retval; -} - -std::string -octave_stream::getl (const octave_value& tc_max_len, bool& err, - const std::string& who) -{ - std::string retval; - - err = false; - - int conv_err = 0; - - int max_len = -1; - - if (tc_max_len.is_defined ()) - { - max_len = convert_to_valid_int (tc_max_len, conv_err); - - if (conv_err || max_len < 0) - { - err = true; - ::error ("%s: invalid maximum length specified", who.c_str ()); - } - } - - if (! error_state) - retval = getl (max_len, err, who); - - return retval; -} - -std::string -octave_stream::gets (octave_idx_type max_len, bool& err, const std::string& who) -{ - std::string retval; - - if (stream_ok ()) - retval = rep->gets (max_len, err, who); - - return retval; -} - -std::string -octave_stream::gets (const octave_value& tc_max_len, bool& err, - const std::string& who) -{ - std::string retval; - - err = false; - - int conv_err = 0; - - int max_len = -1; - - if (tc_max_len.is_defined ()) - { - max_len = convert_to_valid_int (tc_max_len, conv_err); - - if (conv_err || max_len < 0) - { - err = true; - ::error ("%s: invalid maximum length specified", who.c_str ()); - } - } - - if (! error_state) - retval = gets (max_len, err, who); - - return retval; -} - -long -octave_stream::skipl (long count, bool& err, const std::string& who) -{ - long retval = -1; - - if (stream_ok ()) - retval = rep->skipl (count, err, who); - - return retval; -} - -long -octave_stream::skipl (const octave_value& tc_count, bool& err, const std::string& who) -{ - long retval = -1; - - err = false; - - int conv_err = 0; - - int count = 1; - - if (tc_count.is_defined ()) - { - if (tc_count.is_scalar_type () && xisinf (tc_count.scalar_value ())) - count = -1; - else - { - count = convert_to_valid_int (tc_count, conv_err); - - if (conv_err || count < 0) - { - err = true; - ::error ("%s: invalid number of lines specified", who.c_str ()); - } - } - } - - if (! error_state) - retval = skipl (count, err, who); - - return retval; -} - -int -octave_stream::seek (long offset, int origin) -{ - int status = -1; - - if (stream_ok ()) - { - clearerr (); - - // Find current position so we can return to it if needed. - - long orig_pos = rep->tell (); - - // Move to end of file. If successful, find the offset of the end. - - status = rep->seek (0, SEEK_END); - - if (status == 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) - { - // 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; - } - } - } - - return status; -} - -int -octave_stream::seek (const octave_value& tc_offset, - const octave_value& tc_origin) -{ - int retval = -1; - - long xoffset = tc_offset.long_value (true); - - if (! error_state) - { - int conv_err = 0; - - int origin = SEEK_SET; - - if (tc_origin.is_string ()) - { - std::string xorigin = tc_origin.string_value (); - - if (xorigin == "bof") - origin = SEEK_SET; - else if (xorigin == "cof") - origin = SEEK_CUR; - else if (xorigin == "eof") - origin = SEEK_END; - else - conv_err = -1; - } - else - { - int xorigin = convert_to_valid_int (tc_origin, conv_err); - - if (! conv_err) - { - if (xorigin == -1) - origin = SEEK_SET; - else if (xorigin == 0) - origin = SEEK_CUR; - else if (xorigin == 1) - origin = SEEK_END; - else - conv_err = -1; - } - } - - if (! conv_err) - { - retval = seek (xoffset, origin); - - if (retval != 0) - error ("fseek: failed to seek to requested position"); - } - else - error ("fseek: invalid value for origin"); - } - else - error ("fseek: invalid value for offset"); - - return retval; -} - -long -octave_stream::tell (void) -{ - long retval = -1; - - if (stream_ok ()) - retval = rep->tell (); - - return retval; -} - -int -octave_stream::rewind (void) -{ - return seek (0, SEEK_SET); -} - -bool -octave_stream::is_open (void) const -{ - bool retval = false; - - if (stream_ok ()) - retval = rep->is_open (); - - return retval; -} - -void -octave_stream::close (void) -{ - if (stream_ok ()) - rep->close (); -} - -template -octave_value -do_read (octave_stream& strm, octave_idx_type nr, octave_idx_type nc, octave_idx_type block_size, - octave_idx_type skip, bool do_float_fmt_conv, bool do_NA_conv, - oct_mach_info::float_format from_flt_fmt, octave_idx_type& count) -{ - octave_value retval; - - RET_T nda; - - count = 0; - - typedef typename RET_T::element_type ELMT; - ELMT elt_zero = ELMT (); - - ELMT *dat = 0; - - octave_idx_type max_size = 0; - - octave_idx_type final_nr = 0; - octave_idx_type final_nc = 1; - - if (nr > 0) - { - if (nc > 0) - { - nda.resize (dim_vector (nr, nc), elt_zero); - dat = nda.fortran_vec (); - max_size = nr * nc; - } - else - { - nda.resize (dim_vector (nr, 32), elt_zero); - dat = nda.fortran_vec (); - max_size = nr * 32; - } - } - else - { - nda.resize (dim_vector (32, 1), elt_zero); - dat = nda.fortran_vec (); - max_size = 32; - } - - // FIXME -- byte order for Cray? - - bool swap = false; - - if (oct_mach_info::words_big_endian ()) - swap = (from_flt_fmt == oct_mach_info::flt_fmt_ieee_little_endian - || from_flt_fmt == oct_mach_info::flt_fmt_vax_g - || from_flt_fmt == oct_mach_info::flt_fmt_vax_g); - else - swap = (from_flt_fmt == oct_mach_info::flt_fmt_ieee_big_endian); - - union - { - char buf[sizeof (typename strip_template_param::type)]; - typename strip_template_param::type val; - } u; - - std::istream *isp = strm.input_stream (); - - if (isp) - { - std::istream& is = *isp; - - octave_idx_type elts_read = 0; - - for (;;) - { - // FIXME -- maybe there should be a special case for - // skip == 0. - - if (is) - { - if (nr > 0 && nc > 0 && count == max_size) - { - final_nr = nr; - final_nc = nc; - - break; - } - - is.read (u.buf, sizeof (typename strip_template_param::type)); - - // We only swap bytes for integer types. For float - // types, the format conversion will also handle byte - // swapping. - - if (swap) - swap_bytes::type)> (u.buf); - else if (do_float_fmt_conv) - do_float_format_conversion - (u.buf, - sizeof (typename strip_template_param::type), - 1, from_flt_fmt, oct_mach_info::float_format ()); - - typename RET_T::element_type tmp - = static_cast (u.val); - - if (is) - { - if (count == max_size) - { - max_size *= 2; - - if (nr > 0) - nda.resize (dim_vector (nr, max_size / nr), - elt_zero); - else - nda.resize (dim_vector (max_size, 1), elt_zero); - - dat = nda.fortran_vec (); - } - - if (do_NA_conv && __lo_ieee_is_old_NA (tmp)) - tmp = __lo_ieee_replace_old_NA (tmp); - - dat[count++] = tmp; - - elts_read++; - } - - int seek_status = 0; - - if (skip != 0 && elts_read == block_size) - { - seek_status = strm.seek (skip, SEEK_CUR); - elts_read = 0; - } - - if (is.eof () || seek_status < 0) - { - if (nr > 0) - { - if (count > nr) - { - final_nr = nr; - final_nc = (count - 1) / nr + 1; - } - else - { - final_nr = count; - final_nc = 1; - } - } - else - { - final_nr = count; - final_nc = 1; - } - - break; - } - } - else if (is.eof ()) - break; - } - } - - nda.resize (dim_vector (final_nr, final_nc), elt_zero); - - retval = nda; - - return retval; -} - -#define DO_READ_VAL_TEMPLATE(RET_T, READ_T) \ - template octave_value \ - do_read (octave_stream&, octave_idx_type, octave_idx_type, octave_idx_type, octave_idx_type, bool, bool, \ - oct_mach_info::float_format, octave_idx_type&) - -// FIXME -- should we only have float if it is a different -// size from double? - -#define INSTANTIATE_DO_READ(VAL_T) \ - DO_READ_VAL_TEMPLATE (VAL_T, octave_int8); \ - DO_READ_VAL_TEMPLATE (VAL_T, octave_uint8); \ - DO_READ_VAL_TEMPLATE (VAL_T, octave_int16); \ - DO_READ_VAL_TEMPLATE (VAL_T, octave_uint16); \ - DO_READ_VAL_TEMPLATE (VAL_T, octave_int32); \ - DO_READ_VAL_TEMPLATE (VAL_T, octave_uint32); \ - DO_READ_VAL_TEMPLATE (VAL_T, octave_int64); \ - DO_READ_VAL_TEMPLATE (VAL_T, octave_uint64); \ - DO_READ_VAL_TEMPLATE (VAL_T, float); \ - DO_READ_VAL_TEMPLATE (VAL_T, double); \ - DO_READ_VAL_TEMPLATE (VAL_T, char); \ - DO_READ_VAL_TEMPLATE (VAL_T, signed char); \ - DO_READ_VAL_TEMPLATE (VAL_T, unsigned char) - -INSTANTIATE_DO_READ (int8NDArray); -INSTANTIATE_DO_READ (uint8NDArray); -INSTANTIATE_DO_READ (int16NDArray); -INSTANTIATE_DO_READ (uint16NDArray); -INSTANTIATE_DO_READ (int32NDArray); -INSTANTIATE_DO_READ (uint32NDArray); -INSTANTIATE_DO_READ (int64NDArray); -INSTANTIATE_DO_READ (uint64NDArray); -INSTANTIATE_DO_READ (FloatNDArray); -INSTANTIATE_DO_READ (NDArray); -INSTANTIATE_DO_READ (charNDArray); -INSTANTIATE_DO_READ (boolNDArray); - -typedef octave_value (*read_fptr) (octave_stream&, octave_idx_type, octave_idx_type, octave_idx_type, octave_idx_type, bool, bool, - oct_mach_info::float_format ffmt, octave_idx_type&); - -#define FILL_TABLE_ROW(R, VAL_T) \ - read_fptr_table[R][oct_data_conv::dt_int8] = do_read; \ - read_fptr_table[R][oct_data_conv::dt_uint8] = do_read; \ - read_fptr_table[R][oct_data_conv::dt_int16] = do_read; \ - read_fptr_table[R][oct_data_conv::dt_uint16] = do_read; \ - read_fptr_table[R][oct_data_conv::dt_int32] = do_read; \ - read_fptr_table[R][oct_data_conv::dt_uint32] = do_read; \ - read_fptr_table[R][oct_data_conv::dt_int64] = do_read; \ - read_fptr_table[R][oct_data_conv::dt_uint64] = do_read; \ - read_fptr_table[R][oct_data_conv::dt_single] = do_read; \ - read_fptr_table[R][oct_data_conv::dt_double] = do_read; \ - read_fptr_table[R][oct_data_conv::dt_char] = do_read; \ - read_fptr_table[R][oct_data_conv::dt_schar] = do_read; \ - read_fptr_table[R][oct_data_conv::dt_uchar] = do_read; \ - read_fptr_table[R][oct_data_conv::dt_logical] = do_read - -octave_value -octave_stream::read (const Array& size, octave_idx_type block_size, - oct_data_conv::data_type input_type, - oct_data_conv::data_type output_type, - octave_idx_type skip, oct_mach_info::float_format ffmt, - octave_idx_type& char_count) -{ - static bool initialized = false; - - // Table function pointers for return types x read types. - - static read_fptr read_fptr_table[oct_data_conv::dt_unknown][14]; - - if (! initialized) - { - for (int i = 0; i < oct_data_conv::dt_unknown; i++) - for (int j = 0; j < 14; j++) - read_fptr_table[i][j] = 0; - - FILL_TABLE_ROW (oct_data_conv::dt_int8, int8NDArray); - FILL_TABLE_ROW (oct_data_conv::dt_uint8, uint8NDArray); - FILL_TABLE_ROW (oct_data_conv::dt_int16, int16NDArray); - FILL_TABLE_ROW (oct_data_conv::dt_uint16, uint16NDArray); - FILL_TABLE_ROW (oct_data_conv::dt_int32, int32NDArray); - FILL_TABLE_ROW (oct_data_conv::dt_uint32, uint32NDArray); - FILL_TABLE_ROW (oct_data_conv::dt_int64, int64NDArray); - FILL_TABLE_ROW (oct_data_conv::dt_uint64, uint64NDArray); - FILL_TABLE_ROW (oct_data_conv::dt_single, FloatNDArray); - FILL_TABLE_ROW (oct_data_conv::dt_double, NDArray); - FILL_TABLE_ROW (oct_data_conv::dt_char, charNDArray); - FILL_TABLE_ROW (oct_data_conv::dt_schar, charNDArray); - FILL_TABLE_ROW (oct_data_conv::dt_uchar, charNDArray); - FILL_TABLE_ROW (oct_data_conv::dt_logical, boolNDArray); - - initialized = true; - } - - octave_value retval; - - if (stream_ok ()) - { - // FIXME -- we may eventually want to make this extensible. - - // FIXME -- we need a better way to ensure that this - // numbering stays consistent with the order of the elements in the - // data_type enum in the oct_data_conv class. - - char_count = 0; - - octave_idx_type nr = -1; - octave_idx_type nc = -1; - - bool ignore; - - get_size (size, nr, nc, ignore, "fread"); - - if (! error_state) - { - if (nr == 0 || nc == 0) - retval = Matrix (nr, nc); - else - { - if (ffmt == oct_mach_info::flt_fmt_unknown) - ffmt = float_format (); - - read_fptr fcn = read_fptr_table[output_type][input_type]; - - bool do_float_fmt_conv = ((input_type == oct_data_conv::dt_double - || input_type == oct_data_conv::dt_single) - && ffmt != float_format ()); - - bool do_NA_conv = (output_type == oct_data_conv::dt_double); - - if (fcn) - { - retval = (*fcn) (*this, nr, nc, block_size, skip, - do_float_fmt_conv, do_NA_conv, - ffmt, char_count); - - // FIXME -- kluge! - - if (! error_state - && (output_type == oct_data_conv::dt_char - || output_type == oct_data_conv::dt_schar - || output_type == oct_data_conv::dt_uchar)) - retval = retval.char_matrix_value (); - } - else - error ("fread: unable to read and convert requested types"); - } - } - else - invalid_operation ("fread", "reading"); - } - - return retval; -} - -octave_idx_type -octave_stream::write (const octave_value& data, octave_idx_type block_size, - oct_data_conv::data_type output_type, octave_idx_type skip, - oct_mach_info::float_format flt_fmt) -{ - octave_idx_type retval = -1; - - if (stream_ok ()) - { - if (! error_state) - { - if (flt_fmt == oct_mach_info::flt_fmt_unknown) - flt_fmt = float_format (); - - octave_idx_type status = data.write (*this, block_size, output_type, - skip, flt_fmt); - - if (status < 0) - error ("fwrite: write error"); - else - retval = status; - } - else - invalid_operation ("fwrite", "writing"); - } - - return retval; -} - -template -void -write_int (std::ostream& os, bool swap, const T& val) -{ - typename T::val_type tmp = val.value (); - - if (swap) - swap_bytes (&tmp); - - os.write (reinterpret_cast (&tmp), - sizeof (typename T::val_type)); -} - -template void write_int (std::ostream&, bool, const octave_int8&); -template void write_int (std::ostream&, bool, const octave_uint8&); -template void write_int (std::ostream&, bool, const octave_int16&); -template void write_int (std::ostream&, bool, const octave_uint16&); -template void write_int (std::ostream&, bool, const octave_int32&); -template void write_int (std::ostream&, bool, const octave_uint32&); -template void write_int (std::ostream&, bool, const octave_int64&); -template void write_int (std::ostream&, bool, const octave_uint64&); - -template -static inline bool -do_write (std::ostream& os, const T& val, oct_data_conv::data_type output_type, - oct_mach_info::float_format flt_fmt, bool swap, - bool do_float_conversion) -{ - bool retval = true; - - // For compatibility, Octave converts to the output type, then - // writes. This means that truncation happens on the conversion. - // For example, the following program prints 0: - // - // x = int8 (-1) - // f = fopen ("foo.dat", "w"); - // fwrite (f, x, "unsigned char"); - // fclose (f); - // f = fopen ("foo.dat", "r"); - // y = fread (f, 1, "unsigned char"); - // printf ("%d\n", y); - - switch (output_type) - { - case oct_data_conv::dt_char: - case oct_data_conv::dt_schar: - case oct_data_conv::dt_int8: - write_int (os, swap, octave_int8 (val)); - break; - - case oct_data_conv::dt_uchar: - case oct_data_conv::dt_uint8: - write_int (os, swap, octave_uint8 (val)); - break; - - case oct_data_conv::dt_int16: - write_int (os, swap, octave_int16 (val)); - break; - - case oct_data_conv::dt_uint16: - write_int (os, swap, octave_uint16 (val)); - break; - - case oct_data_conv::dt_int32: - write_int (os, swap, octave_int32 (val)); - break; - - case oct_data_conv::dt_uint32: - write_int (os, swap, octave_uint32 (val)); - break; - - case oct_data_conv::dt_int64: - write_int (os, swap, octave_int64 (val)); - break; - - case oct_data_conv::dt_uint64: - write_int (os, swap, octave_uint64 (val)); - break; - - case oct_data_conv::dt_single: - { - float f = static_cast (val); - - if (do_float_conversion) - do_float_format_conversion (&f, 1, flt_fmt); - - os.write (reinterpret_cast (&f), sizeof (float)); - } - break; - - case oct_data_conv::dt_double: - { - double d = static_cast (val); - if (do_float_conversion) - do_double_format_conversion (&d, 1, flt_fmt); - - os.write (reinterpret_cast (&d), sizeof (double)); - } - break; - - default: - retval = false; - (*current_liboctave_error_handler) - ("write: invalid type specification"); - break; - } - - return retval; -} - -template bool -do_write (std::ostream&, const octave_int8&, oct_data_conv::data_type, - oct_mach_info::float_format, bool, bool); - -template bool -do_write (std::ostream&, const octave_uint8&, oct_data_conv::data_type, - oct_mach_info::float_format, bool, bool); - -template bool -do_write (std::ostream&, const octave_int16&, oct_data_conv::data_type, - oct_mach_info::float_format, bool, bool); - -template bool -do_write (std::ostream&, const octave_uint16&, oct_data_conv::data_type, - oct_mach_info::float_format, bool, bool); - -template bool -do_write (std::ostream&, const octave_int32&, oct_data_conv::data_type, - oct_mach_info::float_format, bool, bool); - -template bool -do_write (std::ostream&, const octave_uint32&, oct_data_conv::data_type, - oct_mach_info::float_format, bool, bool); - -template bool -do_write (std::ostream&, const octave_int64&, oct_data_conv::data_type, - oct_mach_info::float_format, bool, bool); - -template bool -do_write (std::ostream&, const octave_uint64&, oct_data_conv::data_type, - oct_mach_info::float_format, bool, bool); - -template -octave_idx_type -octave_stream::write (const Array& data, octave_idx_type block_size, - oct_data_conv::data_type output_type, - octave_idx_type skip, oct_mach_info::float_format flt_fmt) -{ - octave_idx_type retval = -1; - - bool status = true; - - octave_idx_type count = 0; - - const T *d = data.data (); - - octave_idx_type n = data.length (); - - oct_mach_info::float_format native_flt_fmt - = oct_mach_info::float_format (); - - bool do_float_conversion = (flt_fmt != native_flt_fmt); - - // FIXME -- byte order for Cray? - - bool swap = false; - - if (oct_mach_info::words_big_endian ()) - swap = (flt_fmt == oct_mach_info::flt_fmt_ieee_little_endian - || flt_fmt == oct_mach_info::flt_fmt_vax_g - || flt_fmt == oct_mach_info::flt_fmt_vax_g); - else - swap = (flt_fmt == oct_mach_info::flt_fmt_ieee_big_endian); - - for (octave_idx_type i = 0; i < n; i++) - { - std::ostream *osp = output_stream (); - - if (osp) - { - std::ostream& os = *osp; - - if (skip != 0 && (i % block_size) == 0) - { - // Seek to skip when inside bounds of existing file. - // Otherwise, write NUL to skip. - - long orig_pos = tell (); - - seek (0, SEEK_END); - - long eof_pos = tell (); - - // Is it possible for this to fail to return us to the - // original position? - seek (orig_pos, SEEK_SET); - - long remaining = eof_pos - orig_pos; - - if (remaining < skip) - { - seek (0, SEEK_END); - - // FIXME -- probably should try to write larger - // blocks... - - unsigned char zero = 0; - for (octave_idx_type j = 0; j < skip - remaining; j++) - os.write (reinterpret_cast (&zero), 1); - } - else - seek (skip, SEEK_CUR); - } - - if (os) - { - status = do_write (os, d[i], output_type, flt_fmt, swap, - do_float_conversion); - - if (os && status) - count++; - else - break; - } - else - { - status = false; - break; - } - } - else - { - status = false; - break; - } - } - - if (status) - retval = count; - - return retval; -} - -template octave_idx_type -octave_stream::write (const Array&, octave_idx_type, - oct_data_conv::data_type, - octave_idx_type, oct_mach_info::float_format); - -template octave_idx_type -octave_stream::write (const Array&, octave_idx_type, - oct_data_conv::data_type, - octave_idx_type, oct_mach_info::float_format); - -template octave_idx_type -octave_stream::write (const Array&, octave_idx_type, - oct_data_conv::data_type, - octave_idx_type, oct_mach_info::float_format); - -template octave_idx_type -octave_stream::write (const Array&, octave_idx_type, - oct_data_conv::data_type, - octave_idx_type, oct_mach_info::float_format); - -template octave_idx_type -octave_stream::write (const Array&, octave_idx_type, - oct_data_conv::data_type, - octave_idx_type, oct_mach_info::float_format); - -template octave_idx_type -octave_stream::write (const Array&, octave_idx_type, - oct_data_conv::data_type, - octave_idx_type, oct_mach_info::float_format); - -template octave_idx_type -octave_stream::write (const Array&, octave_idx_type, - oct_data_conv::data_type, - octave_idx_type, oct_mach_info::float_format); - -template octave_idx_type -octave_stream::write (const Array&, octave_idx_type, - oct_data_conv::data_type, - octave_idx_type, oct_mach_info::float_format); - -template octave_idx_type -octave_stream::write (const Array&, octave_idx_type, - oct_data_conv::data_type, - octave_idx_type, oct_mach_info::float_format); - -template octave_idx_type -octave_stream::write (const Array&, octave_idx_type, - oct_data_conv::data_type, - octave_idx_type, oct_mach_info::float_format); - -template octave_idx_type -octave_stream::write (const Array&, octave_idx_type, - oct_data_conv::data_type, - octave_idx_type, oct_mach_info::float_format); - -template octave_idx_type -octave_stream::write (const Array&, octave_idx_type, - oct_data_conv::data_type, - octave_idx_type, oct_mach_info::float_format); - -octave_value -octave_stream::scanf (const std::string& fmt, const Array& size, - octave_idx_type& count, const std::string& who) -{ - octave_value retval; - - if (stream_ok ()) - retval = rep->scanf (fmt, size, count, who); - - return retval; -} - -octave_value -octave_stream::scanf (const octave_value& fmt, const Array& size, - octave_idx_type& count, const std::string& who) -{ - octave_value retval = Matrix (); - - if (fmt.is_string ()) - { - std::string sfmt = fmt.string_value (); - - if (fmt.is_sq_string ()) - sfmt = do_string_escapes (sfmt); - - retval = scanf (sfmt, size, count, who); - } - else - { - // Note that this is not ::error () ! - - error (who + ": format must be a string"); - } - - return retval; -} - -octave_value_list -octave_stream::oscanf (const std::string& fmt, const std::string& who) -{ - octave_value_list retval; - - if (stream_ok ()) - retval = rep->oscanf (fmt, who); - - return retval; -} - -octave_value_list -octave_stream::oscanf (const octave_value& fmt, const std::string& who) -{ - octave_value_list retval; - - if (fmt.is_string ()) - { - std::string sfmt = fmt.string_value (); - - if (fmt.is_sq_string ()) - sfmt = do_string_escapes (sfmt); - - retval = oscanf (sfmt, who); - } - else - { - // Note that this is not ::error () ! - - error (who + ": format must be a string"); - } - - return retval; -} - -int -octave_stream::printf (const std::string& fmt, const octave_value_list& args, - const std::string& who) -{ - int retval = -1; - - if (stream_ok ()) - retval = rep->printf (fmt, args, who); - - return retval; -} - -int -octave_stream::printf (const octave_value& fmt, const octave_value_list& args, - const std::string& who) -{ - int retval = 0; - - if (fmt.is_string ()) - { - std::string sfmt = fmt.string_value (); - - if (fmt.is_sq_string ()) - sfmt = do_string_escapes (sfmt); - - retval = printf (sfmt, args, who); - } - else - { - // Note that this is not ::error () ! - - error (who + ": format must be a string"); - } - - return retval; -} - -int -octave_stream::puts (const std::string& s, const std::string& who) -{ - int retval = -1; - - if (stream_ok ()) - retval = rep->puts (s, who); - - return retval; -} - -// FIXME -- maybe this should work for string arrays too. - -int -octave_stream::puts (const octave_value& tc_s, const std::string& who) -{ - int retval = -1; - - if (tc_s.is_string ()) - { - std::string s = tc_s.string_value (); - retval = puts (s, who); - } - else - { - // Note that this is not ::error () ! - - error (who + ": argument must be a string"); - } - - return retval; -} - -bool -octave_stream::eof (void) const -{ - int retval = -1; - - if (stream_ok ()) - retval = rep->eof (); - - return retval; -} - -std::string -octave_stream::error (bool clear, int& err_num) -{ - std::string retval = "invalid stream object"; - - if (stream_ok (false)) - retval = rep->error (clear, err_num); - - return retval; -} - -std::string -octave_stream::name (void) const -{ - std::string retval; - - if (stream_ok ()) - retval = rep->name (); - - return retval; -} - -int -octave_stream::mode (void) const -{ - int retval = 0; - - if (stream_ok ()) - retval = rep->mode (); - - return retval; -} - -oct_mach_info::float_format -octave_stream::float_format (void) const -{ - oct_mach_info::float_format retval = oct_mach_info::flt_fmt_unknown; - - if (stream_ok ()) - retval = rep->float_format (); - - return retval; -} - -std::string -octave_stream::mode_as_string (int mode) -{ - std::string retval = "???"; - std::ios::openmode in_mode = static_cast (mode); - - if (in_mode == std::ios::in) - retval = "r"; - else if (in_mode == std::ios::out - || in_mode == (std::ios::out | std::ios::trunc)) - retval = "w"; - else if (in_mode == (std::ios::out | std::ios::app)) - retval = "a"; - else if (in_mode == (std::ios::in | std::ios::out)) - retval = "r+"; - else if (in_mode == (std::ios::in | std::ios::out | std::ios::trunc)) - retval = "w+"; - else if (in_mode == (std::ios::in | std::ios::out | std::ios::ate)) - retval = "a+"; - else if (in_mode == (std::ios::in | std::ios::binary)) - retval = "rb"; - else if (in_mode == (std::ios::out | std::ios::binary) - || in_mode == (std::ios::out | std::ios::trunc | std::ios::binary)) - retval = "wb"; - else if (in_mode == (std::ios::out | std::ios::app | std::ios::binary)) - retval = "ab"; - else if (in_mode == (std::ios::in | std::ios::out | std::ios::binary)) - retval = "r+b"; - else if (in_mode == (std::ios::in | std::ios::out | std::ios::trunc - | std::ios::binary)) - retval = "w+b"; - else if (in_mode == (std::ios::in | std::ios::out | std::ios::ate - | std::ios::binary)) - retval = "a+b"; - - return retval; -} - -octave_stream_list *octave_stream_list::instance = 0; - -bool -octave_stream_list::instance_ok (void) -{ - bool retval = true; - - if (! instance) - { - instance = new octave_stream_list (); - - if (instance) - singleton_cleanup_list::add (cleanup_instance); - } - - if (! instance) - { - ::error ("unable to create stream list object!"); - - retval = false; - } - - return retval; -} - -int -octave_stream_list::insert (octave_stream& os) -{ - return (instance_ok ()) ? instance->do_insert (os) : -1; -} - -octave_stream -octave_stream_list::lookup (int fid, const std::string& who) -{ - return (instance_ok ()) ? instance->do_lookup (fid, who) : octave_stream (); -} - -octave_stream -octave_stream_list::lookup (const octave_value& fid, const std::string& who) -{ - return (instance_ok ()) ? instance->do_lookup (fid, who) : octave_stream (); -} - -int -octave_stream_list::remove (int fid, const std::string& who) -{ - return (instance_ok ()) ? instance->do_remove (fid, who) : -1; -} - -int -octave_stream_list::remove (const octave_value& fid, const std::string& who) -{ - return (instance_ok ()) ? instance->do_remove (fid, who) : -1; -} - -void -octave_stream_list::clear (bool flush) -{ - if (instance) - instance->do_clear (flush); -} - -string_vector -octave_stream_list::get_info (int fid) -{ - return (instance_ok ()) ? instance->do_get_info (fid) : string_vector (); -} - -string_vector -octave_stream_list::get_info (const octave_value& fid) -{ - return (instance_ok ()) ? instance->do_get_info (fid) : string_vector (); -} - -std::string -octave_stream_list::list_open_files (void) -{ - return (instance_ok ()) ? instance->do_list_open_files () : std::string (); -} - -octave_value -octave_stream_list::open_file_numbers (void) -{ - return (instance_ok ()) - ? instance->do_open_file_numbers () : octave_value (); -} - -int -octave_stream_list::get_file_number (const octave_value& fid) -{ - return (instance_ok ()) ? instance->do_get_file_number (fid) : -1; -} - -int -octave_stream_list::do_insert (octave_stream& os) -{ - // Insert item with key corresponding to file-descriptor. - - int stream_number; - - if ((stream_number = os.file_number ()) == -1) - return stream_number; - - // Should we test for "(list.find (stream_number) != list.end ()) && - // list[stream_number].is_open ()" and respond with "error - // ("internal error: ...")"? It should not happen except for some - // bug or if the user has opened a stream with an interpreted - // command, but closed it directly with a system call in an - // oct-file; then the kernel knows the fd is free, but Octave does - // not know. If it happens, it should not do harm here to simply - // overwrite this entry, although the wrong entry might have done - // harm before. - - if (list.size () < list.max_size ()) - list[stream_number] = os; - else - { - stream_number = -1; - error ("could not create file id"); - } - - return stream_number; - -} - -static void -gripe_invalid_file_id (int fid, const std::string& who) -{ - if (who.empty ()) - ::error ("invalid stream number = %d", fid); - else - ::error ("%s: invalid stream number = %d", who.c_str (), fid); -} - -octave_stream -octave_stream_list::do_lookup (int fid, const std::string& who) const -{ - octave_stream retval; - - if (fid >= 0) - { - if (lookup_cache != list.end () && lookup_cache->first == fid) - retval = lookup_cache->second; - else - { - ostrl_map::const_iterator iter = list.find (fid); - - if (iter != list.end ()) - { - retval = iter->second; - lookup_cache = iter; - } - else - gripe_invalid_file_id (fid, who); - } - } - else - gripe_invalid_file_id (fid, who); - - return retval; -} - -octave_stream -octave_stream_list::do_lookup (const octave_value& fid, - const std::string& who) const -{ - octave_stream retval; - - int i = get_file_number (fid); - - if (! error_state) - retval = do_lookup (i, who); - - return retval; -} - -int -octave_stream_list::do_remove (int fid, const std::string& who) -{ - int retval = -1; - - // Can't remove stdin (std::cin), stdout (std::cout), or stderr - // (std::cerr). - - if (fid > 2) - { - ostrl_map::iterator iter = list.find (fid); - - if (iter != list.end ()) - { - octave_stream os = iter->second; - list.erase (iter); - lookup_cache = list.end (); - - // FIXME: is this check redundant? - if (os.is_valid ()) - { - os.close (); - retval = 0; - } - else - gripe_invalid_file_id (fid, who); - } - else - gripe_invalid_file_id (fid, who); - } - else - gripe_invalid_file_id (fid, who); - - return retval; -} - -int -octave_stream_list::do_remove (const octave_value& fid, const std::string& who) -{ - int retval = -1; - - if (fid.is_string () && fid.string_value () == "all") - { - do_clear (false); - - retval = 0; - } - else - { - int i = get_file_number (fid); - - if (! error_state) - retval = do_remove (i, who); - } - - return retval; -} - -void -octave_stream_list::do_clear (bool flush) -{ - if (flush) - { - // Do flush stdout and stderr. - - list[0].flush (); - list[1].flush (); - } - - octave_stream saved_os[3]; - // But don't delete them or stdin. - for (ostrl_map::iterator iter = list.begin (); iter != list.end (); iter++) - { - int fid = iter->first; - octave_stream os = iter->second; - if (fid < 3) - saved_os[fid] = os; - else if (os.is_valid ()) - os.close (); - } - list.clear (); - for (int fid = 0; fid < 3; fid++) list[fid] = saved_os[fid]; - lookup_cache = list.end (); -} - -string_vector -octave_stream_list::do_get_info (int fid) const -{ - string_vector retval; - - octave_stream os = do_lookup (fid); - - if (os.is_valid ()) - { - retval.resize (3); - - retval(2) = oct_mach_info::float_format_as_string (os.float_format ()); - retval(1) = octave_stream::mode_as_string (os.mode ()); - retval(0) = os.name (); - } - else - ::error ("invalid file id = %d", fid); - - return retval; -} - -string_vector -octave_stream_list::do_get_info (const octave_value& fid) const -{ - string_vector retval; - - int conv_err = 0; - - int int_fid = convert_to_valid_int (fid, conv_err); - - if (! conv_err) - retval = do_get_info (int_fid); - else - ::error ("file id must be a file object or integer value"); - - return retval; -} - -std::string -octave_stream_list::do_list_open_files (void) const -{ - std::string retval; - - std::ostringstream buf; - - buf << "\n" - << " number mode arch name\n" - << " ------ ---- ---- ----\n"; - - for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++) - { - octave_stream os = p->second; - - buf << " " - << std::setiosflags (std::ios::right) - << std::setw (4) << p->first << " " - << std::setiosflags (std::ios::left) - << std::setw (3) - << octave_stream::mode_as_string (os.mode ()) - << " " - << std::setw (9) - << oct_mach_info::float_format_as_string (os.float_format ()) - << " " - << os.name () << "\n"; - } - - buf << "\n"; - - retval = buf.str (); - - return retval; -} - -octave_value -octave_stream_list::do_open_file_numbers (void) const -{ - Matrix retval (1, list.size (), 0.0); - - int num_open = 0; - - for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++) - { - // Skip stdin, stdout, and stderr. - - if (p->first > 2 && p->second) - retval(0,num_open++) = p->first; - } - - retval.resize ((num_open > 0), num_open); - - return retval; -} - -int -octave_stream_list::do_get_file_number (const octave_value& fid) const -{ - int retval = -1; - - if (fid.is_string ()) - { - std::string nm = fid.string_value (); - - for (ostrl_map::const_iterator p = list.begin (); p != list.end (); p++) - { - // stdin (std::cin), stdout (std::cout), and stderr (std::cerr) - // are unnamed. - - if (p->first > 2) - { - octave_stream os = p->second; - - if (os && os.name () == nm) - { - retval = p->first; - break; - } - } - } - } - else - { - int conv_err = 0; - - int int_fid = convert_to_valid_int (fid, conv_err); - - if (conv_err) - ::error ("file id must be a file object, std::string, or integer value"); - else - retval = int_fid; - } - - return retval; -} diff -r a132d206a36a -r b9b6a310ad97 src/oct-stream.h --- a/src/oct-stream.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,738 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_octave_stream_h) -#define octave_octave_stream_h 1 - -class Matrix; -class string_vector; -class octave_value; -class octave_value_list; - -#include -#include -#include -#include - -#include "Array.h" -#include "data-conv.h" -#include "lo-utils.h" -#include "mach-info.h" -#include "oct-refcount.h" - -class -OCTINTERP_API -scanf_format_elt -{ -public: - - enum special_conversion - { - whitespace_conversion = 1, - literal_conversion = 2 - }; - - scanf_format_elt (const char *txt = 0, int w = 0, bool d = false, - char typ = '\0', char mod = '\0', - const std::string& ch_class = std::string ()) - : text (strsave (txt)), width (w), discard (d), type (typ), - modifier (mod), char_class (ch_class) { } - - scanf_format_elt (const scanf_format_elt& e) - : text (strsave (e.text)), width (e.width), discard (e.discard), - type (e.type), modifier (e.modifier), char_class (e.char_class) { } - - scanf_format_elt& operator = (const scanf_format_elt& e) - { - if (this != &e) - { - text = strsave (e.text); - width = e.width; - discard = e.discard; - type = e.type; - modifier = e.modifier; - char_class = e.char_class; - } - - return *this; - } - - ~scanf_format_elt (void) { delete [] text; } - - // The C-style format string. - const char *text; - - // The maximum field width. - int width; - - // TRUE if we are not storing the result of this conversion. - bool discard; - - // Type of conversion -- `d', `i', `o', `u', `x', `e', `f', `g', - // `c', `s', `p', `%', or `['. - char type; - - // A length modifier -- `h', `l', or `L'. - char modifier; - - // The class of characters in a `[' format. - std::string char_class; -}; - -class -OCTINTERP_API -scanf_format_list -{ -public: - - scanf_format_list (const std::string& fmt = std::string ()); - - ~scanf_format_list (void); - - octave_idx_type num_conversions (void) { return nconv; } - - // The length can be different than the number of conversions. - // For example, "x %d y %d z" has 2 conversions but the length of - // the list is 3 because of the characters that appear after the - // last conversion. - - octave_idx_type length (void) { return list.length (); } - - const scanf_format_elt *first (void) - { - curr_idx = 0; - return current (); - } - - const scanf_format_elt *current (void) const - { return list.length () > 0 ? list.elem (curr_idx) : 0; } - - const scanf_format_elt *next (bool cycle = true) - { - curr_idx++; - - if (curr_idx >= list.length ()) - { - if (cycle) - curr_idx = 0; - else - return 0; - } - return current (); - } - - void printme (void) const; - - bool ok (void) const { return (nconv >= 0); } - - operator bool () const { return ok (); } - - bool all_character_conversions (void); - - bool all_numeric_conversions (void); - -private: - - // Number of conversions specified by this format string, or -1 if - // invalid conversions have been found. - octave_idx_type nconv; - - // Index to current element; - octave_idx_type curr_idx; - - // FIXME -- maybe LIST should be a std::list object? - // List of format elements. - Array list; - - // Temporary buffer. - std::ostringstream *buf; - - void add_elt_to_list (int width, bool discard, char type, char modifier, - octave_idx_type& num_elts, - const std::string& char_class = std::string ()); - - void process_conversion (const std::string& s, size_t& i, size_t n, - int& width, bool& discard, char& type, - char& modifier, octave_idx_type& num_elts); - - int finish_conversion (const std::string& s, size_t& i, size_t n, - int& width, bool discard, char& type, - char modifier, octave_idx_type& num_elts); - // No copying! - - scanf_format_list (const scanf_format_list&); - - scanf_format_list& operator = (const scanf_format_list&); -}; - -class -printf_format_elt -{ -public: - - printf_format_elt (const char *txt = 0, int n = 0, int w = 0, - int p = 0, const std::string& f = std::string (), - char typ = '\0', char mod = '\0') - : text (strsave (txt)), args (n), fw (w), prec (p), flags (f), - type (typ), modifier (mod) { } - - printf_format_elt (const printf_format_elt& e) - : text (strsave (e.text)), args (e.args), fw (e.fw), prec (e.prec), - flags (e.flags), type (e.type), modifier (e.modifier) { } - - printf_format_elt& operator = (const printf_format_elt& e) - { - if (this != &e) - { - text = strsave (e.text); - args = e.args; - fw = e.fw; - prec = e.prec; - flags = e.flags; - type = e.type; - modifier = e.modifier; - } - - return *this; - } - - ~printf_format_elt (void) { delete [] text; } - - // The C-style format string. - const char *text; - - // How many args do we expect to consume? - int args; - - // Field width. - int fw; - - // Precision. - int prec; - - // Flags -- `-', `+', ` ', `0', or `#'. - std::string flags; - - // Type of conversion -- `d', `i', `o', `x', `X', `u', `c', `s', - // `f', `e', `E', `g', `G', `p', or `%' - char type; - - // A length modifier -- `h', `l', or `L'. - char modifier; -}; - -class -OCTINTERP_API -printf_format_list -{ -public: - - printf_format_list (const std::string& fmt = std::string ()); - - ~printf_format_list (void); - - octave_idx_type num_conversions (void) { return nconv; } - - const printf_format_elt *first (void) - { - curr_idx = 0; - return current (); - } - - const printf_format_elt *current (void) const - { return list.length () > 0 ? list.elem (curr_idx) : 0; } - - const printf_format_elt *next (bool cycle = true) - { - curr_idx++; - - if (curr_idx >= list.length ()) - { - if (cycle) - curr_idx = 0; - else - return 0; - } - - return current (); - } - - bool last_elt_p (void) { return (curr_idx + 1 == list.length ()); } - - void printme (void) const; - - bool ok (void) const { return (nconv >= 0); } - - operator bool () const { return ok (); } - -private: - - // Number of conversions specified by this format string, or -1 if - // invalid conversions have been found. - octave_idx_type nconv; - - // Index to current element; - octave_idx_type curr_idx; - - // FIXME -- maybe LIST should be a std::list object? - // List of format elements. - Array list; - - // Temporary buffer. - std::ostringstream *buf; - - void add_elt_to_list (int args, const std::string& flags, int fw, - int prec, char type, char modifier, - octave_idx_type& num_elts); - - void process_conversion (const std::string& s, size_t& i, size_t n, - int& args, std::string& flags, int& fw, - int& prec, char& modifier, char& type, - octave_idx_type& num_elts); - - void finish_conversion (const std::string& s, size_t& i, int args, - const std::string& flags, int fw, int prec, - char modifier, char& type, - octave_idx_type& num_elts); - - // No copying! - - printf_format_list (const printf_format_list&); - - printf_format_list& operator = (const printf_format_list&); -}; - -// Provide an interface for Octave streams. - -class -OCTINTERP_API -octave_base_stream -{ -friend class octave_stream; - -public: - - octave_base_stream (std::ios::openmode arg_md = std::ios::in|std::ios::out, - oct_mach_info::float_format ff - = oct_mach_info::native_float_format ()) - : count (0), md (arg_md), flt_fmt (ff), fail (false), open_state (true), - errmsg () - { } - - virtual ~octave_base_stream (void) { } - - // The remaining functions are not specific to input or output only, - // and must be provided by the derived classes. - - // Position a stream at OFFSET relative to ORIGIN. - - virtual int seek (long offset, int origin) = 0; - - // Return current stream position. - - virtual long tell (void) = 0; - - // Return TRUE if EOF has been reached on this stream. - - virtual bool eof (void) const = 0; - - // The name of the file. - - virtual std::string name (void) const = 0; - - // If the derived class provides this function and it returns a - // pointer to a valid istream, scanf(), read(), getl(), and gets() - // will automatically work for this stream. - - virtual std::istream *input_stream (void) { return 0; } - - // If the derived class provides this function and it returns a - // pointer to a valid ostream, flush(), write(), and printf() will - // automatically work for this stream. - - virtual std::ostream *output_stream (void) { return 0; } - - // If the derived class is locale-aware, it must implement this function - // in order to set a new locale. By default, this function avoids messing - // with locales and ignores its input argument. - virtual std::locale imbue ( const std::locale &) - { return std::locale::classic (); } - - // Return TRUE if this stream is open. - - bool is_open (void) const { return open_state; } - - virtual void do_close (void) { } - - void close (void) - { - if (is_open ()) - { - open_state = false; - do_close (); - } - } - - virtual int file_number (void) const - { - // Kluge alert! - - if (name () == "stdin") - return 0; - else if (name () == "stdout") - return 1; - else if (name () == "stderr") - return 2; - else - return -1; - } - - bool ok (void) const { return ! fail; } - - // Return current error message for this stream. - - std::string error (bool clear, int& err_num); - -protected: - - int mode (void) const { return md; } - - oct_mach_info::float_format float_format (void) const { return flt_fmt; } - - // Set current error state and set fail to TRUE. - - void error (const std::string& msg); - void error (const std::string& who, const std::string& msg); - - // Clear any error message and set fail to FALSE. - - void clear (void); - - // Clear stream state. - - void clearerr (void); - -private: - - // A reference count. - octave_refcount count; - - // The permission bits for the file. Should be some combination of - // std::ios::open_mode bits. - int md; - - // Data format. - oct_mach_info::float_format flt_fmt; - - // TRUE if an error has occurred. - bool fail; - - // TRUE if this stream is open. - bool open_state; - - // Should contain error message if fail is TRUE. - std::string errmsg; - - // Functions that are defined for all input streams (input streams - // are those that define is). - - std::string do_gets (octave_idx_type max_len, bool& err, bool strip_newline, - const std::string& who /* = "gets" */); - - std::string getl (octave_idx_type max_len, bool& err, const std::string& who /* = "getl" */); - std::string gets (octave_idx_type max_len, bool& err, const std::string& who /* = "gets" */); - long skipl (long count, bool& err, const std::string& who /* = "skipl" */); - - octave_value do_scanf (scanf_format_list& fmt_list, octave_idx_type nr, octave_idx_type nc, - bool one_elt_size_spec, octave_idx_type& count, - const std::string& who /* = "scanf" */); - - octave_value scanf (const std::string& fmt, const Array& size, - octave_idx_type& count, const std::string& who /* = "scanf" */); - - bool do_oscanf (const scanf_format_elt *elt, octave_value&, - const std::string& who /* = "scanf" */); - - octave_value_list oscanf (const std::string& fmt, - const std::string& who /* = "scanf" */); - - // Functions that are defined for all output streams (output streams - // are those that define os). - - int flush (void); - - int do_printf (printf_format_list& fmt_list, const octave_value_list& args, - const std::string& who /* = "printf" */); - - int printf (const std::string& fmt, const octave_value_list& args, - const std::string& who /* = "printf" */); - - int puts (const std::string& s, const std::string& who /* = "puts" */); - - // We can always do this in terms of seek(), so the derived class - // only has to provide that. - - void invalid_operation (const std::string& who, const char *rw); - - // No copying! - - octave_base_stream (const octave_base_stream&); - - octave_base_stream& operator = (const octave_base_stream&); -}; - -class -OCTINTERP_API -octave_stream -{ -public: - - octave_stream (octave_base_stream *bs = 0); - - ~octave_stream (void); - - octave_stream (const octave_stream&); - - octave_stream& operator = (const octave_stream&); - - int flush (void); - - std::string getl (octave_idx_type max_len, bool& err, const std::string& who /* = "getl" */); - std::string getl (const octave_value& max_len, bool& err, - const std::string& who /* = "getl" */); - - std::string gets (octave_idx_type max_len, bool& err, const std::string& who /* = "gets" */); - std::string gets (const octave_value& max_len, bool& err, - const std::string& who /* = "gets" */); - - long skipl (long count, bool& err, const std::string& who /* = "skipl" */); - long skipl (const octave_value& count, bool& err, const std::string& who /* = "skipl" */); - - int seek (long offset, int origin); - int seek (const octave_value& offset, const octave_value& origin); - - long tell (void); - - int rewind (void); - - bool is_open (void) const; - - void close (void); - - octave_value read (const Array& size, octave_idx_type block_size, - oct_data_conv::data_type input_type, - oct_data_conv::data_type output_type, - octave_idx_type skip, oct_mach_info::float_format flt_fmt, - octave_idx_type& count); - - octave_idx_type write (const octave_value& data, octave_idx_type block_size, - oct_data_conv::data_type output_type, - octave_idx_type skip, oct_mach_info::float_format flt_fmt); - - template - octave_idx_type write (const Array&, octave_idx_type block_size, - oct_data_conv::data_type output_type, - octave_idx_type skip, oct_mach_info::float_format flt_fmt); - - octave_value scanf (const std::string& fmt, const Array& size, - octave_idx_type& count, const std::string& who /* = "scanf" */); - - octave_value scanf (const octave_value& fmt, const Array& size, - octave_idx_type& count, const std::string& who /* = "scanf" */); - - octave_value_list oscanf (const std::string& fmt, - const std::string& who /* = "scanf" */); - - octave_value_list oscanf (const octave_value& fmt, - const std::string& who /* = "scanf" */); - - int printf (const std::string& fmt, const octave_value_list& args, - const std::string& who /* = "printf" */); - - int printf (const octave_value& fmt, const octave_value_list& args, - const std::string& who /* = "printf" */); - - int puts (const std::string& s, const std::string& who /* = "puts" */); - int puts (const octave_value& s, const std::string& who /* = "puts" */); - - bool eof (void) const; - - std::string error (bool clear, int& err_num); - - std::string error (bool clear = false) - { - int err_num; - return error (clear, err_num); - } - - // Set the error message and state. - - void error (const std::string& msg) - { - if (rep) - rep->error (msg); - } - - void error (const char *msg) { error (std::string (msg)); } - - int file_number (void) { return rep ? rep->file_number () : -1; } - - bool is_valid (void) const { return (rep != 0); } - - bool ok (void) const { return rep && rep->ok (); } - - operator bool () const { return ok (); } - - std::string name (void) const; - - int mode (void) const; - - oct_mach_info::float_format float_format (void) const; - - static std::string mode_as_string (int mode); - - std::istream *input_stream (void) - { - return rep ? rep->input_stream () : 0; - } - - std::ostream *output_stream (void) - { - return rep ? rep->output_stream () : 0; - } - - std::locale imbue (const std::locale & loc ) - { - if (!rep) return std::locale::classic (); - - std::istream *is = rep->input_stream (); - std::ostream *os = rep->output_stream (); - - if (os) - { - if (is) - (void) is->imbue (loc); - return os->imbue (loc); - } - return is ? is->imbue (loc) : std::locale::classic (); - } - - void clearerr (void) { if (rep) rep->clearerr (); } - -private: - - // The actual representation of this stream. - octave_base_stream *rep; - - bool stream_ok (bool clear = true) const - { - bool retval = true; - - if (rep) - { - if (clear) - rep->clear (); - } - else - retval = false; - - return retval; - } - - void invalid_operation (const std::string& who, const char *rw) - { - if (rep) - rep->invalid_operation (who, rw); - } -}; - -class -OCTINTERP_API -octave_stream_list -{ -protected: - - octave_stream_list (void) : list (), lookup_cache (list.end ()) { } - -public: - - ~octave_stream_list (void) { } - - static bool instance_ok (void); - - static int insert (octave_stream& os); - - static octave_stream - lookup (int fid, const std::string& who = std::string ()); - - static octave_stream - lookup (const octave_value& fid, const std::string& who = std::string ()); - - static int remove (int fid, const std::string& who = std::string ()); - static int remove (const octave_value& fid, - const std::string& who = std::string ()); - - static void clear (bool flush = true); - - static string_vector get_info (int fid); - static string_vector get_info (const octave_value& fid); - - static std::string list_open_files (void); - - static octave_value open_file_numbers (void); - - static int get_file_number (const octave_value& fid); - -private: - - typedef std::map ostrl_map; - - ostrl_map list; - - mutable ostrl_map::const_iterator lookup_cache; - - static octave_stream_list *instance; - - static void cleanup_instance (void) { delete instance; instance = 0; } - - int do_insert (octave_stream& os); - - octave_stream do_lookup (int fid, const std::string& who = std::string ()) const; - octave_stream do_lookup (const octave_value& fid, - const std::string& who = std::string ()) const; - - int do_remove (int fid, const std::string& who = std::string ()); - int do_remove (const octave_value& fid, const std::string& who = std::string ()); - - void do_clear (bool flush = true); - - string_vector do_get_info (int fid) const; - string_vector do_get_info (const octave_value& fid) const; - - std::string do_list_open_files (void) const; - - octave_value do_open_file_numbers (void) const; - - int do_get_file_number (const octave_value& fid) const; -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/oct-strstrm.cc --- a/src/oct-strstrm.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,66 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "oct-strstrm.h" - -// Position a stream at OFFSET relative to ORIGIN. - -int -octave_base_strstream::seek (long, int) -{ - error ("fseek: invalid operation"); - return -1; -} - -// Return current stream position. - -long -octave_base_strstream::tell (void) -{ - error ("ftell: invalid operation"); - return -1; -} - -octave_stream -octave_istrstream::create (const char *data, std::ios::openmode arg_md, - oct_mach_info::float_format flt_fmt) -{ - return octave_stream (new octave_istrstream (data, arg_md, flt_fmt)); -} - -octave_stream -octave_istrstream::create (const std::string& data, std::ios::openmode arg_md, - oct_mach_info::float_format flt_fmt) -{ - return octave_stream (new octave_istrstream (data, arg_md, flt_fmt)); -} - -octave_stream -octave_ostrstream::create (std::ios::openmode arg_md, - oct_mach_info::float_format flt_fmt) -{ - return octave_stream (new octave_ostrstream (arg_md, flt_fmt)); -} diff -r a132d206a36a -r b9b6a310ad97 src/oct-strstrm.h --- a/src/oct-strstrm.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,176 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_octave_strstream_h) -#define octave_octave_strstream_h 1 - -#include -#include - -#include "oct-stream.h" - -class -octave_base_strstream : public octave_base_stream -{ -public: - - octave_base_strstream (std::ios::openmode m = std::ios::out, - oct_mach_info::float_format ff - = oct_mach_info::native_float_format ()) - : octave_base_stream (m, ff) { } - - // Position a stream at OFFSET relative to ORIGIN. - - int seek (long, int); - - // Return current stream position. - - virtual long tell (void); - - // The name of the file. - - std::string name (void) const { return std::string (); } - - virtual std::streambuf *rdbuf (void) = 0; - - virtual bool bad (void) const = 0; - - virtual void clear (void) = 0; - -protected: - - ~octave_base_strstream (void) { } - -private: - - // No copying! - - octave_base_strstream (const octave_base_strstream&); - - octave_base_strstream& operator = (const octave_base_strstream&); -}; - -class -octave_istrstream : public octave_base_strstream -{ -public: - - octave_istrstream (const char *data, - std::ios::openmode arg_md = std::ios::out, - oct_mach_info::float_format ff - = oct_mach_info::native_float_format ()) - : octave_base_strstream (arg_md, ff), is (data) { } - - octave_istrstream (const std::string& data, - std::ios::openmode arg_md = std::ios::out, - oct_mach_info::float_format ff - = oct_mach_info::native_float_format ()) - : octave_base_strstream (arg_md, ff), is (data.c_str ()) { } - - static octave_stream - create (const char *data, std::ios::openmode arg_md = std::ios::out, - oct_mach_info::float_format ff - = oct_mach_info::native_float_format ()); - - static octave_stream - create (const std::string& data, std::ios::openmode arg_md = std::ios::out, - oct_mach_info::float_format ff - = oct_mach_info::native_float_format ()); - - // Return non-zero if EOF has been reached on this stream. - - bool eof (void) const { return is.eof (); } - - std::istream *input_stream (void) { return &is; } - - std::ostream *output_stream (void) { return 0; } - - long tell (void) { return is.tellg (); } - - std::streambuf *rdbuf (void) { return is ? is.rdbuf () : 0; } - - bool bad (void) const { return is.bad (); } - - void clear (void) { is.clear (); } - -protected: - - ~octave_istrstream (void) { } - -private: - - std::istringstream is; - - // No copying! - - octave_istrstream (const octave_istrstream&); - - octave_istrstream& operator = (const octave_istrstream&); -}; - -class -octave_ostrstream : public octave_base_strstream -{ -public: - - octave_ostrstream (std::ios::openmode arg_md = std::ios::out, - oct_mach_info::float_format ff - = oct_mach_info::native_float_format ()) - : octave_base_strstream (arg_md, ff), os () { } - - static octave_stream - create (std::ios::openmode arg_md = std::ios::out, - oct_mach_info::float_format ff - = oct_mach_info::native_float_format ()); - - // Return non-zero if EOF has been reached on this stream. - - bool eof (void) const { return os.eof (); } - - std::istream *input_stream (void) { return 0; } - - std::ostream *output_stream (void) { return &os; } - - std::string str (void) { return os.str (); } - - std::streambuf *rdbuf (void) { return os ? os.rdbuf () : 0; } - - bool bad (void) const { return os.bad (); } - - void clear (void) { os.clear (); } - -protected: - - ~octave_ostrstream (void) { } - -private: - - std::ostringstream os; - - // No copying! - - octave_ostrstream (const octave_ostrstream&); - - octave_ostrstream& operator = (const octave_ostrstream&); -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/oct.h --- a/src/oct.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_oct_h) -#define octave_oct_h 1 - -// Things that are often included to create .oct files. - -// config.h needs to be first because it includes #defines that can */ -// affect other header files. - -#include "config.h" - -#include "Matrix.h" - -#include "oct-locbuf.h" -#include "defun-dld.h" -#include "error.h" -#include "gripes.h" -#include "help.h" -#include "oct-obj.h" -#include "pager.h" -#include "utils.h" -#include "variables.h" - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/octave.gperf --- a/src/octave.gperf Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,122 +0,0 @@ -%{ -/* - -Copyright (C) 1995-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at -your option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -NOTE: gperf 2.7.2 will silently generate bad code if there are blank -lines following the "%{" marker above. This comment block seems to be -handled correctly. - -*/ -enum octave_kw_id -{ - break_kw, - case_kw, - catch_kw, - classdef_kw, - continue_kw, - do_kw, - else_kw, - elseif_kw, - end_kw, - end_try_catch_kw, - end_unwind_protect_kw, - endclassdef_kw, - endenumeration_kw, - endevents_kw, - endfor_kw, - endfunction_kw, - endif_kw, - endmethods_kw, - endparfor_kw, - endproperties_kw, - endswitch_kw, - endwhile_kw, - enumeration_kw, - events_kw, - for_kw, - function_kw, - get_kw, - global_kw, - if_kw, - magic_file_kw, - magic_line_kw, - methods_kw, - otherwise_kw, - parfor_kw, - persistent_kw, - properties_kw, - return_kw, - set_kw, - static_kw, - switch_kw, - try_kw, - until_kw, - unwind_protect_kw, - unwind_protect_cleanup_kw, - while_kw -}; -%} -struct octave_kw { const char *name; int tok; octave_kw_id kw_id; }; -%% -break, BREAK, break_kw -case, CASE, case_kw -catch, CATCH, catch_kw -classdef, CLASSDEF, classdef_kw -continue, CONTINUE, continue_kw -do, DO, do_kw -else, ELSE, else_kw -elseif, ELSEIF, elseif_kw -end, END, end_kw -end_try_catch, END, end_try_catch_kw -end_unwind_protect, END, end_unwind_protect_kw -endclassdef, END, endclassdef_kw -endenumeration, END, endenumeration_kw -endevents, END, endevents_kw -endfor, END, endfor_kw -endfunction, END, endfunction_kw -endif, END, endif_kw -endmethods, END, endmethods_kw -endparfor, END, endparfor_kw -endproperties, END, endproperties_kw -endswitch, END, endswitch_kw -endwhile, END, endwhile_kw -enumeration, ENUMERATION, enumeration_kw -events, EVENTS, events_kw -for, FOR, for_kw -function, FCN, function_kw -get, GET, get_kw -global, GLOBAL, global_kw -if, IF, if_kw -methods, METHODS, methods_kw -otherwise, OTHERWISE, otherwise_kw -parfor, PARFOR, parfor_kw -persistent, PERSISTENT, persistent_kw -properties, PROPERTIES, properties_kw -return, FUNC_RET, return_kw -set, SET, set_kw -static, PERSISTENT, static_kw -switch, SWITCH, switch_kw -try, TRY, try_kw -until, UNTIL, until_kw -unwind_protect, UNWIND, unwind_protect_kw -unwind_protect_cleanup, CLEANUP, unwind_protect_cleanup_kw -while, WHILE, while_kw -__FILE__, DQ_STRING, magic_file_kw -__LINE__, NUM, magic_line_kw diff -r a132d206a36a -r b9b6a310ad97 src/operators/module.mk --- a/src/operators/module.mk Fri Aug 03 14:59:40 2012 -0400 +++ b/src/operators/module.mk Fri Aug 03 18:05:18 2012 -0400 @@ -129,8 +129,16 @@ operators/op-ui64-ui64.cc \ operators/op-ui8-ui8.cc -octinclude_HEADERS += \ +## These look like included header files to Autotools build process +OPERATOR_INCLUDES = \ operators/op-dm-template.cc \ operators/op-dms-template.cc \ operators/op-int.h \ - operators/op-pm-template.cc + operators/op-pm-template.cc \ + operators/ops.h + +## Special rules for sources which must be built before rest of compilation. +operators/ops.cc: $(OPERATORS_SRC) mkops + $(srcdir)/mkops $(OPERATORS_SRC) > $@-t + mv $@-t $@ + diff -r a132d206a36a -r b9b6a310ad97 src/operators/ops.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/operators/ops.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,397 @@ +/* + +Copyright (C) 1996-2012 John W. Eaton +Copyright (C) 2009 VZLU Prague, a.s. + +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 (octave_ops_h) +#define octave_ops_h 1 + +#include "Array-util.h" + +// Concatenation macros that enforce argument prescan +#define CONCAT2X(x,y) x ## y +#define CONCAT2(x,y) CONCAT2X(x,y) + +#define CONCAT3X(x,y,z) x ## y ## z +#define CONCAT3(x,y,z) CONCAT3X(x,y,z) + +extern void install_ops (void); + +#define INSTALL_UNOP(op, t, f) \ + octave_value_typeinfo::register_unary_op \ + (octave_value::op, t::static_type_id (), CONCAT2(oct_unop_, f)); + +#define INSTALL_NCUNOP(op, t, f) \ + octave_value_typeinfo::register_non_const_unary_op \ + (octave_value::op, t::static_type_id (), CONCAT2(oct_unop_, f)); + +#define INSTALL_BINOP(op, t1, t2, f) \ + octave_value_typeinfo::register_binary_op \ + (octave_value::op, t1::static_type_id (), t2::static_type_id (), \ + CONCAT2(oct_binop_, f)); + +#define INSTALL_CATOP(t1, t2, f) \ + octave_value_typeinfo::register_cat_op \ + (t1::static_type_id (), t2::static_type_id (), CONCAT2(oct_catop_, f)); + +#define INSTALL_ASSIGNOP(op, t1, t2, f) \ + octave_value_typeinfo::register_assign_op \ + (octave_value::op, t1::static_type_id (), t2::static_type_id (), \ + CONCAT2(oct_assignop_, f)); + +#define INSTALL_ASSIGNANYOP(op, t1, f) \ + octave_value_typeinfo::register_assignany_op \ + (octave_value::op, t1::static_type_id (), CONCAT2(oct_assignop_, f)); + +#define INSTALL_ASSIGNCONV(t1, t2, tr) \ + octave_value_typeinfo::register_pref_assign_conv \ + (t1::static_type_id (), t2::static_type_id (), tr::static_type_id ()); + +#define INSTALL_CONVOP(t1, t2, f) \ + octave_value_typeinfo::register_type_conv_op \ + (t1::static_type_id (), t2::static_type_id (), CONCAT2(oct_conv_, f)); + +#define INSTALL_WIDENOP(t1, t2, f) \ + octave_value_typeinfo::register_widening_op \ + (t1::static_type_id (), t2::static_type_id (), CONCAT2(oct_conv_, f)); + +#define CAST_UNOP_ARG(t) \ + t v = dynamic_cast (a) + +#define CAST_BINOP_ARGS(t1, t2) \ + t1 v1 = dynamic_cast (a1); \ + t2 v2 = dynamic_cast (a2) + +#define CAST_CONV_ARG(t) \ + t v = dynamic_cast (a) + +#define ASSIGNOPDECL(name) \ + static octave_value \ + CONCAT2(oct_assignop_, name) (octave_base_value& a1, \ + const octave_value_list& idx, \ + const octave_base_value& a2) + +#define NULLASSIGNOPDECL(name) \ + static octave_value \ + CONCAT2(oct_assignop_, name) (octave_base_value& a, \ + const octave_value_list& idx, \ + const octave_base_value&) + +#define ASSIGNANYOPDECL(name) \ + static octave_value \ + CONCAT2(oct_assignop_, name) (octave_base_value& a1, \ + const octave_value_list& idx, \ + const octave_value& a2) + +#define DEFASSIGNOP(name, t1, t2) \ + ASSIGNOPDECL (name) + +#define DEFASSIGNOP_FN(name, t1, t2, f) \ + ASSIGNOPDECL (name) \ + { \ + CAST_BINOP_ARGS (CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ + \ + v1.f (idx, v2.CONCAT2(t1, _value) ()); \ + return octave_value (); \ + } + +#define DEFNULLASSIGNOP_FN(name, t, f) \ + NULLASSIGNOPDECL (name) \ + { \ + CAST_UNOP_ARG (CONCAT2(octave_, t)&); \ + \ + v.f (idx); \ + return octave_value (); \ + } + +#define DEFNDASSIGNOP_FN(name, t1, t2, e, f) \ + ASSIGNOPDECL (name) \ + { \ + CAST_BINOP_ARGS (CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ + \ + v1.f (idx, v2.CONCAT2(e, _value) ()); \ + return octave_value (); \ + } + +// FIXME: the following currently don't handle index. +#define DEFNDASSIGNOP_OP(name, t1, t2, f, op) \ + ASSIGNOPDECL (name) \ + { \ + CAST_BINOP_ARGS (CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ + \ + assert (idx.empty ()); \ + v1.matrix_ref () op v2.CONCAT2(f, _value) (); \ + \ + return octave_value (); \ + } + +#define DEFNDASSIGNOP_FNOP(name, t1, t2, f, fnop) \ + ASSIGNOPDECL (name) \ + { \ + CAST_BINOP_ARGS (CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ + \ + assert (idx.empty ()); \ + fnop (v1.matrix_ref (), v2.CONCAT2(f, _value) ()); \ + \ + return octave_value (); \ + } + +#define DEFASSIGNANYOP_FN(name, t1, f) \ + ASSIGNANYOPDECL (name) \ + { \ + CONCAT2(octave_, t1)& v1 = dynamic_cast (a1); \ + \ + v1.f (idx, a2); \ + return octave_value (); \ + } + +#define CONVDECL(name) \ + static octave_base_value * \ + CONCAT2(oct_conv_, name) (const octave_base_value& a) + +#define CONVDECLX(name) \ + static octave_base_value * \ + CONCAT2(oct_conv_, name) (const octave_base_value&) + +#define DEFCONV(name, a_dummy, b_dummy) \ + CONVDECL (name) + +#define DEFCONVFNX(name, tfrom, ovtto, tto, e) \ + CONVDECL (name) \ + { \ + CAST_CONV_ARG (const CONCAT2(octave_, tfrom)&); \ + \ + return new CONCAT2(octave_, ovtto) (CONCAT2(tto, NDArray) (v.CONCAT2(e, array_value) ())); \ + } + +#define DEFCONVFNX2(name, tfrom, ovtto, e) \ + CONVDECL (name) \ + { \ + CAST_CONV_ARG (const CONCAT2(octave_, tfrom)&); \ + \ + return new CONCAT2(octave_, ovtto) (v.CONCAT2(e, array_value) ()); \ + } + +#define DEFDBLCONVFN(name, ovtfrom, e) \ + CONVDECL (name) \ + { \ + CAST_CONV_ARG (const CONCAT2(octave_, ovtfrom)&); \ + \ + return new octave_matrix (NDArray (v.CONCAT2(e, _value) ())); \ + } + +#define DEFFLTCONVFN(name, ovtfrom, e) \ + CONVDECL (name) \ + { \ + CAST_CONV_ARG (const CONCAT2(octave_, ovtfrom)&); \ + \ + return new octave_float_matrix (FloatNDArray (v.CONCAT2(e, _value) ())); \ + } + +#define DEFSTRINTCONVFN(name, tto) \ + DEFCONVFNX(name, char_matrix_str, CONCAT2(tto, _matrix), tto, char_) + +#define DEFSTRDBLCONVFN(name, tfrom) \ + DEFCONVFNX(name, tfrom, matrix, , char_) + +#define DEFSTRFLTCONVFN(name, tfrom) \ + DEFCONVFNX(name, tfrom, float_matrix, Float, char_) + +#define DEFCONVFN(name, tfrom, tto) \ + DEFCONVFNX2 (name, tfrom, CONCAT2(tto, _matrix), CONCAT2(tto, _)) + +#define DEFCONVFN2(name, tfrom, sm, tto) \ + DEFCONVFNX2 (name, CONCAT3(tfrom, _, sm), CONCAT2(tto, _matrix), CONCAT2(tto, _)) + +#define UNOPDECL(name, a) \ + static octave_value \ + CONCAT2(oct_unop_, name) (const octave_base_value& a) + +#define DEFUNOPX(name, t) \ + UNOPDECL (name, , ) + +#define DEFUNOP(name, t) \ + UNOPDECL (name, a) + +#define DEFUNOP_OP(name, t, op) \ + UNOPDECL (name, a) \ + { \ + CAST_UNOP_ARG (const CONCAT2(octave_, t)&); \ + return octave_value (op v.CONCAT2(t, _value) ()); \ + } + +#define DEFNDUNOP_OP(name, t, e, op) \ + UNOPDECL (name, a) \ + { \ + CAST_UNOP_ARG (const CONCAT2(octave_, t)&); \ + return octave_value (op v.CONCAT2(e, _value) ()); \ + } + +// FIXME -- in some cases, the constructor isn't necessary. + +#define DEFUNOP_FN(name, t, f) \ + UNOPDECL (name, a) \ + { \ + CAST_UNOP_ARG (const CONCAT2(octave_, t)&); \ + return octave_value (f (v.CONCAT2(t, _value) ())); \ + } + +#define DEFNDUNOP_FN(name, t, e, f) \ + UNOPDECL (name, a) \ + { \ + CAST_UNOP_ARG (const CONCAT2(octave_, t)&); \ + return octave_value (f (v.CONCAT2(e, _value) ())); \ + } + +#define DEFNCUNOP_METHOD(name, t, method) \ + static void \ + CONCAT2(oct_unop_, name) (octave_base_value& a) \ + { \ + CAST_UNOP_ARG (CONCAT2(octave_, t)&); \ + v.method (); \ + } + +#define BINOPDECL(name, a1, a2) \ + static octave_value \ + CONCAT2(oct_binop_, name) (const octave_base_value& a1, const octave_base_value& a2) + +#define DEFBINOPX(name, t1, t2) \ + BINOPDECL (name, , ) + +#define DEFBINOP(name, t1, t2) \ + BINOPDECL (name, a1, a2) + +#define DEFBINOP_OP(name, t1, t2, op) \ + BINOPDECL (name, a1, a2) \ + { \ + CAST_BINOP_ARGS (const CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ + return octave_value \ + (v1.CONCAT2(t1, _value) () op v2.CONCAT2(t2, _value) ()); \ + } + +#define DEFCMPLXCMPOP_OP(name, t1, t2, op) \ + BINOPDECL (name, a1, a2) \ + { \ + CAST_BINOP_ARGS (const CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ + gripe_warn_complex_cmp (); \ + return octave_value \ + (v1.CONCAT2(t1, _value) () op v2.CONCAT2(t2, _value) ()); \ + } + +#define DEFSCALARBOOLOP_OP(name, t1, t2, op) \ + BINOPDECL (name, a1, a2) \ + { \ + CAST_BINOP_ARGS (const CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ + if (xisnan (v1.CONCAT2(t1, _value) ()) || xisnan (v2.CONCAT2(t2, _value) ())) \ + { \ + gripe_nan_to_logical_conversion (); \ + return octave_value (); \ + } \ + else \ + return octave_value \ + (v1.CONCAT2(t1, _value) () op v2.CONCAT2(t2, _value) ()); \ + } + +#define DEFNDBINOP_OP(name, t1, t2, e1, e2, op) \ + BINOPDECL (name, a1, a2) \ + { \ + CAST_BINOP_ARGS (const CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ + return octave_value \ + (v1.CONCAT2(e1, _value) () op v2.CONCAT2(e2, _value) ()); \ + } + +// FIXME -- in some cases, the constructor isn't necessary. + +#define DEFBINOP_FN(name, t1, t2, f) \ + BINOPDECL (name, a1, a2) \ + { \ + CAST_BINOP_ARGS (const CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ + return octave_value (f (v1.CONCAT2(t1, _value) (), v2.CONCAT2(t2, _value) ())); \ + } + +#define DEFNDBINOP_FN(name, t1, t2, e1, e2, f) \ + BINOPDECL (name, a1, a2) \ + { \ + CAST_BINOP_ARGS (const CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ + return octave_value (f (v1.CONCAT2(e1, _value) (), v2.CONCAT2(e2, _value) ())); \ + } + +#define DEFNDCMPLXCMPOP_FN(name, t1, t2, e1, e2, f) \ + BINOPDECL (name, a1, a2) \ + { \ + CAST_BINOP_ARGS (const CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ + return octave_value (f (v1.CONCAT2(e1, _value) (), v2.CONCAT2(e2, _value) ())); \ + } + +#define CATOPDECL(name, a1, a2) \ + static octave_value \ + CONCAT2(oct_catop_, name) (octave_base_value& a1, const octave_base_value& a2, \ + const Array& ra_idx) + +#define DEFCATOPX(name, t1, t2) \ + CATOPDECL (name, , ) + +#define DEFCATOP(name, t1, t2) \ + CATOPDECL (name, a1, a2) + +// FIXME -- in some cases, the constructor isn't necessary. + +#define DEFCATOP_FN(name, t1, t2, f) \ + CATOPDECL (name, a1, a2) \ + { \ + CAST_BINOP_ARGS (CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ + return octave_value (v1.CONCAT2(t1, _value) () . f (v2.CONCAT2(t2, _value) (), ra_idx)); \ + } + +#define DEFNDCATOP_FN(name, t1, t2, e1, e2, f) \ + CATOPDECL (name, a1, a2) \ + { \ + CAST_BINOP_ARGS (CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ + return octave_value (v1.CONCAT2(e1, _value) () . f (v2.CONCAT2(e2, _value) (), ra_idx)); \ + } + +#define DEFNDCHARCATOP_FN(name, t1, t2, f) \ + CATOPDECL (name, a1, a2) \ + { \ + CAST_BINOP_ARGS (CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ + \ + return octave_value (v1.char_array_value () . f (v2.char_array_value (), ra_idx), \ + ((a1.is_sq_string () || a2.is_sq_string ()) \ + ? '\'' : '"')); \ + } + +// For compatibility, the second arg is always converted to the type +// of the first. Hmm. + +#define DEFNDCATOP_FN2(name, t1, t2, tc1, tc2, e1, e2, f) \ + CATOPDECL (name, a1, a2) \ + { \ + CAST_BINOP_ARGS (CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ + return octave_value (tc1 (v1.CONCAT2(e1, _value) ()) . f (tc2 (v2.CONCAT2(e2, _value) ()), ra_idx)); \ + } + +#define CATOP_NONCONFORMANT(msg) \ + gripe_nonconformant (msg, \ + a1.rows (), a1.columns (), \ + a2.rows (), a2.columns ()); \ + return octave_value () + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/ops.h --- a/src/ops.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,397 +0,0 @@ -/* - -Copyright (C) 1996-2012 John W. Eaton -Copyright (C) 2009 VZLU Prague, a.s. - -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 (octave_ops_h) -#define octave_ops_h 1 - -#include "Array-util.h" - -// Concatenation macros that enforce argument prescan -#define CONCAT2X(x,y) x ## y -#define CONCAT2(x,y) CONCAT2X(x,y) - -#define CONCAT3X(x,y,z) x ## y ## z -#define CONCAT3(x,y,z) CONCAT3X(x,y,z) - -extern void install_ops (void); - -#define INSTALL_UNOP(op, t, f) \ - octave_value_typeinfo::register_unary_op \ - (octave_value::op, t::static_type_id (), CONCAT2(oct_unop_, f)); - -#define INSTALL_NCUNOP(op, t, f) \ - octave_value_typeinfo::register_non_const_unary_op \ - (octave_value::op, t::static_type_id (), CONCAT2(oct_unop_, f)); - -#define INSTALL_BINOP(op, t1, t2, f) \ - octave_value_typeinfo::register_binary_op \ - (octave_value::op, t1::static_type_id (), t2::static_type_id (), \ - CONCAT2(oct_binop_, f)); - -#define INSTALL_CATOP(t1, t2, f) \ - octave_value_typeinfo::register_cat_op \ - (t1::static_type_id (), t2::static_type_id (), CONCAT2(oct_catop_, f)); - -#define INSTALL_ASSIGNOP(op, t1, t2, f) \ - octave_value_typeinfo::register_assign_op \ - (octave_value::op, t1::static_type_id (), t2::static_type_id (), \ - CONCAT2(oct_assignop_, f)); - -#define INSTALL_ASSIGNANYOP(op, t1, f) \ - octave_value_typeinfo::register_assignany_op \ - (octave_value::op, t1::static_type_id (), CONCAT2(oct_assignop_, f)); - -#define INSTALL_ASSIGNCONV(t1, t2, tr) \ - octave_value_typeinfo::register_pref_assign_conv \ - (t1::static_type_id (), t2::static_type_id (), tr::static_type_id ()); - -#define INSTALL_CONVOP(t1, t2, f) \ - octave_value_typeinfo::register_type_conv_op \ - (t1::static_type_id (), t2::static_type_id (), CONCAT2(oct_conv_, f)); - -#define INSTALL_WIDENOP(t1, t2, f) \ - octave_value_typeinfo::register_widening_op \ - (t1::static_type_id (), t2::static_type_id (), CONCAT2(oct_conv_, f)); - -#define CAST_UNOP_ARG(t) \ - t v = dynamic_cast (a) - -#define CAST_BINOP_ARGS(t1, t2) \ - t1 v1 = dynamic_cast (a1); \ - t2 v2 = dynamic_cast (a2) - -#define CAST_CONV_ARG(t) \ - t v = dynamic_cast (a) - -#define ASSIGNOPDECL(name) \ - static octave_value \ - CONCAT2(oct_assignop_, name) (octave_base_value& a1, \ - const octave_value_list& idx, \ - const octave_base_value& a2) - -#define NULLASSIGNOPDECL(name) \ - static octave_value \ - CONCAT2(oct_assignop_, name) (octave_base_value& a, \ - const octave_value_list& idx, \ - const octave_base_value&) - -#define ASSIGNANYOPDECL(name) \ - static octave_value \ - CONCAT2(oct_assignop_, name) (octave_base_value& a1, \ - const octave_value_list& idx, \ - const octave_value& a2) - -#define DEFASSIGNOP(name, t1, t2) \ - ASSIGNOPDECL (name) - -#define DEFASSIGNOP_FN(name, t1, t2, f) \ - ASSIGNOPDECL (name) \ - { \ - CAST_BINOP_ARGS (CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ - \ - v1.f (idx, v2.CONCAT2(t1, _value) ()); \ - return octave_value (); \ - } - -#define DEFNULLASSIGNOP_FN(name, t, f) \ - NULLASSIGNOPDECL (name) \ - { \ - CAST_UNOP_ARG (CONCAT2(octave_, t)&); \ - \ - v.f (idx); \ - return octave_value (); \ - } - -#define DEFNDASSIGNOP_FN(name, t1, t2, e, f) \ - ASSIGNOPDECL (name) \ - { \ - CAST_BINOP_ARGS (CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ - \ - v1.f (idx, v2.CONCAT2(e, _value) ()); \ - return octave_value (); \ - } - -// FIXME: the following currently don't handle index. -#define DEFNDASSIGNOP_OP(name, t1, t2, f, op) \ - ASSIGNOPDECL (name) \ - { \ - CAST_BINOP_ARGS (CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ - \ - assert (idx.empty ()); \ - v1.matrix_ref () op v2.CONCAT2(f, _value) (); \ - \ - return octave_value (); \ - } - -#define DEFNDASSIGNOP_FNOP(name, t1, t2, f, fnop) \ - ASSIGNOPDECL (name) \ - { \ - CAST_BINOP_ARGS (CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ - \ - assert (idx.empty ()); \ - fnop (v1.matrix_ref (), v2.CONCAT2(f, _value) ()); \ - \ - return octave_value (); \ - } - -#define DEFASSIGNANYOP_FN(name, t1, f) \ - ASSIGNANYOPDECL (name) \ - { \ - CONCAT2(octave_, t1)& v1 = dynamic_cast (a1); \ - \ - v1.f (idx, a2); \ - return octave_value (); \ - } - -#define CONVDECL(name) \ - static octave_base_value * \ - CONCAT2(oct_conv_, name) (const octave_base_value& a) - -#define CONVDECLX(name) \ - static octave_base_value * \ - CONCAT2(oct_conv_, name) (const octave_base_value&) - -#define DEFCONV(name, a_dummy, b_dummy) \ - CONVDECL (name) - -#define DEFCONVFNX(name, tfrom, ovtto, tto, e) \ - CONVDECL (name) \ - { \ - CAST_CONV_ARG (const CONCAT2(octave_, tfrom)&); \ - \ - return new CONCAT2(octave_, ovtto) (CONCAT2(tto, NDArray) (v.CONCAT2(e, array_value) ())); \ - } - -#define DEFCONVFNX2(name, tfrom, ovtto, e) \ - CONVDECL (name) \ - { \ - CAST_CONV_ARG (const CONCAT2(octave_, tfrom)&); \ - \ - return new CONCAT2(octave_, ovtto) (v.CONCAT2(e, array_value) ()); \ - } - -#define DEFDBLCONVFN(name, ovtfrom, e) \ - CONVDECL (name) \ - { \ - CAST_CONV_ARG (const CONCAT2(octave_, ovtfrom)&); \ - \ - return new octave_matrix (NDArray (v.CONCAT2(e, _value) ())); \ - } - -#define DEFFLTCONVFN(name, ovtfrom, e) \ - CONVDECL (name) \ - { \ - CAST_CONV_ARG (const CONCAT2(octave_, ovtfrom)&); \ - \ - return new octave_float_matrix (FloatNDArray (v.CONCAT2(e, _value) ())); \ - } - -#define DEFSTRINTCONVFN(name, tto) \ - DEFCONVFNX(name, char_matrix_str, CONCAT2(tto, _matrix), tto, char_) - -#define DEFSTRDBLCONVFN(name, tfrom) \ - DEFCONVFNX(name, tfrom, matrix, , char_) - -#define DEFSTRFLTCONVFN(name, tfrom) \ - DEFCONVFNX(name, tfrom, float_matrix, Float, char_) - -#define DEFCONVFN(name, tfrom, tto) \ - DEFCONVFNX2 (name, tfrom, CONCAT2(tto, _matrix), CONCAT2(tto, _)) - -#define DEFCONVFN2(name, tfrom, sm, tto) \ - DEFCONVFNX2 (name, CONCAT3(tfrom, _, sm), CONCAT2(tto, _matrix), CONCAT2(tto, _)) - -#define UNOPDECL(name, a) \ - static octave_value \ - CONCAT2(oct_unop_, name) (const octave_base_value& a) - -#define DEFUNOPX(name, t) \ - UNOPDECL (name, , ) - -#define DEFUNOP(name, t) \ - UNOPDECL (name, a) - -#define DEFUNOP_OP(name, t, op) \ - UNOPDECL (name, a) \ - { \ - CAST_UNOP_ARG (const CONCAT2(octave_, t)&); \ - return octave_value (op v.CONCAT2(t, _value) ()); \ - } - -#define DEFNDUNOP_OP(name, t, e, op) \ - UNOPDECL (name, a) \ - { \ - CAST_UNOP_ARG (const CONCAT2(octave_, t)&); \ - return octave_value (op v.CONCAT2(e, _value) ()); \ - } - -// FIXME -- in some cases, the constructor isn't necessary. - -#define DEFUNOP_FN(name, t, f) \ - UNOPDECL (name, a) \ - { \ - CAST_UNOP_ARG (const CONCAT2(octave_, t)&); \ - return octave_value (f (v.CONCAT2(t, _value) ())); \ - } - -#define DEFNDUNOP_FN(name, t, e, f) \ - UNOPDECL (name, a) \ - { \ - CAST_UNOP_ARG (const CONCAT2(octave_, t)&); \ - return octave_value (f (v.CONCAT2(e, _value) ())); \ - } - -#define DEFNCUNOP_METHOD(name, t, method) \ - static void \ - CONCAT2(oct_unop_, name) (octave_base_value& a) \ - { \ - CAST_UNOP_ARG (CONCAT2(octave_, t)&); \ - v.method (); \ - } - -#define BINOPDECL(name, a1, a2) \ - static octave_value \ - CONCAT2(oct_binop_, name) (const octave_base_value& a1, const octave_base_value& a2) - -#define DEFBINOPX(name, t1, t2) \ - BINOPDECL (name, , ) - -#define DEFBINOP(name, t1, t2) \ - BINOPDECL (name, a1, a2) - -#define DEFBINOP_OP(name, t1, t2, op) \ - BINOPDECL (name, a1, a2) \ - { \ - CAST_BINOP_ARGS (const CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ - return octave_value \ - (v1.CONCAT2(t1, _value) () op v2.CONCAT2(t2, _value) ()); \ - } - -#define DEFCMPLXCMPOP_OP(name, t1, t2, op) \ - BINOPDECL (name, a1, a2) \ - { \ - CAST_BINOP_ARGS (const CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ - gripe_warn_complex_cmp (); \ - return octave_value \ - (v1.CONCAT2(t1, _value) () op v2.CONCAT2(t2, _value) ()); \ - } - -#define DEFSCALARBOOLOP_OP(name, t1, t2, op) \ - BINOPDECL (name, a1, a2) \ - { \ - CAST_BINOP_ARGS (const CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ - if (xisnan (v1.CONCAT2(t1, _value) ()) || xisnan (v2.CONCAT2(t2, _value) ())) \ - { \ - gripe_nan_to_logical_conversion (); \ - return octave_value (); \ - } \ - else \ - return octave_value \ - (v1.CONCAT2(t1, _value) () op v2.CONCAT2(t2, _value) ()); \ - } - -#define DEFNDBINOP_OP(name, t1, t2, e1, e2, op) \ - BINOPDECL (name, a1, a2) \ - { \ - CAST_BINOP_ARGS (const CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ - return octave_value \ - (v1.CONCAT2(e1, _value) () op v2.CONCAT2(e2, _value) ()); \ - } - -// FIXME -- in some cases, the constructor isn't necessary. - -#define DEFBINOP_FN(name, t1, t2, f) \ - BINOPDECL (name, a1, a2) \ - { \ - CAST_BINOP_ARGS (const CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ - return octave_value (f (v1.CONCAT2(t1, _value) (), v2.CONCAT2(t2, _value) ())); \ - } - -#define DEFNDBINOP_FN(name, t1, t2, e1, e2, f) \ - BINOPDECL (name, a1, a2) \ - { \ - CAST_BINOP_ARGS (const CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ - return octave_value (f (v1.CONCAT2(e1, _value) (), v2.CONCAT2(e2, _value) ())); \ - } - -#define DEFNDCMPLXCMPOP_FN(name, t1, t2, e1, e2, f) \ - BINOPDECL (name, a1, a2) \ - { \ - CAST_BINOP_ARGS (const CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ - return octave_value (f (v1.CONCAT2(e1, _value) (), v2.CONCAT2(e2, _value) ())); \ - } - -#define CATOPDECL(name, a1, a2) \ - static octave_value \ - CONCAT2(oct_catop_, name) (octave_base_value& a1, const octave_base_value& a2, \ - const Array& ra_idx) - -#define DEFCATOPX(name, t1, t2) \ - CATOPDECL (name, , ) - -#define DEFCATOP(name, t1, t2) \ - CATOPDECL (name, a1, a2) - -// FIXME -- in some cases, the constructor isn't necessary. - -#define DEFCATOP_FN(name, t1, t2, f) \ - CATOPDECL (name, a1, a2) \ - { \ - CAST_BINOP_ARGS (CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ - return octave_value (v1.CONCAT2(t1, _value) () . f (v2.CONCAT2(t2, _value) (), ra_idx)); \ - } - -#define DEFNDCATOP_FN(name, t1, t2, e1, e2, f) \ - CATOPDECL (name, a1, a2) \ - { \ - CAST_BINOP_ARGS (CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ - return octave_value (v1.CONCAT2(e1, _value) () . f (v2.CONCAT2(e2, _value) (), ra_idx)); \ - } - -#define DEFNDCHARCATOP_FN(name, t1, t2, f) \ - CATOPDECL (name, a1, a2) \ - { \ - CAST_BINOP_ARGS (CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ - \ - return octave_value (v1.char_array_value () . f (v2.char_array_value (), ra_idx), \ - ((a1.is_sq_string () || a2.is_sq_string ()) \ - ? '\'' : '"')); \ - } - -// For compatibility, the second arg is always converted to the type -// of the first. Hmm. - -#define DEFNDCATOP_FN2(name, t1, t2, tc1, tc2, e1, e2, f) \ - CATOPDECL (name, a1, a2) \ - { \ - CAST_BINOP_ARGS (CONCAT2(octave_, t1)&, const CONCAT2(octave_, t2)&); \ - return octave_value (tc1 (v1.CONCAT2(e1, _value) ()) . f (tc2 (v2.CONCAT2(e2, _value) ()), ra_idx)); \ - } - -#define CATOP_NONCONFORMANT(msg) \ - gripe_nonconformant (msg, \ - a1.rows (), a1.columns (), \ - a2.rows (), a2.columns ()); \ - return octave_value () - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/parse-tree/module.mk --- a/src/parse-tree/module.mk Fri Aug 03 14:59:40 2012 -0400 +++ b/src/parse-tree/module.mk Fri Aug 03 18:05:18 2012 -0400 @@ -1,5 +1,6 @@ EXTRA_DIST += \ - parse-tree/module.mk + parse-tree/module.mk \ + parse-tree/octave.gperf PARSER_INCLUDES = \ parse-tree/lex.h \ @@ -42,6 +43,7 @@ parse-tree/pt-unop.h \ parse-tree/pt-walk.h \ parse-tree/pt.h \ + parse-tree/token.h \ $(PARSER_INCLUDES) PARSE_TREE_SRC = \ @@ -71,5 +73,18 @@ parse-tree/pt-stmt.cc \ parse-tree/pt-unop.cc \ parse-tree/pt.cc \ + parse-tree/token.cc \ $(PARSER_SRC) +## Special rules for sources which must be built before rest of compilation. + +## Don't use a pipeline to process gperf output since if gperf +## is missing but sed is not, the exit status of the pipeline +## will still be success and we will end up creating an empty +## oct-gperf.h file. +parse-tree/oct-gperf.h: parse-tree/octave.gperf + $(GPERF) -t -C -D -G -L C++ -Z octave_kw_hash $< > $@-t1 + $(SED) 's,lookup\[,gperf_lookup[,' < $@-t1 > $@-t + mv $@-t $@ + rm -f $@-t1 + diff -r a132d206a36a -r b9b6a310ad97 src/parse-tree/octave.gperf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/parse-tree/octave.gperf Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,122 @@ +%{ +/* + +Copyright (C) 1995-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at +your option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +NOTE: gperf 2.7.2 will silently generate bad code if there are blank +lines following the "%{" marker above. This comment block seems to be +handled correctly. + +*/ +enum octave_kw_id +{ + break_kw, + case_kw, + catch_kw, + classdef_kw, + continue_kw, + do_kw, + else_kw, + elseif_kw, + end_kw, + end_try_catch_kw, + end_unwind_protect_kw, + endclassdef_kw, + endenumeration_kw, + endevents_kw, + endfor_kw, + endfunction_kw, + endif_kw, + endmethods_kw, + endparfor_kw, + endproperties_kw, + endswitch_kw, + endwhile_kw, + enumeration_kw, + events_kw, + for_kw, + function_kw, + get_kw, + global_kw, + if_kw, + magic_file_kw, + magic_line_kw, + methods_kw, + otherwise_kw, + parfor_kw, + persistent_kw, + properties_kw, + return_kw, + set_kw, + static_kw, + switch_kw, + try_kw, + until_kw, + unwind_protect_kw, + unwind_protect_cleanup_kw, + while_kw +}; +%} +struct octave_kw { const char *name; int tok; octave_kw_id kw_id; }; +%% +break, BREAK, break_kw +case, CASE, case_kw +catch, CATCH, catch_kw +classdef, CLASSDEF, classdef_kw +continue, CONTINUE, continue_kw +do, DO, do_kw +else, ELSE, else_kw +elseif, ELSEIF, elseif_kw +end, END, end_kw +end_try_catch, END, end_try_catch_kw +end_unwind_protect, END, end_unwind_protect_kw +endclassdef, END, endclassdef_kw +endenumeration, END, endenumeration_kw +endevents, END, endevents_kw +endfor, END, endfor_kw +endfunction, END, endfunction_kw +endif, END, endif_kw +endmethods, END, endmethods_kw +endparfor, END, endparfor_kw +endproperties, END, endproperties_kw +endswitch, END, endswitch_kw +endwhile, END, endwhile_kw +enumeration, ENUMERATION, enumeration_kw +events, EVENTS, events_kw +for, FOR, for_kw +function, FCN, function_kw +get, GET, get_kw +global, GLOBAL, global_kw +if, IF, if_kw +methods, METHODS, methods_kw +otherwise, OTHERWISE, otherwise_kw +parfor, PARFOR, parfor_kw +persistent, PERSISTENT, persistent_kw +properties, PROPERTIES, properties_kw +return, FUNC_RET, return_kw +set, SET, set_kw +static, PERSISTENT, static_kw +switch, SWITCH, switch_kw +try, TRY, try_kw +until, UNTIL, until_kw +unwind_protect, UNWIND, unwind_protect_kw +unwind_protect_cleanup, CLEANUP, unwind_protect_cleanup_kw +while, WHILE, while_kw +__FILE__, DQ_STRING, magic_file_kw +__LINE__, NUM, magic_line_kw diff -r a132d206a36a -r b9b6a310ad97 src/parse-tree/token.cc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/parse-tree/token.cc Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,170 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include "error.h" +#include "oct-obj.h" +#include "symtab.h" +#include "token.h" +#include "utils.h" + +token::token (int l, int c) +{ + line_num = l; + column_num = c; + type_tag = generic_token; +} + +token::token (const std::string& s, int l, int c) +{ + line_num = l; + column_num = c; + type_tag = string_token; + str = new std::string (s); +} + +token::token (double d, const std::string& s, int l, int c) +{ + line_num = l; + column_num = c; + type_tag = double_token; + num = d; + orig_text = s; +} + +token::token (end_tok_type t, int l, int c) +{ + line_num = l; + column_num = c; + type_tag = ettype_token; + et = t; +} + +token::token (symbol_table::symbol_record *s, int l, int c) +{ + line_num = l; + column_num = c; + type_tag = sym_rec_token; + sr = s; +} + +token::token (symbol_table::symbol_record *cls, + symbol_table::symbol_record *pkg, int l, int c) +{ + line_num = l; + column_num = c; + type_tag = meta_rec_token; + mc.cr = cls; + mc.pr = pkg; +} + +token::token (symbol_table::symbol_record *mth, + symbol_table::symbol_record *cls, + symbol_table::symbol_record *pkg, int l, int c) +{ + line_num = l; + column_num = c; + type_tag = scls_rec_token; + sc.mr = mth; + sc.cr = cls; + sc.pr = pkg; +} + +token::~token (void) +{ + if (type_tag == string_token) + delete str; +} + +std::string +token::text (void) +{ + assert (type_tag == string_token); + return *str; +} + +double +token::number (void) +{ + assert (type_tag == double_token); + return num; +} + +token::end_tok_type +token::ettype (void) +{ + assert (type_tag == ettype_token); + return et; +} + +symbol_table::symbol_record * +token::sym_rec (void) +{ + assert (type_tag == sym_rec_token); + return sr; +} + +symbol_table::symbol_record * +token::method_rec (void) +{ + assert (type_tag == scls_rec_token); + return sc.mr; +} + +symbol_table::symbol_record * +token::class_rec (void) +{ + assert (type_tag == scls_rec_token); + return sc.cr; +} + +symbol_table::symbol_record * +token::package_rec (void) +{ + assert (type_tag == scls_rec_token); + return sc.pr; +} + +symbol_table::symbol_record * +token::meta_class_rec (void) +{ + assert (type_tag == meta_rec_token); + return mc.cr; +} + +symbol_table::symbol_record * +token::meta_package_rec (void) +{ + assert (type_tag == meta_rec_token); + return mc.pr; +} + +std::string +token::text_rep (void) +{ + return orig_text; +} diff -r a132d206a36a -r b9b6a310ad97 src/parse-tree/token.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/parse-tree/token.h Fri Aug 03 18:05:18 2012 -0400 @@ -0,0 +1,125 @@ +/* + +Copyright (C) 1993-2012 John W. Eaton + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if !defined (octave_token_h) +#define octave_token_h 1 + +#include + +class +token +{ +public: + + enum token_type + { + generic_token, + string_token, + double_token, + ettype_token, + sym_rec_token, + scls_rec_token, + meta_rec_token + }; + + enum end_tok_type + { + simple_end, + classdef_end, + enumeration_end, + events_end, + for_end, + function_end, + if_end, + methods_end, + parfor_end, + properties_end, + switch_end, + while_end, + try_catch_end, + unwind_protect_end + }; + + token (int l = -1, int c = -1); + token (const std::string& s, int l = -1, int c = -1); + token (double d, const std::string& s = std::string (), + int l = -1, int c = -1); + token (end_tok_type t, int l = -1, int c = -1); + token (symbol_table::symbol_record *s, int l = -1, int c = -1); + token (symbol_table::symbol_record *cls, + symbol_table::symbol_record *pkg, int l = -1, int c = -1); + token (symbol_table::symbol_record *mth, + symbol_table::symbol_record *cls, + symbol_table::symbol_record *pkg, int l = -1, int c = -1); + + ~token (void); + + int line (void) { return line_num; } + int column (void) { return column_num; } + + std::string text (void); + double number (void); + end_tok_type ettype (void); + symbol_table::symbol_record *sym_rec (void); + + symbol_table::symbol_record *method_rec (void); + symbol_table::symbol_record *class_rec (void); + symbol_table::symbol_record *package_rec (void); + + symbol_table::symbol_record *meta_class_rec (void); + symbol_table::symbol_record *meta_package_rec (void); + + std::string text_rep (void); + +private: + + // No copying! + + token (const token& tok); + + token& operator = (const token& tok); + + int line_num; + int column_num; + token_type type_tag; + union + { + std::string *str; + double num; + end_tok_type et; + symbol_table::symbol_record *sr; + struct + { + symbol_table::symbol_record *mr; + symbol_table::symbol_record *cr; + symbol_table::symbol_record *pr; + } sc; + struct + { + symbol_table::symbol_record *cr; + symbol_table::symbol_record *pr; + } mc; + }; + std::string orig_text; +}; + +#endif diff -r a132d206a36a -r b9b6a310ad97 src/procstream.cc --- a/src/procstream.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -/* - -Copyright (C) 1993-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "procstream.h" - -procstreambase::procstreambase (const std::string& command, int mode) -{ - pb_init (); - - if (! pb.open (command.c_str (), mode)) - std::ios::setstate (std::ios::badbit); -} - -procstreambase::procstreambase (const char *command, int mode) -{ - pb_init (); - - if (! pb.open (command, mode)) - std::ios::setstate (std::ios::badbit); -} - -void -procstreambase::open (const char *command, int mode) -{ - clear (); - - if (! pb.open (command, mode)) - std::ios::setstate (std::ios::badbit); -} - -int -procstreambase::close (void) -{ - int status = 0; - - if (is_open ()) - { - if (! pb.close ()) - std::ios::setstate (std::ios::failbit); - - status = pb.wait_status (); - } - - return status; -} diff -r a132d206a36a -r b9b6a310ad97 src/procstream.h --- a/src/procstream.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,161 +0,0 @@ -/* - -Copyright (C) 1993-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_procstream_h) -#define octave_procstream_h 1 - -#include -#include - -#include - -#include "oct-procbuf.h" - -class -OCTINTERP_API -procstreambase : virtual public std::ios -{ -public: - - procstreambase (void) : pb () { pb_init (); } - - procstreambase (const std::string& name, int mode); - - procstreambase (const char *name, int mode); - - ~procstreambase (void) { close (); } - - void open (const std::string& name, int mode) - { open (name.c_str (), mode); } - - void open (const char *name, int mode); - - int is_open (void) const { return pb.is_open (); } - - int close (void); - - pid_t pid (void) const { return pb.pid (); } - - int file_number (void) const { return pb.file_number (); } - -private: - - octave_procbuf pb; - - void pb_init (void) { init (&pb); } - - procstreambase (const procstreambase&); - - procstreambase& operator = (const procstreambase&); -}; - -class -OCTINTERP_API -iprocstream : public std::istream, public procstreambase -// iprocstream : public procstreambase, public std::istream -{ -public: - - iprocstream (void) : std::istream (0), procstreambase () { } - - iprocstream (const std::string& name, int mode = std::ios::in) - : std::istream (0), procstreambase (name, mode) { } - - iprocstream (const char *name, int mode = std::ios::in) - : std::istream (0), procstreambase (name, mode) { } - - ~iprocstream (void) { } - - void open (const std::string& name, int mode = std::ios::in) - { procstreambase::open (name, mode); } - - void open (const char *name, int mode = std::ios::in) - { procstreambase::open (name, mode); } - -private: - - iprocstream (const iprocstream&); - - iprocstream& operator = (const iprocstream&); -}; - -class -OCTINTERP_API -oprocstream : public std::ostream, public procstreambase -// oprocstream : public procstreambase, public std::ostream -{ -public: - - oprocstream (void) : std::ostream (0), procstreambase () { } - - oprocstream (const std::string& name, int mode = std::ios::out) - : std::ostream (0), procstreambase (name, mode) { } - - oprocstream (const char *name, int mode = std::ios::out) - : std::ostream (0), procstreambase (name, mode) { } - - ~oprocstream (void) { } - - void open (const std::string& name, int mode = std::ios::out) - { procstreambase::open (name, mode); } - - void open (const char *name, int mode = std::ios::out) - { procstreambase::open (name, mode); } - -private: - - oprocstream (const oprocstream&); - - oprocstream& operator = (const oprocstream&); -}; - -class -OCTINTERP_API -procstream : public std::iostream, public procstreambase -// procstream : public procstreambase, public std::iostream -{ -public: - - procstream (void) : std::iostream (0), procstreambase () { } - - procstream (const std::string& name, int mode) - : std::iostream (0), procstreambase (name, mode) { } - - procstream (const char *name, int mode) - : std::iostream (0), procstreambase (name, mode) { } - - ~procstream (void) { } - - void open (const std::string& name, int mode) - { procstreambase::open (name, mode); } - - void open (const char *name, int mode) - { procstreambase::open (name, mode); } - -private: - - procstream (const procstream&); - - procstream& operator = (const procstream&); -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/pt-jit.cc --- a/src/pt-jit.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1907 +0,0 @@ -/* - -Copyright (C) 2012 Max Brister - -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 -. - -*/ - -#define __STDC_LIMIT_MACROS -#define __STDC_CONSTANT_MACROS - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef HAVE_LLVM - -#include "pt-jit.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef OCTAVE_JIT_DEBUG -#include -#endif - -#include "symtab.h" -#include "pt-all.h" - -static llvm::IRBuilder<> builder (llvm::getGlobalContext ()); - -static llvm::LLVMContext& context = llvm::getGlobalContext (); - -// -------------------- jit_convert -------------------- -jit_convert::jit_convert (llvm::Module *module, tree &tee, - jit_type *for_bounds) - : iterator_count (0), for_bounds_count (0), short_count (0), breaking (false) -{ - jit_instruction::reset_ids (); - - entry_block = create ("body"); - final_block = create ("final"); - append (entry_block); - entry_block->mark_alive (); - block = entry_block; - - if (for_bounds) - create_variable (next_for_bounds (false), for_bounds); - - visit (tee); - - // FIXME: Remove if we no longer only compile loops - assert (! breaking); - assert (breaks.empty ()); - assert (continues.empty ()); - - block->append (create (final_block)); - append (final_block); - - for (vmap_t::iterator iter = vmap.begin (); iter != vmap.end (); ++iter) - { - jit_variable *var = iter->second; - const std::string& name = var->name (); - if (name.size () && name[0] != '#') - final_block->append (create (var)); - } - - construct_ssa (); - - // initialize the worklist to instructions derived from constants - for (std::list::iterator iter = constants.begin (); - iter != constants.end (); ++iter) - append_users (*iter); - - // the entry block terminator may be a regular branch statement - if (entry_block->terminator ()) - push_worklist (entry_block->terminator ()); - - // FIXME: Describe algorithm here - while (worklist.size ()) - { - jit_instruction *next = worklist.front (); - worklist.pop_front (); - next->stash_in_worklist (false); - - if (next->infer ()) - { - // terminators need to be handles specially - if (jit_terminator *term = dynamic_cast (next)) - append_users_term (term); - else - append_users (next); - } - } - - remove_dead (); - merge_blocks (); - final_block->label (); - place_releases (); - simplify_phi (); - -#ifdef OCTAVE_JIT_DEBUG - final_block->label (); - std::cout << "-------------------- Compiling tree --------------------\n"; - std::cout << tee.str_print_code () << std::endl; - print_blocks ("octave jit ir"); -#endif - - // for now just init arguments from entry, later we will have to do something - // more interesting - for (jit_block::iterator iter = entry_block->begin (); - iter != entry_block->end (); ++iter) - if (jit_extract_argument *extract - = dynamic_cast (*iter)) - arguments.push_back (std::make_pair (extract->name (), true)); - - convert_llvm to_llvm (*this); - function = to_llvm.convert (module, arguments, blocks, constants); - -#ifdef OCTAVE_JIT_DEBUG - std::cout << "-------------------- llvm ir --------------------"; - llvm::raw_os_ostream llvm_cout (std::cout); - function->print (llvm_cout); - std::cout << std::endl; - llvm::verifyFunction (*function); -#endif -} - -jit_convert::~jit_convert (void) -{ - for (std::list::iterator iter = all_values.begin (); - iter != all_values.end (); ++iter) - delete *iter; -} - -void -jit_convert::visit_anon_fcn_handle (tree_anon_fcn_handle&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_argument_list (tree_argument_list&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_binary_expression (tree_binary_expression& be) -{ - if (be.op_type () >= octave_value::num_binary_ops) - { - tree_boolean_expression *boole; - boole = dynamic_cast (&be); - assert (boole); - bool is_and = boole->op_type () == tree_boolean_expression::bool_and; - - std::string short_name = next_shortcircut_result (); - jit_variable *short_result = create (short_name); - vmap[short_name] = short_result; - - jit_block *done = create (block->name ()); - tree_expression *lhs = be.lhs (); - jit_value *lhsv = visit (lhs); - lhsv = create_checked (&jit_typeinfo::logically_true, lhsv); - - jit_block *short_early = create ("short_early"); - append (short_early); - - jit_block *short_cont = create ("short_cont"); - - if (is_and) - block->append (create (lhsv, short_cont, short_early)); - else - block->append (create (lhsv, short_early, short_cont)); - - block = short_early; - - jit_value *early_result = create (! is_and); - block->append (create (short_result, early_result)); - block->append (create (done)); - - append (short_cont); - block = short_cont; - - tree_expression *rhs = be.rhs (); - jit_value *rhsv = visit (rhs); - rhsv = create_checked (&jit_typeinfo::logically_true, rhsv); - block->append (create (short_result, rhsv)); - block->append (create (done)); - - append (done); - block = done; - result = short_result; - } - else - { - tree_expression *lhs = be.lhs (); - jit_value *lhsv = visit (lhs); - - tree_expression *rhs = be.rhs (); - jit_value *rhsv = visit (rhs); - - const jit_operation& fn = jit_typeinfo::binary_op (be.op_type ()); - result = create_checked (fn, lhsv, rhsv); - } -} - -void -jit_convert::visit_break_command (tree_break_command&) -{ - breaks.push_back (block); - breaking = true; -} - -void -jit_convert::visit_colon_expression (tree_colon_expression& expr) -{ - // in the futher we need to add support for classes and deal with rvalues - jit_value *base = visit (expr.base ()); - jit_value *limit = visit (expr.limit ()); - jit_value *increment; - tree_expression *tinc = expr.increment (); - - if (tinc) - increment = visit (tinc); - else - increment = create (1); - - result = block->append (create (jit_typeinfo::make_range, base, - limit, increment)); -} - -void -jit_convert::visit_continue_command (tree_continue_command&) -{ - continues.push_back (block); - breaking = true; -} - -void -jit_convert::visit_global_command (tree_global_command&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_persistent_command (tree_persistent_command&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_decl_elt (tree_decl_elt&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_decl_init_list (tree_decl_init_list&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_simple_for_command (tree_simple_for_command& cmd) -{ - // Note we do an initial check to see if the loop will run atleast once. - // This allows us to get better type inference bounds on variables defined - // and used only inside the for loop (e.g. the index variable) - - // If we are a nested for loop we need to store the previous breaks - assert (! breaking); - unwind_protect prot; - prot.protect_var (breaks); - prot.protect_var (continues); - prot.protect_var (breaking); - breaks.clear (); - continues.clear (); - - // we need a variable for our iterator, because it is used in multiple blocks - std::string iter_name = next_iterator (); - jit_variable *iterator = create (iter_name); - create (iter_name); - vmap[iter_name] = iterator; - - jit_block *body = create ("for_body"); - append (body); - - jit_block *tail = create ("for_tail"); - - // do control expression, iter init, and condition check in prev_block (block) - // if we are the top level for loop, the bounds is an input argument. - jit_value *control = find_variable (next_for_bounds ()); - if (! control) - control = visit (cmd.control_expr ()); - jit_call *init_iter = create (jit_typeinfo::for_init, control); - block->append (init_iter); - block->append (create (iterator, init_iter)); - - jit_value *check = block->append (create (jit_typeinfo::for_check, - control, iterator)); - block->append (create (check, body, tail)); - block = body; - - // compute the syntactical iterator - jit_call *idx_rhs = create (jit_typeinfo::for_index, control, - iterator); - block->append (idx_rhs); - do_assign (cmd.left_hand_side (), idx_rhs); - - // do loop - tree_statement_list *pt_body = cmd.body (); - pt_body->accept (*this); - - if (breaking && continues.empty ()) - { - // WTF are you doing user? Every branch was a continue, why did you have - // a loop??? Users are silly people... - finish_breaks (tail, breaks); - append (tail); - block = tail; - return; - } - - // check our condition, continues jump to this block - jit_block *check_block = create ("for_check"); - append (check_block); - - if (! breaking) - block->append (create (check_block)); - finish_breaks (check_block, continues); - - block = check_block; - const jit_operation& add_fn = jit_typeinfo::binary_op (octave_value::op_add); - jit_value *one = create (1); - jit_call *iter_inc = create (add_fn, iterator, one); - block->append (iter_inc); - block->append (create (iterator, iter_inc)); - check = block->append (create (jit_typeinfo::for_check, control, - iterator)); - block->append (create (check, body, tail)); - - // breaks will go to our tail - append (tail); - finish_breaks (tail, breaks); - block = tail; -} - -void -jit_convert::visit_complex_for_command (tree_complex_for_command&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_octave_user_script (octave_user_script&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_octave_user_function (octave_user_function&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_octave_user_function_header (octave_user_function&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_octave_user_function_trailer (octave_user_function&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_function_def (tree_function_def&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_identifier (tree_identifier& ti) -{ - if (ti.has_magic_end ()) - { - if (!end_context.size ()) - throw jit_fail_exception ("Illegal end"); - result = block->append (create (end_context)); - } - else - result = get_variable (ti.name ()); -} - -void -jit_convert::visit_if_clause (tree_if_clause&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_if_command (tree_if_command& cmd) -{ - tree_if_command_list *lst = cmd.cmd_list (); - assert (lst); // jwe: Can this be null? - lst->accept (*this); -} - -void -jit_convert::visit_if_command_list (tree_if_command_list& lst) -{ - tree_if_clause *last = lst.back (); - size_t last_else = static_cast (last->is_else_clause ()); - - // entry_blocks represents the block you need to enter in order to execute - // the condition check for the ith clause. For the else, it is simple the - // else body. If there is no else body, then it is padded with the tail - std::vector entry_blocks (lst.size () + 1 - last_else); - std::vector branch_blocks (lst.size (), 0); // final blocks - entry_blocks[0] = block; - - // we need to construct blocks first, because they have jumps to eachother - tree_if_command_list::iterator iter = lst.begin (); - ++iter; - for (size_t i = 1; iter != lst.end (); ++iter, ++i) - { - tree_if_clause *tic = *iter; - if (tic->is_else_clause ()) - entry_blocks[i] = create ("else"); - else - entry_blocks[i] = create ("ifelse_cond"); - } - - jit_block *tail = create ("if_tail"); - if (! last_else) - entry_blocks[entry_blocks.size () - 1] = tail; - - size_t num_incomming = 0; // number of incomming blocks to our tail - iter = lst.begin (); - for (size_t i = 0; iter != lst.end (); ++iter, ++i) - { - tree_if_clause *tic = *iter; - block = entry_blocks[i]; - assert (block); - - if (i) // the first block is prev_block, so it has already been added - append (entry_blocks[i]); - - if (! tic->is_else_clause ()) - { - tree_expression *expr = tic->condition (); - jit_value *cond = visit (expr); - jit_call *check = create_checked (&jit_typeinfo::logically_true, - cond); - jit_block *body = create (i == 0 ? "if_body" - : "ifelse_body"); - append (body); - - jit_instruction *br = create (check, body, - entry_blocks[i + 1]); - block->append (br); - block = body; - } - - tree_statement_list *stmt_lst = tic->commands (); - assert (stmt_lst); // jwe: Can this be null? - stmt_lst->accept (*this); - - if (breaking) - breaking = false; - else - { - ++num_incomming; - block->append (create (tail)); - } - } - - if (num_incomming || ! last_else) - { - append (tail); - block = tail; - } - else - // every branch broke, so we don't have a tail - breaking = true; -} - -void -jit_convert::visit_index_expression (tree_index_expression& exp) -{ - result = resolve (jit_typeinfo::paren_subsref (), exp); -} - -void -jit_convert::visit_matrix (tree_matrix&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_cell (tree_cell&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_multi_assignment (tree_multi_assignment&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_no_op_command (tree_no_op_command&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_constant (tree_constant& tc) -{ - octave_value v = tc.rvalue1 (); - if (v.is_real_scalar () && v.is_double_type ()) - { - double dv = v.double_value (); - result = create (dv); - } - else if (v.is_range ()) - { - Range rv = v.range_value (); - result = create (rv); - } - else if (v.is_complex_scalar ()) - { - Complex cv = v.complex_value (); - result = create (cv); - } - else - throw jit_fail_exception ("Unknown constant"); -} - -void -jit_convert::visit_fcn_handle (tree_fcn_handle&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_parameter_list (tree_parameter_list&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_postfix_expression (tree_postfix_expression&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_prefix_expression (tree_prefix_expression&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_return_command (tree_return_command&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_return_list (tree_return_list&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_simple_assignment (tree_simple_assignment& tsa) -{ - if (tsa.op_type () != octave_value::op_asn_eq) - throw jit_fail_exception ("Unsupported assign"); - - // resolve rhs - tree_expression *rhs = tsa.right_hand_side (); - jit_value *rhsv = visit (rhs); - - result = do_assign (tsa.left_hand_side (), rhsv); -} - -void -jit_convert::visit_statement (tree_statement& stmt) -{ - tree_command *cmd = stmt.command (); - tree_expression *expr = stmt.expression (); - - if (cmd) - visit (cmd); - else - { - // stolen from tree_evaluator::visit_statement - bool do_bind_ans = false; - - if (expr->is_identifier ()) - { - tree_identifier *id = dynamic_cast (expr); - - do_bind_ans = (! id->is_variable ()); - } - else - do_bind_ans = (! expr->is_assignment_expression ()); - - jit_value *expr_result = visit (expr); - - if (do_bind_ans) - do_assign ("ans", expr_result, expr->print_result ()); - else if (expr->is_identifier () && expr->print_result ()) - { - // FIXME: ugly hack, we need to come up with a way to pass - // nargout to visit_identifier - const jit_operation& fn = jit_typeinfo::print_value (); - jit_const_string *name = create (expr->name ()); - block->append (create (fn, name, expr_result)); - } - } -} - -void -jit_convert::visit_statement_list (tree_statement_list& lst) -{ - for (tree_statement_list::iterator iter = lst.begin (); iter != lst.end(); - ++iter) - { - tree_statement *elt = *iter; - // jwe: Can this ever be null? - assert (elt); - elt->accept (*this); - - if (breaking) - break; - } -} - -void -jit_convert::visit_switch_case (tree_switch_case&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_switch_case_list (tree_switch_case_list&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_switch_command (tree_switch_command&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_try_catch_command (tree_try_catch_command&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_unwind_protect_command (tree_unwind_protect_command&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::visit_while_command (tree_while_command& wc) -{ - assert (! breaking); - unwind_protect prot; - prot.protect_var (breaks); - prot.protect_var (continues); - prot.protect_var (breaking); - breaks.clear (); - continues.clear (); - - jit_block *cond_check = create ("while_cond_check"); - block->append (create (cond_check)); - append (cond_check); - block = cond_check; - - tree_expression *expr = wc.condition (); - assert (expr && "While expression can not be null"); - jit_value *check = visit (expr); - check = create_checked (&jit_typeinfo::logically_true, check); - - jit_block *body = create ("while_body"); - append (body); - - jit_block *tail = create ("while_tail"); - block->append (create (check, body, tail)); - block = body; - - tree_statement_list *loop_body = wc.body (); - if (loop_body) - loop_body->accept (*this); - - finish_breaks (tail, breaks); - finish_breaks (cond_check, continues); - - if (! breaking) - block->append (create (cond_check)); - - append (tail); - block = tail; -} - -void -jit_convert::visit_do_until_command (tree_do_until_command&) -{ - throw jit_fail_exception (); -} - -void -jit_convert::append (jit_block *ablock) -{ - blocks.push_back (ablock); - ablock->stash_location (--blocks.end ()); -} - -void -jit_convert::insert_before (block_iterator iter, jit_block *ablock) -{ - iter = blocks.insert (iter, ablock); - ablock->stash_location (iter); -} - -void -jit_convert::insert_after (block_iterator iter, jit_block *ablock) -{ - ++iter; - insert_before (iter, ablock); -} - -jit_variable * -jit_convert::find_variable (const std::string& vname) const -{ - vmap_t::const_iterator iter; - iter = vmap.find (vname); - return iter != vmap.end () ? iter->second : 0; -} - -jit_variable * -jit_convert::get_variable (const std::string& vname) -{ - jit_variable *ret = find_variable (vname); - if (ret) - return ret; - - octave_value val = symbol_table::find (vname); - jit_type *type = jit_typeinfo::type_of (val); - return create_variable (vname, type); -} - -jit_variable * -jit_convert::create_variable (const std::string& vname, jit_type *type) -{ - jit_variable *var = create (vname); - jit_extract_argument *extract; - extract = create (type, var); - entry_block->prepend (extract); - return vmap[vname] = var; -} - -std::string -jit_convert::next_name (const char *prefix, size_t& count, bool inc) -{ - std::stringstream ss; - ss << prefix << count; - if (inc) - ++count; - return ss.str (); -} - -jit_instruction * -jit_convert::resolve (const jit_operation& fres, tree_index_expression& exp, - jit_value *extra_arg) -{ - std::string type = exp.type_tags (); - if (! (type.size () == 1 && type[0] == '(')) - throw jit_fail_exception ("Unsupported index operation"); - - std::list args = exp.arg_lists (); - if (args.size () != 1) - throw jit_fail_exception ("Bad number of arguments in tree_index_expression"); - - tree_argument_list *arg_list = args.front (); - if (! arg_list) - throw jit_fail_exception ("null argument list"); - - if (arg_list->size () < 1) - throw jit_fail_exception ("Empty arg_list"); - - tree_expression *tree_object = exp.expression (); - jit_value *object = visit (tree_object); - - size_t narg = arg_list->size (); - tree_argument_list::iterator iter = arg_list->begin (); - bool have_extra = extra_arg; - std::vector call_args (narg + 1 + have_extra); - call_args[0] = object; - - for (size_t idx = 0; iter != arg_list->end (); ++idx, ++iter) - { - unwind_protect prot; - prot.add_method (&end_context, - &std::vector::pop_back); - end_context.push_back (jit_magic_end::context (object, idx, narg)); - call_args[idx + 1] = visit (*iter); - } - - if (extra_arg) - call_args[call_args.size () - 1] = extra_arg; - - return create_checked (fres, call_args); -} - -jit_value * -jit_convert::do_assign (tree_expression *exp, jit_value *rhs, bool artificial) -{ - if (! exp) - throw jit_fail_exception ("NULL lhs in assign"); - - if (isa (exp)) - return do_assign (exp->name (), rhs, exp->print_result (), artificial); - else if (tree_index_expression *idx - = dynamic_cast (exp)) - { - jit_value *new_object = resolve (jit_typeinfo::paren_subsasgn (), *idx, - rhs); - do_assign (idx->expression (), new_object, true); - - // FIXME: Will not work for values that must be release/grabed - return rhs; - } - else - throw jit_fail_exception ("Unsupported assignment"); -} - -jit_value * -jit_convert::do_assign (const std::string& lhs, jit_value *rhs, - bool print, bool artificial) -{ - jit_variable *var = get_variable (lhs); - jit_assign *assign = block->append (create (var, rhs)); - - if (artificial) - assign->mark_artificial (); - - if (print) - { - const jit_operation& print_fn = jit_typeinfo::print_value (); - jit_const_string *name = create (lhs); - block->append (create (print_fn, name, var)); - } - - return var; -} - -jit_value * -jit_convert::visit (tree& tee) -{ - result = 0; - tee.accept (*this); - - jit_value *ret = result; - result = 0; - return ret; -} - -void -jit_convert::append_users_term (jit_terminator *term) -{ - for (size_t i = 0; i < term->successor_count (); ++i) - { - if (term->alive (i)) - { - jit_block *succ = term->successor (i); - for (jit_block::iterator iter = succ->begin (); iter != succ->end () - && isa (*iter); ++iter) - push_worklist (*iter); - - jit_terminator *sterm = succ->terminator (); - if (sterm) - push_worklist (sterm); - } - } -} - -void -jit_convert::merge_blocks (void) -{ - std::vector dead; - for (block_list::iterator iter = blocks.begin (); iter != blocks.end (); - ++iter) - { - jit_block *b = *iter; - jit_block *merged = b->maybe_merge (); - - if (merged) - { - if (merged == final_block) - final_block = b; - - if (merged == entry_block) - entry_block = b; - - dead.push_back (merged); - } - } - - for (size_t i = 0; i < dead.size (); ++i) - blocks.erase (dead[i]->location ()); -} - -void -jit_convert::construct_ssa (void) -{ - merge_blocks (); - final_block->label (); - final_block->compute_idom (entry_block); - entry_block->compute_df (); - entry_block->create_dom_tree (); - - // insert phi nodes where needed, this is done on a per variable basis - for (vmap_t::iterator iter = vmap.begin (); iter != vmap.end (); ++iter) - { - jit_block::df_set visited, added_phi; - std::list ssa_worklist; - iter->second->use_blocks (visited); - ssa_worklist.insert (ssa_worklist.begin (), visited.begin (), - visited.end ()); - - while (ssa_worklist.size ()) - { - jit_block *b = ssa_worklist.front (); - ssa_worklist.pop_front (); - - for (jit_block::df_iterator diter = b->df_begin (); - diter != b->df_end (); ++diter) - { - jit_block *dblock = *diter; - if (! added_phi.count (dblock)) - { - jit_phi *phi = create (iter->second, - dblock->use_count ()); - dblock->prepend (phi); - added_phi.insert (dblock); - } - - if (! visited.count (dblock)) - { - ssa_worklist.push_back (dblock); - visited.insert (dblock); - } - } - } - } - - do_construct_ssa (*entry_block, entry_block->visit_count ()); -} - -void -jit_convert::do_construct_ssa (jit_block& ablock, size_t avisit_count) -{ - if (ablock.visited (avisit_count)) - return; - - // replace variables with their current SSA value - for (jit_block::iterator iter = ablock.begin (); iter != ablock.end (); ++iter) - { - jit_instruction *instr = *iter; - instr->construct_ssa (); - instr->push_variable (); - } - - // finish phi nodes of successors - for (size_t i = 0; i < ablock.successor_count (); ++i) - { - jit_block *finish = ablock.successor (i); - - for (jit_block::iterator iter = finish->begin (); iter != finish->end () - && isa (*iter);) - { - jit_phi *phi = static_cast (*iter); - jit_variable *var = phi->dest (); - if (var->has_top ()) - { - phi->add_incomming (&ablock, var->top ()); - ++iter; - } - else - { - // temporaries may have extranious phi nodes which can be removed - assert (! phi->use_count ()); - assert (var->name ().size () && var->name ()[0] == '#'); - iter = finish->remove (iter); - } - } - } - - for (size_t i = 0; i < ablock.dom_successor_count (); ++i) - do_construct_ssa (*ablock.dom_successor (i), avisit_count); - - ablock.pop_all (); -} - -void -jit_convert::remove_dead () -{ - block_list::iterator biter; - for (biter = blocks.begin (); biter != blocks.end (); ++biter) - { - jit_block *b = *biter; - if (b->alive ()) - { - for (jit_block::iterator iter = b->begin (); iter != b->end () - && isa (*iter);) - { - jit_phi *phi = static_cast (*iter); - if (phi->prune ()) - iter = b->remove (iter); - else - ++iter; - } - } - } - - for (biter = blocks.begin (); biter != blocks.end ();) - { - jit_block *b = *biter; - if (b->alive ()) - { - // FIXME: A special case for jit_error_check, if we generalize to - // we will need to change! - jit_terminator *term = b->terminator (); - if (term && term->successor_count () == 2 && ! term->alive (0)) - { - jit_block *succ = term->successor (1); - term->remove (); - jit_branch *abreak = b->append (create (succ)); - abreak->infer (); - } - - ++biter; - } - else - { - jit_terminator *term = b->terminator (); - if (term) - term->remove (); - biter = blocks.erase (biter); - } - } -} - -void -jit_convert::place_releases (void) -{ - std::set temporaries; - for (block_list::iterator iter = blocks.begin (); iter != blocks.end (); - ++iter) - { - jit_block& ablock = **iter; - if (ablock.id () != jit_block::NO_ID) - { - release_temp (ablock, temporaries); - release_dead_phi (ablock); - } - } -} - -void -jit_convert::release_temp (jit_block& ablock, std::set& temp) -{ - for (jit_block::iterator iter = ablock.begin (); iter != ablock.end (); - ++iter) - { - jit_instruction *instr = *iter; - - // check for temporaries that require release and live across - // multiple blocks - if (instr->needs_release ()) - { - jit_block *fu_block = instr->first_use_block (); - if (fu_block && fu_block != &ablock) - temp.insert (instr); - } - - if (isa (instr)) - { - // place releases for temporary arguments - for (size_t i = 0; i < instr->argument_count (); ++i) - { - jit_value *arg = instr->argument (i); - if (arg->needs_release ()) - { - jit_call *release = create (&jit_typeinfo::release, - arg); - release->infer (); - ablock.insert_after (iter, release); - ++iter; - temp.erase (arg); - } - } - } - } - - if (! temp.size () || ! isa (ablock.terminator ())) - return; - - // FIXME: If we support try/catch or unwind_protect final_block may not be the - // destination - jit_block *split = ablock.maybe_split (*this, final_block); - jit_terminator *term = split->terminator (); - for (std::set::const_iterator iter = temp.begin (); - iter != temp.end (); ++iter) - { - jit_value *value = *iter; - jit_call *release = create (&jit_typeinfo::release, value); - split->insert_before (term, release); - release->infer (); - } -} - -void -jit_convert::release_dead_phi (jit_block& ablock) -{ - jit_block::iterator iter = ablock.begin (); - while (iter != ablock.end () && isa (*iter)) - { - jit_phi *phi = static_cast (*iter); - ++iter; - - jit_use *use = phi->first_use (); - if (phi->use_count () == 1 && isa (use->user ())) - { - // instead of releasing on assign, release on all incomming branches, - // this can get rid of casts inside loops - for (size_t i = 0; i < phi->argument_count (); ++i) - { - jit_value *arg = phi->argument (i); - jit_block *inc = phi->incomming (i); - jit_block *split = inc->maybe_split (*this, ablock); - jit_terminator *term = split->terminator (); - jit_call *release = create (jit_typeinfo::release, arg); - release->infer (); - split->insert_before (term, release); - } - - phi->replace_with (0); - phi->remove (); - } - } -} - -void -jit_convert::simplify_phi (void) -{ - for (block_list::iterator biter = blocks.begin (); biter != blocks.end (); - ++biter) - { - jit_block &ablock = **biter; - for (jit_block::iterator iter = ablock.begin (); iter != ablock.end () - && isa (*iter); ++iter) - simplify_phi (*static_cast (*iter)); - } -} - -void -jit_convert::simplify_phi (jit_phi& phi) -{ - jit_block& pblock = *phi.parent (); - const jit_operation& cast_fn = jit_typeinfo::cast (phi.type ()); - jit_variable *dest = phi.dest (); - for (size_t i = 0; i < phi.argument_count (); ++i) - { - jit_value *arg = phi.argument (i); - if (arg->type () != phi.type ()) - { - jit_block *pred = phi.incomming (i); - jit_block *split = pred->maybe_split (*this, pblock); - jit_terminator *term = split->terminator (); - jit_instruction *cast = create (cast_fn, arg); - jit_assign *assign = create (dest, cast); - - split->insert_before (term, cast); - split->insert_before (term, assign); - cast->infer (); - assign->infer (); - phi.stash_argument (i, assign); - } - } -} - -void -jit_convert::finish_breaks (jit_block *dest, const block_list& lst) -{ - for (block_list::const_iterator iter = lst.begin (); iter != lst.end (); - ++iter) - { - jit_block *b = *iter; - b->append (create (dest)); - } -} - -// -------------------- jit_convert::convert_llvm -------------------- -llvm::Function * -jit_convert::convert_llvm::convert (llvm::Module *module, - const std::vector >& args, - const std::list& blocks, - const std::list& constants) -{ - jit_type *any = jit_typeinfo::get_any (); - - // argument is an array of octave_base_value*, or octave_base_value** - llvm::Type *arg_type = any->to_llvm (); // this is octave_base_value* - arg_type = arg_type->getPointerTo (); - llvm::FunctionType *ft = llvm::FunctionType::get (llvm::Type::getVoidTy (context), - arg_type, false); - function = llvm::Function::Create (ft, llvm::Function::ExternalLinkage, - "foobar", module); - - try - { - prelude = llvm::BasicBlock::Create (context, "prelude", function); - builder.SetInsertPoint (prelude); - - llvm::Value *arg = function->arg_begin (); - for (size_t i = 0; i < args.size (); ++i) - { - llvm::Value *loaded_arg = builder.CreateConstInBoundsGEP1_32 (arg, i); - arguments[args[i].first] = loaded_arg; - } - - std::list::const_iterator biter; - for (biter = blocks.begin (); biter != blocks.end (); ++biter) - { - jit_block *jblock = *biter; - llvm::BasicBlock *block = llvm::BasicBlock::Create (context, - jblock->name (), - function); - jblock->stash_llvm (block); - } - - jit_block *first = *blocks.begin (); - builder.CreateBr (first->to_llvm ()); - - // constants aren't in the IR, we visit those first - for (std::list::const_iterator iter = constants.begin (); - iter != constants.end (); ++iter) - if (! isa (*iter)) - visit (*iter); - - // convert all instructions - for (biter = blocks.begin (); biter != blocks.end (); ++biter) - visit (*biter); - - // now finish phi nodes - for (biter = blocks.begin (); biter != blocks.end (); ++biter) - { - jit_block& block = **biter; - for (jit_block::iterator piter = block.begin (); - piter != block.end () && isa (*piter); ++piter) - { - jit_instruction *phi = *piter; - finish_phi (static_cast (phi)); - } - } - - jit_block *last = blocks.back (); - builder.SetInsertPoint (last->to_llvm ()); - builder.CreateRetVoid (); - } catch (const jit_fail_exception& e) - { - function->eraseFromParent (); - throw; - } - - return function; -} - -void -jit_convert::convert_llvm::finish_phi (jit_phi *phi) -{ - llvm::PHINode *llvm_phi = phi->to_llvm (); - for (size_t i = 0; i < phi->argument_count (); ++i) - { - llvm::BasicBlock *pred = phi->incomming_llvm (i); - llvm_phi->addIncoming (phi->argument_llvm (i), pred); - } -} - -void -jit_convert::convert_llvm::visit (jit_const_string& cs) -{ - cs.stash_llvm (builder.CreateGlobalStringPtr (cs.value ())); -} - -void -jit_convert::convert_llvm::visit (jit_const_bool& cb) -{ - cb.stash_llvm (llvm::ConstantInt::get (cb.type_llvm (), cb.value ())); -} - -void -jit_convert::convert_llvm::visit (jit_const_scalar& cs) -{ - cs.stash_llvm (llvm::ConstantFP::get (cs.type_llvm (), cs.value ())); -} - -void -jit_convert::convert_llvm::visit (jit_const_complex& cc) -{ - llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm (); - llvm::Constant *values[2]; - Complex value = cc.value (); - values[0] = llvm::ConstantFP::get (scalar_t, value.real ()); - values[1] = llvm::ConstantFP::get (scalar_t, value.imag ()); - cc.stash_llvm (llvm::ConstantVector::get (values)); -} - -void jit_convert::convert_llvm::visit (jit_const_index& ci) -{ - ci.stash_llvm (llvm::ConstantInt::get (ci.type_llvm (), ci.value ())); -} - -void -jit_convert::convert_llvm::visit (jit_const_range& cr) -{ - llvm::StructType *stype = llvm::cast(cr.type_llvm ()); - llvm::Type *scalar_t = jit_typeinfo::get_scalar_llvm (); - llvm::Type *idx = jit_typeinfo::get_index_llvm (); - const jit_range& rng = cr.value (); - - llvm::Constant *constants[4]; - constants[0] = llvm::ConstantFP::get (scalar_t, rng.base); - constants[1] = llvm::ConstantFP::get (scalar_t, rng.limit); - constants[2] = llvm::ConstantFP::get (scalar_t, rng.inc); - constants[3] = llvm::ConstantInt::get (idx, rng.nelem); - - llvm::Value *as_llvm; - as_llvm = llvm::ConstantStruct::get (stype, - llvm::makeArrayRef (constants, 4)); - cr.stash_llvm (as_llvm); -} - -void -jit_convert::convert_llvm::visit (jit_block& b) -{ - llvm::BasicBlock *block = b.to_llvm (); - builder.SetInsertPoint (block); - for (jit_block::iterator iter = b.begin (); iter != b.end (); ++iter) - visit (*iter); -} - -void -jit_convert::convert_llvm::visit (jit_branch& b) -{ - b.stash_llvm (builder.CreateBr (b.successor_llvm ())); -} - -void -jit_convert::convert_llvm::visit (jit_cond_branch& cb) -{ - llvm::Value *cond = cb.cond_llvm (); - llvm::Value *br; - br = builder.CreateCondBr (cond, cb.successor_llvm (0), - cb.successor_llvm (1)); - cb.stash_llvm (br); -} - -void -jit_convert::convert_llvm::visit (jit_call& call) -{ - const jit_function& ol = call.overload (); - - std::vector args (call.arguments ().size ()); - for (size_t i = 0; i < args.size (); ++i) - args[i] = call.argument (i); - - llvm::Value *ret = ol.call (builder, args); - call.stash_llvm (ret); -} - -void -jit_convert::convert_llvm::visit (jit_extract_argument& extract) -{ - llvm::Value *arg = arguments[extract.name ()]; - assert (arg); - arg = builder.CreateLoad (arg); - - const jit_function& ol = extract.overload (); - extract.stash_llvm (ol.call (builder, arg)); -} - -void -jit_convert::convert_llvm::visit (jit_store_argument& store) -{ - const jit_function& ol = store.overload (); - llvm::Value *arg_value = ol.call (builder, store.result ()); - llvm::Value *arg = arguments[store.name ()]; - store.stash_llvm (builder.CreateStore (arg_value, arg)); -} - -void -jit_convert::convert_llvm::visit (jit_phi& phi) -{ - // we might not have converted all incoming branches, so we don't - // set incomming branches now - llvm::PHINode *node = llvm::PHINode::Create (phi.type_llvm (), - phi.argument_count ()); - builder.Insert (node); - phi.stash_llvm (node); -} - -void -jit_convert::convert_llvm::visit (jit_variable&) -{ - throw jit_fail_exception ("ERROR: SSA construction should remove all variables"); -} - -void -jit_convert::convert_llvm::visit (jit_error_check& check) -{ - llvm::Value *cond = jit_typeinfo::insert_error_check (builder); - llvm::Value *br = builder.CreateCondBr (cond, check.successor_llvm (0), - check.successor_llvm (1)); - check.stash_llvm (br); -} - -void -jit_convert::convert_llvm::visit (jit_assign& assign) -{ - jit_value *new_value = assign.src (); - assign.stash_llvm (new_value->to_llvm ()); - - if (assign.artificial ()) - return; - - if (isa (new_value)) - { - const jit_function& ol = jit_typeinfo::get_grab (new_value->type ()); - if (ol.valid ()) - assign.stash_llvm (ol.call (builder, new_value)); - } - - jit_value *overwrite = assign.overwrite (); - if (isa (overwrite)) - { - const jit_function& ol = jit_typeinfo::get_release (overwrite->type ()); - ol.call (builder, overwrite); - } -} - -void -jit_convert::convert_llvm::visit (jit_argument&) -{} - -void -jit_convert::convert_llvm::visit (jit_magic_end& me) -{ - const jit_function& ol = me.overload (); - llvm::Value *ret = ol.call (builder, me.resolve_context ()); - me.stash_llvm (ret); -} - -// -------------------- tree_jit -------------------- - -tree_jit::tree_jit (void) : module (0), engine (0) -{ -} - -tree_jit::~tree_jit (void) -{} - -bool -tree_jit::execute (tree_simple_for_command& cmd, const octave_value& bounds) -{ - const size_t MIN_TRIP_COUNT = 1000; - - size_t tc = trip_count (bounds); - if (! tc || ! initialize ()) - return false; - - jit_info::vmap extra_vars; - extra_vars["#for_bounds0"] = &bounds; - - jit_info *info = cmd.get_info (); - if (! info || ! info->match (extra_vars)) - { - if (tc < MIN_TRIP_COUNT) - return false; - - delete info; - info = new jit_info (*this, cmd, bounds); - cmd.stash_info (info); - } - - return info->execute (extra_vars); -} - -bool -tree_jit::execute (tree_while_command& cmd) -{ - if (! initialize ()) - return false; - - jit_info *info = cmd.get_info (); - if (! info || ! info->match ()) - { - delete info; - info = new jit_info (*this, cmd); - cmd.stash_info (info); - } - - return info->execute (); -} - -bool -tree_jit::initialize (void) -{ - if (engine) - return true; - - if (! module) - { - llvm::InitializeNativeTarget (); - module = new llvm::Module ("octave", context); - } - - // sometimes this fails pre main - engine = llvm::ExecutionEngine::createJIT (module); - - if (! engine) - return false; - - module_pass_manager = new llvm::PassManager (); - module_pass_manager->add (llvm::createAlwaysInlinerPass ()); - - pass_manager = new llvm::FunctionPassManager (module); - pass_manager->add (new llvm::TargetData(*engine->getTargetData ())); - pass_manager->add (llvm::createBasicAliasAnalysisPass ()); - pass_manager->add (llvm::createPromoteMemoryToRegisterPass ()); - pass_manager->add (llvm::createInstructionCombiningPass ()); - pass_manager->add (llvm::createReassociatePass ()); - pass_manager->add (llvm::createGVNPass ()); - pass_manager->add (llvm::createCFGSimplificationPass ()); - pass_manager->doInitialization (); - - jit_typeinfo::initialize (module, engine); - - return true; -} - -size_t -tree_jit::trip_count (const octave_value& bounds) const -{ - if (bounds.is_range ()) - { - Range rng = bounds.range_value (); - return rng.nelem (); - } - - // unsupported type - return 0; -} - - -void -tree_jit::optimize (llvm::Function *fn) -{ - module_pass_manager->run (*module); - pass_manager->run (*fn); - -#ifdef OCTAVE_JIT_DEBUG - std::string error; - llvm::raw_fd_ostream fout ("test.bc", error, - llvm::raw_fd_ostream::F_Binary); - llvm::WriteBitcodeToFile (module, fout); -#endif -} - -// -------------------- jit_info -------------------- -jit_info::jit_info (tree_jit& tjit, tree& tee) - : engine (tjit.get_engine ()), function (0), llvm_function (0) -{ - try - { - jit_convert conv (tjit.get_module (), tee); - initialize (tjit, conv); - } - catch (const jit_fail_exception& e) - { -#ifdef OCTAVE_JIT_DEBUG - if (e.known ()) - std::cout << "jit fail: " << e.what () << std::endl; -#endif - } -} - -jit_info::jit_info (tree_jit& tjit, tree& tee, const octave_value& for_bounds) - : engine (tjit.get_engine ()), function (0), llvm_function (0) -{ - try - { - jit_convert conv (tjit.get_module (), tee, - jit_typeinfo::type_of (for_bounds)); - initialize (tjit, conv); - } - catch (const jit_fail_exception& e) - { -#ifdef OCTAVE_JIT_DEBUG - if (e.known ()) - std::cout << "jit fail: " << e.what () << std::endl; -#endif - } -} - -jit_info::~jit_info (void) -{ - if (llvm_function) - llvm_function->eraseFromParent (); -} - -bool -jit_info::execute (const vmap& extra_vars) const -{ - if (! function) - return false; - - std::vector real_arguments (arguments.size ()); - for (size_t i = 0; i < arguments.size (); ++i) - { - if (arguments[i].second) - { - octave_value current = find (extra_vars, arguments[i].first); - octave_base_value *obv = current.internal_rep (); - obv->grab (); - real_arguments[i] = obv; - } - } - - function (&real_arguments[0]); - - for (size_t i = 0; i < arguments.size (); ++i) - { - const std::string& name = arguments[i].first; - - // do not store for loop bounds temporary - if (name.size () && name[0] != '#') - symbol_table::varref (arguments[i].first) = real_arguments[i]; - } - - return true; -} - -bool -jit_info::match (const vmap& extra_vars) const -{ - if (! function) - return true; - - for (size_t i = 0; i < bounds.size (); ++i) - { - const std::string& arg_name = bounds[i].second; - octave_value value = find (extra_vars, arg_name); - jit_type *type = jit_typeinfo::type_of (value); - - // FIXME: Check for a parent relationship - if (type != bounds[i].first) - return false; - } - - return true; -} - -void -jit_info::initialize (tree_jit& tjit, jit_convert& conv) -{ - llvm_function = conv.get_function (); - arguments = conv.get_arguments (); - bounds = conv.get_bounds (); - - if (llvm_function) - { - tjit.optimize (llvm_function); - -#ifdef OCTAVE_JIT_DEBUG - std::cout << "-------------------- optimized llvm ir " - << "--------------------\n"; - llvm::raw_os_ostream llvm_cout (std::cout); - llvm_function->print (llvm_cout); - llvm_cout.flush (); - std::cout << std::endl; -#endif - - void *void_fn = engine->getPointerToFunction (llvm_function); - function = reinterpret_cast (void_fn); - } -} - -octave_value -jit_info::find (const vmap& extra_vars, const std::string& vname) const -{ - vmap::const_iterator iter = extra_vars.find (vname); - return iter == extra_vars.end () ? symbol_table::varval (vname) - : *iter->second; -} - -#endif - - -/* -Test some simple cases that compile. - -%!test -%! inc = 1e-5; -%! result = 0; -%! for ii = 0:inc:1 -%! result = result + inc * (1/3 * ii * ii); -%! endfor -%! assert (abs (result - 1/9) < 1e-5); - -%!test -%! inc = 1e-5; -%! result = 0; -%! for ii = 0:inc:1 -%! # the ^ operator's result is complex -%! result = result + inc * (1/3 * ii ^ 2); -%! endfor -%! assert (abs (result - 1/9) < 1e-5); - -%!test -%! nr = 1001; -%! mat = zeros (1, nr); -%! for i = 1:nr -%! mat(i) = i; -%! endfor -%! assert (mat == 1:nr); - -%!test -%! nr = 1001; -%! mat = 1:nr; -%! mat(end) = 0; # force mat to a matrix -%! total = 0; -%! for i = 1:nr -%! total = mat(i) + total; -%! endfor -%! assert (sum (mat) == total); - -%!test -%! nr = 1001; -%! mat = [3 1 5]; -%! try -%! for i = 1:nr -%! if i > 500 -%! result = mat(100); -%! else -%! result = i; -%! endif -%! endfor -%! catch -%! end -%! assert (result == 500); - -%!function result = gen_test (n) -%! result = double (rand (1, n) > .01); -%!endfunction - -%!function z = vectorized (A, K) -%! temp = ones (1, K); -%! z = conv (A, temp); -%! z = z > K-1; -%! z = conv (z, temp); -%! z = z(K:end-K+1); -%! z = z >= 1; -%!endfunction - -%!function z = loopy (A, K) -%! z = A; -%! n = numel (A); -%! counter = 0; -%! for ii=1:n -%! if z(ii) -%! counter = counter + 1; -%! else -%! if counter > 0 && counter < K -%! z(ii-counter:ii-1) = 0; -%! endif -%! counter = 0; -%! endif -%! endfor -%! -%! if counter > 0 && counter < K -%! z(end-counter+1:end) = 0; -%! endif -%!endfunction - -%!test -%! test_set = gen_test (10000); -%! assert (all (vectorized (test_set, 3) == loopy (test_set, 3))); - -%!test -%! niter = 1001; -%! i = 0; -%! while (i < niter) -%! i = i + 1; -%! endwhile -%! assert (i == niter); - -%!test -%! niter = 1001; -%! result = 0; -%! m = [5 10]; -%! for i=1:niter -%! result = result + m(end); -%! endfor -%! assert (result == m(end) * niter); - -%!test -%! ndim = 100; -%! result = 0; -%! m = zeros (ndim); -%! m(:) = 1:ndim^2; -%! i = 1; -%! while (i <= ndim) -%! for j = 1:ndim -%! result = result + m(i, j); -%! endfor -%! i = i + 1; -%! endwhile -%! assert (result == sum (sum (m))); - -%!test -%! ndim = 100; -%! m = zeros (ndim); -%! i = 1; -%! while (i <= ndim) -%! for j = 1:ndim -%! m(i, j) = (j - 1) * ndim + i; -%! endfor -%! i = i + 1; -%! endwhile -%! m2 = zeros (ndim); -%! m2(:) = 1:(ndim^2); -%! assert (all (m == m2)); - -%!test -%! ndim = 2; -%! m = zeros (ndim, ndim, ndim, ndim); -%! result = 0; -%! i0 = 1; -%! while (i0 <= ndim) -%! for i1 = 1:ndim -%! for i2 = 1:ndim -%! for i3 = 1:ndim -%! m(i0, i1, i2, i3) = 1; -%! m(i0, i1, i2, i3, 1, 1, 1, 1, 1, 1) = 1; -%! result = result + m(i0, i1, i2, i3); -%! endfor -%! endfor -%! endfor -%! i0 = i0 + 1; -%! endwhile -%! expected = ones (ndim, ndim, ndim, ndim); -%! assert (all (m == expected)); -%! assert (result == sum (expected (:))); - -*/ diff -r a132d206a36a -r b9b6a310ad97 src/pt-jit.h --- a/src/pt-jit.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,491 +0,0 @@ -/* - -Copyright (C) 2012 Max Brister - -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 (octave_tree_jit_h) -#define octave_tree_jit_h 1 - -#ifdef HAVE_LLVM - -#include "jit-ir.h" - -#include "pt-walk.h" - -// -------------------- Current status -------------------- -// Simple binary operations (+-*/) on octave_scalar's (doubles) are optimized. -// a = 5; -// b = a * 5 + a; -// -// Indexing matrices with scalars works. -// -// if, elseif, else, break, continue, and for compile. Compilation is triggered -// at the start of a simple for loop. -// -// The octave low level IR is a linear IR, it works by converting everything to -// calls to jit_operations. This turns expressions like c = a + b into -// c = call binary+ (a, b) -// The jit_operations contain information about overloads for different types. -// For, example, if we know a and b are scalars, then c must also be a scalar. -// -// Support for function calls is in progress. Currently, calls to sin with a -// scalar argument will compile. -// -// TODO: -// 1. Function calls (In progress) -// 2. Cleanup/documentation -// 3. ... -// --------------------------------------------------------- - -// convert between IRs -// FIXME: Class relationships are messy from here on down. They need to be -// cleaned up. -class -jit_convert : public tree_walker -{ -public: - typedef std::pair type_bound; - typedef std::vector type_bound_vector; - - jit_convert (llvm::Module *module, tree &tee, jit_type *for_bounds = 0); - - ~jit_convert (void); - - llvm::Function *get_function (void) const { return function; } - - const std::vector >& get_arguments(void) const - { return arguments; } - - const type_bound_vector& get_bounds (void) const { return bounds; } - - void visit_anon_fcn_handle (tree_anon_fcn_handle&); - - void visit_argument_list (tree_argument_list&); - - void visit_binary_expression (tree_binary_expression&); - - void visit_break_command (tree_break_command&); - - void visit_colon_expression (tree_colon_expression&); - - void visit_continue_command (tree_continue_command&); - - void visit_global_command (tree_global_command&); - - void visit_persistent_command (tree_persistent_command&); - - void visit_decl_elt (tree_decl_elt&); - - void visit_decl_init_list (tree_decl_init_list&); - - void visit_simple_for_command (tree_simple_for_command&); - - void visit_complex_for_command (tree_complex_for_command&); - - void visit_octave_user_script (octave_user_script&); - - void visit_octave_user_function (octave_user_function&); - - void visit_octave_user_function_header (octave_user_function&); - - void visit_octave_user_function_trailer (octave_user_function&); - - void visit_function_def (tree_function_def&); - - void visit_identifier (tree_identifier&); - - void visit_if_clause (tree_if_clause&); - - void visit_if_command (tree_if_command&); - - void visit_if_command_list (tree_if_command_list&); - - void visit_index_expression (tree_index_expression&); - - void visit_matrix (tree_matrix&); - - void visit_cell (tree_cell&); - - void visit_multi_assignment (tree_multi_assignment&); - - void visit_no_op_command (tree_no_op_command&); - - void visit_constant (tree_constant&); - - void visit_fcn_handle (tree_fcn_handle&); - - void visit_parameter_list (tree_parameter_list&); - - void visit_postfix_expression (tree_postfix_expression&); - - void visit_prefix_expression (tree_prefix_expression&); - - void visit_return_command (tree_return_command&); - - void visit_return_list (tree_return_list&); - - void visit_simple_assignment (tree_simple_assignment&); - - void visit_statement (tree_statement&); - - void visit_statement_list (tree_statement_list&); - - void visit_switch_case (tree_switch_case&); - - void visit_switch_case_list (tree_switch_case_list&); - - void visit_switch_command (tree_switch_command&); - - void visit_try_catch_command (tree_try_catch_command&); - - void visit_unwind_protect_command (tree_unwind_protect_command&); - - void visit_while_command (tree_while_command&); - - void visit_do_until_command (tree_do_until_command&); - - // this would be easier with variadic templates - template - T *create (void) - { - T *ret = new T(); - track_value (ret); - return ret; - } - -#define DECL_ARG(n) const ARG ## n& arg ## n -#define JIT_CREATE(N) \ - template \ - T *create (OCT_MAKE_LIST (DECL_ARG, N)) \ - { \ - T *ret = new T (OCT_MAKE_ARG_LIST (arg, N)); \ - track_value (ret); \ - return ret; \ - } - - JIT_CREATE (1) - JIT_CREATE (2) - JIT_CREATE (3) - JIT_CREATE (4) - -#undef JIT_CREATE - -#define JIT_CREATE_CHECKED(N) \ - template \ - jit_call *create_checked (OCT_MAKE_LIST (DECL_ARG, N)) \ - { \ - jit_call *ret = create (OCT_MAKE_ARG_LIST (arg, N)); \ - return create_checked_impl (ret); \ - } - - JIT_CREATE_CHECKED (1) - JIT_CREATE_CHECKED (2) - JIT_CREATE_CHECKED (3) - JIT_CREATE_CHECKED (4) - -#undef JIT_CREATE_CHECKED -#undef DECL_ARG - - typedef std::list block_list; - typedef block_list::iterator block_iterator; - - void append (jit_block *ablock); - - void insert_before (block_iterator iter, jit_block *ablock); - - void insert_before (jit_block *loc, jit_block *ablock) - { - insert_before (loc->location (), ablock); - } - - void insert_after (block_iterator iter, jit_block *ablock); - - void insert_after (jit_block *loc, jit_block *ablock) - { - insert_after (loc->location (), ablock); - } -private: - std::vector > arguments; - type_bound_vector bounds; - - // used instead of return values from visit_* functions - jit_value *result; - - jit_block *entry_block; - - jit_block *final_block; - - jit_block *block; - - llvm::Function *function; - - std::list blocks; - - std::list worklist; - - std::list constants; - - std::list all_values; - - std::vector end_context; - - size_t iterator_count; - size_t for_bounds_count; - size_t short_count; - - typedef std::map vmap_t; - vmap_t vmap; - - jit_call *create_checked_impl (jit_call *ret) - { - block->append (ret); - create_check (ret); - return ret; - } - - jit_error_check *create_check (jit_call *call) - { - jit_block *normal = create (block->name ()); - jit_error_check *ret - = block->append (create (call, normal, final_block)); - append (normal); - block = normal; - - return ret; - } - - // get an existing vairable. If the variable does not exist, it will not be - // created - jit_variable *find_variable (const std::string& vname) const; - - // get a variable, create it if it does not exist. The type will default to - // the variable's current type in the symbol table. - jit_variable *get_variable (const std::string& vname); - - // create a variable of the given name and given type. Will also insert an - // extract statement - jit_variable *create_variable (const std::string& vname, jit_type *type); - - // The name of the next for loop iterator. If inc is false, then the iterator - // counter will not be incremented. - std::string next_iterator (bool inc = true) - { return next_name ("#iter", iterator_count, inc); } - - std::string next_for_bounds (bool inc = true) - { return next_name ("#for_bounds", for_bounds_count, inc); } - - std::string next_shortcircut_result (bool inc = true) - { return next_name ("#shortcircut_result", short_count, inc); } - - std::string next_name (const char *prefix, size_t& count, bool inc); - - jit_instruction *resolve (const jit_operation& fres, - tree_index_expression& exp, - jit_value *extra_arg = 0); - - jit_value *do_assign (tree_expression *exp, jit_value *rhs, - bool artificial = false); - - jit_value *do_assign (const std::string& lhs, jit_value *rhs, bool print, - bool artificial = false); - - jit_value *visit (tree *tee) { return visit (*tee); } - - jit_value *visit (tree& tee); - - void push_worklist (jit_instruction *instr) - { - if (! instr->in_worklist ()) - { - instr->stash_in_worklist (true); - worklist.push_back (instr); - } - } - - void append_users (jit_value *v) - { - for (jit_use *use = v->first_use (); use; use = use->next ()) - push_worklist (use->user ()); - } - - void append_users_term (jit_terminator *term); - - void track_value (jit_value *value) - { - if (value->type ()) - constants.push_back (value); - all_values.push_back (value); - } - - void merge_blocks (void); - - void construct_ssa (void); - - void do_construct_ssa (jit_block& block, size_t avisit_count); - - void remove_dead (); - - void place_releases (void); - - void release_temp (jit_block& ablock, std::set& temp); - - void release_dead_phi (jit_block& ablock); - - void simplify_phi (void); - - void simplify_phi (jit_phi& phi); - - void print_blocks (const std::string& header) - { - std::cout << "-------------------- " << header << " --------------------\n"; - for (std::list::iterator iter = blocks.begin (); - iter != blocks.end (); ++iter) - { - assert (*iter); - (*iter)->print (std::cout, 0); - } - std::cout << std::endl; - } - - void print_dom (void) - { - std::cout << "-------------------- dom info --------------------\n"; - for (std::list::iterator iter = blocks.begin (); - iter != blocks.end (); ++iter) - { - assert (*iter); - (*iter)->print_dom (std::cout); - } - std::cout << std::endl; - } - - bool breaking; // true if we are breaking OR continuing - block_list breaks; - block_list continues; - - void finish_breaks (jit_block *dest, const block_list& lst); - - // this case is much simpler, just convert from the jit ir to llvm - class - convert_llvm : public jit_ir_walker - { - public: - convert_llvm (jit_convert& jc) : jthis (jc) {} - - llvm::Function *convert (llvm::Module *module, - const std::vector >& args, - const std::list& blocks, - const std::list& constants); - -#define JIT_METH(clname) \ - virtual void visit (jit_ ## clname&); - - JIT_VISIT_IR_CLASSES; - -#undef JIT_METH - private: - // name -> llvm argument - std::map arguments; - - void finish_phi (jit_phi *phi); - - void visit (jit_value *jvalue) - { - return visit (*jvalue); - } - - void visit (jit_value &jvalue) - { - jvalue.accept (*this); - } - private: - jit_convert &jthis; - llvm::Function *function; - llvm::BasicBlock *prelude; - }; -}; - -class jit_info; - -class -tree_jit -{ -public: - tree_jit (void); - - ~tree_jit (void); - - bool execute (tree_simple_for_command& cmd, const octave_value& bounds); - - bool execute (tree_while_command& cmd); - - llvm::ExecutionEngine *get_engine (void) const { return engine; } - - llvm::Module *get_module (void) const { return module; } - - void optimize (llvm::Function *fn); - private: - bool initialize (void); - - size_t trip_count (const octave_value& bounds) const; - - // FIXME: Temorary hack to test - typedef std::map compiled_map; - llvm::Module *module; - llvm::PassManager *module_pass_manager; - llvm::FunctionPassManager *pass_manager; - llvm::ExecutionEngine *engine; -}; - -class -jit_info -{ -public: - // we use a pointer here so we don't have to include ov.h - typedef std::map vmap; - - jit_info (tree_jit& tjit, tree& tee); - - jit_info (tree_jit& tjit, tree& tee, const octave_value& for_bounds); - - ~jit_info (void); - - bool execute (const vmap& extra_vars = vmap ()) const; - - bool match (const vmap& extra_vars = vmap ()) const; -private: - typedef jit_convert::type_bound type_bound; - typedef jit_convert::type_bound_vector type_bound_vector; - typedef void (*jited_function)(octave_base_value**); - - void initialize (tree_jit& tjit, jit_convert& conv); - - octave_value find (const vmap& extra_vars, const std::string& vname) const; - - llvm::ExecutionEngine *engine; - jited_function function; - llvm::Function *llvm_function; - - std::vector > arguments; - type_bound_vector bounds; -}; - -#endif -#endif diff -r a132d206a36a -r b9b6a310ad97 src/siglist.c --- a/src/siglist.c Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,232 +0,0 @@ -/* - -Copyright (C) 2000-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "siglist.h" - -/* The following is all borrowed from Emacs. */ - -#if ! (defined HAVE_STRSIGNAL || HAVE_DECL_SYS_SIGLIST) - -static char *my_sys_siglist[NSIG]; - -#ifdef sys_siglist -#undef sys_siglist -#endif -#define sys_siglist my_sys_siglist - -#endif - -void -init_signals (void) -{ -#if ! (defined HAVE_STRSIGNAL || HAVE_DECL_SYS_SIGLIST) - - static int initialized = 0; - - if (! initialized) - { - initialized = 1; - -# ifdef SIGABRT - sys_siglist[SIGABRT] = "Aborted"; -# endif -# ifdef SIGAIO - sys_siglist[SIGAIO] = "LAN I/O interrupt"; -# endif -# ifdef SIGALRM - sys_siglist[SIGALRM] = "Alarm clock"; -# endif -# ifdef SIGBUS - sys_siglist[SIGBUS] = "Bus error"; -# endif -# ifdef SIGCLD - sys_siglist[SIGCLD] = "Child status changed"; -# endif -# ifdef SIGCHLD - sys_siglist[SIGCHLD] = "Child status changed"; -# endif -# ifdef SIGCONT - sys_siglist[SIGCONT] = "Continued"; -# endif -# ifdef SIGDANGER - sys_siglist[SIGDANGER] = "Swap space dangerously low"; -# endif -# ifdef SIGDGNOTIFY - sys_siglist[SIGDGNOTIFY] = "Notification message in queue"; -# endif -# ifdef SIGEMT - sys_siglist[SIGEMT] = "Emulation trap"; -# endif -# ifdef SIGFPE - sys_siglist[SIGFPE] = "Arithmetic exception"; -# endif -# ifdef SIGFREEZE - sys_siglist[SIGFREEZE] = "SIGFREEZE"; -# endif -# ifdef SIGGRANT - sys_siglist[SIGGRANT] = "Monitor mode granted"; -# endif -# ifdef SIGHUP - sys_siglist[SIGHUP] = "Hangup"; -# endif -# ifdef SIGILL - sys_siglist[SIGILL] = "Illegal instruction"; -# endif -# ifdef SIGINT - sys_siglist[SIGINT] = "Interrupt"; -# endif -# ifdef SIGIO - sys_siglist[SIGIO] = "I/O possible"; -# endif -# ifdef SIGIOINT - sys_siglist[SIGIOINT] = "I/O intervention required"; -# endif -# ifdef SIGIOT - sys_siglist[SIGIOT] = "IOT trap"; -# endif -# ifdef SIGKILL - sys_siglist[SIGKILL] = "Killed"; -# endif -# ifdef SIGLOST - sys_siglist[SIGLOST] = "Resource lost"; -# endif -# ifdef SIGLWP - sys_siglist[SIGLWP] = "SIGLWP"; -# endif -# ifdef SIGMSG - sys_siglist[SIGMSG] = "Monitor mode data available"; -# endif -# ifdef SIGPHONE - sys_siglist[SIGWIND] = "SIGPHONE"; -# endif -# ifdef SIGPIPE - sys_siglist[SIGPIPE] = "Broken pipe"; -# endif -# ifdef SIGPOLL - sys_siglist[SIGPOLL] = "Pollable event occurred"; -# endif -# ifdef SIGPROF - sys_siglist[SIGPROF] = "Profiling timer expired"; -# endif -# ifdef SIGPTY - sys_siglist[SIGPTY] = "PTY I/O interrupt"; -# endif -# ifdef SIGPWR - sys_siglist[SIGPWR] = "Power-fail restart"; -# endif -# ifdef SIGQUIT - sys_siglist[SIGQUIT] = "Quit"; -# endif -# ifdef SIGRETRACT - sys_siglist[SIGRETRACT] = "Need to relinguish monitor mode"; -# endif -# ifdef SIGSAK - sys_siglist[SIGSAK] = "Secure attention"; -# endif -# ifdef SIGSEGV - sys_siglist[SIGSEGV] = "Segmentation violation"; -# endif -# ifdef SIGSOUND - sys_siglist[SIGSOUND] = "Sound completed"; -# endif -# ifdef SIGSTOP - sys_siglist[SIGSTOP] = "Stopped (signal)"; -# endif -# ifdef SIGSTP - sys_siglist[SIGSTP] = "Stopped (user)"; -# endif -# ifdef SIGSYS - sys_siglist[SIGSYS] = "Bad argument to system call"; -# endif -# ifdef SIGTERM - sys_siglist[SIGTERM] = "Terminated"; -# endif -# ifdef SIGTHAW - sys_siglist[SIGTHAW] = "SIGTHAW"; -# endif -# ifdef SIGTRAP - sys_siglist[SIGTRAP] = "Trace/breakpoint trap"; -# endif -# ifdef SIGTSTP - sys_siglist[SIGTSTP] = "Stopped (user)"; -# endif -# ifdef SIGTTIN - sys_siglist[SIGTTIN] = "Stopped (tty input)"; -# endif -# ifdef SIGTTOU - sys_siglist[SIGTTOU] = "Stopped (tty output)"; -# endif -# ifdef SIGURG - sys_siglist[SIGURG] = "Urgent I/O condition"; -# endif -# ifdef SIGUSR1 - sys_siglist[SIGUSR1] = "User defined signal 1"; -# endif -# ifdef SIGUSR2 - sys_siglist[SIGUSR2] = "User defined signal 2"; -# endif -# ifdef SIGVTALRM - sys_siglist[SIGVTALRM] = "Virtual timer expired"; -# endif -# ifdef SIGWAITING - sys_siglist[SIGWAITING] = "Process's LWPs are blocked"; -# endif -# ifdef SIGWINCH - sys_siglist[SIGWINCH] = "Window size changed"; -# endif -# ifdef SIGWIND - sys_siglist[SIGWIND] = "SIGWIND"; -# endif -# ifdef SIGXCPU - sys_siglist[SIGXCPU] = "CPU time limit exceeded"; -# endif -# ifdef SIGXFSZ - sys_siglist[SIGXFSZ] = "File size limit exceeded"; -# endif - } - -#endif -} - -#if ! defined (HAVE_STRSIGNAL) - -char * -strsignal (int code) -{ - char *signame = ""; - - if (0 <= code && code < NSIG) - { - /* Cast to suppress warning if the table has const char *. */ - signame = (char *) sys_siglist[code]; - } - - return signame; -} - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/siglist.h --- a/src/siglist.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,47 +0,0 @@ -/* - -Copyright (C) 2000-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_siglist_h) -#define octave_siglist_h 1 - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* This is borrowed from Emacs. */ - -#if ! defined (HAVE_DECL_SYS_SIGLIST) -extern char *sys_siglist[]; -#endif - -extern void init_signals (void); - -#if ! defined (HAVE_STRSIGNAL) -extern char *strsignal (int); -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/sparse-xdiv.cc --- a/src/sparse-xdiv.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,633 +0,0 @@ -/* - -Copyright (C) 2004-2012 David Bateman -Copyright (C) 1998-2004 Andy Adler - -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 -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "Array-util.h" -#include "oct-cmplx.h" -#include "quit.h" -#include "error.h" -#include "lo-ieee.h" - -#include "dSparse.h" -#include "dDiagMatrix.h" -#include "CSparse.h" -#include "CDiagMatrix.h" -#include "oct-spparms.h" -#include "sparse-xdiv.h" - -static void -solve_singularity_warning (double rcond) -{ - warning ("matrix singular to machine precision, rcond = %g", rcond); - warning ("attempting to find minimum norm solution"); -} - -template -bool -mx_leftdiv_conform (const T1& a, const T2& b) -{ - octave_idx_type a_nr = a.rows (); - octave_idx_type b_nr = b.rows (); - - if (a_nr != b_nr) - { - octave_idx_type a_nc = a.cols (); - octave_idx_type b_nc = b.cols (); - - gripe_nonconformant ("operator \\", a_nr, a_nc, b_nr, b_nc); - return false; - } - - return true; -} - -#define INSTANTIATE_MX_LEFTDIV_CONFORM(T1, T2) \ - template bool mx_leftdiv_conform (const T1&, const T2&) - -INSTANTIATE_MX_LEFTDIV_CONFORM (SparseMatrix, SparseMatrix); -INSTANTIATE_MX_LEFTDIV_CONFORM (SparseMatrix, SparseComplexMatrix); -INSTANTIATE_MX_LEFTDIV_CONFORM (SparseComplexMatrix, SparseMatrix); -INSTANTIATE_MX_LEFTDIV_CONFORM (SparseComplexMatrix, SparseComplexMatrix); -INSTANTIATE_MX_LEFTDIV_CONFORM (SparseMatrix, Matrix); -INSTANTIATE_MX_LEFTDIV_CONFORM (SparseMatrix, ComplexMatrix); -INSTANTIATE_MX_LEFTDIV_CONFORM (SparseComplexMatrix, Matrix); -INSTANTIATE_MX_LEFTDIV_CONFORM (SparseComplexMatrix, ComplexMatrix); -INSTANTIATE_MX_LEFTDIV_CONFORM (DiagMatrix, SparseMatrix); -INSTANTIATE_MX_LEFTDIV_CONFORM (DiagMatrix, SparseComplexMatrix); -INSTANTIATE_MX_LEFTDIV_CONFORM (ComplexDiagMatrix, SparseMatrix); -INSTANTIATE_MX_LEFTDIV_CONFORM (ComplexDiagMatrix, SparseComplexMatrix); - -template -bool -mx_div_conform (const T1& a, const T2& b) -{ - octave_idx_type a_nc = a.cols (); - octave_idx_type b_nc = b.cols (); - - if (a_nc != b_nc) - { - octave_idx_type a_nr = a.rows (); - octave_idx_type b_nr = b.rows (); - - gripe_nonconformant ("operator /", a_nr, a_nc, b_nr, b_nc); - return false; - } - - return true; -} - -#define INSTANTIATE_MX_DIV_CONFORM(T1, T2) \ - template bool mx_div_conform (const T1&, const T2&) - -INSTANTIATE_MX_DIV_CONFORM (SparseMatrix, SparseMatrix); -INSTANTIATE_MX_DIV_CONFORM (SparseMatrix, SparseComplexMatrix); -INSTANTIATE_MX_DIV_CONFORM (SparseComplexMatrix, SparseMatrix); -INSTANTIATE_MX_DIV_CONFORM (SparseComplexMatrix, SparseComplexMatrix); -INSTANTIATE_MX_DIV_CONFORM (Matrix, SparseMatrix); -INSTANTIATE_MX_DIV_CONFORM (Matrix, SparseComplexMatrix); -INSTANTIATE_MX_DIV_CONFORM (ComplexMatrix, SparseMatrix); -INSTANTIATE_MX_DIV_CONFORM (ComplexMatrix, SparseComplexMatrix); -INSTANTIATE_MX_DIV_CONFORM (SparseMatrix, DiagMatrix); -INSTANTIATE_MX_DIV_CONFORM (SparseMatrix, ComplexDiagMatrix); -INSTANTIATE_MX_DIV_CONFORM (SparseComplexMatrix, DiagMatrix); -INSTANTIATE_MX_DIV_CONFORM (SparseComplexMatrix, ComplexDiagMatrix); - -// Right division functions. X / Y = X * inv (Y) = (inv (Y') * X')' -// -// Y / X: m cm sm scm -// +-- +---+----+----+----+ -// sparse matrix | 1 | 3 | 5 | 7 | -// +---+----+----+----+ -// sparse complex_matrix | 2 | 4 | 6 | 8 | -// +---+----+----+----+ -// diagonal matrix | 9 | 11 | -// +----+----+ -// complex diag. matrix | 10 | 12 | -// +----+----+ - -// -*- 1 -*- -Matrix -xdiv (const Matrix& a, const SparseMatrix& b, MatrixType &typ) -{ - if (! mx_div_conform (a, b)) - return Matrix (); - - Matrix atmp = a.transpose (); - SparseMatrix btmp = b.transpose (); - MatrixType btyp = typ.transpose (); - - octave_idx_type info; - double rcond = 0.0; - Matrix result = btmp.solve (btyp, atmp, info, rcond, - solve_singularity_warning); - - typ = btyp.transpose (); - return result.transpose (); -} - -// -*- 2 -*- -ComplexMatrix -xdiv (const Matrix& a, const SparseComplexMatrix& b, MatrixType &typ) -{ - if (! mx_div_conform (a, b)) - return ComplexMatrix (); - - Matrix atmp = a.transpose (); - SparseComplexMatrix btmp = b.hermitian (); - MatrixType btyp = typ.transpose (); - - octave_idx_type info; - double rcond = 0.0; - ComplexMatrix result - = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning); - - typ = btyp.transpose (); - return result.hermitian (); -} - -// -*- 3 -*- -ComplexMatrix -xdiv (const ComplexMatrix& a, const SparseMatrix& b, MatrixType &typ) -{ - if (! mx_div_conform (a, b)) - return ComplexMatrix (); - - ComplexMatrix atmp = a.hermitian (); - SparseMatrix btmp = b.transpose (); - MatrixType btyp = typ.transpose (); - - octave_idx_type info; - double rcond = 0.0; - ComplexMatrix result - = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning); - - typ = btyp.transpose (); - return result.hermitian (); -} - -// -*- 4 -*- -ComplexMatrix -xdiv (const ComplexMatrix& a, const SparseComplexMatrix& b, MatrixType &typ) -{ - if (! mx_div_conform (a, b)) - return ComplexMatrix (); - - ComplexMatrix atmp = a.hermitian (); - SparseComplexMatrix btmp = b.hermitian (); - MatrixType btyp = typ.transpose (); - - octave_idx_type info; - double rcond = 0.0; - ComplexMatrix result - = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning); - - typ = btyp.transpose (); - return result.hermitian (); -} - -// -*- 5 -*- -SparseMatrix -xdiv (const SparseMatrix& a, const SparseMatrix& b, MatrixType &typ) -{ - if (! mx_div_conform (a, b)) - return SparseMatrix (); - - SparseMatrix atmp = a.transpose (); - SparseMatrix btmp = b.transpose (); - MatrixType btyp = typ.transpose (); - - octave_idx_type info; - double rcond = 0.0; - SparseMatrix result = btmp.solve (btyp, atmp, info, rcond, - solve_singularity_warning); - - typ = btyp.transpose (); - return result.transpose (); -} - -// -*- 6 -*- -SparseComplexMatrix -xdiv (const SparseMatrix& a, const SparseComplexMatrix& b, MatrixType &typ) -{ - if (! mx_div_conform (a, b)) - return SparseComplexMatrix (); - - SparseMatrix atmp = a.transpose (); - SparseComplexMatrix btmp = b.hermitian (); - MatrixType btyp = typ.transpose (); - - octave_idx_type info; - double rcond = 0.0; - SparseComplexMatrix result - = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning); - - typ = btyp.transpose (); - return result.hermitian (); -} - -// -*- 7 -*- -SparseComplexMatrix -xdiv (const SparseComplexMatrix& a, const SparseMatrix& b, MatrixType &typ) -{ - if (! mx_div_conform (a, b)) - return SparseComplexMatrix (); - - SparseComplexMatrix atmp = a.hermitian (); - SparseMatrix btmp = b.transpose (); - MatrixType btyp = typ.transpose (); - - octave_idx_type info; - double rcond = 0.0; - SparseComplexMatrix result - = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning); - - typ = btyp.transpose (); - return result.hermitian (); -} - -// -*- 8 -*- -SparseComplexMatrix -xdiv (const SparseComplexMatrix& a, const SparseComplexMatrix& b, MatrixType &typ) -{ - if (! mx_div_conform (a, b)) - return SparseComplexMatrix (); - - SparseComplexMatrix atmp = a.hermitian (); - SparseComplexMatrix btmp = b.hermitian (); - MatrixType btyp = typ.transpose (); - - octave_idx_type info; - double rcond = 0.0; - SparseComplexMatrix result - = btmp.solve (btyp, atmp, info, rcond, solve_singularity_warning); - - typ = btyp.transpose (); - return result.hermitian (); -} - -template -RT do_rightdiv_sm_dm (const SM& a, const DM& d) -{ - const octave_idx_type d_nr = d.rows (); - - const octave_idx_type a_nr = a.rows (); - const octave_idx_type a_nc = a.cols (); - - using std::min; - const octave_idx_type nc = min (d_nr, a_nc); - - if ( ! mx_div_conform (a, d)) - return RT (); - - const octave_idx_type nz = a.nnz (); - RT r (a_nr, nc, nz); - - typedef typename DM::element_type DM_elt_type; - const DM_elt_type zero = DM_elt_type (); - - octave_idx_type k_result = 0; - for (octave_idx_type j = 0; j < nc; ++j) - { - octave_quit (); - const DM_elt_type s = d.dgelem (j); - const octave_idx_type colend = a.cidx (j+1); - r.xcidx (j) = k_result; - if (s != zero) - for (octave_idx_type k = a.cidx (j); k < colend; ++k) - { - r.xdata (k_result) = a.data (k) / s; - r.xridx (k_result) = a.ridx (k); - ++k_result; - } - } - r.xcidx (nc) = k_result; - - r.maybe_compress (true); - return r; -} - -// -*- 9 -*- -SparseMatrix -xdiv (const SparseMatrix& a, const DiagMatrix& b, MatrixType &) -{ - return do_rightdiv_sm_dm (a, b); -} - -// -*- 10 -*- -SparseComplexMatrix -xdiv (const SparseMatrix& a, const ComplexDiagMatrix& b, MatrixType &) -{ - return do_rightdiv_sm_dm (a, b); -} - -// -*- 11 -*- -SparseComplexMatrix -xdiv (const SparseComplexMatrix& a, const DiagMatrix& b, MatrixType &) -{ - return do_rightdiv_sm_dm (a, b); -} - -// -*- 12 -*- -SparseComplexMatrix -xdiv (const SparseComplexMatrix& a, const ComplexDiagMatrix& b, MatrixType &) -{ - return do_rightdiv_sm_dm (a, b); -} - -// Funny element by element division operations. -// -// op2 \ op1: s cs -// +-- +---+----+ -// matrix | 1 | 3 | -// +---+----+ -// complex_matrix | 2 | 4 | -// +---+----+ - -Matrix -x_el_div (double a, const SparseMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - Matrix result; - if (a == 0.) - result = Matrix (nr, nc, octave_NaN); - else if (a > 0.) - result = Matrix (nr, nc, octave_Inf); - else - result = Matrix (nr, nc, -octave_Inf); - - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = b.cidx (j); i < b.cidx (j+1); i++) - { - octave_quit (); - result.elem (b.ridx (i), j) = a / b.data (i); - } - - return result; -} - -ComplexMatrix -x_el_div (double a, const SparseComplexMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - ComplexMatrix result (nr, nc, Complex (octave_NaN, octave_NaN)); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = b.cidx (j); i < b.cidx (j+1); i++) - { - octave_quit (); - result.elem (b.ridx (i), j) = a / b.data (i); - } - - return result; -} - -ComplexMatrix -x_el_div (const Complex a, const SparseMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - ComplexMatrix result (nr, nc, (a / 0.0)); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = b.cidx (j); i < b.cidx (j+1); i++) - { - octave_quit (); - result.elem (b.ridx (i), j) = a / b.data (i); - } - - return result; -} - -ComplexMatrix -x_el_div (const Complex a, const SparseComplexMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - ComplexMatrix result (nr, nc, (a / 0.0)); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = b.cidx (j); i < b.cidx (j+1); i++) - { - octave_quit (); - result.elem (b.ridx (i), j) = a / b.data (i); - } - - return result; -} - -// Left division functions. X \ Y = inv (X) * Y -// -// Y \ X : sm scm dm dcm -// +-- +---+----+ -// matrix | 1 | 5 | -// +---+----+ -// complex_matrix | 2 | 6 | -// +---+----+----+----+ -// sparse matrix | 3 | 7 | 9 | 11 | -// +---+----+----+----+ -// sparse complex_matrix | 4 | 8 | 10 | 12 | -// +---+----+----+----+ - -// -*- 1 -*- -Matrix -xleftdiv (const SparseMatrix& a, const Matrix& b, MatrixType &typ) -{ - if (! mx_leftdiv_conform (a, b)) - return Matrix (); - - octave_idx_type info; - double rcond = 0.0; - return a.solve (typ, b, info, rcond, solve_singularity_warning); -} - -// -*- 2 -*- -ComplexMatrix -xleftdiv (const SparseMatrix& a, const ComplexMatrix& b, MatrixType &typ) -{ - if (! mx_leftdiv_conform (a, b)) - return ComplexMatrix (); - - octave_idx_type info; - double rcond = 0.0; - return a.solve (typ, b, info, rcond, solve_singularity_warning); -} - -// -*- 3 -*- -SparseMatrix -xleftdiv (const SparseMatrix& a, const SparseMatrix& b, MatrixType &typ) -{ - if (! mx_leftdiv_conform (a, b)) - return SparseMatrix (); - - octave_idx_type info; - double rcond = 0.0; - return a.solve (typ, b, info, rcond, solve_singularity_warning); -} - -// -*- 4 -*- -SparseComplexMatrix -xleftdiv (const SparseMatrix& a, const SparseComplexMatrix& b, MatrixType &typ) -{ - if (! mx_leftdiv_conform (a, b)) - return SparseComplexMatrix (); - - octave_idx_type info; - double rcond = 0.0; - return a.solve (typ, b, info, rcond, solve_singularity_warning); -} - -// -*- 5 -*- -ComplexMatrix -xleftdiv (const SparseComplexMatrix& a, const Matrix& b, MatrixType &typ) -{ - if (! mx_leftdiv_conform (a, b)) - return ComplexMatrix (); - - octave_idx_type info; - double rcond = 0.0; - return a.solve (typ, b, info, rcond, solve_singularity_warning); -} - -// -*- 6 -*- -ComplexMatrix -xleftdiv (const SparseComplexMatrix& a, const ComplexMatrix& b, MatrixType &typ) -{ - if (! mx_leftdiv_conform (a, b)) - return ComplexMatrix (); - - octave_idx_type info; - double rcond = 0.0; - return a.solve (typ, b, info, rcond, solve_singularity_warning); -} - -// -*- 7 -*- -SparseComplexMatrix -xleftdiv (const SparseComplexMatrix& a, const SparseMatrix& b, MatrixType &typ) -{ - if (! mx_leftdiv_conform (a, b)) - return SparseComplexMatrix (); - - octave_idx_type info; - double rcond = 0.0; - return a.solve (typ, b, info, rcond, solve_singularity_warning); -} - -// -*- 8 -*- -SparseComplexMatrix -xleftdiv (const SparseComplexMatrix& a, const SparseComplexMatrix& b, - MatrixType &typ) -{ - if (! mx_leftdiv_conform (a, b)) - return SparseComplexMatrix (); - - octave_idx_type info; - double rcond = 0.0; - return a.solve (typ, b, info, rcond, solve_singularity_warning); -} - -template -RT do_leftdiv_dm_sm (const DM& d, const SM& a) -{ - const octave_idx_type a_nr = a.rows (); - const octave_idx_type a_nc = a.cols (); - - const octave_idx_type d_nc = d.cols (); - - using std::min; - const octave_idx_type nr = min (d_nc, a_nr); - - if ( ! mx_leftdiv_conform (d, a)) - return RT (); - - const octave_idx_type nz = a.nnz (); - RT r (nr, a_nc, nz); - - typedef typename DM::element_type DM_elt_type; - const DM_elt_type zero = DM_elt_type (); - - octave_idx_type k_result = 0; - for (octave_idx_type j = 0; j < a_nc; ++j) - { - octave_quit (); - const octave_idx_type colend = a.cidx (j+1); - r.xcidx (j) = k_result; - for (octave_idx_type k = a.cidx (j); k < colend; ++k) - { - const octave_idx_type i = a.ridx (k); - if (i < nr) - { - const DM_elt_type s = d.dgelem (i); - if (s != zero) - { - r.xdata (k_result) = a.data (k) / s; - r.xridx (k_result) = i; - ++k_result; - } - } - } - } - r.xcidx (a_nc) = k_result; - - r.maybe_compress (true); - return r; -} - -// -*- 9 -*- -SparseMatrix -xleftdiv (const DiagMatrix& d, const SparseMatrix& a, MatrixType&) -{ - return do_leftdiv_dm_sm (d, a); -} - -// -*- 10 -*- -SparseComplexMatrix -xleftdiv (const DiagMatrix& d, const SparseComplexMatrix& a, MatrixType&) -{ - return do_leftdiv_dm_sm (d, a); -} - -// -*- 11 -*- -SparseComplexMatrix -xleftdiv (const ComplexDiagMatrix& d, const SparseMatrix& a, MatrixType&) -{ - return do_leftdiv_dm_sm (d, a); -} - -// -*- 12 -*- -SparseComplexMatrix -xleftdiv (const ComplexDiagMatrix& d, const SparseComplexMatrix& a, MatrixType&) -{ - return do_leftdiv_dm_sm (d, a); -} diff -r a132d206a36a -r b9b6a310ad97 src/sparse-xdiv.h --- a/src/sparse-xdiv.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,93 +0,0 @@ -/* - -Copyright (C) 2004-2012 David Bateman -Copyright (C) 1998-2004 Andy Adler - -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 (octave_sparse_xdiv_h) -#define octave_sparse_xdiv_h 1 - -#include "oct-cmplx.h" -#include "MatrixType.h" - -class DiagMatrix; -class ComplexDiagMatrix; -class SparseMatrix; -class SparseComplexMatrix; - -extern Matrix xdiv (const Matrix& a, const SparseMatrix& b, MatrixType &typ); -extern ComplexMatrix xdiv (const Matrix& a, const SparseComplexMatrix& b, - MatrixType &typ); -extern ComplexMatrix xdiv (const ComplexMatrix& a, const SparseMatrix& b, - MatrixType &typ); -extern ComplexMatrix xdiv (const ComplexMatrix& a, - const SparseComplexMatrix& b, MatrixType &typ); - -extern SparseMatrix xdiv (const SparseMatrix& a, const SparseMatrix& b, - MatrixType &typ); -extern SparseComplexMatrix xdiv (const SparseMatrix& a, - const SparseComplexMatrix& b, MatrixType &typ); -extern SparseComplexMatrix xdiv (const SparseComplexMatrix& a, - const SparseMatrix& b, MatrixType &typ); -extern SparseComplexMatrix xdiv (const SparseComplexMatrix& a, - const SparseComplexMatrix& b, MatrixType &typ); - -extern SparseMatrix xdiv (const SparseMatrix& a, - const DiagMatrix& b, MatrixType &typ); -extern SparseComplexMatrix xdiv (const SparseMatrix& a, - const ComplexDiagMatrix& b, MatrixType &typ); -extern SparseComplexMatrix xdiv (const SparseComplexMatrix& a, - const DiagMatrix& b, MatrixType &typ); -extern SparseComplexMatrix xdiv (const SparseComplexMatrix& a, - const ComplexDiagMatrix& b, MatrixType &typ); - -extern Matrix x_el_div (double a, const SparseMatrix& b); -extern ComplexMatrix x_el_div (double a, const SparseComplexMatrix& b); -extern ComplexMatrix x_el_div (const Complex a, const SparseMatrix& b); -extern ComplexMatrix x_el_div (const Complex a, - const SparseComplexMatrix& b); - -extern Matrix xleftdiv (const SparseMatrix& a, const Matrix& b, - MatrixType& typ); -extern ComplexMatrix xleftdiv (const SparseMatrix& a, const ComplexMatrix& b, - MatrixType &typ); -extern ComplexMatrix xleftdiv (const SparseComplexMatrix& a, const Matrix& b, - MatrixType &typ); -extern ComplexMatrix xleftdiv (const SparseComplexMatrix& a, - const ComplexMatrix& b, MatrixType &typ); - -extern SparseMatrix xleftdiv (const SparseMatrix& a, const SparseMatrix& b, - MatrixType &typ); -extern SparseComplexMatrix xleftdiv (const SparseMatrix& a, - const SparseComplexMatrix& b, MatrixType &typ); -extern SparseComplexMatrix xleftdiv (const SparseComplexMatrix& a, - const SparseMatrix& b, MatrixType &typ); -extern SparseComplexMatrix xleftdiv (const SparseComplexMatrix& a, - const SparseComplexMatrix& b, MatrixType &typ); - -extern SparseMatrix xleftdiv (const DiagMatrix&, const SparseMatrix&, MatrixType&); -extern SparseComplexMatrix xleftdiv (const ComplexDiagMatrix&, const SparseMatrix&, - MatrixType&); -extern SparseComplexMatrix xleftdiv (const DiagMatrix&, const SparseComplexMatrix&, - MatrixType&); -extern SparseComplexMatrix xleftdiv (const ComplexDiagMatrix&, const SparseComplexMatrix&, - MatrixType&); - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/sparse-xpow.cc --- a/src/sparse-xpow.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,730 +0,0 @@ -/* - -Copyright (C) 2004-2012 David Bateman -Copyright (C) 1998-2004 Andy Adler - -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 -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "Array-util.h" -#include "oct-cmplx.h" -#include "quit.h" - -#include "error.h" -#include "oct-obj.h" -#include "utils.h" - -#include "dSparse.h" -#include "CSparse.h" -#include "ov-re-sparse.h" -#include "ov-cx-sparse.h" -#include "sparse-xpow.h" - -static inline int -xisint (double x) -{ - return (D_NINT (x) == x - && ((x >= 0 && x < INT_MAX) - || (x <= 0 && x > INT_MIN))); -} - - -// Safer pow functions. Only two make sense for sparse matrices, the -// others should all promote to full matrices. - -octave_value -xpow (const SparseMatrix& a, double b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for A^b, A must be a square matrix"); - else - { - if (static_cast (b) == b) - { - int btmp = static_cast (b); - if (btmp == 0) - { - SparseMatrix tmp = SparseMatrix (nr, nr, nr); - for (octave_idx_type i = 0; i < nr; i++) - { - tmp.data (i) = 1.0; - tmp.ridx (i) = i; - } - for (octave_idx_type i = 0; i < nr + 1; i++) - tmp.cidx (i) = i; - - retval = tmp; - } - else - { - SparseMatrix atmp; - if (btmp < 0) - { - btmp = -btmp; - - octave_idx_type info; - double rcond = 0.0; - MatrixType mattyp (a); - - atmp = a.inverse (mattyp, info, rcond, 1); - - if (info == -1) - warning ("inverse: matrix singular to machine\ - precision, rcond = %g", rcond); - } - else - atmp = a; - - SparseMatrix result (atmp); - - btmp--; - - while (btmp > 0) - { - if (btmp & 1) - result = result * atmp; - - btmp >>= 1; - - if (btmp > 0) - atmp = atmp * atmp; - } - - retval = result; - } - } - else - error ("use full(a) ^ full(b)"); - } - - return retval; -} - -octave_value -xpow (const SparseComplexMatrix& a, double b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for A^b, A must be a square matrix"); - else - { - if (static_cast (b) == b) - { - int btmp = static_cast (b); - if (btmp == 0) - { - SparseMatrix tmp = SparseMatrix (nr, nr, nr); - for (octave_idx_type i = 0; i < nr; i++) - { - tmp.data (i) = 1.0; - tmp.ridx (i) = i; - } - for (octave_idx_type i = 0; i < nr + 1; i++) - tmp.cidx (i) = i; - - retval = tmp; - } - else - { - SparseComplexMatrix atmp; - if (btmp < 0) - { - btmp = -btmp; - - octave_idx_type info; - double rcond = 0.0; - MatrixType mattyp (a); - - atmp = a.inverse (mattyp, info, rcond, 1); - - if (info == -1) - warning ("inverse: matrix singular to machine\ - precision, rcond = %g", rcond); - } - else - atmp = a; - - SparseComplexMatrix result (atmp); - - btmp--; - - while (btmp > 0) - { - if (btmp & 1) - result = result * atmp; - - btmp >>= 1; - - if (btmp > 0) - atmp = atmp * atmp; - } - - retval = result; - } - } - else - error ("use full(a) ^ full(b)"); - } - - return retval; -} - -// Safer pow functions that work elementwise for matrices. -// -// op2 \ op1: s m cs cm -// +-- +---+---+----+----+ -// scalar | | * | 3 | * | 9 | -// +---+---+----+----+ -// matrix | 1 | 4 | 7 | 10 | -// +---+---+----+----+ -// complex_scalar | * | 5 | * | 11 | -// +---+---+----+----+ -// complex_matrix | 2 | 6 | 8 | 12 | -// +---+---+----+----+ -// -// * -> not needed. - -// FIXME -- these functions need to be fixed so that things -// like -// -// a = -1; b = [ 0, 0.5, 1 ]; r = a .^ b -// -// and -// -// a = -1; b = [ 0, 0.5, 1 ]; for i = 1:3, r(i) = a .^ b(i), end -// -// produce identical results. Also, it would be nice if -1^0.5 -// produced a pure imaginary result instead of a complex number with a -// small real part. But perhaps that's really a problem with the math -// library... - -// -*- 1 -*- -octave_value -elem_xpow (double a, const SparseMatrix& b) -{ - octave_value retval; - - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - double d1, d2; - - if (a < 0.0 && ! b.all_integers (d1, d2)) - { - Complex atmp (a); - ComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - { - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result(i, j) = std::pow (atmp, b(i,j)); - } - } - - retval = result; - } - else - { - Matrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - { - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result(i, j) = std::pow (a, b(i,j)); - } - } - - retval = result; - } - - return retval; -} - -// -*- 2 -*- -octave_value -elem_xpow (double a, const SparseComplexMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - Complex atmp (a); - ComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - { - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result(i, j) = std::pow (atmp, b(i,j)); - } - } - - return result; -} - -// -*- 3 -*- -octave_value -elem_xpow (const SparseMatrix& a, double b) -{ - // FIXME What should a .^ 0 give?? Matlab gives a - // sparse matrix with same structure as a, which is strictly - // incorrect. Keep compatiability. - - octave_value retval; - - octave_idx_type nz = a.nnz (); - - if (b <= 0.0) - { - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (static_cast (b) != b && a.any_element_is_negative ()) - { - ComplexMatrix result (nr, nc, Complex (std::pow (0.0, b))); - - // FIXME -- avoid apparent GNU libm bug by - // converting A and B to complex instead of just A. - Complex btmp (b); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) - { - octave_quit (); - - Complex atmp (a.data (i)); - - result(a.ridx (i), j) = std::pow (atmp, btmp); - } - - retval = octave_value (result); - } - else - { - Matrix result (nr, nc, (std::pow (0.0, b))); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) - { - octave_quit (); - result(a.ridx (i), j) = std::pow (a.data (i), b); - } - - retval = octave_value (result); - } - } - else if (static_cast (b) != b && a.any_element_is_negative ()) - { - SparseComplexMatrix result (a); - - for (octave_idx_type i = 0; i < nz; i++) - { - octave_quit (); - - // FIXME -- avoid apparent GNU libm bug by - // converting A and B to complex instead of just A. - - Complex atmp (a.data (i)); - Complex btmp (b); - - result.data (i) = std::pow (atmp, btmp); - } - - result.maybe_compress (true); - - retval = result; - } - else - { - SparseMatrix result (a); - - for (octave_idx_type i = 0; i < nz; i++) - { - octave_quit (); - result.data (i) = std::pow (a.data (i), b); - } - - result.maybe_compress (true); - - retval = result; - } - - return retval; -} - -// -*- 4 -*- -octave_value -elem_xpow (const SparseMatrix& a, const SparseMatrix& b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - octave_idx_type b_nr = b.rows (); - octave_idx_type b_nc = b.cols (); - - if (nr != b_nr || nc != b_nc) - { - gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); - return octave_value (); - } - - int convert_to_complex = 0; - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) - { - if (a.data(i) < 0.0) - { - double btmp = b (a.ridx (i), j); - if (static_cast (btmp) != btmp) - { - convert_to_complex = 1; - goto done; - } - } - } - -done: - - // This is a dumb operator for sparse matrices anyway, and there is - // no sensible way to handle the 0.^0 versus the 0.^x cases. Therefore - // allocate a full matrix filled for the 0.^0 case and shrink it later - // as needed - - if (convert_to_complex) - { - SparseComplexMatrix complex_result (nr, nc, Complex (1.0, 0.0)); - - for (octave_idx_type j = 0; j < nc; j++) - { - for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) - { - octave_quit (); - complex_result.xelem (a.ridx (i), j) = - std::pow (Complex (a.data (i)), Complex (b(a.ridx (i), j))); - } - } - complex_result.maybe_compress (true); - retval = complex_result; - } - else - { - SparseMatrix result (nr, nc, 1.0); - - for (octave_idx_type j = 0; j < nc; j++) - { - for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) - { - octave_quit (); - result.xelem (a.ridx (i), j) = std::pow (a.data (i), - b(a.ridx (i), j)); - } - } - result.maybe_compress (true); - retval = result; - } - - return retval; -} - -// -*- 5 -*- -octave_value -elem_xpow (const SparseMatrix& a, const Complex& b) -{ - octave_value retval; - - if (b == 0.0) - // Can this case ever happen, due to automatic retyping with maybe_mutate? - retval = octave_value (NDArray (a.dims (), 1)); - else - { - octave_idx_type nz = a.nnz (); - SparseComplexMatrix result (a); - - for (octave_idx_type i = 0; i < nz; i++) - { - octave_quit (); - result.data (i) = std::pow (Complex (a.data (i)), b); - } - - result.maybe_compress (true); - - retval = result; - } - - return retval; -} - -// -*- 6 -*- -octave_value -elem_xpow (const SparseMatrix& a, const SparseComplexMatrix& b) -{ - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - octave_idx_type b_nr = b.rows (); - octave_idx_type b_nc = b.cols (); - - if (nr != b_nr || nc != b_nc) - { - gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); - return octave_value (); - } - - SparseComplexMatrix result (nr, nc, Complex (1.0, 0.0)); - for (octave_idx_type j = 0; j < nc; j++) - { - for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) - { - octave_quit (); - result.xelem (a.ridx(i), j) = std::pow (a.data (i), b(a.ridx (i), j)); - } - } - - result.maybe_compress (true); - - return result; -} - -// -*- 7 -*- -octave_value -elem_xpow (const Complex& a, const SparseMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - ComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - { - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - double btmp = b (i, j); - if (xisint (btmp)) - result (i, j) = std::pow (a, static_cast (btmp)); - else - result (i, j) = std::pow (a, btmp); - } - } - - return result; -} - -// -*- 8 -*- -octave_value -elem_xpow (const Complex& a, const SparseComplexMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - ComplexMatrix result (nr, nc); - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a, b (i, j)); - } - - return result; -} - -// -*- 9 -*- -octave_value -elem_xpow (const SparseComplexMatrix& a, double b) -{ - octave_value retval; - - if (b <= 0) - { - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - ComplexMatrix result (nr, nc, Complex (std::pow (0.0, b))); - - if (xisint (b)) - { - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) - { - octave_quit (); - result (a.ridx (i), j) = - std::pow (a.data (i), static_cast (b)); - } - } - else - { - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) - { - octave_quit (); - result (a.ridx (i), j) = std::pow (a.data (i), b); - } - } - - retval = result; - } - else - { - octave_idx_type nz = a.nnz (); - - SparseComplexMatrix result (a); - - if (xisint (b)) - { - for (octave_idx_type i = 0; i < nz; i++) - { - octave_quit (); - result.data (i) = std::pow (a.data (i), static_cast (b)); - } - } - else - { - for (octave_idx_type i = 0; i < nz; i++) - { - octave_quit (); - result.data (i) = std::pow (a.data (i), b); - } - } - - result.maybe_compress (true); - - retval = result; - } - - return retval; -} - -// -*- 10 -*- -octave_value -elem_xpow (const SparseComplexMatrix& a, const SparseMatrix& b) -{ - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - octave_idx_type b_nr = b.rows (); - octave_idx_type b_nc = b.cols (); - - if (nr != b_nr || nc != b_nc) - { - gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); - return octave_value (); - } - - SparseComplexMatrix result (nr, nc, Complex (1.0, 0.0)); - for (octave_idx_type j = 0; j < nc; j++) - { - for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) - { - octave_quit (); - double btmp = b(a.ridx (i), j); - Complex tmp; - - if (xisint (btmp)) - result.xelem (a.ridx (i), j) = std::pow (a.data (i), - static_cast (btmp)); - else - result.xelem (a.ridx (i), j) = std::pow (a.data (i), btmp); - } - } - - result.maybe_compress (true); - - return result; -} - -// -*- 11 -*- -octave_value -elem_xpow (const SparseComplexMatrix& a, const Complex& b) -{ - octave_value retval; - - if (b == 0.0) - // Can this case ever happen, due to automatic retyping with maybe_mutate? - retval = octave_value (NDArray (a.dims (), 1)); - else - { - - octave_idx_type nz = a.nnz (); - - SparseComplexMatrix result (a); - - for (octave_idx_type i = 0; i < nz; i++) - { - octave_quit (); - result.data (i) = std::pow (a.data (i), b); - } - - result.maybe_compress (true); - - retval = result; - } - - return retval; -} - -// -*- 12 -*- -octave_value -elem_xpow (const SparseComplexMatrix& a, const SparseComplexMatrix& b) -{ - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - octave_idx_type b_nr = b.rows (); - octave_idx_type b_nc = b.cols (); - - if (nr != b_nr || nc != b_nc) - { - gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); - return octave_value (); - } - - SparseComplexMatrix result (nr, nc, Complex (1.0, 0.0)); - for (octave_idx_type j = 0; j < nc; j++) - { - for (octave_idx_type i = a.cidx (j); i < a.cidx (j+1); i++) - { - octave_quit (); - result.xelem (a.ridx (i), j) = std::pow (a.data (i), b(a.ridx (i), j)); - } - } - result.maybe_compress (true); - - return result; -} diff -r a132d206a36a -r b9b6a310ad97 src/sparse-xpow.h --- a/src/sparse-xpow.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,57 +0,0 @@ -/* - -Copyright (C) 2004-2012 David Bateman -Copyright (C) 1998-2004 Andy Adler - -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 (octave_sparse_xpow_h) -#define octave_sparse_xpow_h 1 - -#include "oct-cmplx.h" - -class SparseMatrix; -class SparseComplexMatrix; -class octave_value; - -extern octave_value xpow (const SparseMatrix& a, double b); -extern octave_value xpow (const SparseComplexMatrix& a, double b); - -extern octave_value elem_xpow (double a, const SparseMatrix& b); -extern octave_value elem_xpow (double a, const SparseComplexMatrix& b); - -extern octave_value elem_xpow (const SparseMatrix& a, double b); -extern octave_value elem_xpow (const SparseMatrix& a, const SparseMatrix& b); -extern octave_value elem_xpow (const SparseMatrix& a, const Complex& b); -extern octave_value elem_xpow (const SparseMatrix& a, - const SparseComplexMatrix& b); - -extern octave_value elem_xpow (const Complex& a, const SparseMatrix& b); -extern octave_value elem_xpow (const Complex& a, - const SparseComplexMatrix& b); - -extern octave_value elem_xpow (const SparseComplexMatrix& a, double b); -extern octave_value elem_xpow (const SparseComplexMatrix& a, - const SparseMatrix& b); -extern octave_value elem_xpow (const SparseComplexMatrix& a, - const Complex& b); -extern octave_value elem_xpow (const SparseComplexMatrix& a, - const SparseComplexMatrix& b); - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/token.cc --- a/src/token.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,170 +0,0 @@ -/* - -Copyright (C) 1993-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "error.h" -#include "oct-obj.h" -#include "symtab.h" -#include "token.h" -#include "utils.h" - -token::token (int l, int c) -{ - line_num = l; - column_num = c; - type_tag = generic_token; -} - -token::token (const std::string& s, int l, int c) -{ - line_num = l; - column_num = c; - type_tag = string_token; - str = new std::string (s); -} - -token::token (double d, const std::string& s, int l, int c) -{ - line_num = l; - column_num = c; - type_tag = double_token; - num = d; - orig_text = s; -} - -token::token (end_tok_type t, int l, int c) -{ - line_num = l; - column_num = c; - type_tag = ettype_token; - et = t; -} - -token::token (symbol_table::symbol_record *s, int l, int c) -{ - line_num = l; - column_num = c; - type_tag = sym_rec_token; - sr = s; -} - -token::token (symbol_table::symbol_record *cls, - symbol_table::symbol_record *pkg, int l, int c) -{ - line_num = l; - column_num = c; - type_tag = meta_rec_token; - mc.cr = cls; - mc.pr = pkg; -} - -token::token (symbol_table::symbol_record *mth, - symbol_table::symbol_record *cls, - symbol_table::symbol_record *pkg, int l, int c) -{ - line_num = l; - column_num = c; - type_tag = scls_rec_token; - sc.mr = mth; - sc.cr = cls; - sc.pr = pkg; -} - -token::~token (void) -{ - if (type_tag == string_token) - delete str; -} - -std::string -token::text (void) -{ - assert (type_tag == string_token); - return *str; -} - -double -token::number (void) -{ - assert (type_tag == double_token); - return num; -} - -token::end_tok_type -token::ettype (void) -{ - assert (type_tag == ettype_token); - return et; -} - -symbol_table::symbol_record * -token::sym_rec (void) -{ - assert (type_tag == sym_rec_token); - return sr; -} - -symbol_table::symbol_record * -token::method_rec (void) -{ - assert (type_tag == scls_rec_token); - return sc.mr; -} - -symbol_table::symbol_record * -token::class_rec (void) -{ - assert (type_tag == scls_rec_token); - return sc.cr; -} - -symbol_table::symbol_record * -token::package_rec (void) -{ - assert (type_tag == scls_rec_token); - return sc.pr; -} - -symbol_table::symbol_record * -token::meta_class_rec (void) -{ - assert (type_tag == meta_rec_token); - return mc.cr; -} - -symbol_table::symbol_record * -token::meta_package_rec (void) -{ - assert (type_tag == meta_rec_token); - return mc.pr; -} - -std::string -token::text_rep (void) -{ - return orig_text; -} diff -r a132d206a36a -r b9b6a310ad97 src/token.h --- a/src/token.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/* - -Copyright (C) 1993-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_token_h) -#define octave_token_h 1 - -#include - -class -token -{ -public: - - enum token_type - { - generic_token, - string_token, - double_token, - ettype_token, - sym_rec_token, - scls_rec_token, - meta_rec_token - }; - - enum end_tok_type - { - simple_end, - classdef_end, - enumeration_end, - events_end, - for_end, - function_end, - if_end, - methods_end, - parfor_end, - properties_end, - switch_end, - while_end, - try_catch_end, - unwind_protect_end - }; - - token (int l = -1, int c = -1); - token (const std::string& s, int l = -1, int c = -1); - token (double d, const std::string& s = std::string (), - int l = -1, int c = -1); - token (end_tok_type t, int l = -1, int c = -1); - token (symbol_table::symbol_record *s, int l = -1, int c = -1); - token (symbol_table::symbol_record *cls, - symbol_table::symbol_record *pkg, int l = -1, int c = -1); - token (symbol_table::symbol_record *mth, - symbol_table::symbol_record *cls, - symbol_table::symbol_record *pkg, int l = -1, int c = -1); - - ~token (void); - - int line (void) { return line_num; } - int column (void) { return column_num; } - - std::string text (void); - double number (void); - end_tok_type ettype (void); - symbol_table::symbol_record *sym_rec (void); - - symbol_table::symbol_record *method_rec (void); - symbol_table::symbol_record *class_rec (void); - symbol_table::symbol_record *package_rec (void); - - symbol_table::symbol_record *meta_class_rec (void); - symbol_table::symbol_record *meta_package_rec (void); - - std::string text_rep (void); - -private: - - // No copying! - - token (const token& tok); - - token& operator = (const token& tok); - - int line_num; - int column_num; - token_type type_tag; - union - { - std::string *str; - double num; - end_tok_type et; - symbol_table::symbol_record *sr; - struct - { - symbol_table::symbol_record *mr; - symbol_table::symbol_record *cr; - symbol_table::symbol_record *pr; - } sc; - struct - { - symbol_table::symbol_record *cr; - symbol_table::symbol_record *pr; - } mc; - }; - std::string orig_text; -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/txt-eng-ft.cc --- a/src/txt-eng-ft.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,669 +0,0 @@ -/* - -Copyright (C) 2009-2012 Michael Goffioul - -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 -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#if defined (HAVE_FREETYPE) - -#if defined (HAVE_FONTCONFIG) -#include -#endif - -#include - -#include "singleton-cleanup.h" - -#include "error.h" -#include "pr-output.h" -#include "txt-eng-ft.h" - -// FIXME -- maybe issue at most one warning per glyph/font/size/weight -// combination. - -static void -gripe_missing_glyph (char c) -{ - warning_with_id ("Octave:missing-glyph", - "ft_render: skipping missing glyph for character `%c'", - c); -} - -static void -gripe_glyph_render (char c) -{ - warning_with_id ("Octave:glyph-render", - "ft_render: unable to render glyph for character `%c'", - c); -} - -#ifdef _MSC_VER -// This is just a trick to avoid multiply symbols definition. -// PermMatrix.h contains a dllexport'ed Array -// that will make MSVC not to generate new instantiation and -// use the imported one. -#include "PermMatrix.h" -#endif - -class -ft_manager -{ -public: - static bool instance_ok (void) - { - bool retval = true; - - if (! instance) - { - instance = new ft_manager (); - - if (instance) - singleton_cleanup_list::add (cleanup_instance); - } - - if (! instance) - { - ::error ("unable to create ft_manager!"); - - retval = false; - } - - return retval; - } - - static void cleanup_instance (void) { delete instance; instance = 0; } - - static FT_Face get_font (const std::string& name, const std::string& weight, - const std::string& angle, double size) - { return (instance_ok () - ? instance->do_get_font (name, weight, angle, size) - : 0); } - -private: - - static ft_manager *instance; - -private: - - // No copying! - - ft_manager (const ft_manager&); - - ft_manager& operator = (const ft_manager&); - - ft_manager (void) - : library (), freetype_initialized (false), fontconfig_initialized (false) - { - if (FT_Init_FreeType (&library)) - ::error ("unable to initialize freetype library"); - else - freetype_initialized = true; - -#if defined (HAVE_FONTCONFIG) - if (! FcInit ()) - ::error ("unable to initialize fontconfig library"); - else - fontconfig_initialized = true; -#endif - } - - ~ft_manager (void) - { - if (freetype_initialized) - FT_Done_FreeType (library); - -#if defined (HAVE_FONTCONFIG) - // FIXME -- Skip the call to FcFini because it can trigger the - // assertion - // - // octave: fccache.c:507: FcCacheFini: Assertion `fcCacheChains[i] == ((void *)0)' failed. - // - // if (fontconfig_initialized) - // FcFini (); -#endif - } - - - FT_Face do_get_font (const std::string& name, const std::string& weight, - const std::string& angle, double size) - { - FT_Face retval = 0; - - std::string file; - -#if defined (HAVE_FONTCONFIG) - if (fontconfig_initialized) - { - int fc_weight, fc_angle; - - if (weight == "bold") - fc_weight = FC_WEIGHT_BOLD; - else if (weight == "light") - fc_weight = FC_WEIGHT_LIGHT; - else if (weight == "demi") - fc_weight = FC_WEIGHT_DEMIBOLD; - else - fc_weight = FC_WEIGHT_NORMAL; - - if (angle == "italic") - fc_angle = FC_SLANT_ITALIC; - else if (angle == "oblique") - fc_angle = FC_SLANT_OBLIQUE; - else - fc_angle = FC_SLANT_ROMAN; - - FcPattern *pat = FcPatternCreate (); - - FcPatternAddString (pat, FC_FAMILY, - (reinterpret_cast - (name == "*" ? "sans" : name.c_str ()))); - - FcPatternAddInteger (pat, FC_WEIGHT, fc_weight); - FcPatternAddInteger (pat, FC_SLANT, fc_angle); - FcPatternAddDouble (pat, FC_PIXEL_SIZE, size); - - if (FcConfigSubstitute (0, pat, FcMatchPattern)) - { - FcResult res; - FcPattern *match; - - FcDefaultSubstitute (pat); - match = FcFontMatch (0, pat, &res); - - // FIXME -- originally, this test also required that - // res != FcResultNoMatch. Is that really needed? - if (match) - { - unsigned char *tmp; - - FcPatternGetString (match, FC_FILE, 0, &tmp); - file = reinterpret_cast (tmp); - } - else - ::warning ("could not match any font: %s-%s-%s-%g", - name.c_str (), weight.c_str (), angle.c_str (), - size); - - if (match) - FcPatternDestroy (match); - } - - FcPatternDestroy (pat); - } -#endif - - if (file.empty ()) - { -#ifdef __WIN32__ - file = "C:/WINDOWS/Fonts/verdana.ttf"; -#else - // FIXME: find a "standard" font for UNIX platforms -#endif - } - - if (! file.empty () && FT_New_Face (library, file.c_str (), 0, &retval)) - ::warning ("ft_manager: unable to load font: %s", file.c_str ()); - - return retval; - } - -private: - FT_Library library; - bool freetype_initialized; - bool fontconfig_initialized; -}; - -ft_manager* ft_manager::instance = 0; - -// --------------------------------------------------------------------------- - -ft_render::ft_render (void) - : text_processor (), face (0), bbox (1, 4, 0.0), - xoffset (0), yoffset (0), multiline_halign (0), - multiline_align_xoffsets (), mode (MODE_BBOX), - red (0), green (0), blue (0) -{ -} - -ft_render::~ft_render (void) -{ - if (face) - FT_Done_Face (face); -} - -void -ft_render::set_font (const std::string& name, const std::string& weight, - const std::string& angle, double size) -{ - if (face) - FT_Done_Face (face); - - // FIXME: take "fontunits" into account - face = ft_manager::get_font (name, weight, angle, size); - - if (face) - { - if (FT_Set_Char_Size (face, 0, size*64, 0, 0)) - ::warning ("ft_render: unable to set font size to %d", size); - } - else - ::warning ("ft_render: unable to load appropriate font"); -} - -void -ft_render::set_mode (int m) -{ - mode = m; - - switch (mode) - { - case MODE_BBOX: - xoffset = yoffset = 0; - bbox = Matrix (1, 4, 0.0); - break; - case MODE_RENDER: - if (bbox.numel () != 4) - { - ::warning ("ft_render: invalid bounding box, cannot render"); - - xoffset = yoffset = 0; - pixels = uint8NDArray (); - } - else - { - pixels = uint8NDArray (dim_vector (4, bbox(2), bbox(3)), - static_cast (0)); - xoffset = 0; - yoffset = -bbox(1)-1; - } - break; - default: - ::error ("ft_render: invalid mode `%d'", mode); - break; - } -} - -void -ft_render::visit (text_element_string& e) -{ - 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 (str[i] != '\n' - && (! glyph_index - || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))) - gripe_missing_glyph (str[i]); - else - { - switch (mode) - { - case MODE_RENDER: - if (str[i] == '\n') - { - glyph_index = FT_Get_Char_Index (face, ' '); - if (!glyph_index || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)) - { - gripe_missing_glyph (' '); - } - 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)) - { - gripe_glyph_render (str[i]); - } - else - { - FT_Bitmap& bitmap = face->glyph->bitmap; - int x0, y0; - - if (previous) - { - FT_Vector delta; - - FT_Get_Kerning (face, previous, glyph_index, FT_KERNING_DEFAULT, &delta); - xoffset += (delta.x >> 6); - } - - 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++) - { - unsigned char pix = bitmap.buffer[r*bitmap.width+c]; - if (x0+c < 0 || x0+c >= pixels.dim2 () - || y0-r < 0 || y0-r >= pixels.dim3 ()) - { - //::error ("out-of-bound indexing!!"); - } - else if (pixels(3, x0+c, y0-r).value () == 0) - { - pixels(0, x0+c, y0-r) = red; - pixels(1, x0+c, y0-r) = green; - pixels(2, x0+c, y0-r) = blue; - pixels(3, x0+c, y0-r) = pix; - } - } - - xoffset += (face->glyph->advance.x >> 6); - } - break; - - case MODE_BBOX: - if (str[i] == '\n') - { - glyph_index = FT_Get_Char_Index (face, ' '); - if (! glyph_index - || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)) - { - gripe_missing_glyph (' '); - } - 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 - { - // 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; - - 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; - } - - 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); - - 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; - } - } - } -} - -void -ft_render::reset (void) -{ - set_mode (MODE_BBOX); - set_color (Matrix (1, 3, 0.0)); -} - -void -ft_render::set_color (Matrix c) -{ - if (c.numel () == 3) - { - red = static_cast (c(0)*255); - green = static_cast (c(1)*255); - blue = static_cast (c(2)*255); - } - else - ::warning ("ft_render::set_color: invalid color"); -} - -uint8NDArray -ft_render::render (text_element* elt, Matrix& box, int rotation) -{ - set_mode (MODE_BBOX); - elt->accept (*this); - box = bbox; - - set_mode (MODE_RENDER); - if (pixels.numel () > 0) - { - elt->accept (*this); - - switch (rotation) - { - case ROTATION_0: - break; - case ROTATION_90: - { - Array perm (dim_vector (3, 1)); - perm(0) = 0; - perm(1) = 2; - perm(2) = 1; - pixels = pixels.permute (perm); - - Array idx (dim_vector (3, 1)); - idx(0) = idx_vector (':'); - idx(1) = idx_vector (pixels.dim2 ()-1, -1, -1); - idx(2) = idx_vector (':'); - pixels = uint8NDArray (pixels.index (idx)); - } - break; - case ROTATION_180: - { - Array idx (dim_vector (3, 1)); - idx(0) = idx_vector (':'); - idx(1) = idx_vector (pixels.dim2 ()-1, -1, -1); - idx(2)= idx_vector (pixels.dim3 ()-1, -1, -1); - pixels = uint8NDArray (pixels.index (idx)); - } - break; - case ROTATION_270: - { - Array perm (dim_vector (3, 1)); - perm(0) = 0; - perm(1) = 2; - perm(2) = 1; - pixels = pixels.permute (perm); - - Array idx (dim_vector (3, 1)); - idx(0) = idx_vector (':'); - idx(1) = idx_vector (':'); - idx(2) = idx_vector (pixels.dim3 ()-1, -1, -1); - pixels = uint8NDArray (pixels.index (idx)); - } - break; - } - } - - return pixels; -} - -Matrix -ft_render::get_extent (text_element *elt, double rotation) -{ - set_mode (MODE_BBOX); - elt->accept (*this); - - Matrix extent (1, 2, 0.0); - - switch (rotation_to_mode (rotation)) - { - case ROTATION_0: - case ROTATION_180: - extent(0) = bbox(2); - extent(1) = bbox(3); - break; - case ROTATION_90: - case ROTATION_270: - extent(0) = bbox(3); - extent(1) = bbox(2); - } - - return extent; -} - -Matrix -ft_render::get_extent (const std::string& txt, double rotation) -{ - text_element *elt = text_parser_none ().parse (txt); - Matrix extent = get_extent (elt, rotation); - delete elt; - - return extent; -} - -int -ft_render::rotation_to_mode (double rotation) const -{ - if (rotation == 0.0) - return ROTATION_0; - else if (rotation == 90.0) - return ROTATION_90; - else if (rotation == 180.0) - return ROTATION_180; - else if (rotation == 270.0) - return ROTATION_270; - else - return ROTATION_0; -} - -void -ft_render::text_to_pixels (const std::string& txt, - uint8NDArray& pixels_, Matrix& box, - int halign, int valign, double rotation) -{ - // 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); - delete elt; - - if (pixels_.numel () == 0) - { - // nothing to render - return; - } - - switch (halign) - { - default: box(0) = 0; break; - case 1: box(0) = -box(2)/2; break; - case 2: box(0) = -box(2); break; - } - switch (valign) - { - default: box(1) = 0; break; - case 1: box(1) = -box(3)/2; break; - case 2: box(1) = -box(3); break; - case 3: break; - } - - switch (rot_mode) - { - case ROTATION_90: - std::swap (box(0), box(1)); - std::swap (box(2), box(3)); - box(0) = -box(0)-box(2); - break; - case ROTATION_180: - box(0) = -box(0)-box(2); - box(1) = -box(1)-box(3); - break; - case ROTATION_270: - std::swap (box(0), box(1)); - std::swap (box(2), box(3)); - box(1) = -box(1)-box(3); - break; - } -} - -#endif // HAVE_FREETYPE diff -r a132d206a36a -r b9b6a310ad97 src/txt-eng-ft.h --- a/src/txt-eng-ft.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,107 +0,0 @@ -/* - -Copyright (C) 2009-2012 Michael Goffioul - -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 (txt_eng_ft_h) -#define txt_eng_ft_h 1 - -#if HAVE_FREETYPE - -#include - -#include -#include FT_FREETYPE_H - -#include -#include -#include "txt-eng.h" - -class -OCTINTERP_API -ft_render : public text_processor -{ -public: - enum { - MODE_BBOX = 0, - MODE_RENDER = 1 - }; - - enum { - ROTATION_0 = 0, - ROTATION_90 = 1, - ROTATION_180 = 2, - ROTATION_270 = 3 - }; - -public: - ft_render (void); - - ~ft_render (void); - - void visit (text_element_string& e); - - void reset (void); - - uint8NDArray get_pixels (void) const { return pixels; } - - Matrix get_boundingbox (void) const { return bbox; } - - uint8NDArray render (text_element* elt, Matrix& box, - int rotation = ROTATION_0); - - Matrix get_extent (text_element *elt, double rotation = 0.0); - Matrix get_extent (const std::string& txt, double rotation = 0.0); - - void set_font (const std::string& name, const std::string& weight, - const std::string& angle, double size); - - void set_color (Matrix c); - - void set_mode (int m); - - void text_to_pixels (const std::string& txt, - uint8NDArray& pixels_, Matrix& bbox, - int halign, int valign, double rotation); - -private: - int rotation_to_mode (double rotation) const; - - // No copying! - - ft_render (const ft_render&); - - ft_render& operator = (const ft_render&); - -private: - FT_Face face; - Matrix bbox; - uint8NDArray pixels; - int xoffset; - int yoffset; - int multiline_halign; - std::vector multiline_align_xoffsets; - int mode; - uint8_t red, green, blue; -}; - -#endif // HAVE_FREETYPE - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/txt-eng.h --- a/src/txt-eng.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,193 +0,0 @@ -/* - -Copyright (C) 2009-2012 Michael Goffioul - -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 (txt_eng_h) -#define txt_eng_h 1 - -#include "base-list.h" - -class text_element; -class text_element_string; -class text_element_list; -class text_subscript_element; -class text_superscript_element; - -class text_processor; - -class -OCTINTERP_API -text_element -{ -public: - text_element (void) { } - - virtual ~text_element (void) { } - - virtual void accept (text_processor& p) = 0; - -private: - text_element (const text_element&); -}; - -class -OCTINTERP_API -text_element_string : public text_element -{ -public: - text_element_string (const std::string& s = "") - : text_element (), str (s) { } - - ~text_element_string (void) { } - - std::string string_value (void) const { return str; } - - void accept (text_processor& p); - -private: - std::string str; - -private: - text_element_string (const text_element_string &); -}; - -class -OCTINTERP_API -text_element_list : - public text_element, - public octave_base_list -{ -public: - text_element_list (void) - : text_element (), octave_base_list () { } - - ~text_element_list (void) - { - while (! empty ()) - { - iterator it = begin (); - delete (*it); - erase (it); - } - } - - void accept (text_processor& p); -}; - -class -OCTINTERP_API -text_subscript_element : public text_element_list -{ -public: - text_subscript_element (void) - : text_element_list () { } - - ~text_subscript_element (void) { } - - void accept (text_processor& p); -}; - -class -OCTINTERP_API -text_superscript_element : public text_element_list -{ -public: - text_superscript_element (void) - : text_element_list () { } - - ~text_superscript_element (void) { } - - void accept (text_processor& p); -}; - -class -OCTINTERP_API -text_processor -{ -public: - virtual void visit (text_element_string& e) = 0; - - virtual void visit (text_element_list& e) - { - for (text_element_list::iterator it = e.begin (); - it != e.end (); ++it) - { - (*it)->accept (*this); - } - } - - virtual void visit (text_subscript_element& e) - { visit (dynamic_cast (e)); } - - virtual void visit (text_superscript_element& e) - { visit (dynamic_cast (e)); } - - virtual void reset (void) { } - -protected: - text_processor (void) { } - - virtual ~text_processor (void) { } -}; - -#define TEXT_ELEMENT_ACCEPT(cls) \ -inline void \ -cls::accept (text_processor& p) \ -{ p.visit (*this); } - -TEXT_ELEMENT_ACCEPT(text_element_string) -TEXT_ELEMENT_ACCEPT(text_element_list) -TEXT_ELEMENT_ACCEPT(text_subscript_element) -TEXT_ELEMENT_ACCEPT(text_superscript_element) - -class -OCTINTERP_API -text_parser -{ -public: - text_parser (void) { } - - virtual ~text_parser (void) { } - - virtual text_element* parse (const std::string& s) = 0; -}; - -class -OCTINTERP_API -text_parser_none : public text_parser -{ -public: - text_parser_none (void) : text_parser () { } - - ~text_parser_none (void) { } - - // FIXME: is it possible to use reference counting to manage the - // memory for the object returned by the text parser? That would be - // preferable to having to know when and where to delete the object it - // creates... - - text_element* parse (const std::string& s) - { - return new text_element_string (s); - } -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/unwind-prot.cc --- a/src/unwind-prot.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/* - -Copyright (C) 1993-2012 John W. Eaton -Copyright (C) 2009 VZLU Prague - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "error.h" -#include "unwind-prot.h" -#include "utils.h" - -void unwind_protect_safe::gripe_exception (void) -{ - // FIXME: can this throw an exception? - error ("internal: unhandled exception in unwind_protect handler"); -} diff -r a132d206a36a -r b9b6a310ad97 src/unwind-prot.h --- a/src/unwind-prot.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,344 +0,0 @@ -/* - -Copyright (C) 1993-2012 John W. Eaton -Copyright (C) 2009-2010 VZLU Prague - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_unwind_prot_h) -#define octave_unwind_prot_h 1 - -#include - -#include -#include - -// This class allows registering cleanup actions. -class -OCTINTERP_API -unwind_protect -{ -public: - - // A generic unwind_protect element. Knows how to run itself and discard itself. - // Also, contains a pointer to the next element. - class elem - { - elem *next; - - public: - elem (void) : next (0) { } - - virtual void run (void) { } - - virtual ~elem (void) { } - - friend class unwind_protect; - - private: - - // No copying! - - elem (const elem&); - - elem& operator = (const elem&); - }; - - // An element that merely runs a void (*)(void) function. - - class fcn_elem : public elem - { - public: - fcn_elem (void (*fptr) (void)) - : e_fptr (fptr) { } - - void run (void) { e_fptr (); } - - private: - void (*e_fptr) (void); - }; - - // An element that stores a variable of type T along with a void (*) (T) - // function pointer, and calls the function with the parameter. - - template - class fcn_arg_elem : public elem - { - public: - fcn_arg_elem (void (*fcn) (T), T arg) - : e_fcn (fcn), e_arg (arg) { } - - void run (void) { e_fcn (e_arg); } - - private: - - // No copying! - - fcn_arg_elem (const fcn_arg_elem&); - - fcn_arg_elem& operator = (const fcn_arg_elem&); - - void (*e_fcn) (T); - T e_arg; - }; - - // An element that stores a variable of type T along with a void (*) (const T&) - // function pointer, and calls the function with the parameter. - - template - class fcn_crefarg_elem : public elem - { - public: - fcn_crefarg_elem (void (*fcn) (const T&), T arg) - : e_fcn (fcn), e_arg (arg) { } - - void run (void) { e_fcn (e_arg); } - - private: - void (*e_fcn) (const T&); - T e_arg; - }; - - // An element for calling a member function. - - template - class method_elem : public elem - { - public: - method_elem (T *obj, void (T::*method) (void)) - : e_obj (obj), e_method (method) { } - - void run (void) { (e_obj->*e_method) (); } - - private: - - T *e_obj; - void (T::*e_method) (void); - - // No copying! - - method_elem (const method_elem&); - - method_elem operator = (const method_elem&); - }; - - // An element that stores arbitrary variable, and restores it. - - template - class restore_var_elem : public elem - { - public: - restore_var_elem (T& ref, const T& val) - : e_ptr (&ref), e_val (val) { } - - void run (void) { *e_ptr = e_val; } - - private: - - // No copying! - - restore_var_elem (const restore_var_elem&); - - restore_var_elem& operator = (const restore_var_elem&); - - T *e_ptr, e_val; - }; - - // Deletes a class allocated using new. - - template - class delete_ptr_elem : public elem - { - public: - delete_ptr_elem (T *ptr) - : e_ptr (ptr) { } - - void run (void) { delete e_ptr; } - - private: - - T *e_ptr; - - // No copying! - - delete_ptr_elem (const delete_ptr_elem&); - - delete_ptr_elem operator = (const delete_ptr_elem&); - }; - - unwind_protect (void) : head () { } - - void add (elem *new_elem) - { - new_elem->next = head; - head = new_elem; - } - - // For backward compatibility. - void add (void (*fcn) (void *), void *ptr = 0) - { - add (new fcn_arg_elem (fcn, ptr)); - } - - // Call to void func (void). - void add_fcn (void (*fcn) (void)) - { - add (new fcn_elem (fcn)); - } - - // Call to void func (T). - template - void add_fcn (void (*action) (T), T val) - { - add (new fcn_arg_elem (action, val)); - } - - // Call to void func (const T&). - template - void add_fcn (void (*action) (const T&), T val) - { - add (new fcn_crefarg_elem (action, val)); - } - - // Call to T::method (void). - template - void add_method (T *obj, void (T::*method) (void)) - { - add (new method_elem (obj, method)); - } - - // Call to delete (T*). - - template - void add_delete (T *obj) - { - add (new delete_ptr_elem (obj)); - } - - // Protect any variable. - template - void protect_var (T& var) - { - add (new restore_var_elem (var, var)); - } - - // Protect any variable, value given. - template - void protect_var (T& var, const T& val) - { - add (new restore_var_elem (var, val)); - } - - operator bool (void) const - { - return head != 0; - } - - void run_top (void) - { - if (head) - { - // No leak on exception! - std::auto_ptr ptr (head); - head = ptr->next; - ptr->run (); - } - } - - void run_top (int num) - { - while (num-- > 0) - run_top (); - } - - void discard_top (void) - { - if (head) - { - elem *ptr = head; - head = ptr->next; - delete ptr; - } - } - - void discard_top (int num) - { - while (num-- > 0) - discard_top (); - } - - void run (void) - { - while (head) - run_top (); - } - - void discard (void) - { - while (head) - discard_top (); - } - - // Destructor should not raise an exception, so all actions registered should - // be exception-safe (but setting error_state is allowed). If you're not sure, - // see unwind_protect_safe. - ~unwind_protect (void) - { - run (); - } - -private: - - elem *head; - - // No copying! - - unwind_protect (const unwind_protect&); - - unwind_protect& operator = (const unwind_protect&); -}; - -// Like unwind_protect, but this one will guard against the possibility of seeing -// an exception (or interrupt) in the cleanup actions. Not that we can do much about -// it, but at least we won't crash. - -class -OCTINTERP_API -unwind_protect_safe : public unwind_protect -{ - static void gripe_exception (void); - -public: - ~unwind_protect_safe (void) - { - while (*this) - { - try - { - run_top (); - } - catch (...) // Yes, the black hole. Remember we're in a dtor. - { - gripe_exception (); - } - } - } -}; - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/xdiv.cc --- a/src/xdiv.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1000 +0,0 @@ -/* - -Copyright (C) 1993-2012 John W. Eaton -Copyright (C) 2008 Jaroslav Hajek -Copyright (C) 2009-2010 VZLU Prague - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "Array-util.h" -#include "CMatrix.h" -#include "dMatrix.h" -#include "CNDArray.h" -#include "dNDArray.h" -#include "fCMatrix.h" -#include "fMatrix.h" -#include "fCNDArray.h" -#include "fNDArray.h" -#include "oct-cmplx.h" -#include "dDiagMatrix.h" -#include "fDiagMatrix.h" -#include "CDiagMatrix.h" -#include "fCDiagMatrix.h" -#include "quit.h" - -#include "error.h" -#include "xdiv.h" - -static inline bool -result_ok (octave_idx_type info) -{ - assert (info != -1); - - return (info != -2); -} - -static void -solve_singularity_warning (double rcond) -{ - warning_with_id ("Octave:singular-matrix-div", - "matrix singular to machine precision, rcond = %g", rcond); -} - -template -bool -mx_leftdiv_conform (const T1& a, const T2& b, blas_trans_type blas_trans) -{ - 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 = 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); - return false; - } - - return true; -} - -#define INSTANTIATE_MX_LEFTDIV_CONFORM(T1, 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); -INSTANTIATE_MX_LEFTDIV_CONFORM (ComplexMatrix, Matrix); -INSTANTIATE_MX_LEFTDIV_CONFORM (ComplexMatrix, ComplexMatrix); - -template -bool -mx_div_conform (const T1& a, const T2& b) -{ - octave_idx_type a_nc = a.cols (); - octave_idx_type b_nc = b.cols (); - - if (a_nc != b_nc) - { - octave_idx_type a_nr = a.rows (); - octave_idx_type b_nr = b.rows (); - - gripe_nonconformant ("operator /", a_nr, a_nc, b_nr, b_nc); - return false; - } - - return true; -} - -#define INSTANTIATE_MX_DIV_CONFORM(T1, T2) \ - template bool mx_div_conform (const T1&, const T2&) - -INSTANTIATE_MX_DIV_CONFORM (Matrix, Matrix); -INSTANTIATE_MX_DIV_CONFORM (Matrix, ComplexMatrix); -INSTANTIATE_MX_DIV_CONFORM (ComplexMatrix, Matrix); -INSTANTIATE_MX_DIV_CONFORM (ComplexMatrix, ComplexMatrix); - -// Right division functions. -// -// op2 / op1: m cm -// +-- +---+----+ -// matrix | 1 | 3 | -// +---+----+ -// complex_matrix | 2 | 4 | -// +---+----+ - -// -*- 1 -*- -Matrix -xdiv (const Matrix& a, const Matrix& b, MatrixType &typ) -{ - if (! mx_div_conform (a, b)) - return Matrix (); - - octave_idx_type info; - double rcond = 0.0; - - Matrix result - = b.solve (typ, a.transpose (), info, rcond, - solve_singularity_warning, true, blas_trans); - - return result.transpose (); -} - -// -*- 2 -*- -ComplexMatrix -xdiv (const Matrix& a, const ComplexMatrix& b, MatrixType &typ) -{ - if (! mx_div_conform (a, b)) - return ComplexMatrix (); - - octave_idx_type info; - double rcond = 0.0; - - ComplexMatrix result - = b.solve (typ, a.transpose (), info, rcond, - solve_singularity_warning, true, blas_trans); - - return result.transpose (); -} - -// -*- 3 -*- -ComplexMatrix -xdiv (const ComplexMatrix& a, const Matrix& b, MatrixType &typ) -{ - if (! mx_div_conform (a, b)) - return ComplexMatrix (); - - octave_idx_type info; - double rcond = 0.0; - - ComplexMatrix result - = b.solve (typ, a.transpose (), info, rcond, - solve_singularity_warning, true, blas_trans); - - return result.transpose (); -} - -// -*- 4 -*- -ComplexMatrix -xdiv (const ComplexMatrix& a, const ComplexMatrix& b, MatrixType &typ) -{ - if (! mx_div_conform (a, b)) - return ComplexMatrix (); - - octave_idx_type info; - double rcond = 0.0; - - ComplexMatrix result - = b.solve (typ, a.transpose (), info, rcond, - solve_singularity_warning, true, blas_trans); - - return result.transpose (); -} - -// Funny element by element division operations. -// -// op2 \ op1: s cs -// +-- +---+----+ -// matrix | 1 | 3 | -// +---+----+ -// complex_matrix | 2 | 4 | -// +---+----+ - -Matrix -x_el_div (double a, const Matrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.columns (); - - Matrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = a / b (i, j); - } - - return result; -} - -ComplexMatrix -x_el_div (double a, const ComplexMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.columns (); - - ComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = a / b (i, j); - } - - return result; -} - -ComplexMatrix -x_el_div (const Complex a, const Matrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.columns (); - - ComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = a / b (i, j); - } - - return result; -} - -ComplexMatrix -x_el_div (const Complex a, const ComplexMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.columns (); - - ComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = a / b (i, j); - } - - return result; -} - -// Funny element by element division operations. -// -// op2 \ op1: s cs -// +-- +---+----+ -// N-d array | 1 | 3 | -// +---+----+ -// complex N-d array | 2 | 4 | -// +---+----+ - -NDArray -x_el_div (double a, const NDArray& b) -{ - NDArray result (b.dims ()); - - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - result (i) = a / b (i); - } - - return result; -} - -ComplexNDArray -x_el_div (double a, const ComplexNDArray& b) -{ - ComplexNDArray result (b.dims ()); - - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - result (i) = a / b (i); - } - - return result; -} - -ComplexNDArray -x_el_div (const Complex a, const NDArray& b) -{ - ComplexNDArray result (b.dims ()); - - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - result (i) = a / b (i); - } - - return result; -} - -ComplexNDArray -x_el_div (const Complex a, const ComplexNDArray& b) -{ - ComplexNDArray result (b.dims ()); - - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - result (i) = a / b (i); - } - - return result; -} - -// Left division functions. -// -// op2 \ op1: m cm -// +-- +---+----+ -// matrix | 1 | 3 | -// +---+----+ -// complex_matrix | 2 | 4 | -// +---+----+ - -// -*- 1 -*- -Matrix -xleftdiv (const Matrix& a, const Matrix& b, MatrixType &typ, blas_trans_type transt) -{ - if (! mx_leftdiv_conform (a, b, transt)) - return Matrix (); - - octave_idx_type info; - double rcond = 0.0; - return a.solve (typ, b, info, rcond, solve_singularity_warning, true, transt); -} - -// -*- 2 -*- -ComplexMatrix -xleftdiv (const Matrix& a, const ComplexMatrix& b, MatrixType &typ, blas_trans_type transt) -{ - if (! mx_leftdiv_conform (a, b, transt)) - return ComplexMatrix (); - - octave_idx_type info; - double rcond = 0.0; - - return a.solve (typ, b, info, rcond, solve_singularity_warning, true, transt); -} - -// -*- 3 -*- -ComplexMatrix -xleftdiv (const ComplexMatrix& a, const Matrix& b, MatrixType &typ, blas_trans_type transt) -{ - if (! mx_leftdiv_conform (a, b, transt)) - return ComplexMatrix (); - - octave_idx_type info; - double rcond = 0.0; - return a.solve (typ, b, info, rcond, solve_singularity_warning, true, transt); -} - -// -*- 4 -*- -ComplexMatrix -xleftdiv (const ComplexMatrix& a, const ComplexMatrix& b, MatrixType &typ, blas_trans_type transt) -{ - if (! mx_leftdiv_conform (a, b, transt)) - return ComplexMatrix (); - - octave_idx_type info; - double rcond = 0.0; - return a.solve (typ, b, info, rcond, solve_singularity_warning, true, transt); -} - -static void -solve_singularity_warning (float rcond) -{ - warning ("matrix singular to machine precision, rcond = %g", rcond); - warning ("attempting to find minimum norm solution"); -} - -INSTANTIATE_MX_LEFTDIV_CONFORM (FloatMatrix, FloatMatrix); -INSTANTIATE_MX_LEFTDIV_CONFORM (FloatMatrix, FloatComplexMatrix); -INSTANTIATE_MX_LEFTDIV_CONFORM (FloatComplexMatrix, FloatMatrix); -INSTANTIATE_MX_LEFTDIV_CONFORM (FloatComplexMatrix, FloatComplexMatrix); - -INSTANTIATE_MX_DIV_CONFORM (FloatMatrix, FloatMatrix); -INSTANTIATE_MX_DIV_CONFORM (FloatMatrix, FloatComplexMatrix); -INSTANTIATE_MX_DIV_CONFORM (FloatComplexMatrix, FloatMatrix); -INSTANTIATE_MX_DIV_CONFORM (FloatComplexMatrix, FloatComplexMatrix); - -// Right division functions. -// -// op2 / op1: m cm -// +-- +---+----+ -// matrix | 1 | 3 | -// +---+----+ -// complex_matrix | 2 | 4 | -// +---+----+ - -// -*- 1 -*- -FloatMatrix -xdiv (const FloatMatrix& a, const FloatMatrix& b, MatrixType &typ) -{ - if (! mx_div_conform (a, b)) - return FloatMatrix (); - - octave_idx_type info; - float rcond = 0.0; - - FloatMatrix result - = b.solve (typ, a.transpose (), info, rcond, - solve_singularity_warning, true, blas_trans); - - return result.transpose (); -} - -// -*- 2 -*- -FloatComplexMatrix -xdiv (const FloatMatrix& a, const FloatComplexMatrix& b, MatrixType &typ) -{ - if (! mx_div_conform (a, b)) - return FloatComplexMatrix (); - - octave_idx_type info; - float rcond = 0.0; - - FloatComplexMatrix result - = b.solve (typ, a.transpose (), info, rcond, - solve_singularity_warning, true, blas_trans); - - return result.transpose (); -} - -// -*- 3 -*- -FloatComplexMatrix -xdiv (const FloatComplexMatrix& a, const FloatMatrix& b, MatrixType &typ) -{ - if (! mx_div_conform (a, b)) - return FloatComplexMatrix (); - - octave_idx_type info; - float rcond = 0.0; - - FloatComplexMatrix result - = b.solve (typ, a.transpose (), info, rcond, - solve_singularity_warning, true, blas_trans); - - return result.transpose (); -} - -// -*- 4 -*- -FloatComplexMatrix -xdiv (const FloatComplexMatrix& a, const FloatComplexMatrix& b, MatrixType &typ) -{ - if (! mx_div_conform (a, b)) - return FloatComplexMatrix (); - - octave_idx_type info; - float rcond = 0.0; - - FloatComplexMatrix result - = b.solve (typ, a.transpose (), info, rcond, - solve_singularity_warning, true, blas_trans); - - return result.transpose (); -} - -// Funny element by element division operations. -// -// op2 \ op1: s cs -// +-- +---+----+ -// matrix | 1 | 3 | -// +---+----+ -// complex_matrix | 2 | 4 | -// +---+----+ - -FloatMatrix -x_el_div (float a, const FloatMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.columns (); - - FloatMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = a / b (i, j); - } - - return result; -} - -FloatComplexMatrix -x_el_div (float a, const FloatComplexMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.columns (); - - FloatComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = a / b (i, j); - } - - return result; -} - -FloatComplexMatrix -x_el_div (const FloatComplex a, const FloatMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.columns (); - - FloatComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = a / b (i, j); - } - - return result; -} - -FloatComplexMatrix -x_el_div (const FloatComplex a, const FloatComplexMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.columns (); - - FloatComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = a / b (i, j); - } - - return result; -} - -// Funny element by element division operations. -// -// op2 \ op1: s cs -// +-- +---+----+ -// N-d array | 1 | 3 | -// +---+----+ -// complex N-d array | 2 | 4 | -// +---+----+ - -FloatNDArray -x_el_div (float a, const FloatNDArray& b) -{ - FloatNDArray result (b.dims ()); - - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - result (i) = a / b (i); - } - - return result; -} - -FloatComplexNDArray -x_el_div (float a, const FloatComplexNDArray& b) -{ - FloatComplexNDArray result (b.dims ()); - - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - result (i) = a / b (i); - } - - return result; -} - -FloatComplexNDArray -x_el_div (const FloatComplex a, const FloatNDArray& b) -{ - FloatComplexNDArray result (b.dims ()); - - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - result (i) = a / b (i); - } - - return result; -} - -FloatComplexNDArray -x_el_div (const FloatComplex a, const FloatComplexNDArray& b) -{ - FloatComplexNDArray result (b.dims ()); - - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - result (i) = a / b (i); - } - - return result; -} - -// Left division functions. -// -// op2 \ op1: m cm -// +-- +---+----+ -// matrix | 1 | 3 | -// +---+----+ -// complex_matrix | 2 | 4 | -// +---+----+ - -// -*- 1 -*- -FloatMatrix -xleftdiv (const FloatMatrix& a, const FloatMatrix& b, MatrixType &typ, blas_trans_type transt) -{ - if (! mx_leftdiv_conform (a, b, transt)) - return FloatMatrix (); - - octave_idx_type info; - float rcond = 0.0; - return a.solve (typ, b, info, rcond, solve_singularity_warning, true, transt); -} - -// -*- 2 -*- -FloatComplexMatrix -xleftdiv (const FloatMatrix& a, const FloatComplexMatrix& b, MatrixType &typ, blas_trans_type transt) -{ - if (! mx_leftdiv_conform (a, b, transt)) - return FloatComplexMatrix (); - - octave_idx_type info; - float rcond = 0.0; - - return a.solve (typ, b, info, rcond, solve_singularity_warning, true, transt); -} - -// -*- 3 -*- -FloatComplexMatrix -xleftdiv (const FloatComplexMatrix& a, const FloatMatrix& b, MatrixType &typ, blas_trans_type transt) -{ - if (! mx_leftdiv_conform (a, b, transt)) - return FloatComplexMatrix (); - - octave_idx_type info; - float rcond = 0.0; - return a.solve (typ, b, info, rcond, solve_singularity_warning, true, transt); -} - -// -*- 4 -*- -FloatComplexMatrix -xleftdiv (const FloatComplexMatrix& a, const FloatComplexMatrix& b, MatrixType &typ, blas_trans_type transt) -{ - if (! mx_leftdiv_conform (a, b, transt)) - return FloatComplexMatrix (); - - octave_idx_type info; - float rcond = 0.0; - return a.solve (typ, b, info, rcond, solve_singularity_warning, true, transt); -} - -// Diagonal matrix division. - -template -MT -mdm_div_impl (const MT& a, const DMT& d) -{ - if (! mx_div_conform (a, d)) - return MT (); - - octave_idx_type m = a.rows (), n = d.rows (), l = d.length (); - MT x (m, n); - typedef typename DMT::element_type S; - typedef typename MT::element_type T; - const T *aa = a.data (); - const S *dd = d.data (); - T *xx = x.fortran_vec (); - - for (octave_idx_type j = 0; j < l; j++) - { - const S del = dd[j]; - if (del != S ()) - for (octave_idx_type i = 0; i < m; i++) - xx[i] = aa[i] / del; - else - for (octave_idx_type i = 0; i < m; i++) - xx[i] = T (); - aa += m; xx += m; - } - - for (octave_idx_type i = l*m; i < n*m; i++) - xx[i] = T (); - - return x; -} - -// Right division functions. -// -// op2 / op1: dm cdm -// +-- +---+----+ -// matrix | 1 | | -// +---+----+ -// complex_matrix | 2 | 3 | -// +---+----+ - -// -*- 1 -*- -Matrix -xdiv (const Matrix& a, const DiagMatrix& b) -{ return mdm_div_impl (a, b); } - -// -*- 2 -*- -ComplexMatrix -xdiv (const ComplexMatrix& a, const DiagMatrix& b) -{ return mdm_div_impl (a, b); } - -// -*- 3 -*- -ComplexMatrix -xdiv (const ComplexMatrix& a, const ComplexDiagMatrix& b) -{ return mdm_div_impl (a, b); } - -// Right division functions, float type. -// -// op2 / op1: dm cdm -// +-- +---+----+ -// matrix | 1 | | -// +---+----+ -// complex_matrix | 2 | 3 | -// +---+----+ - -// -*- 1 -*- -FloatMatrix -xdiv (const FloatMatrix& a, const FloatDiagMatrix& b) -{ return mdm_div_impl (a, b); } - -// -*- 2 -*- -FloatComplexMatrix -xdiv (const FloatComplexMatrix& a, const FloatDiagMatrix& b) -{ return mdm_div_impl (a, b); } - -// -*- 3 -*- -FloatComplexMatrix -xdiv (const FloatComplexMatrix& a, const FloatComplexDiagMatrix& b) -{ return mdm_div_impl (a, b); } - -template -MT -dmm_leftdiv_impl (const DMT& d, const MT& 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 (); - MT x (m, n); - typedef typename DMT::element_type S; - typedef typename MT::element_type T; - const T *aa = a.data (); - const S *dd = d.data (); - T *xx = x.fortran_vec (); - - for (octave_idx_type j = 0; j < n; j++) - { - for (octave_idx_type i = 0; i < l; i++) - xx[i] = dd[i] != S () ? aa[i] / dd[i] : T (); - for (octave_idx_type i = l; i < m; i++) - xx[i] = T (); - aa += k; xx += m; - } - - return x; -} - -// Left division functions. -// -// op2 \ op1: m cm -// +---+----+ -// diag_matrix | 1 | 2 | -// +---+----+ -// complex_diag_matrix | | 3 | -// +---+----+ - -// -*- 1 -*- -Matrix -xleftdiv (const DiagMatrix& a, const Matrix& b) -{ return dmm_leftdiv_impl (a, b); } - -// -*- 2 -*- -ComplexMatrix -xleftdiv (const DiagMatrix& a, const ComplexMatrix& b) -{ return dmm_leftdiv_impl (a, b); } - -// -*- 3 -*- -ComplexMatrix -xleftdiv (const ComplexDiagMatrix& a, const ComplexMatrix& b) -{ return dmm_leftdiv_impl (a, b); } - -// Left division functions, float type. -// -// op2 \ op1: m cm -// +---+----+ -// diag_matrix | 1 | 2 | -// +---+----+ -// complex_diag_matrix | | 3 | -// +---+----+ - -// -*- 1 -*- -FloatMatrix -xleftdiv (const FloatDiagMatrix& a, const FloatMatrix& b) -{ return dmm_leftdiv_impl (a, b); } - -// -*- 2 -*- -FloatComplexMatrix -xleftdiv (const FloatDiagMatrix& a, const FloatComplexMatrix& b) -{ return dmm_leftdiv_impl (a, b); } - -// -*- 3 -*- -FloatComplexMatrix -xleftdiv (const FloatComplexDiagMatrix& a, const FloatComplexMatrix& b) -{ return dmm_leftdiv_impl (a, b); } - -// Diagonal by diagonal matrix division. - -template -MT -dmdm_div_impl (const MT& a, const DMT& d) -{ - if (! mx_div_conform (a, d)) - return MT (); - - octave_idx_type m = a.rows (), n = d.rows (), k = d.cols (); - octave_idx_type l = std::min (m, n), lk = std::min (l, k); - MT x (m, n); - typedef typename DMT::element_type S; - typedef typename MT::element_type T; - const T *aa = a.data (); - const S *dd = d.data (); - T *xx = x.fortran_vec (); - - for (octave_idx_type i = 0; i < lk; i++) - xx[i] = dd[i] != S () ? aa[i] / dd[i] : T (); - for (octave_idx_type i = lk; i < l; i++) - xx[i] = T (); - - return x; -} - -// Right division functions. -// -// op2 / op1: dm cdm -// +-- +---+----+ -// diag_matrix | 1 | | -// +---+----+ -// complex_diag_matrix | 2 | 3 | -// +---+----+ - -// -*- 1 -*- -DiagMatrix -xdiv (const DiagMatrix& a, const DiagMatrix& b) -{ return dmdm_div_impl (a, b); } - -// -*- 2 -*- -ComplexDiagMatrix -xdiv (const ComplexDiagMatrix& a, const DiagMatrix& b) -{ return dmdm_div_impl (a, b); } - -// -*- 3 -*- -ComplexDiagMatrix -xdiv (const ComplexDiagMatrix& a, const ComplexDiagMatrix& b) -{ return dmdm_div_impl (a, b); } - -// Right division functions, float type. -// -// op2 / op1: dm cdm -// +-- +---+----+ -// diag_matrix | 1 | | -// +---+----+ -// complex_diag_matrix | 2 | 3 | -// +---+----+ - -// -*- 1 -*- -FloatDiagMatrix -xdiv (const FloatDiagMatrix& a, const FloatDiagMatrix& b) -{ return dmdm_div_impl (a, b); } - -// -*- 2 -*- -FloatComplexDiagMatrix -xdiv (const FloatComplexDiagMatrix& a, const FloatDiagMatrix& b) -{ return dmdm_div_impl (a, b); } - -// -*- 3 -*- -FloatComplexDiagMatrix -xdiv (const FloatComplexDiagMatrix& a, const FloatComplexDiagMatrix& b) -{ return dmdm_div_impl (a, b); } - -template -MT -dmdm_leftdiv_impl (const DMT& d, const MT& a) -{ - if (! mx_leftdiv_conform (d, a, blas_no_trans)) - return MT (); - - octave_idx_type m = d.cols (), n = a.cols (), k = d.rows (); - octave_idx_type l = std::min (m, n), lk = std::min (l, k); - MT x (m, n); - typedef typename DMT::element_type S; - typedef typename MT::element_type T; - const T *aa = a.data (); - const S *dd = d.data (); - T *xx = x.fortran_vec (); - - for (octave_idx_type i = 0; i < lk; i++) - xx[i] = dd[i] != S () ? aa[i] / dd[i] : T (); - for (octave_idx_type i = lk; i < l; i++) - xx[i] = T (); - - return x; -} - -// Left division functions. -// -// op2 \ op1: dm cdm -// +---+----+ -// diag_matrix | 1 | 2 | -// +---+----+ -// complex_diag_matrix | | 3 | -// +---+----+ - -// -*- 1 -*- -DiagMatrix -xleftdiv (const DiagMatrix& a, const DiagMatrix& b) -{ return dmdm_leftdiv_impl (a, b); } - -// -*- 2 -*- -ComplexDiagMatrix -xleftdiv (const DiagMatrix& a, const ComplexDiagMatrix& b) -{ return dmdm_leftdiv_impl (a, b); } - -// -*- 3 -*- -ComplexDiagMatrix -xleftdiv (const ComplexDiagMatrix& a, const ComplexDiagMatrix& b) -{ return dmdm_leftdiv_impl (a, b); } - -// Left division functions, float type. -// -// op2 \ op1: dm cdm -// +---+----+ -// diag_matrix | 1 | 2 | -// +---+----+ -// complex_diag_matrix | | 3 | -// +---+----+ - -// -*- 1 -*- -FloatDiagMatrix -xleftdiv (const FloatDiagMatrix& a, const FloatDiagMatrix& b) -{ return dmdm_leftdiv_impl (a, b); } - -// -*- 2 -*- -FloatComplexDiagMatrix -xleftdiv (const FloatDiagMatrix& a, const FloatComplexDiagMatrix& b) -{ return dmdm_leftdiv_impl (a, b); } - -// -*- 3 -*- -FloatComplexDiagMatrix -xleftdiv (const FloatComplexDiagMatrix& a, const FloatComplexDiagMatrix& b) -{ return dmdm_leftdiv_impl (a, b); } diff -r a132d206a36a -r b9b6a310ad97 src/xdiv.h --- a/src/xdiv.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,129 +0,0 @@ -/* - -Copyright (C) 1993-2012 John W. Eaton -Copyright (C) 2008 Jaroslav Hajek - -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 (octave_xdiv_h) -#define octave_xdiv_h 1 - -#include "mx-defs.h" -#include "MatrixType.h" - -extern Matrix xdiv (const Matrix& a, const Matrix& b, MatrixType &typ); -extern ComplexMatrix xdiv (const Matrix& a, const ComplexMatrix& b, - MatrixType &typ); -extern ComplexMatrix xdiv (const ComplexMatrix& a, const Matrix& b, - MatrixType &typ); -extern ComplexMatrix xdiv (const ComplexMatrix& a, const ComplexMatrix& b, - MatrixType &typ); - -extern Matrix x_el_div (double a, const Matrix& b); -extern ComplexMatrix x_el_div (double a, const ComplexMatrix& b); -extern ComplexMatrix x_el_div (const Complex a, const Matrix& b); -extern ComplexMatrix x_el_div (const Complex a, const ComplexMatrix& b); - -extern NDArray x_el_div (double a, const NDArray& b); -extern ComplexNDArray x_el_div (double a, const ComplexNDArray& b); -extern ComplexNDArray x_el_div (const Complex a, const NDArray& b); -extern ComplexNDArray x_el_div (const Complex a, const ComplexNDArray& b); - -extern Matrix xleftdiv (const Matrix& a, const Matrix& b, MatrixType &typ, - blas_trans_type transt = blas_no_trans); -extern ComplexMatrix xleftdiv (const Matrix& a, const ComplexMatrix& b, - MatrixType &typ, blas_trans_type transt = blas_no_trans); -extern ComplexMatrix xleftdiv (const ComplexMatrix& a, const Matrix& b, - MatrixType &typ, blas_trans_type transt = blas_no_trans); -extern ComplexMatrix xleftdiv (const ComplexMatrix& a, const ComplexMatrix& b, - MatrixType &typ, blas_trans_type transt = blas_no_trans); - -extern FloatMatrix xdiv (const FloatMatrix& a, const FloatMatrix& b, MatrixType &typ); -extern FloatComplexMatrix xdiv (const FloatMatrix& a, const FloatComplexMatrix& b, - MatrixType &typ); -extern FloatComplexMatrix xdiv (const FloatComplexMatrix& a, const FloatMatrix& b, - MatrixType &typ); -extern FloatComplexMatrix xdiv (const FloatComplexMatrix& a, const FloatComplexMatrix& b, - MatrixType &typ); - -extern FloatMatrix x_el_div (float a, const FloatMatrix& b); -extern FloatComplexMatrix x_el_div (float a, const FloatComplexMatrix& b); -extern FloatComplexMatrix x_el_div (const FloatComplex a, const FloatMatrix& b); -extern FloatComplexMatrix x_el_div (const FloatComplex a, const FloatComplexMatrix& b); - -extern FloatNDArray x_el_div (float a, const FloatNDArray& b); -extern FloatComplexNDArray x_el_div (float a, const FloatComplexNDArray& b); -extern FloatComplexNDArray x_el_div (const FloatComplex a, const FloatNDArray& b); -extern FloatComplexNDArray x_el_div (const FloatComplex a, const FloatComplexNDArray& b); - -extern FloatMatrix xleftdiv (const FloatMatrix& a, const FloatMatrix& b, MatrixType &typ, - blas_trans_type transt = blas_no_trans); -extern FloatComplexMatrix xleftdiv (const FloatMatrix& a, const FloatComplexMatrix& b, - MatrixType &typ, blas_trans_type transt = blas_no_trans); -extern FloatComplexMatrix xleftdiv (const FloatComplexMatrix& a, const FloatMatrix& b, - MatrixType &typ, blas_trans_type transt = blas_no_trans); -extern FloatComplexMatrix xleftdiv (const FloatComplexMatrix& a, const FloatComplexMatrix& b, - MatrixType &typ, blas_trans_type transt = blas_no_trans); - - -extern Matrix xdiv (const Matrix& a, const DiagMatrix& b); -extern ComplexMatrix xdiv (const ComplexMatrix& a, const DiagMatrix& b); -extern ComplexMatrix xdiv (const ComplexMatrix& a, const ComplexDiagMatrix& b); - -extern DiagMatrix xdiv (const DiagMatrix& a, const DiagMatrix& b); -extern ComplexDiagMatrix xdiv (const ComplexDiagMatrix& a, const DiagMatrix& b); -extern ComplexDiagMatrix xdiv (const ComplexDiagMatrix& a, const ComplexDiagMatrix& b); - -extern FloatMatrix xdiv (const FloatMatrix& a, const FloatDiagMatrix& b); -extern FloatComplexMatrix xdiv (const FloatComplexMatrix& a, - const FloatDiagMatrix& b); -extern FloatComplexMatrix xdiv (const FloatMatrix& a, - const FloatComplexDiagMatrix& b); -extern FloatComplexMatrix xdiv (const FloatComplexMatrix& a, - const FloatComplexDiagMatrix& b); - -extern FloatDiagMatrix xdiv (const FloatDiagMatrix& a, const FloatDiagMatrix& b); -extern FloatComplexDiagMatrix xdiv (const FloatComplexDiagMatrix& a, - const FloatDiagMatrix& b); -extern FloatComplexDiagMatrix xdiv (const FloatComplexDiagMatrix& a, - const FloatComplexDiagMatrix& b); - -extern Matrix xleftdiv (const DiagMatrix& a, const Matrix& b); -extern ComplexMatrix xleftdiv (const DiagMatrix& a, const ComplexMatrix& b); -extern ComplexMatrix xleftdiv (const ComplexDiagMatrix& a, const ComplexMatrix& b); - -extern DiagMatrix xleftdiv (const DiagMatrix& a, const DiagMatrix& b); -extern ComplexDiagMatrix xleftdiv (const DiagMatrix& a, const ComplexDiagMatrix& b); -extern ComplexDiagMatrix xleftdiv (const ComplexDiagMatrix& a, const ComplexDiagMatrix& b); - -extern FloatMatrix xleftdiv (const FloatDiagMatrix& a, - const FloatMatrix& b); -extern FloatComplexMatrix xleftdiv (const FloatDiagMatrix& a, - const FloatComplexMatrix& b); -extern FloatComplexMatrix xleftdiv (const FloatComplexDiagMatrix& a, - const FloatComplexMatrix& b); - -extern FloatDiagMatrix xleftdiv (const FloatDiagMatrix& a, - const FloatDiagMatrix& b); -extern FloatComplexDiagMatrix xleftdiv (const FloatDiagMatrix& a, - const FloatComplexDiagMatrix& b); -extern FloatComplexDiagMatrix xleftdiv (const FloatComplexDiagMatrix& a, - const FloatComplexDiagMatrix& b); - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/xgl2ps.c --- a/src/xgl2ps.c Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/* - -Copyright (C) 2009-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -// Wrapper for "imported" file gl2ps.c so that config.h will be included -// before any other system or gnulib headers. - -#ifdef HAVE_CONFIG_H -#include -#endif - -#if defined (HAVE_OPENGL) - -#include "gl2ps.c" - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/xnorm.cc --- a/src/xnorm.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,212 +0,0 @@ -/* - -Copyright (C) 2008-2012 VZLU Prague, a.s. - -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 -. - -*/ - -// author: Jaroslav Hajek - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include -#include - -#include "oct-norm.h" - -#include "error.h" -#include "xnorm.h" -#include "ov.h" -#include "gripes.h" - -octave_value xnorm (const octave_value& x, const octave_value& p) -{ - octave_value retval; - - bool isvector = (x.columns () == 1 || x.rows () == 1); - bool iscomplex = x.is_complex_type (); - bool issparse = x.is_sparse_type (); - bool isfloat = x.is_single_type (); - - if (isfloat || x.is_double_type ()) - { - if (isvector) - { - if (isfloat & iscomplex) - retval = xnorm (x.float_complex_column_vector_value (), - p.float_value ()); - else if (isfloat) - retval = xnorm (x.float_column_vector_value (), - p.float_value ()); - else if (iscomplex) - retval = xnorm (x.complex_column_vector_value (), - p.double_value ()); - else - retval = xnorm (x.column_vector_value (), - p.double_value ()); - } - else if (issparse) - { - if (iscomplex) - retval = xnorm (x.sparse_complex_matrix_value (), - p.double_value ()); - else - retval = xnorm (x.sparse_matrix_value (), - p.double_value ()); - } - else - { - if (isfloat & iscomplex) - retval = xnorm (x.float_complex_matrix_value (), - p.float_value ()); - else if (isfloat) - retval = xnorm (x.float_matrix_value (), - p.float_value ()); - else if (iscomplex) - retval = xnorm (x.complex_matrix_value (), - p.double_value ()); - else - retval = xnorm (x.matrix_value (), - p.double_value ()); - } - } - else - gripe_wrong_type_arg ("xnorm", x, true); - - return retval; -} - -octave_value xcolnorms (const octave_value& x, const octave_value& p) -{ - octave_value retval; - - bool iscomplex = x.is_complex_type (); - bool issparse = x.is_sparse_type (); - bool isfloat = x.is_single_type (); - - if (isfloat || x.is_double_type ()) - { - if (issparse) - { - if (iscomplex) - retval = xcolnorms (x.sparse_complex_matrix_value (), - p.double_value ()); - else - retval = xcolnorms (x.sparse_matrix_value (), - p.double_value ()); - } - else - { - if (isfloat & iscomplex) - retval = xcolnorms (x.float_complex_matrix_value (), - p.float_value ()); - else if (isfloat) - retval = xcolnorms (x.float_matrix_value (), - p.float_value ()); - else if (iscomplex) - retval = xcolnorms (x.complex_matrix_value (), - p.double_value ()); - else - retval = xcolnorms (x.matrix_value (), - p.double_value ()); - } - } - else - gripe_wrong_type_arg ("xcolnorms", x, true); - - return retval; -} - -octave_value xrownorms (const octave_value& x, const octave_value& p) -{ - octave_value retval; - - bool iscomplex = x.is_complex_type (); - bool issparse = x.is_sparse_type (); - bool isfloat = x.is_single_type (); - - if (isfloat || x.is_double_type ()) - { - if (issparse) - { - if (iscomplex) - retval = xrownorms (x.sparse_complex_matrix_value (), - p.double_value ()); - else - retval = xrownorms (x.sparse_matrix_value (), - p.double_value ()); - } - else - { - if (isfloat & iscomplex) - retval = xrownorms (x.float_complex_matrix_value (), - p.float_value ()); - else if (isfloat) - retval = xrownorms (x.float_matrix_value (), - p.float_value ()); - else if (iscomplex) - retval = xrownorms (x.complex_matrix_value (), - p.double_value ()); - else - retval = xrownorms (x.matrix_value (), - p.double_value ()); - } - } - else - gripe_wrong_type_arg ("xrownorms", x, true); - - return retval; -} - -octave_value xfrobnorm (const octave_value& x) -{ - octave_value retval; - - bool iscomplex = x.is_complex_type (); - bool issparse = x.is_sparse_type (); - bool isfloat = x.is_single_type (); - - if (isfloat || x.is_double_type ()) - { - if (issparse) - { - if (iscomplex) - retval = xfrobnorm (x.sparse_complex_matrix_value ()); - else - retval = xfrobnorm (x.sparse_matrix_value ()); - } - else - { - if (isfloat & iscomplex) - retval = xfrobnorm (x.float_complex_matrix_value ()); - else if (isfloat) - retval = xfrobnorm (x.float_matrix_value ()); - else if (iscomplex) - retval = xfrobnorm (x.complex_matrix_value ()); - else - retval = xfrobnorm (x.matrix_value ()); - } - } - else - gripe_wrong_type_arg ("xfrobnorm", x, true); - - return retval; -} diff -r a132d206a36a -r b9b6a310ad97 src/xnorm.h --- a/src/xnorm.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -/* - -Copyright (C) 2008-2012 VZLU Prague, a.s. - -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 -. - -*/ - -// author: Jaroslav Hajek - -#if !defined (octave_xnorm_h) -#define octave_xnorm_h 1 - -#include "oct-norm.h" - -class octave_value; - -extern OCTINTERP_API octave_value xnorm (const octave_value& x, const octave_value& p); -extern OCTINTERP_API octave_value xcolnorms (const octave_value& x, const octave_value& p); -extern OCTINTERP_API octave_value xrownorms (const octave_value& x, const octave_value& p); -extern OCTINTERP_API octave_value xfrobnorm (const octave_value& x); - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/xpow.cc --- a/src/xpow.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2858 +0,0 @@ -/* - -Copyright (C) 1993-2012 John W. Eaton -Copyright (C) 2009-2010 VZLU Prague - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include -#include - -#include "Array-util.h" -#include "CColVector.h" -#include "CDiagMatrix.h" -#include "fCDiagMatrix.h" -#include "CMatrix.h" -#include "EIG.h" -#include "fEIG.h" -#include "dDiagMatrix.h" -#include "fDiagMatrix.h" -#include "dMatrix.h" -#include "PermMatrix.h" -#include "mx-cm-cdm.h" -#include "oct-cmplx.h" -#include "Range.h" -#include "quit.h" - -#include "error.h" -#include "oct-obj.h" -#include "utils.h" -#include "xpow.h" - -#include "bsxfun.h" - -#ifdef _OPENMP -#include -#endif - -static inline int -xisint (double x) -{ - return (D_NINT (x) == x - && ((x >= 0 && x < INT_MAX) - || (x <= 0 && x > INT_MIN))); -} - -// Safer pow functions. -// -// op2 \ op1: s m cs cm -// +-- +---+---+----+----+ -// scalar | | 1 | 5 | 7 | 11 | -// +---+---+----+----+ -// matrix | 2 | * | 8 | * | -// +---+---+----+----+ -// complex_scalar | 3 | 6 | 9 | 12 | -// +---+---+----+----+ -// complex_matrix | 4 | * | 10 | * | -// +---+---+----+----+ - -// -*- 1 -*- -octave_value -xpow (double a, double b) -{ - double retval; - - if (a < 0.0 && ! xisint (b)) - { - Complex atmp (a); - - return std::pow (atmp, b); - } - else - retval = std::pow (a, b); - - return retval; -} - -// -*- 2 -*- -octave_value -xpow (double a, const Matrix& b) -{ - octave_value retval; - - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for x^A, A must be a square matrix"); - else - { - EIG b_eig (b); - - if (! error_state) - { - ComplexColumnVector lambda (b_eig.eigenvalues ()); - ComplexMatrix Q (b_eig.eigenvectors ()); - - for (octave_idx_type i = 0; i < nr; i++) - { - Complex elt = lambda(i); - if (std::imag (elt) == 0.0) - lambda(i) = std::pow (a, std::real (elt)); - else - lambda(i) = std::pow (a, elt); - } - ComplexDiagMatrix D (lambda); - - ComplexMatrix C = Q * D * Q.inverse (); - if (a > 0) - retval = real (C); - else - retval = C; - } - else - error ("xpow: matrix diagonalization failed"); - } - - return retval; -} - -// -*- 3 -*- -octave_value -xpow (double a, const Complex& b) -{ - Complex result = std::pow (a, b); - return result; -} - -// -*- 4 -*- -octave_value -xpow (double a, const ComplexMatrix& b) -{ - octave_value retval; - - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for x^A, A must be a square matrix"); - else - { - EIG b_eig (b); - - if (! error_state) - { - ComplexColumnVector lambda (b_eig.eigenvalues ()); - ComplexMatrix Q (b_eig.eigenvectors ()); - - for (octave_idx_type i = 0; i < nr; i++) - { - Complex elt = lambda(i); - if (std::imag (elt) == 0.0) - lambda(i) = std::pow (a, std::real (elt)); - else - lambda(i) = std::pow (a, elt); - } - ComplexDiagMatrix D (lambda); - - retval = ComplexMatrix (Q * D * Q.inverse ()); - } - else - error ("xpow: matrix diagonalization failed"); - } - - return retval; -} - -// -*- 5 -*- -octave_value -xpow (const Matrix& a, double b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for A^b, A must be a square matrix"); - else - { - if (static_cast (b) == b) - { - int btmp = static_cast (b); - if (btmp == 0) - { - retval = DiagMatrix (nr, nr, 1.0); - } - else - { - // Too much copying? - // FIXME -- we shouldn't do this if the exponent is - // large... - - Matrix atmp; - if (btmp < 0) - { - btmp = -btmp; - - octave_idx_type info; - double rcond = 0.0; - MatrixType mattype (a); - - atmp = a.inverse (mattype, info, rcond, 1); - - if (info == -1) - warning ("inverse: matrix singular to machine\ - precision, rcond = %g", rcond); - } - else - atmp = a; - - Matrix result (atmp); - - btmp--; - - while (btmp > 0) - { - if (btmp & 1) - result = result * atmp; - - btmp >>= 1; - - if (btmp > 0) - atmp = atmp * atmp; - } - - retval = result; - } - } - else - { - EIG a_eig (a); - - if (! error_state) - { - ComplexColumnVector lambda (a_eig.eigenvalues ()); - ComplexMatrix Q (a_eig.eigenvectors ()); - - for (octave_idx_type i = 0; i < nr; i++) - lambda(i) = std::pow (lambda(i), b); - - ComplexDiagMatrix D (lambda); - - retval = ComplexMatrix (Q * D * Q.inverse ()); - } - else - error ("xpow: matrix diagonalization failed"); - } - } - - return retval; -} - -// -*- 5d -*- -octave_value -xpow (const DiagMatrix& a, double b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for A^b, A must be a square matrix"); - else - { - if (static_cast (b) == b) - { - DiagMatrix r (nr, nc); - for (octave_idx_type i = 0; i < nc; i++) - r.dgelem (i) = std::pow (a.dgelem (i), b); - retval = r; - } - else - { - ComplexDiagMatrix r (nr, nc); - for (octave_idx_type i = 0; i < nc; i++) - r.dgelem (i) = std::pow (static_cast (a.dgelem (i)), b); - retval = r; - } - } - - return retval; -} - -// -*- 5p -*- -octave_value -xpow (const PermMatrix& a, double b) -{ - octave_value retval; - int btmp = static_cast (b); - if (btmp == b) - return a.power (btmp); - else - return xpow (Matrix (a), b); -} - -// -*- 6 -*- -octave_value -xpow (const Matrix& a, const Complex& b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for A^b, A must be a square matrix"); - else - { - EIG a_eig (a); - - if (! error_state) - { - ComplexColumnVector lambda (a_eig.eigenvalues ()); - ComplexMatrix Q (a_eig.eigenvectors ()); - - for (octave_idx_type i = 0; i < nr; i++) - lambda(i) = std::pow (lambda(i), b); - - ComplexDiagMatrix D (lambda); - - retval = ComplexMatrix (Q * D * Q.inverse ()); - } - else - error ("xpow: matrix diagonalization failed"); - } - - return retval; -} - -// -*- 7 -*- -octave_value -xpow (const Complex& a, double b) -{ - Complex result; - - if (xisint (b)) - result = std::pow (a, static_cast (b)); - else - result = std::pow (a, b); - - return result; -} - -// -*- 8 -*- -octave_value -xpow (const Complex& a, const Matrix& b) -{ - octave_value retval; - - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for x^A, A must be a square matrix"); - else - { - EIG b_eig (b); - - if (! error_state) - { - ComplexColumnVector lambda (b_eig.eigenvalues ()); - ComplexMatrix Q (b_eig.eigenvectors ()); - - for (octave_idx_type i = 0; i < nr; i++) - { - Complex elt = lambda(i); - if (std::imag (elt) == 0.0) - lambda(i) = std::pow (a, std::real (elt)); - else - lambda(i) = std::pow (a, elt); - } - ComplexDiagMatrix D (lambda); - - retval = ComplexMatrix (Q * D * Q.inverse ()); - } - else - error ("xpow: matrix diagonalization failed"); - } - - return retval; -} - -// -*- 9 -*- -octave_value -xpow (const Complex& a, const Complex& b) -{ - Complex result; - result = std::pow (a, b); - return result; -} - -// -*- 10 -*- -octave_value -xpow (const Complex& a, const ComplexMatrix& b) -{ - octave_value retval; - - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for x^A, A must be a square matrix"); - else - { - EIG b_eig (b); - - if (! error_state) - { - ComplexColumnVector lambda (b_eig.eigenvalues ()); - ComplexMatrix Q (b_eig.eigenvectors ()); - - for (octave_idx_type i = 0; i < nr; i++) - { - Complex elt = lambda(i); - if (std::imag (elt) == 0.0) - lambda(i) = std::pow (a, std::real (elt)); - else - lambda(i) = std::pow (a, elt); - } - ComplexDiagMatrix D (lambda); - - retval = ComplexMatrix (Q * D * Q.inverse ()); - } - else - error ("xpow: matrix diagonalization failed"); - } - - return retval; -} - -// -*- 11 -*- -octave_value -xpow (const ComplexMatrix& a, double b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for A^b, A must be a square matrix"); - else - { - if (static_cast (b) == b) - { - int btmp = static_cast (b); - if (btmp == 0) - { - retval = DiagMatrix (nr, nr, 1.0); - } - else - { - // Too much copying? - // FIXME -- we shouldn't do this if the exponent is - // large... - - ComplexMatrix atmp; - if (btmp < 0) - { - btmp = -btmp; - - octave_idx_type info; - double rcond = 0.0; - MatrixType mattype (a); - - atmp = a.inverse (mattype, info, rcond, 1); - - if (info == -1) - warning ("inverse: matrix singular to machine\ - precision, rcond = %g", rcond); - } - else - atmp = a; - - ComplexMatrix result (atmp); - - btmp--; - - while (btmp > 0) - { - if (btmp & 1) - result = result * atmp; - - btmp >>= 1; - - if (btmp > 0) - atmp = atmp * atmp; - } - - retval = result; - } - } - else - { - EIG a_eig (a); - - if (! error_state) - { - ComplexColumnVector lambda (a_eig.eigenvalues ()); - ComplexMatrix Q (a_eig.eigenvectors ()); - - for (octave_idx_type i = 0; i < nr; i++) - lambda(i) = std::pow (lambda(i), b); - - ComplexDiagMatrix D (lambda); - - retval = ComplexMatrix (Q * D * Q.inverse ()); - } - else - error ("xpow: matrix diagonalization failed"); - } - } - - return retval; -} - -// -*- 12 -*- -octave_value -xpow (const ComplexMatrix& a, const Complex& b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for A^b, A must be a square matrix"); - else - { - EIG a_eig (a); - - if (! error_state) - { - ComplexColumnVector lambda (a_eig.eigenvalues ()); - ComplexMatrix Q (a_eig.eigenvectors ()); - - for (octave_idx_type i = 0; i < nr; i++) - lambda(i) = std::pow (lambda(i), b); - - ComplexDiagMatrix D (lambda); - - retval = ComplexMatrix (Q * D * Q.inverse ()); - } - else - error ("xpow: matrix diagonalization failed"); - } - - return retval; -} - -// -*- 12d -*- -octave_value -xpow (const ComplexDiagMatrix& a, const Complex& b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for A^b, A must be a square matrix"); - else - { - ComplexDiagMatrix r (nr, nc); - for (octave_idx_type i = 0; i < nc; i++) - r(i, i) = std::pow (a(i, i), b); - retval = r; - } - - return retval; -} - -// mixed -octave_value -xpow (const ComplexDiagMatrix& a, double b) -{ - return xpow (a, static_cast (b)); -} - -octave_value -xpow (const DiagMatrix& a, const Complex& b) -{ - return xpow (ComplexDiagMatrix (a), b); -} - - -// Safer pow functions that work elementwise for matrices. -// -// op2 \ op1: s m cs cm -// +-- +---+---+----+----+ -// scalar | | * | 3 | * | 9 | -// +---+---+----+----+ -// matrix | 1 | 4 | 7 | 10 | -// +---+---+----+----+ -// complex_scalar | * | 5 | * | 11 | -// +---+---+----+----+ -// complex_matrix | 2 | 6 | 8 | 12 | -// +---+---+----+----+ -// -// * -> not needed. - -// FIXME -- these functions need to be fixed so that things -// like -// -// a = -1; b = [ 0, 0.5, 1 ]; r = a .^ b -// -// and -// -// a = -1; b = [ 0, 0.5, 1 ]; for i = 1:3, r(i) = a .^ b(i), end -// -// produce identical results. Also, it would be nice if -1^0.5 -// produced a pure imaginary result instead of a complex number with a -// small real part. But perhaps that's really a problem with the math -// library... - -// -*- 1 -*- -octave_value -elem_xpow (double a, const Matrix& b) -{ - octave_value retval; - - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - double d1, d2; - - if (a < 0.0 && ! b.all_integers (d1, d2)) - { - Complex atmp (a); - ComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (atmp, b (i, j)); - } - - retval = result; - } - else - { - Matrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a, b (i, j)); - } - - retval = result; - } - - return retval; -} - -// -*- 2 -*- -octave_value -elem_xpow (double a, const ComplexMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - ComplexMatrix result (nr, nc); - Complex atmp (a); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (atmp, b (i, j)); - } - - return result; -} - -static inline bool -same_sign (double a, double b) -{ - return (a >= 0 && b >= 0) || (a <= 0 && b <= 0); -} - -octave_value -elem_xpow (double a, const Range& r) -{ - octave_value retval; - - // Only optimize powers with ranges that are integer and monotonic in - // magnitude. - if (r.nelem () > 1 && r.all_elements_are_ints () - && same_sign (r.base (), r.limit ())) - { - octave_idx_type n = r.nelem (); - Matrix result (1, n); - if (same_sign (r.base (), r.inc ())) - { - double base = std::pow (a, r.base ()); - double inc = std::pow (a, r.inc ()); - result(0) = base; - for (octave_idx_type i = 1; i < n; i++) - result(i) = (base *= inc); - } - else - { - // Don't use Range::limit () here. - double limit = std::pow (a, r.base () + (n-1) * r.inc ()); - double inc = std::pow (a, -r.inc ()); - result(n-1) = limit; - for (octave_idx_type i = n-2; i >= 0; i--) - result(i) = (limit *= inc); - } - - retval = result; - } - else - retval = elem_xpow (a, r.matrix_value ()); - - return retval; -} - -// -*- 3 -*- -octave_value -elem_xpow (const Matrix& a, double b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (! xisint (b) && a.any_element_is_negative ()) - { - ComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - - Complex atmp (a (i, j)); - - result (i, j) = std::pow (atmp, b); - } - - retval = result; - } - else - { - Matrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a (i, j), b); - } - - retval = result; - } - - return retval; -} - -// -*- 4 -*- -octave_value -elem_xpow (const Matrix& a, const Matrix& b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - octave_idx_type b_nr = b.rows (); - octave_idx_type b_nc = b.cols (); - - if (nr != b_nr || nc != b_nc) - { - gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); - return octave_value (); - } - - int convert_to_complex = 0; - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - double atmp = a (i, j); - double btmp = b (i, j); - if (atmp < 0.0 && static_cast (btmp) != btmp) - { - convert_to_complex = 1; - goto done; - } - } - -done: - - if (convert_to_complex) - { - ComplexMatrix complex_result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - Complex atmp (a (i, j)); - Complex btmp (b (i, j)); - complex_result (i, j) = std::pow (atmp, btmp); - } - - retval = complex_result; - } - else - { - Matrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a (i, j), b (i, j)); - } - - retval = result; - } - - return retval; -} - -// -*- 5 -*- -octave_value -elem_xpow (const Matrix& a, const Complex& b) -{ - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - ComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (Complex (a (i, j)), b); - } - - return result; -} - -// -*- 6 -*- -octave_value -elem_xpow (const Matrix& a, const ComplexMatrix& b) -{ - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - octave_idx_type b_nr = b.rows (); - octave_idx_type b_nc = b.cols (); - - if (nr != b_nr || nc != b_nc) - { - gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); - return octave_value (); - } - - ComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (Complex (a (i, j)), b (i, j)); - } - - return result; -} - -// -*- 7 -*- -octave_value -elem_xpow (const Complex& a, const Matrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - ComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - double btmp = b (i, j); - if (xisint (btmp)) - result (i, j) = std::pow (a, static_cast (btmp)); - else - result (i, j) = std::pow (a, btmp); - } - - return result; -} - -// -*- 8 -*- -octave_value -elem_xpow (const Complex& a, const ComplexMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - ComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a, b (i, j)); - } - - return result; -} - -octave_value -elem_xpow (const Complex& a, const Range& r) -{ - octave_value retval; - - // Only optimize powers with ranges that are integer and monotonic in - // magnitude. - if (r.nelem () > 1 && r.all_elements_are_ints () - && same_sign (r.base (), r.limit ())) - { - octave_idx_type n = r.nelem (); - ComplexMatrix result (1, n); - - if (same_sign (r.base (), r.inc ())) - { - Complex base = std::pow (a, r.base ()); - Complex inc = std::pow (a, r.inc ()); - result(0) = base; - for (octave_idx_type i = 1; i < n; i++) - result(i) = (base *= inc); - } - else - { - // Don't use Range::limit () here. - Complex limit = std::pow (a, r.base () + (n-1) * r.inc ()); - Complex inc = std::pow (a, -r.inc ()); - result(n-1) = limit; - for (octave_idx_type i = n-2; i >= 0; i--) - result(i) = (limit *= inc); - } - - retval = result; - } - else - retval = elem_xpow (a, r.matrix_value ()); - - - return retval; -} - -// -*- 9 -*- -octave_value -elem_xpow (const ComplexMatrix& a, double b) -{ - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - ComplexMatrix result (nr, nc); - - if (xisint (b)) - { - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a (i, j), static_cast (b)); - } - } - else - { - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a (i, j), b); - } - } - - return result; -} - -// -*- 10 -*- -octave_value -elem_xpow (const ComplexMatrix& a, const Matrix& b) -{ - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - octave_idx_type b_nr = b.rows (); - octave_idx_type b_nc = b.cols (); - - if (nr != b_nr || nc != b_nc) - { - gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); - return octave_value (); - } - - ComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - double btmp = b (i, j); - if (xisint (btmp)) - result (i, j) = std::pow (a (i, j), static_cast (btmp)); - else - result (i, j) = std::pow (a (i, j), btmp); - } - - return result; -} - -// -*- 11 -*- -octave_value -elem_xpow (const ComplexMatrix& a, const Complex& b) -{ - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - ComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a (i, j), b); - } - - return result; -} - -// -*- 12 -*- -octave_value -elem_xpow (const ComplexMatrix& a, const ComplexMatrix& b) -{ - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - octave_idx_type b_nr = b.rows (); - octave_idx_type b_nc = b.cols (); - - if (nr != b_nr || nc != b_nc) - { - gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); - return octave_value (); - } - - ComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a (i, j), b (i, j)); - } - - return result; -} - -// Safer pow functions that work elementwise for N-d arrays. -// -// op2 \ op1: s nd cs cnd -// +-- +---+---+----+----+ -// scalar | | * | 3 | * | 9 | -// +---+---+----+----+ -// N_d | 1 | 4 | 7 | 10 | -// +---+---+----+----+ -// complex_scalar | * | 5 | * | 11 | -// +---+---+----+----+ -// complex_N_d | 2 | 6 | 8 | 12 | -// +---+---+----+----+ -// -// * -> not needed. - -// FIXME -- these functions need to be fixed so that things -// like -// -// a = -1; b = [ 0, 0.5, 1 ]; r = a .^ b -// -// and -// -// a = -1; b = [ 0, 0.5, 1 ]; for i = 1:3, r(i) = a .^ b(i), end -// -// produce identical results. Also, it would be nice if -1^0.5 -// produced a pure imaginary result instead of a complex number with a -// small real part. But perhaps that's really a problem with the math -// library... - -// -*- 1 -*- -octave_value -elem_xpow (double a, const NDArray& b) -{ - octave_value retval; - - if (a < 0.0 && ! b.all_integers ()) - { - Complex atmp (a); - ComplexNDArray result (b.dims ()); - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - result(i) = std::pow (atmp, b(i)); - } - - retval = result; - } - else - { - NDArray result (b.dims ()); - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - result (i) = std::pow (a, b(i)); - } - - retval = result; - } - - return retval; -} - -// -*- 2 -*- -octave_value -elem_xpow (double a, const ComplexNDArray& b) -{ - ComplexNDArray result (b.dims ()); - - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - result(i) = std::pow (a, b(i)); - } - - return result; -} - -// -*- 3 -*- -octave_value -elem_xpow (const NDArray& a, double b) -{ - octave_value retval; - - if (! xisint (b)) - { - if (a.any_element_is_negative ()) - { - ComplexNDArray result (a.dims ()); - - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - - Complex atmp (a (i)); - - result(i) = std::pow (atmp, b); - } - - retval = result; - } - else - { - NDArray result (a.dims ()); - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - result(i) = std::pow (a(i), b); - } - - retval = result; - } - } - else - { - NoAlias result (a.dims ()); - - int ib = static_cast (b); - if (ib == 2) - { - for (octave_idx_type i = 0; i < a.length (); i++) - result(i) = a(i) * a(i); - } - else if (ib == 3) - { - for (octave_idx_type i = 0; i < a.length (); i++) - result(i) = a(i) * a(i) * a(i); - } - else if (ib == -1) - { - for (octave_idx_type i = 0; i < a.length (); i++) - result(i) = 1.0 / a(i); - } - else - { - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - result(i) = std::pow (a(i), ib); - } - } - - retval = result; - } - - return retval; -} - -// -*- 4 -*- -octave_value -elem_xpow (const NDArray& a, const NDArray& b) -{ - octave_value retval; - - dim_vector a_dims = a.dims (); - dim_vector b_dims = b.dims (); - - if (a_dims != b_dims) - { - if (is_valid_bsxfun ("operator .^", 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 (); - - bool convert_to_complex = false; - - for (octave_idx_type i = 0; i < len; i++) - { - octave_quit (); - double atmp = a(i); - double btmp = b(i); - if (atmp < 0.0 && static_cast (btmp) != btmp) - { - convert_to_complex = true; - goto done; - } - } - -done: - - if (convert_to_complex) - { - ComplexNDArray complex_result (a_dims); - - for (octave_idx_type i = 0; i < len; i++) - { - octave_quit (); - Complex atmp (a(i)); - complex_result(i) = std::pow (atmp, b(i)); - } - - retval = complex_result; - } - else - { - NDArray result (a_dims); - - for (octave_idx_type i = 0; i < len; i++) - { - octave_quit (); - result(i) = std::pow (a(i), b(i)); - } - - retval = result; - } - - return retval; -} - -// -*- 5 -*- -octave_value -elem_xpow (const NDArray& a, const Complex& b) -{ - ComplexNDArray result (a.dims ()); - - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - result(i) = std::pow (a(i), b); - } - - return result; -} - -// -*- 6 -*- -octave_value -elem_xpow (const NDArray& a, const ComplexNDArray& b) -{ - dim_vector a_dims = a.dims (); - dim_vector b_dims = b.dims (); - - if (a_dims != b_dims) - { - if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) - { - return bsxfun_pow (a, b); - } - else - { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); - } - } - - ComplexNDArray result (a_dims); - - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - result(i) = std::pow (a(i), b(i)); - } - - return result; -} - -// -*- 7 -*- -octave_value -elem_xpow (const Complex& a, const NDArray& b) -{ - ComplexNDArray result (b.dims ()); - - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - double btmp = b(i); - if (xisint (btmp)) - result(i) = std::pow (a, static_cast (btmp)); - else - result(i) = std::pow (a, btmp); - } - - return result; -} - -// -*- 8 -*- -octave_value -elem_xpow (const Complex& a, const ComplexNDArray& b) -{ - ComplexNDArray result (b.dims ()); - - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - result(i) = std::pow (a, b(i)); - } - - return result; -} - -// -*- 9 -*- -octave_value -elem_xpow (const ComplexNDArray& a, double b) -{ - ComplexNDArray result (a.dims ()); - - if (xisint (b)) - { - if (b == -1) - { - for (octave_idx_type i = 0; i < a.length (); i++) - result.xelem (i) = 1.0 / a(i); - } - else - { - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - result(i) = std::pow (a(i), static_cast (b)); - } - } - } - else - { - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - result(i) = std::pow (a(i), b); - } - } - - return result; -} - -// -*- 10 -*- -octave_value -elem_xpow (const ComplexNDArray& a, const NDArray& b) -{ - dim_vector a_dims = a.dims (); - dim_vector b_dims = b.dims (); - - if (a_dims != b_dims) - { - if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) - { - return bsxfun_pow (a, b); - } - else - { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); - } - } - - ComplexNDArray result (a_dims); - - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - double btmp = b(i); - if (xisint (btmp)) - result(i) = std::pow (a(i), static_cast (btmp)); - else - result(i) = std::pow (a(i), btmp); - } - - return result; -} - -// -*- 11 -*- -octave_value -elem_xpow (const ComplexNDArray& a, const Complex& b) -{ - ComplexNDArray result (a.dims ()); - - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - result(i) = std::pow (a(i), b); - } - - return result; -} - -// -*- 12 -*- -octave_value -elem_xpow (const ComplexNDArray& a, const ComplexNDArray& b) -{ - dim_vector a_dims = a.dims (); - dim_vector b_dims = b.dims (); - - if (a_dims != b_dims) - { - if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) - { - return bsxfun_pow (a, b); - } - else - { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); - } - } - - ComplexNDArray result (a_dims); - - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - result(i) = std::pow (a(i), b(i)); - } - - return result; -} - -static inline int -xisint (float x) -{ - return (D_NINT (x) == x - && ((x >= 0 && x < INT_MAX) - || (x <= 0 && x > INT_MIN))); -} - -// Safer pow functions. -// -// op2 \ op1: s m cs cm -// +-- +---+---+----+----+ -// scalar | | 1 | 5 | 7 | 11 | -// +---+---+----+----+ -// matrix | 2 | * | 8 | * | -// +---+---+----+----+ -// complex_scalar | 3 | 6 | 9 | 12 | -// +---+---+----+----+ -// complex_matrix | 4 | * | 10 | * | -// +---+---+----+----+ - -// -*- 1 -*- -octave_value -xpow (float a, float b) -{ - float retval; - - if (a < 0.0 && ! xisint (b)) - { - FloatComplex atmp (a); - - return std::pow (atmp, b); - } - else - retval = std::pow (a, b); - - return retval; -} - -// -*- 2 -*- -octave_value -xpow (float a, const FloatMatrix& b) -{ - octave_value retval; - - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for x^A, A must be a square matrix"); - else - { - FloatEIG b_eig (b); - - if (! error_state) - { - FloatComplexColumnVector lambda (b_eig.eigenvalues ()); - FloatComplexMatrix Q (b_eig.eigenvectors ()); - - for (octave_idx_type i = 0; i < nr; i++) - { - FloatComplex elt = lambda(i); - if (std::imag (elt) == 0.0) - lambda(i) = std::pow (a, std::real (elt)); - else - lambda(i) = std::pow (a, elt); - } - FloatComplexDiagMatrix D (lambda); - - FloatComplexMatrix C = Q * D * Q.inverse (); - - if (a > 0) - retval = real (C); - else - retval = C; - } - else - error ("xpow: matrix diagonalization failed"); - } - - return retval; -} - -// -*- 3 -*- -octave_value -xpow (float a, const FloatComplex& b) -{ - FloatComplex result = std::pow (a, b); - return result; -} - -// -*- 4 -*- -octave_value -xpow (float a, const FloatComplexMatrix& b) -{ - octave_value retval; - - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for x^A, A must be a square matrix"); - else - { - FloatEIG b_eig (b); - - if (! error_state) - { - FloatComplexColumnVector lambda (b_eig.eigenvalues ()); - FloatComplexMatrix Q (b_eig.eigenvectors ()); - - for (octave_idx_type i = 0; i < nr; i++) - { - FloatComplex elt = lambda(i); - if (std::imag (elt) == 0.0) - lambda(i) = std::pow (a, std::real (elt)); - else - lambda(i) = std::pow (a, elt); - } - FloatComplexDiagMatrix D (lambda); - - retval = FloatComplexMatrix (Q * D * Q.inverse ()); - } - else - error ("xpow: matrix diagonalization failed"); - } - - return retval; -} - -// -*- 5 -*- -octave_value -xpow (const FloatMatrix& a, float b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for A^b, A must be a square matrix"); - else - { - if (static_cast (b) == b) - { - int btmp = static_cast (b); - if (btmp == 0) - { - retval = FloatDiagMatrix (nr, nr, 1.0); - } - else - { - // Too much copying? - // FIXME -- we shouldn't do this if the exponent is - // large... - - FloatMatrix atmp; - if (btmp < 0) - { - btmp = -btmp; - - octave_idx_type info; - float rcond = 0.0; - MatrixType mattype (a); - - atmp = a.inverse (mattype, info, rcond, 1); - - if (info == -1) - warning ("inverse: matrix singular to machine\ - precision, rcond = %g", rcond); - } - else - atmp = a; - - FloatMatrix result (atmp); - - btmp--; - - while (btmp > 0) - { - if (btmp & 1) - result = result * atmp; - - btmp >>= 1; - - if (btmp > 0) - atmp = atmp * atmp; - } - - retval = result; - } - } - else - { - FloatEIG a_eig (a); - - if (! error_state) - { - FloatComplexColumnVector lambda (a_eig.eigenvalues ()); - FloatComplexMatrix Q (a_eig.eigenvectors ()); - - for (octave_idx_type i = 0; i < nr; i++) - lambda(i) = std::pow (lambda(i), b); - - FloatComplexDiagMatrix D (lambda); - - retval = FloatComplexMatrix (Q * D * Q.inverse ()); - } - else - error ("xpow: matrix diagonalization failed"); - } - } - - return retval; -} - -// -*- 5d -*- -octave_value -xpow (const FloatDiagMatrix& a, float b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for A^b, A must be a square matrix"); - else - { - if (static_cast (b) == b) - { - FloatDiagMatrix r (nr, nc); - for (octave_idx_type i = 0; i < nc; i++) - r.dgelem (i) = std::pow (a.dgelem (i), b); - retval = r; - } - else - { - FloatComplexDiagMatrix r (nr, nc); - for (octave_idx_type i = 0; i < nc; i++) - r.dgelem (i) = std::pow (static_cast (a.dgelem (i)), b); - retval = r; - } - } - - return retval; -} - -// -*- 6 -*- -octave_value -xpow (const FloatMatrix& a, const FloatComplex& b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for A^b, A must be a square matrix"); - else - { - FloatEIG a_eig (a); - - if (! error_state) - { - FloatComplexColumnVector lambda (a_eig.eigenvalues ()); - FloatComplexMatrix Q (a_eig.eigenvectors ()); - - for (octave_idx_type i = 0; i < nr; i++) - lambda(i) = std::pow (lambda(i), b); - - FloatComplexDiagMatrix D (lambda); - - retval = FloatComplexMatrix (Q * D * Q.inverse ()); - } - else - error ("xpow: matrix diagonalization failed"); - } - - return retval; -} - -// -*- 7 -*- -octave_value -xpow (const FloatComplex& a, float b) -{ - FloatComplex result; - - if (xisint (b)) - result = std::pow (a, static_cast (b)); - else - result = std::pow (a, b); - - return result; -} - -// -*- 8 -*- -octave_value -xpow (const FloatComplex& a, const FloatMatrix& b) -{ - octave_value retval; - - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for x^A, A must be a square matrix"); - else - { - FloatEIG b_eig (b); - - if (! error_state) - { - FloatComplexColumnVector lambda (b_eig.eigenvalues ()); - FloatComplexMatrix Q (b_eig.eigenvectors ()); - - for (octave_idx_type i = 0; i < nr; i++) - { - FloatComplex elt = lambda(i); - if (std::imag (elt) == 0.0) - lambda(i) = std::pow (a, std::real (elt)); - else - lambda(i) = std::pow (a, elt); - } - FloatComplexDiagMatrix D (lambda); - - retval = FloatComplexMatrix (Q * D * Q.inverse ()); - } - else - error ("xpow: matrix diagonalization failed"); - } - - return retval; -} - -// -*- 9 -*- -octave_value -xpow (const FloatComplex& a, const FloatComplex& b) -{ - FloatComplex result; - result = std::pow (a, b); - return result; -} - -// -*- 10 -*- -octave_value -xpow (const FloatComplex& a, const FloatComplexMatrix& b) -{ - octave_value retval; - - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for x^A, A must be a square matrix"); - else - { - FloatEIG b_eig (b); - - if (! error_state) - { - FloatComplexColumnVector lambda (b_eig.eigenvalues ()); - FloatComplexMatrix Q (b_eig.eigenvectors ()); - - for (octave_idx_type i = 0; i < nr; i++) - { - FloatComplex elt = lambda(i); - if (std::imag (elt) == 0.0) - lambda(i) = std::pow (a, std::real (elt)); - else - lambda(i) = std::pow (a, elt); - } - FloatComplexDiagMatrix D (lambda); - - retval = FloatComplexMatrix (Q * D * Q.inverse ()); - } - else - error ("xpow: matrix diagonalization failed"); - } - - return retval; -} - -// -*- 11 -*- -octave_value -xpow (const FloatComplexMatrix& a, float b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for A^b, A must be a square matrix"); - else - { - if (static_cast (b) == b) - { - int btmp = static_cast (b); - if (btmp == 0) - { - retval = FloatDiagMatrix (nr, nr, 1.0); - } - else - { - // Too much copying? - // FIXME -- we shouldn't do this if the exponent is - // large... - - FloatComplexMatrix atmp; - if (btmp < 0) - { - btmp = -btmp; - - octave_idx_type info; - float rcond = 0.0; - MatrixType mattype (a); - - atmp = a.inverse (mattype, info, rcond, 1); - - if (info == -1) - warning ("inverse: matrix singular to machine\ - precision, rcond = %g", rcond); - } - else - atmp = a; - - FloatComplexMatrix result (atmp); - - btmp--; - - while (btmp > 0) - { - if (btmp & 1) - result = result * atmp; - - btmp >>= 1; - - if (btmp > 0) - atmp = atmp * atmp; - } - - retval = result; - } - } - else - { - FloatEIG a_eig (a); - - if (! error_state) - { - FloatComplexColumnVector lambda (a_eig.eigenvalues ()); - FloatComplexMatrix Q (a_eig.eigenvectors ()); - - for (octave_idx_type i = 0; i < nr; i++) - lambda(i) = std::pow (lambda(i), b); - - FloatComplexDiagMatrix D (lambda); - - retval = FloatComplexMatrix (Q * D * Q.inverse ()); - } - else - error ("xpow: matrix diagonalization failed"); - } - } - - return retval; -} - -// -*- 12 -*- -octave_value -xpow (const FloatComplexMatrix& a, const FloatComplex& b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for A^b, A must be a square matrix"); - else - { - FloatEIG a_eig (a); - - if (! error_state) - { - FloatComplexColumnVector lambda (a_eig.eigenvalues ()); - FloatComplexMatrix Q (a_eig.eigenvectors ()); - - for (octave_idx_type i = 0; i < nr; i++) - lambda(i) = std::pow (lambda(i), b); - - FloatComplexDiagMatrix D (lambda); - - retval = FloatComplexMatrix (Q * D * Q.inverse ()); - } - else - error ("xpow: matrix diagonalization failed"); - } - - return retval; -} - -// -*- 12d -*- -octave_value -xpow (const FloatComplexDiagMatrix& a, const FloatComplex& b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (nr == 0 || nc == 0 || nr != nc) - error ("for A^b, A must be a square matrix"); - else - { - FloatComplexDiagMatrix r (nr, nc); - for (octave_idx_type i = 0; i < nc; i++) - r(i, i) = std::pow (a(i, i), b); - retval = r; - } - - return retval; -} - -// mixed -octave_value -xpow (const FloatComplexDiagMatrix& a, float b) -{ - return xpow (a, static_cast (b)); -} - -octave_value -xpow (const FloatDiagMatrix& a, const FloatComplex& b) -{ - return xpow (FloatComplexDiagMatrix (a), b); -} - -// Safer pow functions that work elementwise for matrices. -// -// op2 \ op1: s m cs cm -// +-- +---+---+----+----+ -// scalar | | * | 3 | * | 9 | -// +---+---+----+----+ -// matrix | 1 | 4 | 7 | 10 | -// +---+---+----+----+ -// complex_scalar | * | 5 | * | 11 | -// +---+---+----+----+ -// complex_matrix | 2 | 6 | 8 | 12 | -// +---+---+----+----+ -// -// * -> not needed. - -// FIXME -- these functions need to be fixed so that things -// like -// -// a = -1; b = [ 0, 0.5, 1 ]; r = a .^ b -// -// and -// -// a = -1; b = [ 0, 0.5, 1 ]; for i = 1:3, r(i) = a .^ b(i), end -// -// produce identical results. Also, it would be nice if -1^0.5 -// produced a pure imaginary result instead of a complex number with a -// small real part. But perhaps that's really a problem with the math -// library... - -// -*- 1 -*- -octave_value -elem_xpow (float a, const FloatMatrix& b) -{ - octave_value retval; - - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - float d1, d2; - - if (a < 0.0 && ! b.all_integers (d1, d2)) - { - FloatComplex atmp (a); - FloatComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (atmp, b (i, j)); - } - - retval = result; - } - else - { - FloatMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a, b (i, j)); - } - - retval = result; - } - - return retval; -} - -// -*- 2 -*- -octave_value -elem_xpow (float a, const FloatComplexMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - FloatComplexMatrix result (nr, nc); - FloatComplex atmp (a); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (atmp, b (i, j)); - } - - return result; -} - -// -*- 3 -*- -octave_value -elem_xpow (const FloatMatrix& a, float b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - if (! xisint (b) && a.any_element_is_negative ()) - { - FloatComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - - FloatComplex atmp (a (i, j)); - - result (i, j) = std::pow (atmp, b); - } - - retval = result; - } - else - { - FloatMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a (i, j), b); - } - - retval = result; - } - - return retval; -} - -// -*- 4 -*- -octave_value -elem_xpow (const FloatMatrix& a, const FloatMatrix& b) -{ - octave_value retval; - - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - octave_idx_type b_nr = b.rows (); - octave_idx_type b_nc = b.cols (); - - if (nr != b_nr || nc != b_nc) - { - gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); - return octave_value (); - } - - int convert_to_complex = 0; - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - float atmp = a (i, j); - float btmp = b (i, j); - if (atmp < 0.0 && static_cast (btmp) != btmp) - { - convert_to_complex = 1; - goto done; - } - } - -done: - - if (convert_to_complex) - { - FloatComplexMatrix complex_result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - FloatComplex atmp (a (i, j)); - FloatComplex btmp (b (i, j)); - complex_result (i, j) = std::pow (atmp, btmp); - } - - retval = complex_result; - } - else - { - FloatMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a (i, j), b (i, j)); - } - - retval = result; - } - - return retval; -} - -// -*- 5 -*- -octave_value -elem_xpow (const FloatMatrix& a, const FloatComplex& b) -{ - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - FloatComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (FloatComplex (a (i, j)), b); - } - - return result; -} - -// -*- 6 -*- -octave_value -elem_xpow (const FloatMatrix& a, const FloatComplexMatrix& b) -{ - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - octave_idx_type b_nr = b.rows (); - octave_idx_type b_nc = b.cols (); - - if (nr != b_nr || nc != b_nc) - { - gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); - return octave_value (); - } - - FloatComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (FloatComplex (a (i, j)), b (i, j)); - } - - return result; -} - -// -*- 7 -*- -octave_value -elem_xpow (const FloatComplex& a, const FloatMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - FloatComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - float btmp = b (i, j); - if (xisint (btmp)) - result (i, j) = std::pow (a, static_cast (btmp)); - else - result (i, j) = std::pow (a, btmp); - } - - return result; -} - -// -*- 8 -*- -octave_value -elem_xpow (const FloatComplex& a, const FloatComplexMatrix& b) -{ - octave_idx_type nr = b.rows (); - octave_idx_type nc = b.cols (); - - FloatComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a, b (i, j)); - } - - return result; -} - -// -*- 9 -*- -octave_value -elem_xpow (const FloatComplexMatrix& a, float b) -{ - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - FloatComplexMatrix result (nr, nc); - - if (xisint (b)) - { - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a (i, j), static_cast (b)); - } - } - else - { - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a (i, j), b); - } - } - - return result; -} - -// -*- 10 -*- -octave_value -elem_xpow (const FloatComplexMatrix& a, const FloatMatrix& b) -{ - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - octave_idx_type b_nr = b.rows (); - octave_idx_type b_nc = b.cols (); - - if (nr != b_nr || nc != b_nc) - { - gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); - return octave_value (); - } - - FloatComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - float btmp = b (i, j); - if (xisint (btmp)) - result (i, j) = std::pow (a (i, j), static_cast (btmp)); - else - result (i, j) = std::pow (a (i, j), btmp); - } - - return result; -} - -// -*- 11 -*- -octave_value -elem_xpow (const FloatComplexMatrix& a, const FloatComplex& b) -{ - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - FloatComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a (i, j), b); - } - - return result; -} - -// -*- 12 -*- -octave_value -elem_xpow (const FloatComplexMatrix& a, const FloatComplexMatrix& b) -{ - octave_idx_type nr = a.rows (); - octave_idx_type nc = a.cols (); - - octave_idx_type b_nr = b.rows (); - octave_idx_type b_nc = b.cols (); - - if (nr != b_nr || nc != b_nc) - { - gripe_nonconformant ("operator .^", nr, nc, b_nr, b_nc); - return octave_value (); - } - - FloatComplexMatrix result (nr, nc); - - for (octave_idx_type j = 0; j < nc; j++) - for (octave_idx_type i = 0; i < nr; i++) - { - octave_quit (); - result (i, j) = std::pow (a (i, j), b (i, j)); - } - - return result; -} - -// Safer pow functions that work elementwise for N-d arrays. -// -// op2 \ op1: s nd cs cnd -// +-- +---+---+----+----+ -// scalar | | * | 3 | * | 9 | -// +---+---+----+----+ -// N_d | 1 | 4 | 7 | 10 | -// +---+---+----+----+ -// complex_scalar | * | 5 | * | 11 | -// +---+---+----+----+ -// complex_N_d | 2 | 6 | 8 | 12 | -// +---+---+----+----+ -// -// * -> not needed. - -// FIXME -- these functions need to be fixed so that things -// like -// -// a = -1; b = [ 0, 0.5, 1 ]; r = a .^ b -// -// and -// -// a = -1; b = [ 0, 0.5, 1 ]; for i = 1:3, r(i) = a .^ b(i), end -// -// produce identical results. Also, it would be nice if -1^0.5 -// produced a pure imaginary result instead of a complex number with a -// small real part. But perhaps that's really a problem with the math -// library... - -// -*- 1 -*- -octave_value -elem_xpow (float a, const FloatNDArray& b) -{ - octave_value retval; - - if (a < 0.0 && ! b.all_integers ()) - { - FloatComplex atmp (a); - FloatComplexNDArray result (b.dims ()); - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - result(i) = std::pow (atmp, b(i)); - } - - retval = result; - } - else - { - FloatNDArray result (b.dims ()); - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - result (i) = std::pow (a, b(i)); - } - - retval = result; - } - - return retval; -} - -// -*- 2 -*- -octave_value -elem_xpow (float a, const FloatComplexNDArray& b) -{ - FloatComplexNDArray result (b.dims ()); - - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - result(i) = std::pow (a, b(i)); - } - - return result; -} - -// -*- 3 -*- -octave_value -elem_xpow (const FloatNDArray& a, float b) -{ - octave_value retval; - - if (! xisint (b)) - { - if (a.any_element_is_negative ()) - { - FloatComplexNDArray result (a.dims ()); - - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - - FloatComplex atmp (a (i)); - - result(i) = std::pow (atmp, b); - } - - retval = result; - } - else - { - FloatNDArray result (a.dims ()); - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - result(i) = std::pow (a(i), b); - } - - retval = result; - } - } - else - { - NoAlias result (a.dims ()); - - int ib = static_cast (b); - if (ib == 2) - { - for (octave_idx_type i = 0; i < a.length (); i++) - result(i) = a(i) * a(i); - } - else if (ib == 3) - { - for (octave_idx_type i = 0; i < a.length (); i++) - result(i) = a(i) * a(i) * a(i); - } - else if (ib == -1) - { - for (octave_idx_type i = 0; i < a.length (); i++) - result(i) = 1.0f / a(i); - } - else - { - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - result(i) = std::pow (a(i), ib); - } - } - - retval = result; - } - - return retval; -} - -// -*- 4 -*- -octave_value -elem_xpow (const FloatNDArray& a, const FloatNDArray& b) -{ - octave_value retval; - - dim_vector a_dims = a.dims (); - dim_vector b_dims = b.dims (); - - if (a_dims != b_dims) - { - if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) - { - //Potentially complex results - FloatNDArray xa = octave_value_extract (a); - FloatNDArray xb = octave_value_extract (b); - if (! xb.all_integers () && xa.any_element_is_negative ()) - return octave_value (bsxfun_pow (FloatComplexNDArray (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 (); - - bool convert_to_complex = false; - - for (octave_idx_type i = 0; i < len; i++) - { - octave_quit (); - float atmp = a(i); - float btmp = b(i); - if (atmp < 0.0 && static_cast (btmp) != btmp) - { - convert_to_complex = true; - goto done; - } - } - -done: - - if (convert_to_complex) - { - FloatComplexNDArray complex_result (a_dims); - - for (octave_idx_type i = 0; i < len; i++) - { - octave_quit (); - FloatComplex atmp (a(i)); - complex_result(i) = std::pow (atmp, b(i)); - } - - retval = complex_result; - } - else - { - FloatNDArray result (a_dims); - - for (octave_idx_type i = 0; i < len; i++) - { - octave_quit (); - result(i) = std::pow (a(i), b(i)); - } - - retval = result; - } - - return retval; -} - -// -*- 5 -*- -octave_value -elem_xpow (const FloatNDArray& a, const FloatComplex& b) -{ - FloatComplexNDArray result (a.dims ()); - - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - result(i) = std::pow (a(i), b); - } - - return result; -} - -// -*- 6 -*- -octave_value -elem_xpow (const FloatNDArray& a, const FloatComplexNDArray& b) -{ - dim_vector a_dims = a.dims (); - dim_vector b_dims = b.dims (); - - if (a_dims != b_dims) - { - if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) - { - return bsxfun_pow (a, b); - } - else - { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); - } - } - - FloatComplexNDArray result (a_dims); - - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - result(i) = std::pow (a(i), b(i)); - } - - return result; -} - -// -*- 7 -*- -octave_value -elem_xpow (const FloatComplex& a, const FloatNDArray& b) -{ - FloatComplexNDArray result (b.dims ()); - - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - float btmp = b(i); - if (xisint (btmp)) - result(i) = std::pow (a, static_cast (btmp)); - else - result(i) = std::pow (a, btmp); - } - - return result; -} - -// -*- 8 -*- -octave_value -elem_xpow (const FloatComplex& a, const FloatComplexNDArray& b) -{ - FloatComplexNDArray result (b.dims ()); - - for (octave_idx_type i = 0; i < b.length (); i++) - { - octave_quit (); - result(i) = std::pow (a, b(i)); - } - - return result; -} - -// -*- 9 -*- -octave_value -elem_xpow (const FloatComplexNDArray& a, float b) -{ - FloatComplexNDArray result (a.dims ()); - - if (xisint (b)) - { - if (b == -1) - { - for (octave_idx_type i = 0; i < a.length (); i++) - result.xelem (i) = 1.0f / a(i); - } - else - { - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - result(i) = std::pow (a(i), static_cast (b)); - } - } - } - else - { - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - result(i) = std::pow (a(i), b); - } - } - - return result; -} - -// -*- 10 -*- -octave_value -elem_xpow (const FloatComplexNDArray& a, const FloatNDArray& b) -{ - dim_vector a_dims = a.dims (); - dim_vector b_dims = b.dims (); - - if (a_dims != b_dims) - { - if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) - { - return bsxfun_pow (a, b); - } - else - { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); - } - } - - FloatComplexNDArray result (a_dims); - - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - float btmp = b(i); - if (xisint (btmp)) - result(i) = std::pow (a(i), static_cast (btmp)); - else - result(i) = std::pow (a(i), btmp); - } - - return result; -} - -// -*- 11 -*- -octave_value -elem_xpow (const FloatComplexNDArray& a, const FloatComplex& b) -{ - FloatComplexNDArray result (a.dims ()); - - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - result(i) = std::pow (a(i), b); - } - - return result; -} - -// -*- 12 -*- -octave_value -elem_xpow (const FloatComplexNDArray& a, const FloatComplexNDArray& b) -{ - dim_vector a_dims = a.dims (); - dim_vector b_dims = b.dims (); - - if (a_dims != b_dims) - { - if (is_valid_bsxfun ("operator .^", a_dims, b_dims)) - { - return bsxfun_pow (a, b); - } - else - { - gripe_nonconformant ("operator .^", a_dims, b_dims); - return octave_value (); - } - } - - FloatComplexNDArray result (a_dims); - - for (octave_idx_type i = 0; i < a.length (); i++) - { - octave_quit (); - result(i) = std::pow (a(i), b(i)); - } - - return result; -} diff -r a132d206a36a -r b9b6a310ad97 src/xpow.h --- a/src/xpow.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,158 +0,0 @@ -/* - -Copyright (C) 1993-2012 John W. Eaton - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -. - -*/ - -#if !defined (octave_xpow_h) -#define octave_xpow_h 1 - -#include "oct-cmplx.h" - -class Matrix; -class ComplexMatrix; -class FloatMatrix; -class FloatComplexMatrix; -class DiagMatrix; -class ComplexDiagMatrix; -class FloatDiagMatrix; -class FloatComplexDiagMatrix; -class PermMatrix; -class NDArray; -class FloatNDArray; -class ComplexNDArray; -class FloatComplexNDArray; -class octave_value; -class Range; - -extern OCTINTERP_API octave_value xpow (double a, double b); -extern OCTINTERP_API octave_value xpow (double a, const Matrix& b); -extern OCTINTERP_API octave_value xpow (double a, const Complex& b); -extern OCTINTERP_API octave_value xpow (double a, const ComplexMatrix& b); - -extern OCTINTERP_API octave_value xpow (const Matrix& a, double b); -extern OCTINTERP_API octave_value xpow (const Matrix& a, const Complex& b); - -extern OCTINTERP_API octave_value xpow (const DiagMatrix& a, double b); -extern OCTINTERP_API octave_value xpow (const DiagMatrix& a, const Complex& b); - -extern OCTINTERP_API octave_value xpow (const PermMatrix& a, double b); - -extern OCTINTERP_API octave_value xpow (const Complex& a, double b); -extern OCTINTERP_API octave_value xpow (const Complex& a, const Matrix& b); -extern OCTINTERP_API octave_value xpow (const Complex& a, const Complex& b); -extern OCTINTERP_API octave_value xpow (const Complex& a, const ComplexMatrix& b); - -extern OCTINTERP_API octave_value xpow (const ComplexMatrix& a, double b); -extern OCTINTERP_API octave_value xpow (const ComplexMatrix& a, const Complex& b); - -extern OCTINTERP_API octave_value xpow (const ComplexDiagMatrix& a, double b); -extern OCTINTERP_API octave_value xpow (const ComplexDiagMatrix& a, const Complex& b); - -extern OCTINTERP_API octave_value elem_xpow (double a, const Matrix& b); -extern OCTINTERP_API octave_value elem_xpow (double a, const ComplexMatrix& b); -extern OCTINTERP_API octave_value elem_xpow (double a, const Range& r); - -extern OCTINTERP_API octave_value elem_xpow (const Matrix& a, double b); -extern OCTINTERP_API octave_value elem_xpow (const Matrix& a, const Matrix& b); -extern OCTINTERP_API octave_value elem_xpow (const Matrix& a, const Complex& b); -extern OCTINTERP_API octave_value elem_xpow (const Matrix& a, const ComplexMatrix& b); - -extern OCTINTERP_API octave_value elem_xpow (const Complex& a, const Matrix& b); -extern OCTINTERP_API octave_value elem_xpow (const Complex& a, const ComplexMatrix& b); -extern OCTINTERP_API octave_value elem_xpow (const Complex& a, const Range& r); - -extern OCTINTERP_API octave_value elem_xpow (const ComplexMatrix& a, double b); -extern OCTINTERP_API octave_value elem_xpow (const ComplexMatrix& a, const Matrix& b); -extern OCTINTERP_API octave_value elem_xpow (const ComplexMatrix& a, const Complex& b); -extern OCTINTERP_API octave_value elem_xpow (const ComplexMatrix& a, const ComplexMatrix& b); - - -extern OCTINTERP_API octave_value elem_xpow (double a, const NDArray& b); -extern OCTINTERP_API octave_value elem_xpow (double a, const ComplexNDArray& b); - -extern OCTINTERP_API octave_value elem_xpow (const NDArray& a, double b); -extern OCTINTERP_API octave_value elem_xpow (const NDArray& a, const NDArray& b); -extern OCTINTERP_API octave_value elem_xpow (const NDArray& a, const Complex& b); -extern OCTINTERP_API octave_value elem_xpow (const NDArray& a, const ComplexNDArray& b); - -extern OCTINTERP_API octave_value elem_xpow (const Complex& a, const NDArray& b); -extern OCTINTERP_API octave_value elem_xpow (const Complex& a, const ComplexNDArray& b); - -extern OCTINTERP_API octave_value elem_xpow (const ComplexNDArray& a, double b); -extern OCTINTERP_API octave_value elem_xpow (const ComplexNDArray& a, const NDArray& b); -extern OCTINTERP_API octave_value elem_xpow (const ComplexNDArray& a, const Complex& b); -extern OCTINTERP_API octave_value elem_xpow (const ComplexNDArray& a, const ComplexNDArray& b); - -extern OCTINTERP_API octave_value xpow (float a, float b); -extern OCTINTERP_API octave_value xpow (float a, const FloatMatrix& b); -extern OCTINTERP_API octave_value xpow (float a, const FloatComplex& b); -extern OCTINTERP_API octave_value xpow (float a, const FloatComplexMatrix& b); - -extern OCTINTERP_API octave_value xpow (const FloatMatrix& a, float b); -extern OCTINTERP_API octave_value xpow (const FloatMatrix& a, const FloatComplex& b); - -extern OCTINTERP_API octave_value xpow (const FloatDiagMatrix& a, float b); -extern OCTINTERP_API octave_value xpow (const FloatDiagMatrix& a, const FloatComplex& b); - -extern OCTINTERP_API octave_value xpow (const FloatComplex& a, float b); -extern OCTINTERP_API octave_value xpow (const FloatComplex& a, const FloatMatrix& b); -extern OCTINTERP_API octave_value xpow (const FloatComplex& a, const FloatComplex& b); -extern OCTINTERP_API octave_value xpow (const FloatComplex& a, const FloatComplexMatrix& b); - -extern OCTINTERP_API octave_value xpow (const FloatComplexMatrix& a, float b); -extern OCTINTERP_API octave_value xpow (const FloatComplexMatrix& a, const FloatComplex& b); - -extern OCTINTERP_API octave_value xpow (const FloatComplexDiagMatrix& a, float b); -extern OCTINTERP_API octave_value xpow (const FloatComplexDiagMatrix& a, const FloatComplex& b); - -extern OCTINTERP_API octave_value elem_xpow (float a, const FloatMatrix& b); -extern OCTINTERP_API octave_value elem_xpow (float a, const FloatComplexMatrix& b); - -extern OCTINTERP_API octave_value elem_xpow (const FloatMatrix& a, float b); -extern OCTINTERP_API octave_value elem_xpow (const FloatMatrix& a, const FloatMatrix& b); -extern OCTINTERP_API octave_value elem_xpow (const FloatMatrix& a, const FloatComplex& b); -extern OCTINTERP_API octave_value elem_xpow (const FloatMatrix& a, const FloatComplexMatrix& b); - -extern OCTINTERP_API octave_value elem_xpow (const FloatComplex& a, const FloatMatrix& b); -extern OCTINTERP_API octave_value elem_xpow (const FloatComplex& a, const FloatComplexMatrix& b); - -extern OCTINTERP_API octave_value elem_xpow (const FloatComplexMatrix& a, float b); -extern OCTINTERP_API octave_value elem_xpow (const FloatComplexMatrix& a, const FloatMatrix& b); -extern OCTINTERP_API octave_value elem_xpow (const FloatComplexMatrix& a, const FloatComplex& b); -extern OCTINTERP_API octave_value elem_xpow (const FloatComplexMatrix& a, const FloatComplexMatrix& b); - - -extern OCTINTERP_API octave_value elem_xpow (float a, const FloatNDArray& b); -extern OCTINTERP_API octave_value elem_xpow (float a, const FloatComplexNDArray& b); - -extern OCTINTERP_API octave_value elem_xpow (const FloatNDArray& a, float b); -extern OCTINTERP_API octave_value elem_xpow (const FloatNDArray& a, const FloatNDArray& b); -extern OCTINTERP_API octave_value elem_xpow (const FloatNDArray& a, const FloatComplex& b); -extern OCTINTERP_API octave_value elem_xpow (const FloatNDArray& a, const FloatComplexNDArray& b); - -extern OCTINTERP_API octave_value elem_xpow (const FloatComplex& a, const FloatNDArray& b); -extern OCTINTERP_API octave_value elem_xpow (const FloatComplex& a, const FloatComplexNDArray& b); - -extern OCTINTERP_API octave_value elem_xpow (const FloatComplexNDArray& a, float b); -extern OCTINTERP_API octave_value elem_xpow (const FloatComplexNDArray& a, const FloatNDArray& b); -extern OCTINTERP_API octave_value elem_xpow (const FloatComplexNDArray& a, const FloatComplex& b); -extern OCTINTERP_API octave_value elem_xpow (const FloatComplexNDArray& a, const FloatComplexNDArray& b); - -#endif diff -r a132d206a36a -r b9b6a310ad97 src/zfstream.cc --- a/src/zfstream.cc Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,625 +0,0 @@ -/* - -Copyright (C) 2005-2012 Ludwig Schwardt, Kevin Ruland - - -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 -. - -*/ - -/* - - This file is adapted from the zlib 1.2.2 contrib/iostream3 code, - written by - - Ludwig Schwardt - original version by Kevin Ruland - -*/ - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -#include "zfstream.h" - -#ifdef HAVE_ZLIB - -#include // for strcpy, strcat, strlen (mode strings) -#include // for BUFSIZ - -// Internal buffer sizes (default and "unbuffered" versions) -#define STASHED_CHARACTERS 16 -#define BIGBUFSIZE (256 * 1024 + STASHED_CHARACTERS) -#define SMALLBUFSIZE 1 - -/*****************************************************************************/ - -// Default constructor -gzfilebuf::gzfilebuf () -: file(0), io_mode(std::ios_base::openmode(0)), own_fd(false), - buffer(0), buffer_size(BIGBUFSIZE), own_buffer(true) -{ - // No buffers to start with - this->disable_buffer (); -} - -// Destructor -gzfilebuf::~gzfilebuf () -{ - // Sync output buffer and close only if responsible for file - // (i.e. attached streams should be left open at this stage) - this->sync (); - if (own_fd) - this->close (); - // Make sure internal buffer is deallocated - this->disable_buffer (); -} - -// Set compression level and strategy -int -gzfilebuf::setcompression (int comp_level, - int comp_strategy) -{ - return gzsetparams (file, comp_level, comp_strategy); -} - -// Open gzipped file -gzfilebuf* -gzfilebuf::open (const char *name, - std::ios_base::openmode mode) -{ - // Fail if file already open - if (this->is_open ()) - return 0; - // Don't support simultaneous read/write access (yet) - if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) - return 0; - - // Build mode string for gzopen and check it [27.8.1.3.2] - char char_mode[6] = "\0\0\0\0\0"; - if (! this->open_mode (mode, char_mode)) - return 0; - - // Attempt to open file - if ((file = gzopen (name, char_mode)) == 0) - return 0; - - // On success, allocate internal buffer and set flags - this->enable_buffer (); - io_mode = mode; - own_fd = true; - return this; -} - -// Attach to gzipped file -gzfilebuf* -gzfilebuf::attach (int fd, - std::ios_base::openmode mode) -{ - // Fail if file already open - if (this->is_open ()) - return 0; - // Don't support simultaneous read/write access (yet) - if ((mode & std::ios_base::in) && (mode & std::ios_base::out)) - return 0; - - // Build mode string for gzdopen and check it [27.8.1.3.2] - char char_mode[6] = "\0\0\0\0\0"; - if (! this->open_mode (mode, char_mode)) - return 0; - - // Attempt to attach to file - if ((file = gzdopen (fd, char_mode)) == 0) - return 0; - - // On success, allocate internal buffer and set flags - this->enable_buffer (); - io_mode = mode; - own_fd = false; - return this; -} - -// Close gzipped file -gzfilebuf* -gzfilebuf::close () -{ - // Fail immediately if no file is open - if (! this->is_open ()) - return 0; - // Assume success - gzfilebuf* retval = this; - // Attempt to sync and close gzipped file - if (this->sync () == -1) - retval = 0; - if (gzclose (file) < 0) - retval = 0; - // File is now gone anyway (postcondition [27.8.1.3.8]) - file = 0; - own_fd = false; - // Destroy internal buffer if it exists - this->disable_buffer (); - return retval; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -// Convert int open mode to mode string -bool -gzfilebuf::open_mode (std::ios_base::openmode mode, - char* c_mode) const -{ - // FIXME -- do we need testb? - // bool testb = mode & std::ios_base::binary; - bool testi = mode & std::ios_base::in; - bool testo = mode & std::ios_base::out; - bool testt = mode & std::ios_base::trunc; - bool testa = mode & std::ios_base::app; - - // Check for valid flag combinations - see [27.8.1.3.2] (Table 92) - // Original zfstream hardcoded the compression level to maximum here... - // Double the time for less than 1% size improvement seems - // excessive though - keeping it at the default level - // To change back, just append "9" to the next three mode strings - if (!testi && testo && !testt && !testa) - strcpy (c_mode, "w"); - if (!testi && testo && !testt && testa) - strcpy (c_mode, "a"); - if (!testi && testo && testt && !testa) - strcpy (c_mode, "w"); - if (testi && !testo && !testt && !testa) - strcpy (c_mode, "r"); - // No read/write mode yet -// if (testi && testo && !testt && !testa) -// strcpy(c_mode, "r+"); -// if (testi && testo && testt && !testa) -// strcpy(c_mode, "w+"); - - // Mode string should be empty for invalid combination of flags - if (strlen (c_mode) == 0) - return false; - - strcat (c_mode, "b"); - - return true; -} - -// Determine number of characters in internal get buffer -std::streamsize -gzfilebuf::showmanyc () -{ - // Calls to underflow will fail if file not opened for reading - if (! this->is_open () || !(io_mode & std::ios_base::in)) - return -1; - // Make sure get area is in use - if (this->gptr () && (this->gptr () < this->egptr ())) - return std::streamsize (this->egptr () - this->gptr ()); - else - return 0; -} - -// Puts back a character to the stream in two cases. Firstly, when there -// is no putback position available, and secondly when the character putback -// differs from the one in the file. We can only support the first case -// with gzipped files. -gzfilebuf::int_type -gzfilebuf::pbackfail (gzfilebuf::int_type c) -{ - if (this->is_open ()) - { - if (gzseek (file, this->gptr () - this->egptr () - 1, SEEK_CUR) < 0) - return traits_type::eof (); - - // Invalidates contents of the buffer - enable_buffer (); - - // Attempt to fill internal buffer from gzipped file - // (buffer must be guaranteed to exist...) - int bytes_read = gzread (file, buffer, buffer_size); - // Indicates error or EOF - if (bytes_read <= 0) - { - // Reset get area - this->setg (buffer, buffer, buffer); - return traits_type::eof (); - } - - // Make all bytes read from file available as get area - this->setg (buffer, buffer, buffer + bytes_read); - - // If next character in get area differs from putback character - // flag a failure - gzfilebuf::int_type ret = traits_type::to_int_type (*(this->gptr ())); - if (ret != c) - return traits_type::eof (); - else - return ret; - } - else - return traits_type::eof (); -} - -// Fill get area from gzipped file -gzfilebuf::int_type -gzfilebuf::underflow () -{ - // If something is left in the get area by chance, return it - // (this shouldn't normally happen, as underflow is only supposed - // to be called when gptr >= egptr, but it serves as error check) - if (this->gptr () && (this->gptr () < this->egptr ())) - return traits_type::to_int_type (*(this->gptr ())); - - // If the file hasn't been opened for reading, produce error - if (! this->is_open () || !(io_mode & std::ios_base::in)) - return traits_type::eof (); - - // Copy the final characters to the front of the buffer - int stash = 0; - if (this->eback () && buffer && buffer_size > STASHED_CHARACTERS) - { - char_type *ptr1 = buffer; - char_type *ptr2 = this->egptr () - STASHED_CHARACTERS + 1; - if (ptr2 > this->eback ()) - while (stash++ <= STASHED_CHARACTERS) - *ptr1++ = *ptr2++; - } - - // Attempt to fill internal buffer from gzipped file - // (buffer must be guaranteed to exist...) - int bytes_read = gzread (file, buffer + stash, buffer_size - stash); - - // Indicates error or EOF - if (bytes_read <= 0) - { - // Reset get area - this->setg (buffer, buffer, buffer); - return traits_type::eof (); - } - // Make all bytes read from file plus the stash available as get area - this->setg (buffer, buffer + stash, buffer + bytes_read + stash); - - // Return next character in get area - return traits_type::to_int_type (*(this->gptr ())); -} - -// Write put area to gzipped file -gzfilebuf::int_type -gzfilebuf::overflow (int_type c) -{ - // Determine whether put area is in use - if (this->pbase ()) - { - // Double-check pointer range - if (this->pptr () > this->epptr () || this->pptr () < this->pbase ()) - return traits_type::eof (); - // Add extra character to buffer if not EOF - if (! traits_type::eq_int_type (c, traits_type::eof ())) - { - *(this->pptr ()) = traits_type::to_char_type (c); - this->pbump (1); - } - // Number of characters to write to file - int bytes_to_write = this->pptr () - this->pbase (); - // Overflow doesn't fail if nothing is to be written - if (bytes_to_write > 0) - { - // If the file hasn't been opened for writing, produce error - if (! this->is_open () || !(io_mode & std::ios_base::out)) - return traits_type::eof (); - // If gzipped file won't accept all bytes written to it, fail - if (gzwrite (file, this->pbase (), bytes_to_write) != bytes_to_write) - return traits_type::eof (); - // Reset next pointer to point to pbase on success - this->pbump (-bytes_to_write); - } - } - // Write extra character to file if not EOF - else if (! traits_type::eq_int_type (c, traits_type::eof ())) - { - // If the file hasn't been opened for writing, produce error - if (! this->is_open () || !(io_mode & std::ios_base::out)) - return traits_type::eof (); - // Impromptu char buffer (allows "unbuffered" output) - char_type last_char = traits_type::to_char_type (c); - // If gzipped file won't accept this character, fail - if (gzwrite (file, &last_char, 1) != 1) - return traits_type::eof (); - } - - // If you got here, you have succeeded (even if c was EOF) - // The return value should therefore be non-EOF - if (traits_type::eq_int_type (c, traits_type::eof ())) - return traits_type::not_eof (c); - else - return c; -} - -// Assign new buffer -std::streambuf* -gzfilebuf::setbuf (char_type* p, - std::streamsize n) -{ - // First make sure stuff is sync'ed, for safety - if (this->sync () == -1) - return 0; - // If buffering is turned off on purpose via setbuf(0,0), still allocate one... - // "Unbuffered" only really refers to put [27.8.1.4.10], while get needs at - // least a buffer of size 1 (very inefficient though, therefore make it bigger?) - // This follows from [27.5.2.4.3]/12 (gptr needs to point at something, it seems) - if (!p || !n) - { - // Replace existing buffer (if any) with small internal buffer - this->disable_buffer (); - buffer = 0; - buffer_size = 0; - own_buffer = true; - this->enable_buffer (); - } - else - { - // Replace existing buffer (if any) with external buffer - this->disable_buffer (); - buffer = p; - buffer_size = n; - own_buffer = false; - this->enable_buffer (); - } - return this; -} - -// Write put area to gzipped file (i.e. ensures that put area is empty) -int -gzfilebuf::sync () -{ - return traits_type::eq_int_type (this->overflow (), traits_type::eof ()) ? -1 : 0; -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -// Allocate internal buffer -void -gzfilebuf::enable_buffer () -{ - // If internal buffer required, allocate one - if (own_buffer && !buffer) - { - // Check for buffered vs. "unbuffered" - if (buffer_size > 0) - { - // Allocate internal buffer - buffer = new char_type [buffer_size]; - // Get area starts empty and will be expanded by underflow as need arises - this->setg (buffer, buffer, buffer); - // Setup entire internal buffer as put area. - // The one-past-end pointer actually points to the last element of the buffer, - // so that overflow(c) can safely add the extra character c to the sequence. - // These pointers remain in place for the duration of the buffer - this->setp (buffer, buffer + buffer_size - 1); - } - else - { - // Even in "unbuffered" case, (small?) get buffer is still required - buffer_size = SMALLBUFSIZE; - buffer = new char_type [buffer_size]; - this->setg (buffer, buffer, buffer); - // "Unbuffered" means no put buffer - this->setp (0, 0); - } - } - else - { - // If buffer already allocated, reset buffer pointers just to make sure no - // stale chars are lying around - this->setg (buffer, buffer, buffer); - this->setp (buffer, buffer + buffer_size - 1); - } -} - -// Destroy internal buffer -void -gzfilebuf::disable_buffer () -{ - // If internal buffer exists, deallocate it - if (own_buffer && buffer) - { - // Preserve unbuffered status by zeroing size - if (! this->pbase ()) - buffer_size = 0; - delete[] buffer; - buffer = 0; - this->setg (0, 0, 0); - this->setp (0, 0); - } - else - { - // Reset buffer pointers to initial state if external buffer exists - this->setg (buffer, buffer, buffer); - if (buffer) - this->setp (buffer, buffer + buffer_size - 1); - else - this->setp (0, 0); - } -} - -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - -// Seek functions -gzfilebuf::pos_type -gzfilebuf::seekoff (off_type off, std::ios_base::seekdir way, - std::ios_base::openmode) -{ - pos_type ret = pos_type (off_type (-1)); - - if (this->is_open ()) - { - off_type computed_off = off; - - if ((io_mode & std::ios_base::in) && way == std::ios_base::cur) - computed_off += this->gptr () - this->egptr (); - - if (way == std::ios_base::beg) - ret = pos_type (gzseek (file, computed_off, SEEK_SET)); - else if (way == std::ios_base::cur) - ret = pos_type (gzseek (file, computed_off, SEEK_CUR)); - else - // Can't seek from end of a gzipped file, so this will give -1 - ret = pos_type (gzseek (file, computed_off, SEEK_END)); - - if (io_mode & std::ios_base::in) - // Invalidates contents of the buffer - enable_buffer (); - else - // flush contents of buffer to file - overflow (); - } - - return ret; -} - -gzfilebuf::pos_type -gzfilebuf::seekpos (pos_type sp, std::ios_base::openmode) -{ - pos_type ret = pos_type (off_type (-1)); - - if (this->is_open ()) - { - ret = pos_type (gzseek (file, sp, SEEK_SET)); - - if (io_mode & std::ios_base::in) - // Invalidates contents of the buffer - enable_buffer (); - else - // flush contents of buffer to file - overflow (); - } - - return ret; -} - -/*****************************************************************************/ - -// Default constructor initializes stream buffer -gzifstream::gzifstream () -: std::istream (0), sb () -{ this->init (&sb); } - -// Initialize stream buffer and open file -gzifstream::gzifstream (const char* name, - std::ios_base::openmode mode) -: std::istream (0), sb () -{ - this->init (&sb); - this->open (name, mode); -} - -// Initialize stream buffer and attach to file -gzifstream::gzifstream (int fd, - std::ios_base::openmode mode) -: std::istream (0), sb () -{ - this->init (&sb); - this->attach (fd, mode); -} - -// Open file and go into fail() state if unsuccessful -void -gzifstream::open (const char* name, - std::ios_base::openmode mode) -{ - if (! sb.open (name, mode | std::ios_base::in)) - this->setstate (std::ios_base::failbit); - else - this->clear (); -} - -// Attach to file and go into fail() state if unsuccessful -void -gzifstream::attach (int fd, - std::ios_base::openmode mode) -{ - if (! sb.attach (fd, mode | std::ios_base::in)) - this->setstate (std::ios_base::failbit); - else - this->clear (); -} - -// Close file -void -gzifstream::close () -{ - if (! sb.close ()) - this->setstate (std::ios_base::failbit); -} - -/*****************************************************************************/ - -// Default constructor initializes stream buffer -gzofstream::gzofstream () -: std::ostream (0), sb () -{ this->init (&sb); } - -// Initialize stream buffer and open file -gzofstream::gzofstream (const char* name, - std::ios_base::openmode mode) -: std::ostream (0), sb () -{ - this->init (&sb); - this->open (name, mode); -} - -// Initialize stream buffer and attach to file -gzofstream::gzofstream (int fd, - std::ios_base::openmode mode) -: std::ostream (0), sb () -{ - this->init (&sb); - this->attach (fd, mode); -} - -// Open file and go into fail() state if unsuccessful -void -gzofstream::open (const char* name, - std::ios_base::openmode mode) -{ - if (! sb.open (name, mode | std::ios_base::out)) - this->setstate (std::ios_base::failbit); - else - this->clear (); -} - -// Attach to file and go into fail() state if unsuccessful -void -gzofstream::attach (int fd, - std::ios_base::openmode mode) -{ - if (! sb.attach (fd, mode | std::ios_base::out)) - this->setstate (std::ios_base::failbit); - else - this->clear (); -} - -// Close file -void -gzofstream::close () -{ - if (! sb.close ()) - this->setstate (std::ios_base::failbit); -} - -#endif // HAVE_ZLIB diff -r a132d206a36a -r b9b6a310ad97 src/zfstream.h --- a/src/zfstream.h Fri Aug 03 14:59:40 2012 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,515 +0,0 @@ -/* - -Copyright (C) 2005-2012 Ludwig Schwardt, Kevin Ruland - -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 -. - -*/ - -/* - - This file is adapted from the zlib 1.2.2 contrib/iostream3 code, - written by - - Ludwig Schwardt - original version by Kevin Ruland - -*/ - -#ifndef ZFSTREAM_H -#define ZFSTREAM_H - -#ifdef HAVE_ZLIB - -#include - -#include "zlib.h" - -/*****************************************************************************/ - -/** - * @brief Gzipped file stream buffer class. - * - * This class implements basic_filebuf for gzipped files. It doesn't yet support - * seeking (allowed by zlib but slow/limited), putback and read/write access - * (tricky). Otherwise, it attempts to be a drop-in replacement for the standard - * file streambuf. -*/ -class gzfilebuf : public std::streambuf -{ -public: - // Default constructor. - gzfilebuf (); - - // Destructor. - virtual - ~gzfilebuf (); - - /** - * @brief Set compression level and strategy on the fly. - * @param comp_level Compression level (see zlib.h for allowed values) - * @param comp_strategy Compression strategy (see zlib.h for allowed values) - * @return Z_OK on success, Z_STREAM_ERROR otherwise. - * - * Unfortunately, these parameters cannot be modified separately, as the - * previous zfstream version assumed. Since the strategy is seldom changed, - * it can default and setcompression(level) then becomes like the old - * setcompressionlevel(level). - */ - int - setcompression (int comp_level, - int comp_strategy = Z_DEFAULT_STRATEGY); - - /** - * @brief Check if file is open. - * @return True if file is open. - */ - bool - is_open () const { return (file != 0); } - - /** - * @brief Open gzipped file. - * @param name File name. - * @param mode Open mode flags. - * @return @c this on success, NULL on failure. - */ - gzfilebuf* - open (const char* name, - std::ios_base::openmode mode); - - /** - * @brief Attach to already open gzipped file. - * @param fd File descriptor. - * @param mode Open mode flags. - * @return @c this on success, NULL on failure. - */ - gzfilebuf* - attach (int fd, - std::ios_base::openmode mode); - - /** - * @brief Close gzipped file. - * @return @c this on success, NULL on failure. - */ - gzfilebuf* - close (); - -protected: - /** - * @brief Convert ios open mode int to mode string used by zlib. - * @return True if valid mode flag combination. - */ - bool - open_mode (std::ios_base::openmode mode, - char* c_mode) const; - - /** - * @brief Number of characters available in stream buffer. - * @return Number of characters. - * - * This indicates number of characters in get area of stream buffer. - * These characters can be read without accessing the gzipped file. - */ - virtual std::streamsize - showmanyc (); - - /** - * @brief Fill get area from gzipped file. - * @return First character in get area on success, EOF on error. - * - * This actually reads characters from gzipped file to stream - * buffer. Always buffered. - */ - virtual int_type - underflow (); - - /** - * @brief Write put area to gzipped file. - * @param c Extra character to add to buffer contents. - * @return Non-EOF on success, EOF on error. - * - * This actually writes characters in stream buffer to - * gzipped file. With unbuffered output this is done one - * character at a time. - */ - virtual int_type - overflow (int_type c = traits_type::eof ()); - - /** - * @brief Installs external stream buffer. - * @param p Pointer to char buffer. - * @param n Size of external buffer. - * @return @c this on success, NULL on failure. - * - * Call setbuf(0,0) to enable unbuffered output. - */ - virtual std::streambuf* - setbuf (char_type* p, - std::streamsize n); - - /** - * @brief Flush stream buffer to file. - * @return 0 on success, -1 on error. - * - * This calls underflow(EOF) to do the job. - */ - virtual int - sync (); - - /** - * @brief Alters the stream positions. - * - * Each derived class provides its own appropriate behavior. - */ - virtual pos_type - seekoff (off_type off, std::ios_base::seekdir way, - std::ios_base::openmode mode = - std::ios_base::in|std::ios_base::out); - - /** - * @brief Alters the stream positions. - * - * Each derived class provides its own appropriate behavior. - */ - virtual pos_type - seekpos (pos_type sp, std::ios_base::openmode mode = - std::ios_base::in|std::ios_base::out); - - virtual int_type - pbackfail (int_type c = traits_type::eof ()); - -// -// Some future enhancements -// -// virtual int_type uflow(); -// virtual int_type pbackfail(int_type c = traits_type::eof()); - -private: - - // No copying! - - gzfilebuf (const gzfilebuf&); - - gzfilebuf& operator = (const gzfilebuf&); - - /** - * @brief Allocate internal buffer. - * - * This function is safe to call multiple times. It will ensure - * that a proper internal buffer exists if it is required. If the - * buffer already exists or is external, the buffer pointers will be - * reset to their original state. - */ - void - enable_buffer (); - - /** - * @brief Destroy internal buffer. - * - * This function is safe to call multiple times. It will ensure - * that the internal buffer is deallocated if it exists. In any - * case, it will also reset the buffer pointers. - */ - void - disable_buffer (); - - /** - * Underlying file pointer. - */ - gzFile file; - - /** - * Mode in which file was opened. - */ - std::ios_base::openmode io_mode; - - /** - * @brief True if this object owns file descriptor. - * - * This makes the class responsible for closing the file - * upon destruction. - */ - bool own_fd; - - /** - * @brief Stream buffer. - * - * For simplicity this remains allocated on the free store for the - * entire life span of the gzfilebuf object, unless replaced by setbuf. - */ - char_type* buffer; - - /** - * @brief Stream buffer size. - * - * Defaults to system default buffer size (typically 8192 bytes). - * Modified by setbuf. - */ - std::streamsize buffer_size; - - /** - * @brief True if this object owns stream buffer. - * - * This makes the class responsible for deleting the buffer - * upon destruction. - */ - bool own_buffer; -}; - -/*****************************************************************************/ - -/** - * @brief Gzipped file input stream class. - * - * This class implements ifstream for gzipped files. Seeking and putback - * is not supported yet. -*/ -class gzifstream : public std::istream -{ -public: - // Default constructor - gzifstream (); - - /** - * @brief Construct stream on gzipped file to be opened. - * @param name File name. - * @param mode Open mode flags (forced to contain ios::in). - */ - explicit - gzifstream (const char* name, - std::ios_base::openmode mode = std::ios_base::in); - - /** - * @brief Construct stream on already open gzipped file. - * @param fd File descriptor. - * @param mode Open mode flags (forced to contain ios::in). - */ - explicit - gzifstream (int fd, - std::ios_base::openmode mode = std::ios_base::in); - - /** - * Obtain underlying stream buffer. - */ - gzfilebuf* - rdbuf () const - { return const_cast(&sb); } - - /** - * @brief Check if file is open. - * @return True if file is open. - */ - bool - is_open () { return sb.is_open (); } - - /** - * @brief Open gzipped file. - * @param name File name. - * @param mode Open mode flags (forced to contain ios::in). - * - * Stream will be in state good() if file opens successfully; - * otherwise in state fail(). This differs from the behavior of - * ifstream, which never sets the state to good() and therefore - * won't allow you to reuse the stream for a second file unless - * you manually clear() the state. The choice is a matter of - * convenience. - */ - void - open (const char* name, - std::ios_base::openmode mode = std::ios_base::in); - - /** - * @brief Attach to already open gzipped file. - * @param fd File descriptor. - * @param mode Open mode flags (forced to contain ios::in). - * - * Stream will be in state good() if attach succeeded; otherwise - * in state fail(). - */ - void - attach (int fd, - std::ios_base::openmode mode = std::ios_base::in); - - /** - * @brief Close gzipped file. - * - * Stream will be in state fail() if close failed. - */ - void - close (); - -private: - /** - * Underlying stream buffer. - */ - gzfilebuf sb; -}; - -/*****************************************************************************/ - -/** - * @brief Gzipped file output stream class. - * - * This class implements ofstream for gzipped files. Seeking and putback - * is not supported yet. -*/ -class gzofstream : public std::ostream -{ -public: - // Default constructor - gzofstream (); - - /** - * @brief Construct stream on gzipped file to be opened. - * @param name File name. - * @param mode Open mode flags (forced to contain ios::out). - */ - explicit - gzofstream (const char* name, - std::ios_base::openmode mode = std::ios_base::out); - - /** - * @brief Construct stream on already open gzipped file. - * @param fd File descriptor. - * @param mode Open mode flags (forced to contain ios::out). - */ - explicit - gzofstream (int fd, - std::ios_base::openmode mode = std::ios_base::out); - - /** - * Obtain underlying stream buffer. - */ - gzfilebuf* - rdbuf () const - { return const_cast(&sb); } - - /** - * @brief Check if file is open. - * @return True if file is open. - */ - bool - is_open () { return sb.is_open (); } - - /** - * @brief Open gzipped file. - * @param name File name. - * @param mode Open mode flags (forced to contain ios::out). - * - * Stream will be in state good() if file opens successfully; - * otherwise in state fail(). This differs from the behavior of - * ofstream, which never sets the state to good() and therefore - * won't allow you to reuse the stream for a second file unless - * you manually clear() the state. The choice is a matter of - * convenience. - */ - void - open (const char* name, - std::ios_base::openmode mode = std::ios_base::out); - - /** - * @brief Attach to already open gzipped file. - * @param fd File descriptor. - * @param mode Open mode flags (forced to contain ios::out). - * - * Stream will be in state good() if attach succeeded; otherwise - * in state fail(). - */ - void - attach (int fd, - std::ios_base::openmode mode = std::ios_base::out); - - /** - * @brief Close gzipped file. - * - * Stream will be in state fail() if close failed. - */ - void - close (); - -private: - /** - * Underlying stream buffer. - */ - gzfilebuf sb; -}; - -/*****************************************************************************/ - -/** - * @brief Gzipped file output stream manipulator class. - * - * This class defines a two-argument manipulator for gzofstream. It is used - * as base for the setcompression(int,int) manipulator. -*/ -template - class gzomanip2 - { - public: - // Allows insertor to peek at internals - template - friend gzofstream& - operator<<(gzofstream&, - const gzomanip2&); - - // Constructor - gzomanip2 (gzofstream& (*f)(gzofstream&, T1, T2), - T1 v1, - T2 v2); - private: - // Underlying manipulator function - gzofstream& - (*func)(gzofstream&, T1, T2); - - // Arguments for manipulator function - T1 val1; - T2 val2; - }; - -/*****************************************************************************/ - -// Manipulator function thunks through to stream buffer -inline gzofstream& -setcompression (gzofstream &gzs, int l, int s = Z_DEFAULT_STRATEGY) -{ - (gzs.rdbuf ())->setcompression (l, s); - return gzs; -} - -// Manipulator constructor stores arguments -template - inline - gzomanip2::gzomanip2 (gzofstream &(*f)(gzofstream &, T1, T2), - T1 v1, - T2 v2) - : func(f), val1(v1), val2(v2) - { } - -// Insertor applies underlying manipulator function to stream -template - inline gzofstream& - operator<<(gzofstream& s, const gzomanip2& m) - { return (*m.func)(s, m.val1, m.val2); } - -// Insert this onto stream to simplify setting of compression level -inline gzomanip2 -setcompression (int l, int s = Z_DEFAULT_STRATEGY) -{ return gzomanip2(&setcompression, l, s); } - -#endif // HAVE_ZLIB - -#endif // ZFSTREAM_H