1 /*
2  * MBDyn (C) is a multibody analysis code.
3  * http://www.mbdyn.org
4  *
5  * Copyright (C) 1996-2017
6  *
7  * Pierangelo Masarati	<masarati@aero.polimi.it>
8  * Paolo Mantegazza	<mantegazza@aero.polimi.it>
9  *
10  * Dipartimento di Ingegneria Aerospaziale - Politecnico di Milano
11  * via La Masa, 34 - 20156 Milano, Italy
12  * http://www.aero.polimi.it
13  *
14  * Changing this copyright notice is forbidden.
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation (version 2 of the License).
19  *
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29  */
30 
31 /*
32  AUTHOR: Reinhard Resch <r.resch@secop.com>
33         Copyright (C) 2011(-2017) all rights reserved.
34 
35         The copyright of this code is transferred
36         to Pierangelo Masarati and Paolo Mantegazza
37         for use in the software MBDyn as described
38         in the GNU Public License version 2.1
39 */
40 
41 #include <mbconfig.h>
42 
43 #ifdef USE_OCTAVE
44 
45 #include <octave/oct.h>
46 #include <octave/parse.h>
47 #include <octave/dynamic-ld.h>
48 #include <octave/oct-map.h>
49 #include <octave/oct-stream.h>
50 #include <octave/ov-base-scalar.h>
51 
52 #include <iostream>
53 
54 using namespace std;
55 
56 #include "octave_object.h"
57 
58 namespace oct {
59 
lookup_method(const std::string & method_name) const60 octave_object::method_function* octave_object::class_object::lookup_method(const std::string& method_name)const
61 {
62 	typedef method_table_t::const_iterator iter_t;
63 
64 	iter_t p = method_table.find(method_name);
65 
66 	if ( p != method_table.end() )
67 		return p->second;
68 
69 	if ( parent_object != NULL )
70 	{
71 		return parent_object->lookup_method(method_name);
72 	}
73 	else
74 	{
75 		cerr << "octave_object::class_object::lookup_method(\"" << method_name << "\") failed!" << endl;
76 		const class_object* class_obj = this;
77 
78 		cerr << "dump of octave_object::class_object::method_table:" << endl;
79 
80 		while ( class_obj != NULL )
81 		{
82 			for ( iter_t p = class_obj->method_table.begin(); p != class_obj->method_table.end(); ++p )
83 				cerr << " " << p->first << "->" << p->second <<  endl;
84 			class_obj = class_obj->parent_object;
85 		}
86 	}
87 
88 	return NULL;
89 }
90 
91 octave_object::class_object octave_object::dispatch_class_object(NULL,NULL);
92 
octave_object()93 octave_object::octave_object()
94 {
95 
96 }
97 
~octave_object()98 octave_object::~octave_object()
99 {
100 
101 }
102 
any_arg_is_magic_colon(const octave_value_list & args)103 static bool any_arg_is_magic_colon (const octave_value_list& args)
104 {
105   int nargin = args.length ();
106 
107   for (int i = 0; i < nargin; i++)
108     if (args(i).is_magic_colon ())
109       return true;
110 
111   return false;
112 }
113 
114 #if TRACE_SUBSREF == 1
115 
print_args(const octave_value_list & args)116 static void print_args(const octave_value_list& args)
117 {
118   int nargin = args.length ();
119 
120   for (int i = 0; i < nargin; i++)
121   {
122     args(i).print(octave_stdout);
123 
124     if( i < nargin - 1 )
125     	octave_stdout << ',';
126   }
127 }
128 
129 #endif
130 
lookup_method(const std::string & method_name)131 octave_object::method_function* octave_object::lookup_method(const std::string& method_name)
132 {
133 	return get_class_object()->lookup_method(method_name);
134 }
135 
subsref(const std::string & type,const std::list<octave_value_list> & idx,int nargout)136 octave_value_list octave_object::subsref (const std::string& type,
137 		const std::list<octave_value_list>& idx,
138 		int nargout)
139 {
140 	#if TRACE_SUBSREF == 1
141 	{
142 		octave_stdout << endl;
143 		octave_stdout << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << endl;
144 		octave_stdout << "type=" << type << endl;
145 
146 		typedef std::list<octave_value_list>::const_iterator iter_t;
147 
148 		int i = 0;
149 
150 		for ( iter_t it = idx.begin(); it != idx.end(); ++it, ++i )
151 		{
152 			octave_stdout << "idx(" << i << ")=";
153 			print_args(*it);
154 			octave_stdout << endl;
155 		}
156 	}
157 	#endif
158 
159 	octave_value_list retval;
160 	size_t skip = 1;
161 
162 	if ( type.length() < 1 )
163 	{
164 		panic_impossible();
165 	}
166 
167 	const char operator_char = type[0];
168 
169 	switch( operator_char )
170 	{
171 	case '.':
172 	{
173 		octave_value_list method_name_list = idx.front();
174 
175 		if ( method_name_list.length () != 1 || !method_name_list(0).is_string() )
176 			panic_impossible();
177 
178 		const std::string method_name = method_name_list(0).string_value();
179 
180 		method_function *method_pfn = lookup_method(method_name);
181 
182 		if ( method_pfn == NULL )
183 		{
184 			error("octave_object: class \"%s\" has no member \"%s\"", class_name().c_str(), method_name.c_str());
185 			return retval;
186 		}
187 
188 		if ( idx.size() < 2 || type[1] != '(')
189 		{
190 			retval = (*method_pfn)(this,octave_value_list(),nargout);
191 		}
192 		else
193 		{
194 			skip = 2;
195 			std::list<octave_value_list>::const_iterator pidx = idx.begin();
196 			pidx++;
197 
198 			if (any_arg_is_magic_colon (*pidx))
199 			{
200 				error("octave object: invalid use of colon in method argument list");
201 				return retval;
202 			}
203 			else
204 			{
205 				retval = (*method_pfn)(this,*pidx,nargout);
206 			}
207 		}
208 	}
209 	break;
210 	case '(':
211 	{
212 		if (idx.size() < 1)
213 		{
214 			error("octave object: invalid number of indices");
215 			return retval;
216 		}
217 
218 		retval = (*this)(idx.front());
219 	}
220 	break;
221 	case '{':
222 	{
223 		std::string nm = type_name();
224 		error("%s cannot be indexed with %c", nm.c_str(), operator_char);
225 		return retval;
226 
227 	}
228 	break;
229 
230 	default:
231 		panic_impossible();
232 	}
233 
234 	if ( !error_state && idx.size() > skip )
235 	{
236 		retval = retval(0).next_subsref(type, idx, skip);
237 	}
238 
239 	return retval;
240 }
241 
operator ()(const octave_value_list & idx) const242 octave_value octave_object::operator()(const octave_value_list& idx) const
243 {
244 	std::string nm = type_name();
245 	error("%s cannot be indexed with %c", nm.c_str(), '(');
246 	return octave_value();
247 }
248 
subsref(const std::string & type,const std::list<octave_value_list> & idx)249 octave_value octave_object::subsref(const std::string& type,
250 	  	  	  	  	  	  	 const std::list<octave_value_list>& idx)
251 {
252 	octave_value_list ret_val = subsref(type,idx,1);
253 
254 	if ( ret_val.length() < 1 )
255 		return octave_value();
256 
257 	return ret_val(0);
258 }
259 
error(const char * fmt,...)260 void error(const char* fmt, ...)
261 {
262 	va_list va;
263 	va_start(va, fmt);
264 	::verror(fmt, va);
265 	va_end(va);
266 }
267 
268 } // namespace
269 
270 #endif // USE_OCTAVE
271