1 /*
2     Qalculate (library)
3 
4     Copyright (C) 2003-2007, 2008, 2016  Hanna Knutsson (hanna.knutsson@protonmail.com)
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 */
11 
12 #include "support.h"
13 
14 #include "ExpressionItem.h"
15 #include "Calculator.h"
16 #include "util.h"
17 
18 using std::string;
19 using std::vector;
20 
ExpressionName(string sname)21 ExpressionName::ExpressionName(string sname) : suffix(false), unicode(false), plural(false), reference(false), avoid_input(false), completion_only(false) {
22 	name = sname;
23 	if(text_length_is_one(sname)) {
24 		abbreviation = true;
25 		case_sensitive = true;
26 	} else {
27 		abbreviation = false;
28 		case_sensitive = false;
29 	}
30 	if(sname.length() > 2) {
31 		size_t i = sname.find('_', 1);
32 		if(i != string::npos && i < sname.length() - 1 && sname.find('_', i + 1) == string::npos) suffix = true;
33 	}
34 }
ExpressionName()35 ExpressionName::ExpressionName() : abbreviation(false), suffix(false), unicode(false), plural(false), reference(false), avoid_input(false), case_sensitive(false), completion_only(false) {
36 }
operator =(const ExpressionName & ename)37 void ExpressionName::operator = (const ExpressionName &ename) {
38 	name = ename.name;
39 	abbreviation = ename.abbreviation;
40 	case_sensitive = ename.case_sensitive;
41 	suffix = ename.suffix;
42 	unicode = ename.unicode;
43 	plural = ename.plural;
44 	reference = ename.reference;
45 	avoid_input = ename.avoid_input;
46 	completion_only = ename.completion_only;
47 }
operator ==(const ExpressionName & ename) const48 bool ExpressionName::operator == (const ExpressionName &ename) const {
49 	return name == ename.name && abbreviation == ename.abbreviation && case_sensitive == ename.case_sensitive && suffix == ename.suffix && unicode == ename.unicode && plural == ename.plural && reference == ename.reference && avoid_input == ename.avoid_input && completion_only == ename.completion_only;
50 }
operator !=(const ExpressionName & ename) const51 bool ExpressionName::operator != (const ExpressionName &ename) const {
52 	return name != ename.name || abbreviation != ename.abbreviation || case_sensitive != ename.case_sensitive || suffix != ename.suffix || unicode != ename.unicode || plural != ename.plural || reference != ename.reference || avoid_input != ename.avoid_input || completion_only != ename.completion_only;
53 }
54 
ExpressionItem(string cat_,string name_,string title_,string descr_,bool is_local,bool is_builtin,bool is_active)55 ExpressionItem::ExpressionItem(string cat_, string name_, string title_, string descr_, bool is_local, bool is_builtin, bool is_active) {
56 
57 	b_local = is_local;
58 	b_builtin = is_builtin;
59 	remove_blank_ends(name_);
60 	remove_blank_ends(cat_);
61 	remove_blank_ends(title_);
62 
63 	if(!name_.empty()) {
64 		names.resize(1);
65 		names[0].name = name_;
66 		names[0].unicode = false;
67 		names[0].abbreviation = false;
68 		names[0].case_sensitive = text_length_is_one(name_);
69 		size_t i = name_.find('_');
70 		if(i != string::npos && i > 0 && i < name_.length() - 1 && name_.find('_', i + 1) == string::npos) names[0].suffix = true;
71 		else names[0].suffix = false;
72 		names[0].avoid_input = false;
73 		names[0].reference = true;
74 		names[0].plural = false;
75 	}
76 
77 	stitle = title_;
78 	scat = cat_;
79 	sdescr = descr_;
80 	b_changed = false;
81 	b_approx = false;
82 	i_precision = -1;
83 	b_active = is_active;
84 	b_registered = false;
85 	b_hidden = false;
86 	b_destroyed = false;
87 	i_ref = 0;
88 
89 }
ExpressionItem()90 ExpressionItem::ExpressionItem() {
91 	b_changed = false;
92 	b_approx = false;
93 	i_precision = -1;
94 	b_active = true;
95 	b_local = true;
96 	b_builtin = false;
97 	b_registered = false;
98 	b_hidden = false;
99 	b_destroyed = false;
100 	i_ref = 0;
101 }
~ExpressionItem()102 ExpressionItem::~ExpressionItem() {
103 }
set(const ExpressionItem * item)104 void ExpressionItem::set(const ExpressionItem *item) {
105 	b_changed = item->hasChanged();
106 	b_approx = item->isApproximate();
107 	i_precision = item->precision();
108 	b_active = item->isActive();
109 	for(size_t i = 1; i <= item->countNames(); i++) {
110 		names.push_back(item->getName(1));
111 	}
112 	stitle = item->title(false);
113 	scat = item->category();
114 	sdescr = item->description();
115 	b_local = item->isLocal();
116 	b_builtin = item->isBuiltin();
117 	b_hidden = item->isHidden();
118 }
destroy()119 bool ExpressionItem::destroy() {
120 	CALCULATOR->expressionItemDeleted(this);
121 	if(v_refs.size() > 0) {
122 		return false;
123 	} else if(i_ref > 0) {
124 		b_destroyed = true;
125 	} else {
126 		delete this;
127 	}
128 	return true;
129 }
isRegistered() const130 bool ExpressionItem::isRegistered() const {
131 	return b_registered;
132 }
setRegistered(bool is_registered)133 void ExpressionItem::setRegistered(bool is_registered) {
134 	b_registered = is_registered;
135 }
title(bool return_name_if_no_title,bool use_unicode,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const136 const string &ExpressionItem::title(bool return_name_if_no_title, bool use_unicode, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
137 	if(return_name_if_no_title && stitle.empty()) {
138 		return preferredName(false, use_unicode, false, false, can_display_unicode_string_function, can_display_unicode_string_arg).name;
139 	}
140 	return stitle;
141 }
setTitle(string title_)142 void ExpressionItem::setTitle(string title_) {
143 	remove_blank_ends(title_);
144 	if(stitle != title_) {
145 		stitle = title_;
146 		b_changed = true;
147 	}
148 }
description() const149 const string &ExpressionItem::description() const {
150 	return sdescr;
151 }
setDescription(string descr_)152 void ExpressionItem::setDescription(string descr_) {
153 	remove_blank_ends(descr_);
154 	if(sdescr != descr_) {
155 		sdescr = descr_;
156 		b_changed = true;
157 	}
158 }
name(bool use_unicode,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const159 const string &ExpressionItem::name(bool use_unicode, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
160 	bool undisplayable_uni = false;
161 	for(size_t i = 0; i < names.size(); i++) {
162 		if(names[i].unicode == use_unicode && (!names[i].completion_only || i + 1 == names.size())) {
163 			if(use_unicode && can_display_unicode_string_function && !((*can_display_unicode_string_function) (names[i].name.c_str(), can_display_unicode_string_arg))) {
164 				undisplayable_uni = true;
165 			} else {
166 				return names[i].name;
167 			}
168 		}
169 	}
170 	if(undisplayable_uni) return name(false);
171 	if(names.size() > 0) return names[0].name;
172 	return empty_string;
173 }
referenceName() const174 const string &ExpressionItem::referenceName() const {
175 	for(size_t i = 0; i < names.size(); i++) {
176 		if(names[i].reference) {
177 			return names[i].name;
178 		}
179 	}
180 	if(names.size() > 0) return names[0].name;
181 	return empty_string;
182 }
183 
preferredName(bool abbreviation,bool use_unicode,bool plural,bool reference,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const184 const ExpressionName &ExpressionItem::preferredName(bool abbreviation, bool use_unicode, bool plural, bool reference, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
185 	if(names.size() == 1) return names[0];
186 	int index = -1;
187 	for(size_t i = 0; i < names.size(); i++) {
188 		if((!reference || names[i].reference) && names[i].abbreviation == abbreviation && names[i].unicode == use_unicode && names[i].plural == plural && !names[i].completion_only && (!use_unicode || !can_display_unicode_string_function || (*can_display_unicode_string_function) (names[i].name.c_str(), can_display_unicode_string_arg))) return names[i];
189 		if(index < 0) {
190 			index = i;
191 		} else if(names[i].completion_only != names[index].completion_only) {
192 			if(!names[i].completion_only) index = i;
193 		} else if(reference && names[i].reference != names[index].reference) {
194 			if(names[i].reference) index = i;
195 		} else if(!use_unicode && names[i].unicode != names[index].unicode) {
196 			if(!names[i].unicode) index = i;
197 		} else if(names[i].abbreviation != names[index].abbreviation) {
198 			if(names[i].abbreviation == abbreviation) index = i;
199 		} else if(names[i].plural != names[index].plural) {
200 			if(names[i].plural == plural) index = i;
201 		} else if(use_unicode && names[i].unicode != names[index].unicode) {
202 			if(names[i].unicode) index = i;
203 		}
204 	}
205 	if(use_unicode && names[index].unicode && can_display_unicode_string_function && !((*can_display_unicode_string_function) (names[index].name.c_str(), can_display_unicode_string_arg))) {
206 		return preferredName(abbreviation, false, plural, reference, can_display_unicode_string_function, can_display_unicode_string_arg);
207 	}
208 	if(index >= 0) return names[index];
209 	return empty_expression_name;
210 }
preferredInputName(bool abbreviation,bool use_unicode,bool plural,bool reference,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const211 const ExpressionName &ExpressionItem::preferredInputName(bool abbreviation, bool use_unicode, bool plural, bool reference, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
212 	if(names.size() == 1) return names[0];
213 	int index = -1;
214 	for(size_t i = 0; i < names.size(); i++) {
215 		if((!reference || names[i].reference) && names[i].abbreviation == abbreviation && names[i].unicode == use_unicode && names[i].plural == plural && !names[i].avoid_input && !names[i].completion_only) return names[i];
216 		if(index < 0) {
217 			index = i;
218 		} else if(names[i].completion_only != names[index].completion_only) {
219 			if(!names[i].completion_only) index = i;
220 		} else if(reference && names[i].reference != names[index].reference) {
221 			if(names[i].reference) index = i;
222 		} else if(!use_unicode && names[i].unicode != names[index].unicode) {
223 			if(!names[i].unicode) index = i;
224 		} else if(names[i].avoid_input != names[index].avoid_input) {
225 			if(!names[i].avoid_input) index = i;
226 		} else if(abbreviation && names[i].abbreviation != names[index].abbreviation) {
227 			if(names[i].abbreviation) index = i;
228 		} else if(plural && names[i].plural != names[index].plural) {
229 			if(names[i].plural) index = i;
230 		} else if(!abbreviation && names[i].abbreviation != names[index].abbreviation) {
231 			if(!names[i].abbreviation) index = i;
232 		} else if(!plural && names[i].plural != names[index].plural) {
233 			if(!names[i].plural) index = i;
234 		} else if(use_unicode && names[i].unicode != names[index].unicode) {
235 			if(names[i].unicode) index = i;
236 		}
237 	}
238 	if(use_unicode && names[index].unicode && can_display_unicode_string_function && !((*can_display_unicode_string_function) (names[index].name.c_str(), can_display_unicode_string_arg))) {
239 		return preferredInputName(abbreviation, false, plural, reference, can_display_unicode_string_function, can_display_unicode_string_arg);
240 	}
241 	if(index >= 0) return names[index];
242 	return empty_expression_name;
243 }
preferredDisplayName(bool abbreviation,bool use_unicode,bool plural,bool reference,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const244 const ExpressionName &ExpressionItem::preferredDisplayName(bool abbreviation, bool use_unicode, bool plural, bool reference, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
245 	return preferredName(abbreviation, use_unicode, plural, reference, can_display_unicode_string_function, can_display_unicode_string_arg);
246 }
getName(size_t index) const247 const ExpressionName &ExpressionItem::getName(size_t index) const {
248 	if(index > 0 && index <= names.size()) return names[index - 1];
249 	return empty_expression_name;
250 }
setName(const ExpressionName & ename,size_t index,bool force)251 void ExpressionItem::setName(const ExpressionName &ename, size_t index, bool force) {
252 	if(index < 1) addName(ename, 1);
253 	if(index > names.size()) addName(ename);
254 	if(b_registered && names[index - 1].name != ename.name) {
255 		names[index - 1] = ename;
256 		names[index - 1].name = CALCULATOR->getName(ename.name, this, force);
257 		b_changed = true;
258 		CALCULATOR->nameChanged(this);
259 	} else if(ename != names[index - 1]) {
260 		names[index - 1] = ename;
261 		b_changed = true;
262 	}
263 }
setName(string sname,size_t index,bool force)264 void ExpressionItem::setName(string sname, size_t index, bool force) {
265 	if(index < 1) addName(sname, 1);
266 	if(index > names.size()) addName(sname);
267 	if(b_registered && names[index - 1].name != sname) {
268 		names[index - 1].name = CALCULATOR->getName(sname, this, force);
269 		b_changed = true;
270 		CALCULATOR->nameChanged(this);
271 	} else if(sname != names[index - 1].name) {
272 		names[index - 1].name = sname;
273 		b_changed = true;
274 	}
275 }
addName(const ExpressionName & ename,size_t index,bool force)276 void ExpressionItem::addName(const ExpressionName &ename, size_t index, bool force) {
277 	if(index < 1 || index > names.size()) {
278 		names.push_back(ename);
279 		index = names.size();
280 	} else {
281 		names.insert(names.begin() + (index - 1), ename);
282 	}
283 	if(b_registered) {
284 		names[index - 1].name = CALCULATOR->getName(names[index - 1].name, this, force);
285 		CALCULATOR->nameChanged(this);
286 	}
287 	b_changed = true;
288 }
addName(string sname,size_t index,bool force)289 void ExpressionItem::addName(string sname, size_t index, bool force) {
290 	if(index < 1 || index > names.size()) {
291 		names.push_back(ExpressionName(sname));
292 		index = names.size();
293 	} else {
294 		names.insert(names.begin() + (index - 1), ExpressionName(sname));
295 	}
296 	if(b_registered) {
297 		names[index - 1].name = CALCULATOR->getName(names[index - 1].name, this, force);
298 		CALCULATOR->nameChanged(this);
299 	}
300 	b_changed = true;
301 }
countNames() const302 size_t ExpressionItem::countNames() const {
303 	return names.size();
304 }
clearNames()305 void ExpressionItem::clearNames() {
306 	if(names.size() > 0) {
307 		names.clear();
308 		if(b_registered) {
309 			CALCULATOR->nameChanged(this);
310 		}
311 		b_changed = true;
312 	}
313 }
clearNonReferenceNames()314 void ExpressionItem::clearNonReferenceNames() {
315 	bool b = false;
316 	for(vector<ExpressionName>::iterator it = names.begin(); it != names.end(); ++it) {
317 		if(!it->reference) {
318 			it = names.erase(it);
319 			--it;
320 			b = true;
321 		}
322 	}
323 	if(b) {
324 		if(b_registered) {
325 			CALCULATOR->nameChanged(this);
326 		}
327 		b_changed = true;
328 	}
329 }
removeName(size_t index)330 void ExpressionItem::removeName(size_t index) {
331 	if(index > 0 && index <= names.size()) {
332 		names.erase(names.begin() + (index - 1));
333 		if(b_registered) {
334 			CALCULATOR->nameChanged(this);
335 		}
336 		b_changed = true;
337 	}
338 }
hasName(const string & sname,bool case_sensitive) const339 size_t ExpressionItem::hasName(const string &sname, bool case_sensitive) const {
340 	for(size_t i = 0; i < names.size(); i++) {
341 		if(case_sensitive && names[i].case_sensitive && sname == names[i].name) return i + 1;
342 		if((!case_sensitive || !names[i].case_sensitive) && equalsIgnoreCase(names[i].name, sname)) return i + 1;
343 	}
344 	return 0;
345 }
hasNameCaseSensitive(const string & sname) const346 size_t ExpressionItem::hasNameCaseSensitive(const string &sname) const {
347 	for(size_t i = 0; i < names.size(); i++) {
348 		if(sname == names[i].name) return i + 1;
349 	}
350 	return 0;
351 }
findName(int abbreviation,int use_unicode,int plural,bool (* can_display_unicode_string_function)(const char *,void *),void * can_display_unicode_string_arg) const352 const ExpressionName &ExpressionItem::findName(int abbreviation, int use_unicode, int plural, bool (*can_display_unicode_string_function) (const char*, void*), void *can_display_unicode_string_arg) const {
353 	for(size_t i = 0; i < names.size(); i++) {
354 		if((abbreviation < 0 || names[i].abbreviation == abbreviation) && (use_unicode < 0 || names[i].unicode == use_unicode) && (plural < 0 || names[i].plural == plural) && (!names[i].unicode || !can_display_unicode_string_function || ((*can_display_unicode_string_function) (names[i].name.c_str(), can_display_unicode_string_arg)))) return names[i];
355 	}
356 	return empty_expression_name;
357 }
358 
category() const359 const string &ExpressionItem::category() const {
360 	return scat;
361 }
setCategory(string cat_)362 void ExpressionItem::setCategory(string cat_) {
363 	remove_blank_ends(cat_);
364 	if(scat != cat_) {
365 		scat = cat_;
366 		b_changed = true;
367 	}
368 }
isLocal() const369 bool ExpressionItem::isLocal() const {
370 	return b_local;
371 }
setLocal(bool is_local,int will_be_active)372 bool ExpressionItem::setLocal(bool is_local, int will_be_active) {
373 	if(b_builtin) return false;
374 	if(is_local != b_local) {
375 		if(!b_local) {
376 			bool was_active = b_active;
377 			b_active = false;
378 			ExpressionItem *item = copy();
379 			b_local = is_local;
380 			b_active = was_active;
381 			if(will_be_active) {
382 				setActive(true);
383 			} else if(will_be_active == 0) {
384 				setActive(false);
385 			}
386 			CALCULATOR->addExpressionItem(item);
387 			if(was_active != item->isActive()) {
388 				item->setChanged(true);
389 			}
390 			if(was_active && will_be_active == 0) {
391 				item->setActive(true);
392 			}
393 		}
394 		b_local = is_local;
395 	} else if(will_be_active >= 0) {
396 		setActive(will_be_active);
397 	}
398 	return true;
399 }
isBuiltin() const400 bool ExpressionItem::isBuiltin() const {
401 	return b_builtin;
402 }
hasChanged() const403 bool ExpressionItem::hasChanged() const {
404 	return b_changed;
405 }
setChanged(bool has_changed)406 void ExpressionItem::setChanged(bool has_changed) {
407 	b_changed = has_changed;
408 }
isApproximate() const409 bool ExpressionItem::isApproximate() const {
410 	return b_approx;
411 }
setApproximate(bool is_approx)412 void ExpressionItem::setApproximate(bool is_approx) {
413 	if(is_approx != b_approx) {
414 		b_approx = is_approx;
415 		if(!b_approx) i_precision = -1;
416 		b_changed = true;
417 	}
418 }
precision() const419 int ExpressionItem::precision() const {
420 	return i_precision;
421 }
setPrecision(int prec)422 void ExpressionItem::setPrecision(int prec) {
423 	if(i_precision != prec) {
424 		i_precision = prec;
425 		if(i_precision >= 0) b_approx = true;
426 		b_changed = true;
427 	}
428 }
isActive() const429 bool ExpressionItem::isActive() const {
430 	return b_active;
431 }
setActive(bool is_active)432 void ExpressionItem::setActive(bool is_active) {
433 	if(is_active != b_active) {
434 		b_active = is_active;
435 		if(b_registered) {
436 			if(is_active) {
437 				CALCULATOR->expressionItemActivated(this);
438 			} else {
439 				CALCULATOR->expressionItemDeactivated(this);
440 			}
441 		}
442 		b_changed = true;
443 	}
444 }
isHidden() const445 bool ExpressionItem::isHidden() const {
446 	return b_hidden;
447 }
setHidden(bool is_hidden)448 void ExpressionItem::setHidden(bool is_hidden) {
449 	if(is_hidden != b_hidden) {
450 		b_hidden = is_hidden;
451 		b_changed = true;
452 	}
453 }
454 
refcount() const455 int ExpressionItem::refcount() const {
456 	return i_ref;
457 }
ref()458 void ExpressionItem::ref() {
459 	i_ref++;
460 }
unref()461 void ExpressionItem::unref() {
462 	i_ref--;
463 	if(b_destroyed && i_ref <= 0) {
464 		delete this;
465 	}
466 }
ref(ExpressionItem * o)467 void ExpressionItem::ref(ExpressionItem *o) {
468 	i_ref++;
469 	v_refs.push_back(o);
470 }
unref(ExpressionItem * o)471 void ExpressionItem::unref(ExpressionItem *o) {
472 	for(size_t i = 0; i < v_refs.size(); i++) {
473 		if(v_refs[i] == o) {
474 			i_ref--;
475 			v_refs.erase(v_refs.begin() + i);
476 			break;
477 		}
478 	}
479 }
getReferencer(size_t index) const480 ExpressionItem *ExpressionItem::getReferencer(size_t index) const {
481 	if(index > 0 && index <= v_refs.size()) {
482 		return v_refs[index - 1];
483 	}
484 	return NULL;
485 }
changeReference(ExpressionItem *,ExpressionItem *)486 bool ExpressionItem::changeReference(ExpressionItem*, ExpressionItem*) {
487 	return false;
488 }
id() const489 int ExpressionItem::id() const {
490 	return 0;
491 }
492