1 
2 /*
3  *  Math2
4  *  Copyright (c) 2003-2006 by Mattias Hultgren <mattias_hultgren@tele2.se>
5  *
6  *  See math2.h
7  */
8 
9 
10 #include "math2.h"
11 #include "keyfile.h"
12 #include <string.h>
13 #include <stdio.h>
14 #include <new>
15 
16 namespace math
17 {
18 
append_to_string(utf8_string & str,const Format & fmt,bool show_name) const19 void Variable::append_to_string( utf8_string &str, const Format &fmt, bool show_name ) const
20        throw(error_obj)
21 {
22 	utf8_string tmp_str;
23 
24 	try
25 	{
26 		if( has_name()  &&  show_name )
27 		{
28 			str.append( *get_name() );
29 			tmp_str = " = ";
30 			str.append( tmp_str );
31 		}
32 
33 		switch( get_type() )
34 		{
35 		case VariableType_Matrix:
36 			get_matrix()->append_to_string( str, fmt, (has_name()  &&  show_name) );
37 			break;
38 
39 		case VariableType_String:
40 			tmp_str = "\"";
41 			str.append( tmp_str );
42 			str.append( *get_string() );
43 			str.append( tmp_str );
44 			break;
45 
46 		case VariableType_Complex:
47 			get_complex()->append_to_string( str, fmt );
48 			break;
49 
50 		case VariableType_Picture:
51 			{
52 				const Picture *pic = get_picture();
53 				char tmp[100];
54 				snprintf( tmp, 100, "%s %ldx%ld", _("Picture"), pic->pic.get_width(),
55 				          pic->pic.get_height() );
56 				tmp_str = tmp;
57 				str.append( tmp_str );
58 			}
59 			break;
60 
61 		case VariableType_Array:
62 			{
63 				const Array *array = get_array();
64 
65 				if( array->get_size() > 0 )
66 				{
67 					tmp_str = "( ";
68 					str.append( tmp_str );
69 					if( array->get_variable(0)->get_type() == VariableType_Complex )
70 						array->get_variable(0)->get_complex()->append_to_string( str, fmt );
71 					else if( array->get_variable(0)->get_type() == VariableType_Boolean )
72 					{
73 						tmp_str = (array->get_variable(0)->get_boolean() ? "true" : "false");
74 						str.append( tmp_str );
75 					}
76 					else
77 					{
78 						tmp_str = VARIABLE_TYPE_NAMES[array->get_variable(0)->get_type()];
79 						str.append( tmp_str );
80 					}
81 				}
82 				else
83 				{
84 					tmp_str = "( ";
85 					str.append( tmp_str );
86 					tmp_str = _("Empty array");
87 					str.append( tmp_str );
88 				}
89 
90 				for( uint32 i=1; i<array->get_size(); i++ )
91 				{
92 					tmp_str = ", ";
93 					str.append( tmp_str );
94 					if( array->get_variable(i)->get_type() == VariableType_Complex )
95 						array->get_variable(i)->get_complex()->append_to_string( str, fmt );
96 					else if( array->get_variable(i)->get_type() == VariableType_Boolean )
97 					{
98 						tmp_str = (array->get_variable(i)->get_boolean() ? "true" : "false");
99 						str.append( tmp_str );
100 					}
101 					else
102 					{
103 						tmp_str = VARIABLE_TYPE_NAMES[array->get_variable(i)->get_type()];
104 						str.append( tmp_str );
105 					}
106 				}
107 
108 				tmp_str = " )";
109 				str.append( tmp_str );
110 			}
111 			break;
112 
113 		case VariableType_Boolean:
114 			tmp_str = (get_boolean() ? "true" : "false");
115 			str.append( tmp_str );
116 			break;
117 
118 		case VariableType_Void:
119 			str.append( "void" );
120 			break;
121 		}
122 	}
123 	catch(error_obj error) {  throw error;                 }
124 	catch(...)             {  THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") );  }
125 }
126 
127 
Variable()128 Variable::Variable()
129 {
130 	type = VariableType_Boolean;
131 
132 	isconstant = false;
133 	can_change_type = true;
134 
135 	inuse = false;
136 
137 	boolean = true;
138 
139 	change_func = 0;
140 	delete_func = 0;
141 }
Variable(const Variable & src)142 Variable::Variable(const Variable &src) throw(error_obj)
143 {
144 	type = VariableType_Boolean;
145 
146 	isconstant = false;
147 	can_change_type = true;
148 
149 	inuse = false;
150 
151 	boolean = true;
152 
153 	change_func = 0;
154 	delete_func = 0;
155 
156 	*this = src;
157 }
158 
~Variable()159 Variable::~Variable()
160 {
161 	if( delete_func != 0 )
162 		(*delete_func)(this);
163 	change_func = 0;
164 	isconstant = false;
165 	clear();
166 }
167 
168 // this function only copies the value/Matrix/function/list/string of the Variable
operator =(const Variable & src)169 void Variable::operator=(const Variable &src) throw(error_obj)
170 {
171 	if(&src == this)
172 		return;
173 
174 	switch(src.type)
175 	{
176 	case VariableType_Boolean:
177 		set_boolean(src.boolean);
178 		break;
179 
180 	case VariableType_Complex:
181 		set_complex( *Complex_ptr(src.complex_buf) );
182 		break;
183 
184 	case VariableType_Matrix:
185 		set_matrix(src.matr);
186 		break;
187 
188 	case VariableType_String:
189 		if(src.str == 0)
190 			set_string("");
191 		else
192 		{
193 			if(src.code_line != 0)
194 				set_code_line( src.str->c_str() );
195 			else
196 				set_string( *src.str );
197 		}
198 		break;
199 
200 	case VariableType_Array:
201 		set_array(src.array);
202 		break;
203 
204 	case VariableType_Picture:
205 		set_picture(src.pic);
206 		break;
207 
208 	case VariableType_Void:
209 		set_void();
210 		break;
211 
212 	default: // this should only occur when I've forgotten to add a curtain Variable-type to this function
213 		{
214 			char tmp_err[ERROR_OBJ_MSG_LEN];
215 			snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Data type is unsupported by '%s'"), "Variable::operator=" );
216 			THROW_ERROR( ErrorType_General, tmp_err );
217 		}
218 	}
219 }
220 
operator ==(const Variable & var) const221 bool Variable::operator==( const Variable &var ) const
222 {
223 	if( type != var.type )
224 		return false;
225 
226 	else if( type == VariableType_Complex )
227 		return (*get_complex() == *var.get_complex());
228 
229 	else if( type == VariableType_Boolean )
230 		return (get_boolean() == var.get_boolean());
231 
232 	else if( type == VariableType_Matrix )
233 		return (*get_matrix() == *var.get_matrix());
234 
235 	else if( type == VariableType_String )
236 		return (*get_string() == *var.get_string());
237 
238 	else if( type == VariableType_Picture )
239 		return (*get_picture() == *var.get_picture());
240 
241 	else  if( type == VariableType_Array )
242 		return (*get_array() == *var.get_array());
243 
244 	else // if( type == VariableType_Void )
245 		return var.is_void();
246 }
247 
set_to_constant(void)248 void Variable::set_to_constant(void)
249 {
250 	isconstant = true;
251 }
252 
set_can_change_type(bool boolean)253 void Variable::set_can_change_type(bool boolean) throw(error_obj)
254 {
255 	if(isconstant == true)
256 		THROW_ERROR( ErrorType_General, _("Tried to change a constant.") );
257 
258 	can_change_type = boolean;
259 }
260 
set_name(const utf8_string & newname)261 void Variable::set_name(const utf8_string &newname) throw(error_obj)
262 {
263 	if(isconstant == true)
264 		THROW_ERROR( ErrorType_General, _("Tried to change a constant.") );
265 
266 	try{  name = newname;  }
267 	catch(...) {  THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") );  }
268 }
269 
get_matrix(void) const270 const Matrix* Variable::get_matrix(void) const throw(error_obj)
271 {
272 	if(type != VariableType_Matrix)
273 		THROW_ERROR( ErrorType_General, _("Variable type isn't Matrix") );
274 
275 	if(matr == 0)
276 		THROW_ERROR( ErrorType_Internal, "Variable has a NULL-object" );
277 
278 	return matr;
279 }
280 
get_matrix_rw(void)281 Matrix* Variable::get_matrix_rw(void) throw(error_obj)
282 {
283 	if(type != VariableType_Matrix)
284 		THROW_ERROR( ErrorType_General, _("Variable type isn't Matrix") );
285 
286 	if(matr == 0)
287 		THROW_ERROR( ErrorType_Internal, "Variable has a NULL-object" );
288 
289 	if(isconstant == true)
290 		THROW_ERROR( ErrorType_General, _("Tried to change a constant.") );
291 
292 	return matr;
293 }
294 
get_array(void) const295 const Array* Variable::get_array(void) const throw(error_obj)
296 {
297 	if(type != VariableType_Array)
298 		THROW_ERROR( ErrorType_General, _("Variable type isn't Array") );
299 
300 	if(array == 0)
301 		THROW_ERROR( ErrorType_Internal, "Variable has a NULL-object" );
302 
303 	return array;
304 }
305 
get_array_rw(void)306 Array* Variable::get_array_rw(void) throw(error_obj)
307 {
308 	if(type != VariableType_Array)
309 		THROW_ERROR( ErrorType_General, _("Variable type isn't Array") );
310 
311 	if(array == 0)
312 		THROW_ERROR( ErrorType_Internal, "Variable has a NULL-object" );
313 
314 	if(isconstant == true)
315 		THROW_ERROR( ErrorType_General, _("Tried to change a constant.") );
316 
317 	return array;
318 }
319 
get_picture(void) const320 const Picture* Variable::get_picture(void) const throw(error_obj)
321 {
322 	if(type != VariableType_Picture)
323 		THROW_ERROR( ErrorType_General, _("Variable type isn't Picture") );
324 
325 	if(pic == 0)
326 		THROW_ERROR( ErrorType_Internal, "Variable has a NULL-object" );
327 
328 	return pic;
329 }
330 
get_picture_rw(void)331 Picture* Variable::get_picture_rw(void) throw(error_obj)
332 {
333 	if(type != VariableType_Picture)
334 		THROW_ERROR( ErrorType_General, _("Variable type isn't Picture") );
335 
336 	if(pic == 0)
337 		THROW_ERROR( ErrorType_Internal, "Variable has a NULL-object" );
338 
339 	if(isconstant == true)
340 		THROW_ERROR( ErrorType_General, _("Tried to change a constant.") );
341 
342 	return pic;
343 }
344 
clear(void)345 void Variable::clear(void) throw(error_obj)
346 {
347 	if(isconstant == true)
348 		THROW_ERROR( ErrorType_General, _("Tried to change a constant.") );
349 	switch(type)
350 	{
351 	case VariableType_Boolean:
352 		boolean = true;
353 		break;
354 
355 	case VariableType_Complex:
356 		if( boolean )
357 			Complex_ptr( complex_buf )->~Complex();
358 		boolean = false;
359 		break;
360 
361 	case VariableType_String:
362 		delete code_line;
363 		delete str;
364 		code_line = 0;
365 		str = 0;
366 		break;
367 
368 	case VariableType_Matrix:
369 		delete matr;
370 		matr = 0;
371 		break;
372 
373 	case VariableType_Array:
374 		delete array;
375 		array = 0;
376 		break;
377 
378 	case VariableType_Picture:
379 		delete pic;
380 		pic = 0;
381 		break;
382 
383 	case VariableType_Void:
384 		break;
385 
386 	default: // this should only occur when I've forgotten to add a curtain Variable-type to this function
387 		{
388 			char tmp_err[ERROR_OBJ_MSG_LEN];
389 			snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Data type is unsupported by '%s'"), "Variable::clear" );
390 			THROW_ERROR( ErrorType_General, tmp_err );
391 		}
392 	}
393 	if(change_func != 0)
394 		(*change_func)(this);
395 }
396 
signal_changed(void)397 void Variable::signal_changed(void)
398 {
399 	if( change_func != 0 )
400 		(*change_func)( this );
401 }
402 
set_complex(const Complex & newvalue)403 void Variable::set_complex(const Complex &newvalue) throw(error_obj)
404 {
405 	if(isconstant == true)
406 		THROW_ERROR( ErrorType_General, _("Tried to change a constant.") );
407 
408 	if(type != VariableType_Complex)
409 	{
410 		if(can_change_type == false)
411 			THROW_ERROR( ErrorType_General, _("Tried to change type of a type locked variable.") );
412 
413 		void (*tmp)(Variable *ptr);
414 		tmp = change_func;
415 		change_func = 0;
416 
417 		clear();
418 
419 		type = VariableType_Complex;
420 		boolean = false;
421 
422 		change_func = tmp;
423 	}
424 
425 	if( !boolean )
426 	{
427 		try{  new (complex_buf) Complex;  boolean = true;  }
428 		catch(...) {  THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") );  }
429 	}
430 
431 	*Complex_ptr(complex_buf) = newvalue;
432 
433 	if(change_func != 0)
434 		(*change_func)(this);
435 }
436 
set_boolean(bool newbool)437 void Variable::set_boolean(bool newbool) throw(error_obj)
438 {
439 	if(isconstant == true)
440 		THROW_ERROR( ErrorType_General, _("Tried to change a constant.") );
441 	if( can_change_type == false  &&  type != VariableType_Boolean )
442 		THROW_ERROR( ErrorType_General, _("Tried to change type of a type locked variable.") );
443 
444 	clear();
445 
446 	type  = VariableType_Boolean;
447 	boolean = newbool;
448 
449 	if(change_func != 0)
450 		(*change_func)(this);
451 }
452 
set_array(const Array * newarray)453 void Variable::set_array(const Array *newarray) throw(error_obj)
454 {
455 	if(isconstant == true)
456 		THROW_ERROR( ErrorType_General, _("Tried to change a constant.") );
457 	if( can_change_type == false  &&  type != VariableType_Array )
458 		THROW_ERROR( ErrorType_General, _("Tried to change type of a type locked variable.") );
459 
460 	if(type == VariableType_Array)
461 	{
462 		if(array == newarray) // the array's are the same
463 			return;
464 	}
465 	clear();
466 
467 	type = VariableType_Array;
468 	array = 0;
469 
470 	if(newarray == 0)
471 		return;
472 
473 	try{  array = new Array;  }
474 	catch(...) {  THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") );  }
475 
476 	try{  *array = *newarray;  }
477 	catch(...)
478 	{
479 		clear();
480 		throw;
481 	}
482 
483 	if(change_func != 0)
484 		(*change_func)(this);
485 }
486 
set_matrix(const Matrix * newmatrix)487 void Variable::set_matrix(const Matrix *newmatrix) throw(error_obj)
488 {
489 	if(isconstant == true)
490 		THROW_ERROR( ErrorType_General, _("Tried to change a constant.") );
491 	if( can_change_type == false  &&  type != VariableType_Matrix )
492 		THROW_ERROR( ErrorType_General, _("Tried to change type of a type locked variable.") );
493 
494 	if(type == VariableType_Matrix)
495 	{
496 		if(matr == newmatrix) // the Matrix' are the same
497 			return;
498 	}
499 	else
500 	{
501 		clear();
502 
503 		type  = VariableType_Matrix;
504 		matr = 0;
505 
506 		if(newmatrix == 0)
507 			return;
508 
509 		try{  matr = new Matrix;  }
510 		catch(...) {  THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") );  }
511 	}
512 
513 	try{  *matr = *newmatrix;  }
514 	catch(...)
515 	{
516 		clear();
517 		throw;
518 	}
519 
520 	if(change_func != 0)
521 		(*change_func)(this);
522 }
523 
set_picture(const Picture * newpic)524 void Variable::set_picture(const Picture *newpic) throw(error_obj)
525 {
526 	if(isconstant == true)
527 		THROW_ERROR( ErrorType_General, _("Tried to change a constant.") );
528 	if( can_change_type == false  &&  type != VariableType_Picture )
529 		THROW_ERROR( ErrorType_General, _("Tried to change type of a type locked variable.") );
530 
531 	if(type == VariableType_Picture)
532 	{
533 		if(pic == newpic) // the Picture's are the same
534 			return;
535 	}
536 	else
537 	{
538 		clear();
539 
540 		type = VariableType_Picture;
541 		pic = 0;
542 
543 		if(newpic == 0)
544 			return;
545 
546 		try{  pic = new Picture;  }
547 		catch(...) {  THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") );  }
548 	}
549 
550 	try{  *pic = *newpic;  }
551 	catch(...)
552 	{
553 		clear();
554 		throw;
555 	}
556 
557 	if(change_func != 0)
558 		(*change_func)(this);
559 }
560 
get_string(void) const561 const utf8_string* Variable::get_string(void) const throw(error_obj)
562 {
563 	if(type != VariableType_String)
564 		THROW_ERROR( ErrorType_General, _("Variable type isn't String") );
565 
566 	if(str == 0)
567 		THROW_ERROR( ErrorType_Internal, "Variable has a NULL-object" );
568 
569 	return str;
570 }
571 
get_string_rw(void)572 utf8_string* Variable::get_string_rw(void) throw(error_obj)
573 {
574 	if(type != VariableType_String)
575 		THROW_ERROR( ErrorType_General, _("Variable type isn't String") );
576 
577 	if(str == 0)
578 		THROW_ERROR( ErrorType_Internal, "Variable has a NULL-object" );
579 
580 	if(isconstant == true)
581 		THROW_ERROR( ErrorType_General, _("Tried to change a constant.") );
582 
583 	return str;
584 }
585 
get_name(void) const586 const utf8_string* Variable::get_name(void) const throw(error_obj)
587 {
588 	if( name.get_length() == 0 )
589 		THROW_ERROR( ErrorType_General, _("Variable has no name.") );
590 
591 	return &name;
592 }
593 
calc_code_line(Variable * res)594 void Variable::calc_code_line( Variable *res ) throw(error_obj)
595 {
596 	bool tmp_isconstant;
597 
598 	if(type != VariableType_String)
599 		THROW_ERROR( ErrorType_General, _("Variable isn't String") );
600 
601 	if(code_line == 0)
602 	{
603 		if(str == 0)
604 			THROW_ERROR( ErrorType_Internal, "Variable has a NULL-object" );
605 
606 		try{  code_line = new CodeLine;  }
607 		catch(...) {  THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") );  }
608 
609 		code_line->set_code_line( str->c_str() );
610 	}
611 
612 	if(inuse)
613 	{
614 		char tmp_err[ERROR_OBJ_MSG_LEN];
615 		snprintf( tmp_err, ERROR_OBJ_MSG_LEN, _("Circle reference of variable %s"), name.c_str() );
616 		THROW_ERROR( ErrorType_General, tmp_err );
617 	}
618 
619 	if( has_name() ) // a nameless Variable can't have a circle reference
620 		inuse = true;
621 	tmp_isconstant = isconstant;
622 	isconstant = true;
623 
624 	try{  code_line->calc( res );  }
625 	catch(...)
626 	{
627 		inuse = false;
628 		isconstant = tmp_isconstant;
629 		throw;
630 	}
631 	inuse = false;
632 	isconstant = tmp_isconstant;
633 }
634 
set_string(const utf8_string & newstring)635 void Variable::set_string(const utf8_string &newstring) throw(error_obj)
636 {
637 	if( isconstant == true )
638 		THROW_ERROR( ErrorType_General, _("Tried to change a constant.") );
639 	if( can_change_type == false  &&  type != VariableType_String )
640 		THROW_ERROR( ErrorType_General, _("Tried to change type of a type locked variable.") );
641 
642 	clear();
643 
644 	type = VariableType_String;
645 	str = 0;
646 	code_line = 0;
647 
648 	try{  str = new utf8_string(newstring);  }
649 	catch(...) {  THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") );  }
650 
651 	if(change_func != 0)
652 		(*change_func)(this);
653 }
654 
set_code_line(const char * new_code_line)655 void Variable::set_code_line(const char *new_code_line) throw(error_obj)
656 {
657 	void (*tmp_change_func)(Variable *ptr);
658 
659 	tmp_change_func = change_func;
660 	change_func = 0;
661 
662 	set_string( new_code_line );
663 
664 	change_func = tmp_change_func;
665 
666 	code_line = 0;
667 
668 	if(new_code_line == 0)
669 		return;
670 	if(new_code_line[0] == 0)
671 		return;
672 
673 	try{  code_line = new CodeLine;  }
674 	catch(...) {  THROW_ERROR( ErrorType_Memory, _("Couldn't get memory.") );  }
675 
676 
677 	code_line->set_code_line(new_code_line);
678 
679 
680 	if(change_func != 0)
681 		(*change_func)(this);
682 }
683 
get_complex(void) const684 const Complex* Variable::get_complex(void) const throw(error_obj)
685 {
686 	if(type != VariableType_Complex)
687 		THROW_ERROR( ErrorType_General, _("Variable type isn't Complex") );
688 
689 	if( !boolean )
690 		THROW_ERROR( ErrorType_Internal, "Variable has a NULL-object" );
691 
692 	return Complex_ptr(complex_buf);
693 }
694 
get_complex_rw(void)695 Complex* Variable::get_complex_rw(void) throw(error_obj)
696 {
697 	if(type != VariableType_Complex)
698 		THROW_ERROR( ErrorType_General, _("Variable type isn't Complex") );
699 
700 	if( !boolean )
701 		THROW_ERROR( ErrorType_Internal, "Variable has a NULL-object" );
702 
703 	return Complex_ptr(complex_buf);
704 }
705 
get_boolean(void) const706 bool Variable::get_boolean(void) const throw(error_obj)
707 {
708 	if(type == VariableType_Boolean)
709 		return boolean;
710 
711 	THROW_ERROR( ErrorType_General, _("Variable type isn't Boolean") );
712 }
713 
set_void(void)714 void Variable::set_void(void)
715 {
716 	if(isconstant == true)
717 		THROW_ERROR( ErrorType_General, _("Tried to change a constant.") );
718 
719 	if( can_change_type == false  &&  type != VariableType_Void )
720 		THROW_ERROR( ErrorType_General, _("Tried to change type of a type locked variable.") );
721 
722 	void (*tmp)(Variable *ptr);
723 	tmp = change_func;
724 	change_func = 0;
725 
726 	clear();
727 
728 	type = VariableType_Void;
729 
730 	change_func = tmp;
731 
732 	if(change_func != 0)
733 		(*change_func)(this);
734 }
735 
736 } // namespace math
737