kspread

kcalc_core.cpp
1/*
2 $Id: kcalc_core.cpp 541875 2006-05-17 14:42:51Z zander $
3
4 kCalculator, a scientific calculator for the X window system using the
5 TQt widget libraries, available at no cost at http://www.troll.no
6
7 The stack engine conatined in this file was take from
8 Martin Bartlett's xfrmcalc
9
10 portions: Copyright (C) 1996 Bernd Johannes Wuebben
11 wuebben@math.cornell.edu
12
13 portions: Copyright (C) 1995 Martin Bartlett
14
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 2 of the License, or
18 (at your option) any later version.
19
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 51 Franklin Street, Fifth Floor,
28 * Boston, MA 02110-1301, USA.
29
30*/
31
32#include <config.h>
33#include <assert.h>
34#include <stdio.h>
35#include <errno.h>
36#include <limits.h>
37#include <math.h>
38#include <signal.h>
39#include <tdelocale.h>
40#include <tdemessagebox.h>
41#include <knotifyclient.h>
42
43#include "kcalc.h"
44
45//What's that?!? (Werner)
46//#define i18n( x ) x
47
48// Undefine HAVE_LONG_DOUBLE for Beta 4 since RedHat 5.0 comes with a borken
49// glibc
50
51#ifdef HAVE_LONG_DOUBLE
52#undef HAVE_LONG_DOUBLE
53#endif
54
55#ifndef HAVE_FUNC_ISINF
56#ifdef HAVE_IEEEFP_H
57#include <ieeefp.h>
58#else
59#include <math.h>
60#endif
61
62int isinf(double x) { return !finite(x) && x==x; }
63#endif
64
65extern TQPtrList<CALCAMNT> temp_stack;
66last_input_type last_input;
67char display_str[DSP_SIZE+1];
68
69stack_ptr top_of_stack = NULL;
70stack_ptr top_type_stack[2] = { NULL, NULL };
71int stack_next, stack_last;
72stack_item process_stack[STACK_SIZE];
73
74bool inverse = false;
75int precedence_base = 0;
76num_base current_base = NB_DECIMAL;
77int input_limit = 0;
78int input_count = 0;
79
80//item_contents display_data = { ITEM_AMOUNT, 0 };
81item_contents display_data;
82
83int display_size = DEC_SIZE;
84
85int hyp_mode = 0;
86int angle_mode = ANG_DEGREE;
87int refresh_display; // if 1 we start a new number
88int display_error = 0;
89int decimal_point = 0;
90int percent_mode = 0;
91bool eestate = false; // if true then we are in ee input mode
92
93CALCAMNT pi;
94CALCAMNT memory_num = 0.0;
95
96int precedence[14] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 6 };
97
98 int adjust_op[14][3] = {
99 {FUNC_NULL, FUNC_NULL, FUNC_NULL},
100 {FUNC_OR, FUNC_OR, FUNC_XOR },
101 {FUNC_XOR, FUNC_XOR, FUNC_XOR },
102 {FUNC_AND, FUNC_AND, FUNC_AND },
103 {FUNC_LSH, FUNC_LSH, FUNC_RSH },
104 {FUNC_RSH, FUNC_RSH, FUNC_RSH },
105 {FUNC_ADD, FUNC_ADD, FUNC_ADD },
106 {FUNC_SUBTRACT, FUNC_SUBTRACT, FUNC_SUBTRACT},
107 {FUNC_MULTIPLY, FUNC_MULTIPLY, FUNC_MULTIPLY},
108 {FUNC_DIVIDE, FUNC_DIVIDE, FUNC_DIVIDE},
109 {FUNC_MOD, FUNC_MOD, FUNC_INTDIV },
110 {FUNC_POWER, FUNC_POWER, FUNC_PWR_ROOT},
111 {FUNC_PWR_ROOT, FUNC_PWR_ROOT, FUNC_PWR_ROOT},
112 {FUNC_INTDIV, FUNC_INTDIV, FUNC_INTDIV},
113 };
114/*
115 char *function_desc[] = {
116
117 "Null",
118 "Or",
119 "Exclusive Or",
120 "And",
121 "Left Shift",
122 "Right Shift",
123 "Add",
124 "Subtract",
125 "Multiply",
126 "Divide",
127 "Modulus"
128 "Power"
129 "Reciprocal Power"
130 "Integer Division"
131 };
132 */
133 Arith Arith_ops[14] = { NULL,
134 ExecOr,
135 ExecXor,
136 ExecAnd,
137 ExecLsh,
138 ExecRsh,
139 ExecAdd, ExecSubtract,
140 ExecMultiply,
141 ExecDivide, ExecMod,
142 ExecPower, ExecPwrRoot,
143 ExecIntDiv
144 };
145
146 Prcnt Prcnt_ops[14] = { NULL,
147 NULL,
148 NULL,
149 NULL,
150 NULL,
151 NULL,
152 ExecAddSubP, ExecAddSubP,
153 ExecMultiplyP,
154 ExecDivideP, ExecDivideP,
155 ExecPowerP, ExecPwrRootP,
156 ExecDivideP
157 };
158
159
160void TQtCalculator::InitializeCalculator(void) {
161
162 //
163 // Basic initialization involves initializing the calcultion
164 // stack, forcing the display to refresh to zero, and setting
165 // up the floating point excetion signal handler to trap the
166 // errors that the code can/has not been written to trap.
167 //
168 // We also calculate pi as double the arc sine of 1.
169 //
170
171 display_data.s_item_type = ITEM_AMOUNT;
172 display_data.s_item_data.item_amount = 0.0;
173 display_data.s_item_data.item_func_data.item_function = 0;
174 display_data.s_item_data.item_func_data.item_precedence = 0;
175
176 void fpe_handler(int fpe_parm);
177 struct sigaction fpe_trap;
178
179 fpe_trap.sa_handler = &fpe_handler;
180#ifdef SA_RESTART
181 fpe_trap.sa_flags = SA_RESTART;
182#endif
183
184 sigaction(SIGFPE, &fpe_trap, NULL);
185
186 RefreshCalculator();
187 pi = ASIN(1.0) * 2L;
188}
189
190void fpe_handler(int fpe_parm)
191{
192 (void) fpe_parm;
193
194 display_error = 1;
195 DISPLAY_AMOUNT = 0L;
196
197}
198
199void TQtCalculator::setData( const TQRect& _range, const char *_sheet )
200{
201 sheet_range = _range;
202 sheet_name = _sheet;
203}
204
205void TQtCalculator::setValue( double _value )
206{
207 last_input = DIGIT;
208 DISPLAY_AMOUNT = _value;
209 decimal_point = 0;
210 refresh_display = 1;
211 input_count = 0;
212
213 UpdateDisplay();
214}
215
216void TQtCalculator::setLabel( const char *_text )
217{
218 last_input = DIGIT;
219 DISPLAY_AMOUNT = 0L;
220 decimal_point = 0;
221 refresh_display = 0;
222 input_count = 0;
223
224 calc_display->setText( _text );
225}
226
227void TQtCalculator::RefreshCalculator(void)
228{
229 InitStack();
230 display_error = 0;
231 DISPLAY_AMOUNT = 0L;
232 inverse = false;
233 UpdateDisplay();
234 last_input = DIGIT; // must set last to DIGIT after Update Display in order
235 // not to get a display holding e.g. 0.000
236 input_count = 0;
237 decimal_point = 0;
238}
239
240void TQtCalculator::EnterDigit(int data)
241{
242
243 if(eestate){
244
245 TQString string;
246 string.setNum(data);
247 strcat(display_str, string.latin1());
248 DISPLAY_AMOUNT = (CALCAMNT) strtod(display_str,0);
249 UpdateDisplay();
250 return;
251
252 }
253
254 last_input = DIGIT;
255 if (refresh_display) {
256 DISPLAY_AMOUNT = 0L;
257 decimal_point = 0;
258 refresh_display = 0;
259 input_count = 0;
260 }
261
262 if (!(input_limit && input_count >= input_limit))
263 if (DISPLAY_AMOUNT < 0)
264 DISPLAY_AMOUNT = decimal_point ?
265 DISPLAY_AMOUNT - ((CALCAMNT)data /
266 POW((float)current_base, decimal_point++)) :
267 (current_base * DISPLAY_AMOUNT) - data;
268 else
269 DISPLAY_AMOUNT = decimal_point ?
270 DISPLAY_AMOUNT + ((CALCAMNT)data /
271 POW((float)current_base, decimal_point++)) :
272 (current_base * DISPLAY_AMOUNT) + data;
273
274 if (decimal_point){
275 input_count ++;
276
277#ifdef MYDEBUG
278 printf("EnterDigit() inc dec.point:%d\n",input_count);
279#endif
280
281 }
282 UpdateDisplay();
283}
284
285void TQtCalculator::button0()
286{
287 EnterDigit(0);
288}
289
290void TQtCalculator::button1()
291{
292 EnterDigit(1);
293 }
294
295void TQtCalculator::button2()
296{
297 if (current_base == NB_BINARY)
298 return;
299 EnterDigit(2);
300}
301
302void TQtCalculator::button3()
303{
304 if (current_base == NB_BINARY)
305 return;
306 EnterDigit(3);
307}
308
309void TQtCalculator::button4()
310{
311 if (current_base == NB_BINARY)
312 return;
313 EnterDigit(4);
314}
315
316void TQtCalculator::button5()
317{
318 if (current_base == NB_BINARY)
319 return;
320 EnterDigit(5);
321}
322
323void TQtCalculator::button6()
324{
325 if (current_base == NB_BINARY)
326 return;
327 EnterDigit(6);
328}
329
330void TQtCalculator::button7()
331{
332 if (current_base == NB_BINARY)
333 return;
334 EnterDigit(7);
335}
336
337void TQtCalculator::button8()
338{
339 if ((current_base == NB_BINARY) || (current_base == NB_OCTAL))
340 return;
341 EnterDigit(8);
342}
343
344void TQtCalculator::button9()
345{
346 if ((current_base == NB_BINARY) || (current_base == NB_OCTAL))
347 return;
348 EnterDigit(9);
349}
350
351
352void TQtCalculator::buttonA()
353{
354 if ((current_base == NB_BINARY) || (current_base == NB_OCTAL)
355 || (current_base == NB_DECIMAL))
356 return;
357 EnterDigit(10);
358}
359
360
361void TQtCalculator::buttonB()
362{
363 if ((current_base == NB_BINARY) || (current_base == NB_OCTAL)
364 || (current_base == NB_DECIMAL))
365 return;
366 EnterDigit(11);
367}
368
369
370void TQtCalculator::buttonC()
371{
372 if ((current_base == NB_BINARY) || (current_base == NB_OCTAL)
373 || (current_base == NB_DECIMAL))
374 return;
375 EnterDigit(12);
376}
377
378
379void TQtCalculator::buttonD()
380{
381 if ((current_base == NB_BINARY) || (current_base == NB_OCTAL)
382 || (current_base == NB_DECIMAL))
383 return;
384 EnterDigit(13);
385}
386
387
388void TQtCalculator::buttonE()
389{
390 if ((current_base == NB_BINARY) || (current_base == NB_OCTAL)
391 || (current_base == NB_DECIMAL))
392 return;
393 EnterDigit(14);
394}
395
396void TQtCalculator::buttonF()
397{
398 if ((current_base == NB_BINARY) || (current_base == NB_OCTAL)
399 || (current_base == NB_DECIMAL))
400 return;
401 EnterDigit(15);
402}
403
404
405
406void TQtCalculator::EnterDecimal()
407{
408
409 if(eestate){
410 KNotifyClient::beep();
411 return;
412 }
413
414 decimal_point = 1;
415 if (refresh_display) {
416 DISPLAY_AMOUNT = 0L;
417 refresh_display = 0;
418 input_count = 0;
419 }
420
421 if (last_input == DIGIT && !strpbrk( display_str,".")){
422
423 // if the last input was a DIGIT and we don't have already a period in our
424 // display string then display a period
425
426 calc_display->setText(strcat(display_str, "."));
427 }
428 else {
429
430 // the last input wasn't a DIGIT so we are about to
431 // input a new number in particular we neet do display a "0.".
432
433 DISPLAY_AMOUNT = 0L;
434 refresh_display = 0;
435 // decimal_point = 1;
436 // input_count = 1;
437 strcpy(display_str, "0.");
438 calc_display->setText(display_str);
439 }
440}
441
442
443void TQtCalculator::Or()
444{
445 eestate = false;
446 if (inverse){
447 EnterStackFunction(2); // XOR
448 inverse = false;
449 }
450 else {
451 EnterStackFunction(1); // OR
452 }
453 last_input = OPERATION;
454}
455
456void TQtCalculator::And()
457{
458 eestate = false;
459 last_input = OPERATION;
460 EnterStackFunction(3);
461}
462
463
464void TQtCalculator::Shift()
465{
466 eestate = false;
467 last_input = OPERATION;
468 if (inverse){
469 EnterStackFunction(5); // Rsh
470 inverse = false;
471 }
472 else {
473 EnterStackFunction(4); // Lsh
474 }
475
476}
477
478void TQtCalculator::Plus()
479{
480 eestate = false;
481 last_input = OPERATION;
482 EnterStackFunction(6);
483}
484
485void TQtCalculator::Minus()
486{
487 eestate = false;
488 last_input = OPERATION;
489 EnterStackFunction(7);
490
491}
492
493void TQtCalculator::Multiply()
494{
495 eestate = false;
496 last_input = OPERATION;
497 EnterStackFunction(8);
498}
499
500void TQtCalculator::Divide()
501{
502 eestate = false;
503 last_input = OPERATION;
504 EnterStackFunction(9);
505}
506
507void TQtCalculator::Mod()
508{
509 eestate = false;
510 last_input = OPERATION;
511 if (inverse){
512 EnterStackFunction(13); // InvMod
513 inverse = false;
514 }
515 else {
516 EnterStackFunction(10); // Mod
517 }
518}
519
520void TQtCalculator::Power()
521{
522 eestate = false;
523 last_input = OPERATION;
524 if (inverse){
525 EnterStackFunction(12); // InvPower
526 inverse = false;
527 }
528 else {
529 EnterStackFunction(11); // Power
530 }
531
532}
533
534
535
536void TQtCalculator::EnterStackFunction(int data)
537{
538 item_contents new_item;
539 int new_precedence;
540 int dummy;
541
542 dummy = 0;
543
544 /*
545 if (inverse ) {
546 dummy = 3;
547 inverse = false;
548 }
549 else {
550 dummy = 1;
551 }
552 */
553
554 // printf("data %d dummy %d\n",data,dummy);
555 data = adjust_op[data][dummy];
556 // printf("data %d \n",data );
557
558 PushStack(&display_data);
559
560 new_item.s_item_type = ITEM_FUNCTION;
561 new_item.s_item_data.item_func_data.item_function = data;
562 new_item.s_item_data.item_func_data.item_precedence =
563 new_precedence = precedence[data] + precedence_base;
564
565 refresh_display = 1;
566 if (UpdateStack(new_precedence))
567 UpdateDisplay();
568 PushStack(&new_item);
569}
570
571void TQtCalculator::EnterNegate()
572{
573
574 if(eestate){
575 TQString string;
576 string = display_str;
577 int pos;
578 pos = string.findRev('e',-1,false);
579 if(pos == -1)
580 return;
581
582 if(display_str[pos+1] == '+')
583 display_str[pos+1] = '-';
584 else{
585 if(display_str[pos+1] == '-')
586 display_str[pos+1] = '+';
587 else{
588 string.insert(pos +1,'-');
589 strncpy(display_str,string.latin1(),DSP_SIZE);
590 }
591 }
592 DISPLAY_AMOUNT = (CALCAMNT)strtod(display_str,0);
593 UpdateDisplay();
594 }
595 else{
596 // last_input = OPERATION;
597 if (DISPLAY_AMOUNT != 0) {
598 DISPLAY_AMOUNT *= -1;
599 UpdateDisplay();
600 }
601 }
602 last_input = DIGIT;
603}
604
605void TQtCalculator::EnterOpenParen()
606{
607 eestate = false;
608 last_input = OPERATION;
609 precedence_base += PRECEDENCE_INCR;
610 refresh_display = 1;
611
612}
613
614void TQtCalculator::EnterCloseParen()
615{
616 eestate = false;
617 last_input = OPERATION;
618 PushStack(&display_data);
619 refresh_display = 1;
620 if (UpdateStack(precedence_base))
621 UpdateDisplay();
622 if ((precedence_base -= PRECEDENCE_INCR) < 0)
623 precedence_base = 0;
624
625}
626
627void TQtCalculator::EnterRecip()
628{
629 eestate = false;
630 last_input = OPERATION;
631 DISPLAY_AMOUNT = 1 / DISPLAY_AMOUNT;
632 refresh_display = 1;
633 UpdateDisplay();
634}
635
636void TQtCalculator::EnterInt()
637{
638 eestate = false;
639 CALCAMNT work_amount1 = 0.0, work_amount2 = 0.0;
640
641 last_input = OPERATION;
642 if (!inverse){
643 work_amount2 = MODF(DISPLAY_AMOUNT, &work_amount1);
644 DISPLAY_AMOUNT = work_amount2 ;
645 }
646 else {
647 DISPLAY_AMOUNT = work_amount1;
648 inverse = false;
649 }
650
651 refresh_display = 1;
652 UpdateDisplay();
653
654}
655
656void TQtCalculator::EnterFactorial()
657{
658 eestate = false;
659 CALCAMNT work_amount1, work_amount2;
660 int incr;
661
662 MODF(DISPLAY_AMOUNT, &work_amount1);
663
664 incr = work_amount1 < 0 ? -1 : 1;
665 work_amount2 = work_amount1 - incr;
666 while (work_amount1 != 0 && work_amount2 != 0 && !display_error) {
667 work_amount1 *= work_amount2;
668 work_amount2 -= incr;
669 if(isinf(work_amount1)) {
670 display_error=1;
671 break;
672 }
673 }
674
675 if( work_amount1 == 0.0)
676 work_amount1 = 1.0;
677
678 DISPLAY_AMOUNT = work_amount1;
679 refresh_display = 1;
680 last_input = OPERATION;
681 UpdateDisplay();
682
683}
684
685void TQtCalculator::EnterSquare()
686{
687 eestate = false;
688 if (!inverse){
689 DISPLAY_AMOUNT *= DISPLAY_AMOUNT;
690 }
691 else if (DISPLAY_AMOUNT < 0)
692 display_error = 1;
693 else
694 DISPLAY_AMOUNT = SQRT(DISPLAY_AMOUNT);
695 refresh_display = 1;
696 inverse = false;
697 last_input = OPERATION;
698 UpdateDisplay();
699
700}
701
702void TQtCalculator::EnterNotCmp()
703{
704 eestate = false;
705 CALCAMNT boh_work_d;
706 long boh_work;
707
708 MODF(DISPLAY_AMOUNT, &boh_work_d);
709 if (FABS(boh_work_d) > LONG_MAX)
710 display_error = 1;
711 else {
712 boh_work = (long int) boh_work_d;
713 DISPLAY_AMOUNT = ~boh_work;
714 }
715 refresh_display = 1;
716 last_input = OPERATION;
717 UpdateDisplay();
718
719}
720
721void TQtCalculator::EnterHyp()
722{
723
724 switch(kcalcdefaults.style){
725 case 2:
726 case 1:{
727 if ( !sheet_name.isEmpty() )
728 useData();
729
730 if(!inverse){
731 eestate = false; // terminate ee input mode
732 DISPLAY_AMOUNT = stats.count();
733 last_input = OPERATION;
734 refresh_display = 1;
735 UpdateDisplay();
736 }
737 else{
738 inverse = false;
739 eestate = false; // terminate ee input mode
740 DISPLAY_AMOUNT = stats.sum();
741 last_input = OPERATION;
742 refresh_display = 1;
743 UpdateDisplay();
744 }
745
746 break;
747 }
748
749 case 0: {
750 // toggle between hyperbolic and standart trig functions
751 hyp_mode = !hyp_mode;
752
753 if (hyp_mode){
754 statusHYPLabel->setText("HYP");
755 }
756 else{
757 statusHYPLabel->setText("");
758 }
759 break;
760 }
761 }
762}
763
764
765void TQtCalculator::ExecSin(){
766
767 switch(kcalcdefaults.style){
768
769 case 0:{ // trig mode
770
771 ComputeSin();
772 break;
773 }
774
775 case 1:{ // stats mode
776 if ( !sheet_name.isEmpty() )
777 useData();
778
779 ComputeMean();
780 break;
781 }
782
783 case 2:{ // sheet mode
784 if ( !sheet_name.isEmpty() )
785 useData();
786
787 ComputeMin();
788 break;
789 }
790
791 }
792
793}
794
795void TQtCalculator::ComputeSum()
796{
797 inverse = false;
798 eestate = false;
799 DISPLAY_AMOUNT = stats.sum();
800 if (stats.error())
801 display_error = 1;
802
803 refresh_display = 1;
804 last_input = OPERATION;
805 UpdateDisplay();
806}
807
808void TQtCalculator::ComputeMul()
809{
810 inverse = false;
811 eestate = false;
812 DISPLAY_AMOUNT = stats.mul();
813 if (stats.error())
814 display_error = 1;
815
816 refresh_display = 1;
817 last_input = OPERATION;
818 UpdateDisplay();
819}
820
821void TQtCalculator::ComputeMin()
822{
823 inverse = false;
824 eestate = false;
825 DISPLAY_AMOUNT = stats.min();
826 if (stats.error())
827 display_error = 1;
828
829 refresh_display = 1;
830 last_input = OPERATION;
831 UpdateDisplay();
832}
833
834void TQtCalculator::ComputeMax()
835{
836 inverse = false;
837 eestate = false;
838 DISPLAY_AMOUNT = stats.max();
839 if (stats.error())
840 display_error = 1;
841
842 refresh_display = 1;
843 last_input = OPERATION;
844 UpdateDisplay();
845}
846
847void TQtCalculator::ComputeMean(){
848
849 if(!inverse){
850 eestate = false;
851 DISPLAY_AMOUNT = stats.mean();
852 if (stats.error())
853 display_error = 1;
854
855 refresh_display = 1;
856 last_input = OPERATION;
857 UpdateDisplay();
858 }
859 else{
860 inverse = false;
861 eestate = false;
862 DISPLAY_AMOUNT = stats.sum_of_squares();
863 if (stats.error())
864 display_error = 1;
865 refresh_display = 1;
866 last_input = OPERATION;
867 UpdateDisplay();
868
869 }
870
871}
872
873void TQtCalculator::ComputeSin()
874{
875 CALCAMNT work_amount;
876 eestate = false;
877 work_amount = DISPLAY_AMOUNT;
878
879 if (hyp_mode){
880 // sinh or arcsinh
881 if (!inverse){
882 DISPLAY_AMOUNT = SINH( work_amount);
883 }
884 else {
885 DISPLAY_AMOUNT = ASINH( work_amount);
886 if (errno == EDOM || errno == ERANGE)
887 display_error = 1;
888 inverse = false; // reset the inverse flag
889 }
890 }
891 else {
892 // sine or arcsine
893 if (!inverse){
894 // sine
895 switch (angle_mode) {
896 case ANG_DEGREE:
897 work_amount = DEG2RAD(DISPLAY_AMOUNT);
898 break;
899 case ANG_GRADIENT:
900 work_amount = GRA2RAD(DISPLAY_AMOUNT);
901 break;
902 case ANG_RADIAN:
903 work_amount = DISPLAY_AMOUNT;
904 break;
905 }
906 DISPLAY_AMOUNT = SIN( work_amount);
907 }
908 else {
909 // arcsine
910 DISPLAY_AMOUNT = ASIN(work_amount);
911 switch (angle_mode) {
912 case ANG_DEGREE:
913 work_amount = RAD2DEG(DISPLAY_AMOUNT);
914 break;
915 case ANG_GRADIENT:
916 work_amount = RAD2GRA(DISPLAY_AMOUNT);
917 break;
918 case ANG_RADIAN:
919 work_amount = DISPLAY_AMOUNT;
920 break;
921 }
922 DISPLAY_AMOUNT = work_amount;
923 if (errno == EDOM || errno == ERANGE)
924 display_error = 1;
925 inverse = false; // reset the inverse flag
926 }
927 }
928
929// Now a cheat to help the weird case of COS 90 degrees not being 0!!!
930
931 if (DISPLAY_AMOUNT < POS_ZERO && DISPLAY_AMOUNT > NEG_ZERO)
932 DISPLAY_AMOUNT=0;
933 refresh_display = 1;
934 last_input = OPERATION;
935 UpdateDisplay();
936
937}
938
939void TQtCalculator::ExecCos(){
940
941 switch(kcalcdefaults.style){
942
943 case 0:{ // trig mode
944
945 ComputeCos();
946 break;
947 }
948
949 case 1:{ // stats mode
950 if ( !sheet_name.isEmpty() )
951 useData();
952
953 ComputeStd();
954 break;
955 }
956
957 case 2:{ // sheet mode
958 if ( !sheet_name.isEmpty() )
959 useData();
960
961 ComputeMax();
962 break;
963 }
964
965 }
966
967}
968
969void TQtCalculator::ComputeStd(){
970
971 if(!inverse){ // std (n-1)
972 inverse = false;
973 eestate = false;
974 DISPLAY_AMOUNT = stats.std();
975
976 if (stats.error()){
977 display_error = 1;
978 }
979
980 refresh_display = 1;
981 last_input = OPERATION;
982 UpdateDisplay();
983 }
984 else{ // std (n)
985
986 inverse = false;
987 eestate = false;
988 DISPLAY_AMOUNT = stats.sample_std();
989
990 if (stats.error())
991 display_error = 1;
992
993 refresh_display = 1;
994 last_input = OPERATION;
995 UpdateDisplay();
996
997
998
999 }
1000
1001}
1002
1003void TQtCalculator::ComputeCos()
1004{
1005 CALCAMNT work_amount;
1006 eestate = false;
1007 work_amount = DISPLAY_AMOUNT;
1008
1009 if (hyp_mode){
1010 // cosh or arccosh
1011 if (!inverse){
1012 DISPLAY_AMOUNT = COSH( work_amount);
1013 }
1014 else {
1015 DISPLAY_AMOUNT = ACOSH( work_amount);
1016 if (errno == EDOM || errno == ERANGE)
1017 display_error = 1;
1018 inverse = false; // reset the inverse flag
1019 }
1020 }
1021 else {
1022 // cosine or arccosine
1023 if (!inverse){
1024 // sine
1025 switch (angle_mode) {
1026 case ANG_DEGREE:
1027 work_amount = DEG2RAD(DISPLAY_AMOUNT);
1028 break;
1029 case ANG_GRADIENT:
1030 work_amount = GRA2RAD(DISPLAY_AMOUNT);
1031 break;
1032 case ANG_RADIAN:
1033 work_amount = DISPLAY_AMOUNT;
1034 break;
1035 }
1036 DISPLAY_AMOUNT = COS( work_amount);
1037 }
1038 else {
1039 // arccosine
1040 DISPLAY_AMOUNT = ACOS(work_amount);
1041 switch (angle_mode) {
1042 case ANG_DEGREE:
1043 work_amount = RAD2DEG(DISPLAY_AMOUNT);
1044 break;
1045 case ANG_GRADIENT:
1046 work_amount = RAD2GRA(DISPLAY_AMOUNT);
1047 break;
1048 case ANG_RADIAN:
1049 work_amount = DISPLAY_AMOUNT;
1050 break;
1051 }
1052
1053 DISPLAY_AMOUNT = work_amount;
1054
1055 if (errno == EDOM || errno == ERANGE)
1056 display_error = 1;
1057 inverse = false; // reset the inverse flag
1058 }
1059 }
1060
1061// Now a cheat to help the weird case of COS 90 degrees not being 0!!!
1062
1063
1064 if (DISPLAY_AMOUNT < POS_ZERO && DISPLAY_AMOUNT > NEG_ZERO)
1065 DISPLAY_AMOUNT=0;
1066 refresh_display = 1;
1067 last_input = OPERATION;
1068 UpdateDisplay();
1069
1070}
1071
1072void TQtCalculator::ExecTan(){
1073
1074 switch(kcalcdefaults.style){
1075
1076 case 0:{ // trig mode
1077
1078 ComputeTan();
1079 break;
1080 }
1081
1082 case 2:
1083 case 1:{ // stats mode
1084
1085 if ( !sheet_name.isEmpty() )
1086 useData();
1087
1088 ComputeMedean();
1089 break;
1090 }
1091
1092 }
1093
1094}
1095
1096void TQtCalculator::ComputeMedean(){
1097
1098 if(!inverse){ // std (n-1)
1099 inverse = false;
1100 eestate = false;
1101 DISPLAY_AMOUNT = stats.median();
1102
1103 if (stats.error()){
1104 display_error = 1;
1105 }
1106
1107 refresh_display = 1;
1108 last_input = OPERATION;
1109 UpdateDisplay();
1110 }
1111 else{ // std (n)
1112
1113 inverse = false;
1114 eestate = false;
1115 DISPLAY_AMOUNT = stats.median();
1116
1117 if (stats.error())
1118 display_error = 1;
1119
1120 refresh_display = 1;
1121 last_input = OPERATION;
1122 UpdateDisplay();
1123
1124 }
1125}
1126
1127
1128void TQtCalculator::ComputeTan()
1129{
1130 CALCAMNT work_amount;
1131 eestate = false;
1132 work_amount = DISPLAY_AMOUNT;
1133
1134 if (hyp_mode){
1135 // tanh or arctanh
1136 if (!inverse){
1137 DISPLAY_AMOUNT = TANH( work_amount);
1138 }
1139 else {
1140 DISPLAY_AMOUNT = ATANH( work_amount);
1141 if (errno == EDOM || errno == ERANGE)
1142 display_error = 1;
1143 inverse = false; // reset the inverse flag
1144 }
1145 }
1146 else {
1147 // tan or arctan
1148 if (!inverse){
1149 // tan
1150 switch (angle_mode) {
1151 case ANG_DEGREE:
1152 work_amount = DEG2RAD(DISPLAY_AMOUNT);
1153 break;
1154 case ANG_GRADIENT:
1155 work_amount = GRA2RAD(DISPLAY_AMOUNT);
1156 break;
1157 case ANG_RADIAN:
1158 work_amount = DISPLAY_AMOUNT;
1159 break;
1160 }
1161 DISPLAY_AMOUNT = TAN( work_amount);
1162 if (errno == EDOM || errno == ERANGE)
1163 display_error = 1;
1164 }
1165 else {
1166 // arctan
1167 DISPLAY_AMOUNT = ATAN(work_amount);
1168 switch (angle_mode) {
1169 case ANG_DEGREE:
1170 work_amount = RAD2DEG(DISPLAY_AMOUNT);
1171 break;
1172 case ANG_GRADIENT:
1173 work_amount = RAD2GRA(DISPLAY_AMOUNT);
1174 break;
1175 case ANG_RADIAN:
1176 work_amount = DISPLAY_AMOUNT;
1177 break;
1178 }
1179
1180 DISPLAY_AMOUNT = work_amount;
1181
1182 if (errno == EDOM || errno == ERANGE)
1183 display_error = 1;
1184 inverse = false; // reset the inverse flag
1185 }
1186 }
1187
1188// Now a cheat to help the weird case of COS 90 degrees not being 0!!!
1189
1190 if (DISPLAY_AMOUNT < POS_ZERO && DISPLAY_AMOUNT > NEG_ZERO)
1191 DISPLAY_AMOUNT=0;
1192 refresh_display = 1;
1193 last_input = OPERATION;
1194 UpdateDisplay();
1195
1196}
1197
1198
1199void TQtCalculator::EnterPercent()
1200{
1201 eestate = false;
1202 last_input = OPERATION;
1203 percent_mode = 1;
1204 EnterEqual();
1205 percent_mode = 0;
1206
1207}
1208
1209void TQtCalculator::EnterLogr()
1210{
1211
1212 switch(kcalcdefaults.style){
1213 case 2:
1214 {
1215 if ( !sheet_name.isEmpty() )
1216 useData();
1217
1218 ComputeSum();
1219 break;
1220 }
1221 case 1:{
1222
1223 if ( !sheet_name.isEmpty() )
1224 useData();
1225
1226 if(!inverse){
1227 eestate = false; // terminate ee input mode
1228 stats.enterData(DISPLAY_AMOUNT);
1229 last_input = OPERATION;
1230 refresh_display = 1;
1231 DISPLAY_AMOUNT = stats.count();
1232 UpdateDisplay();
1233 }
1234 else{
1235 inverse = false;
1236 last_input = OPERATION;
1237 refresh_display = 1;
1238 stats.clearLast();
1239 setStatusLabel("Last stat item erased");
1240 DISPLAY_AMOUNT = stats.count();
1241 UpdateDisplay();
1242
1243 }
1244
1245 break;
1246 }
1247 case 0:{
1248
1249 eestate = false;
1250 last_input = OPERATION;
1251
1252 if (!inverse) {
1253 if (DISPLAY_AMOUNT <= 0)
1254 display_error = 1;
1255 else
1256 DISPLAY_AMOUNT = LOG_TEN(DISPLAY_AMOUNT);
1257 refresh_display = 1;
1258 UpdateDisplay();
1259 } else if (inverse) {
1260 DISPLAY_AMOUNT = POW(10, DISPLAY_AMOUNT);
1261 refresh_display = 1;
1262 inverse = false;
1263 UpdateDisplay();
1264 }
1265 break;
1266 }
1267 }
1268}
1269
1270void TQtCalculator::EnterLogn()
1271{
1272
1273 switch(kcalcdefaults.style){
1274 case 2:{
1275
1276 if ( !sheet_name.isEmpty() )
1277 useData();
1278
1279 ComputeMul();
1280
1281 break;
1282 }
1283 case 1:{
1284
1285 if ( !sheet_name.isEmpty() )
1286 useData();
1287
1288 if(!inverse){
1289
1290 stats.clearAll();
1291 setStatusLabel(i18n("Stat mem cleared"));
1292
1293 }
1294 else{
1295 inverse = false;
1296 UpdateDisplay();
1297 }
1298
1299 break;
1300 }
1301 case 0:{
1302 eestate = false;
1303 last_input = OPERATION;
1304 if (!inverse) {
1305 if (DISPLAY_AMOUNT <= 0)
1306 display_error = 1;
1307 else
1308 DISPLAY_AMOUNT = LOG(DISPLAY_AMOUNT);
1309 refresh_display = 1;
1310 UpdateDisplay();
1311 } else if (inverse) {
1312 DISPLAY_AMOUNT = EXP(DISPLAY_AMOUNT);
1313 refresh_display = 1;
1314 inverse =false;
1315 UpdateDisplay();
1316 }
1317 break;
1318 }
1319 }
1320
1321}
1322
1323
1324void TQtCalculator::base_selected(int number){
1325
1326 switch(number){
1327 case 0:
1328 SetHex();
1329 break;
1330 case 1:
1331 SetDec();
1332 break;
1333 case 2:
1334 SetOct();
1335 break;
1336 case 3:
1337 SetBin();
1338 break;
1339 default: // we shouldn't ever end up here
1340 SetDec();
1341 }
1342}
1343
1344
1345void TQtCalculator::angle_selected(int number){
1346
1347 switch(number){
1348 case 0:
1349 SetDeg();
1350 break;
1351 case 1:
1352 SetRad();
1353 break;
1354 case 2:
1355 SetGra();
1356 break;
1357 default: // we shouldn't ever end up here
1358 SetRad();
1359 }
1360}
1361
1362void TQtCalculator::SetInverse(){
1363
1364 inverse = ! inverse;
1365 if (inverse){
1366 statusINVLabel->setText("INV");
1367 }
1368 else{
1369 statusINVLabel->setText("NORM");
1370 }
1371}
1372
1373
1374void TQtCalculator::SetDeg() {
1375 angle_mode = ANG_DEGREE;
1376}
1377
1378void TQtCalculator::SetGra() {
1379 angle_mode = ANG_GRADIENT;
1380}
1381
1382void TQtCalculator::SetRad() {
1383 angle_mode = ANG_RADIAN;
1384
1385}
1386
1387void TQtCalculator::SetHex() {
1388 /*
1389 * Set Hex Mode
1390 */
1391
1392 current_base = NB_HEX;
1393 display_size = BOH_SIZE;
1394 decimal_point = 0;
1395 input_limit = 8;
1396
1397 UpdateDisplay();
1398}
1399
1400void TQtCalculator::SetOct() {
1401 /*
1402 * Set Oct Mode
1403 */
1404
1405 current_base = NB_OCTAL;
1406 display_size = BOH_SIZE;
1407 decimal_point = 0;
1408 input_limit = 11;
1409
1410 UpdateDisplay();
1411}
1412
1413void TQtCalculator::SetBin() {
1414 /*
1415 * Set Bin Mode
1416 */
1417
1418 current_base = NB_BINARY;
1419 display_size = BOH_SIZE;
1420 decimal_point = 0;
1421 input_limit = 16;
1422
1423 UpdateDisplay();
1424}
1425
1426void TQtCalculator::SetDec()
1427{
1428 /*
1429 * Set Dec Mode
1430 */
1431
1432 current_base = NB_DECIMAL;
1433 display_size = DEC_SIZE;
1434 input_limit = 0;
1435
1436
1437 UpdateDisplay();
1438}
1439
1440
1441void TQtCalculator::EE()
1442{
1443 if(inverse){
1444 DISPLAY_AMOUNT = pi;
1445 inverse = false;
1446 UpdateDisplay();
1447 }
1448 else{
1449 if(eestate == true)
1450 eestate = false;
1451 else{
1452 eestate = true;
1453 strcat(display_str,"e");
1454 }
1455
1456 UpdateDisplay();
1457 }
1458
1459}
1460
1461void TQtCalculator::MR()
1462{
1463 eestate = false;
1464 last_input = OPERATION;
1465 DISPLAY_AMOUNT = memory_num;
1466 refresh_display = 1;
1467 UpdateDisplay();
1468
1469}
1470
1471void TQtCalculator::Mplusminus()
1472{
1473
1474 eestate = false;
1475 EnterEqual();
1476 if (!inverse)
1477 memory_num += DISPLAY_AMOUNT;
1478 else {
1479 memory_num -= DISPLAY_AMOUNT;
1480 inverse = false;
1481 }
1482}
1483
1484void TQtCalculator::MC()
1485{
1486
1487 memory_num = 0;
1488 refresh_display = 1;
1489}
1490
1491void TQtCalculator::EnterEqual()
1492{
1493 eestate = false;
1494 last_input = OPERATION;
1495 PushStack(&display_data);
1496 refresh_display = 1;
1497
1498 /* if (UpdateStack(0))*/
1499 UpdateStack(0);
1500
1501 UpdateDisplay();
1502 precedence_base = 0;
1503
1504 CALCAMNT* number ;
1505
1506 if(temp_stack.count() > TEMP_STACK_SIZE){
1507
1508 number = temp_stack.getFirst();
1509 temp_stack.removeFirst();
1510
1511 if(number)
1512 free(number);
1513 }
1514
1515 number = (CALCAMNT*) malloc(sizeof(CALCAMNT));
1516 *number = DISPLAY_AMOUNT;
1517
1518 //printf("appending %Lg\n",*number);
1519
1520 temp_stack.append(number);
1521
1522
1523}
1524
1525void TQtCalculator::Clear(){
1526
1527 eestate = false;
1528
1529 input_count = 0;
1530 decimal_point = 0;
1531
1532 if(last_input == OPERATION){
1533 // printf("LAST_INPUT = OPERATION\n");
1534 last_input = DIGIT;
1535 PopStack();
1536 }
1537 else{
1538 // printf("LAST_INPUT = DIGIT\n");
1539 last_input = DIGIT;
1540 }
1541
1542
1543 if( display_error){
1544 display_error = 0;
1545 refresh_display = 0;
1546 }
1547
1548 if (!refresh_display) {
1549 DISPLAY_AMOUNT = 0L;
1550 UpdateDisplay();
1551 }
1552
1553}
1554
1555void TQtCalculator::ClearAll()
1556{
1557
1558 eestate = false;
1559 // last_input = OPERATION;
1560 last_input = DIGIT;
1561 RefreshCalculator();
1562 refresh_display = 1;
1563
1564}
1565
1566
1567
1568void TQtCalculator::UpdateDisplay()
1569{
1570
1571 // this needs to be rewritten based on whether we are currently
1572 // inputting a number so that the period and the 0 after a period
1573 // are correctly displayed.
1574
1575 CALCAMNT boh_work_d;
1576 long boh_work = 0;
1577 int str_size = 0;
1578
1579 if(eestate && (current_base == NB_DECIMAL)){
1580
1581 calc_display->setText(display_str);
1582 return;
1583 }
1584
1585 if (current_base != NB_DECIMAL) {
1586 MODF(DISPLAY_AMOUNT, &boh_work_d);
1587 if (boh_work_d < LONG_MIN || boh_work_d > ULONG_MAX)
1588 display_error = 1;
1589
1590 /*
1591 * We may be in that never-never land where boh numbers
1592 * turn from positive to negative - if so then we do
1593 * just that, allowing boh negative numbers to be entered
1594 * as read (from dumps and the like!)
1595 */
1596 else if (boh_work_d > LONG_MAX) {
1597 DISPLAY_AMOUNT =
1598 LONG_MIN+(boh_work_d-LONG_MAX-1);
1599 boh_work = (long)DISPLAY_AMOUNT;
1600 }
1601 else {
1602 DISPLAY_AMOUNT = boh_work_d;
1603 boh_work = (long) boh_work_d;
1604 }
1605 }
1606
1607 if (!display_error) {
1608
1609 if (current_base == NB_BINARY)
1610 str_size = cvb(display_str,
1611 boh_work,
1612 BOH_SIZE);
1613 else if (current_base == NB_OCTAL)
1614 str_size = sprintf(display_str,
1615 "%lo",
1616 boh_work);
1617 else if (current_base == NB_DECIMAL) {
1618
1619 if(!kcalcdefaults.fixed || last_input == DIGIT
1620 || (DISPLAY_AMOUNT > 1.0e+16)){
1621
1622 // if I don't guard against the DISPLAY_AMOUNT being too large
1623 // kcalc will segfault on larger amount. Such as from typing
1624 // from 5*5*******
1625
1626 str_size = sprintf(display_str,
1627
1628#ifdef HAVE_LONG_DOUBLE
1629 "%.*Lg", // was *Lg
1630
1631 kcalcdefaults.precision +1,
1632#else
1633 "%.*g",
1634
1635 kcalcdefaults.precision +1,
1636#endif
1637 DISPLAY_AMOUNT);
1638 }
1639 else{//fixed
1640
1641 str_size = sprintf(display_str,
1642
1643#ifdef HAVE_LONG_DOUBLE
1644 "%.*Lf", // was *Lg
1645
1646 kcalcdefaults.fixedprecision ,
1647#else
1648 "%.*f",
1649
1650 kcalcdefaults.fixedprecision ,
1651#endif
1652 DISPLAY_AMOUNT);
1653
1654 }// fixed
1655
1656 if ( input_count > 0 && !strpbrk(display_str,"e") &&
1657 last_input == DIGIT ) {
1658
1659#ifdef HAVE_LONG_DOUBLE
1660 str_size = sprintf(display_str,
1661 "%.*Lf",
1662 (kcalcdefaults.precision +1 > input_count)?
1663 input_count : kcalcdefaults.precision ,
1664 DISPLAY_AMOUNT);
1665#else
1666 str_size = sprintf(display_str,
1667 "%.*f",
1668 (kcalcdefaults.precision +1 > input_count)?
1669 input_count : kcalcdefaults.precision ,
1670 DISPLAY_AMOUNT);
1671#endif
1672 }
1673
1674 }
1675 else
1676 if (current_base == NB_HEX)
1677 str_size = sprintf(display_str,
1678 "%lX",
1679 boh_work);
1680 else
1681 display_error = 1;
1682 }
1683
1684 if (display_error || str_size < 0) {
1685 display_error = 1;
1686 strcpy(display_str,"Error");
1687 if(kcalcdefaults.beep)
1688 KNotifyClient::beep();
1689 }
1690 calc_display->setText(display_str);
1691
1692
1693 if (inverse){
1694 statusINVLabel->setText("INV");
1695 }
1696 else{
1697 statusINVLabel->setText("NORM");
1698 }
1699
1700 if (hyp_mode){
1701 statusHYPLabel->setText("HYP");
1702 }
1703 else{
1704 statusHYPLabel->setText("");
1705 }
1706
1707
1708}
1709
1710int cvb(char *out_str, long amount, int max_digits)
1711{
1712 /*
1713 * A routine that converts a long int to
1714 * binary display format
1715 */
1716
1717 char work_str[(sizeof(amount) * CHAR_BIT) + 1];
1718 int work_char = 0,
1719 lead_zero = 1,
1720 lead_one = 1,
1721 lead_one_count = 0,
1722 work_size = sizeof(amount) * CHAR_BIT;
1723 unsigned long bit_mask = (1 << ((sizeof(amount) * CHAR_BIT) - 1));
1724
1725 while (bit_mask) {
1726
1727 if (amount & bit_mask) {
1728 if (lead_one)
1729 lead_one_count++;
1730 lead_zero = 0;
1731 work_str[work_char++] = '1';
1732 } else {
1733 lead_one = 0;
1734 if (!lead_zero)
1735 work_str[work_char++] = '0';
1736 }
1737 bit_mask >>= 1;
1738 }
1739 if (!work_char)
1740 work_str[work_char++] = '0';
1741 work_str[work_char] = '\0';
1742
1743 if (work_char-lead_one_count < max_digits)
1744 return strlen(strcpy(out_str,
1745 &work_str[lead_one_count ?
1746 work_size - max_digits :
1747 0]));
1748 else
1749 return -1;
1750}
1751
1752int UpdateStack(int run_precedence)
1753{
1754 item_contents new_item, *top_item , *top_function;
1755 CALCAMNT left_op =0.0 , right_op =0.0;
1756 int op_function= 0, return_value = 0;
1757
1758 new_item.s_item_type = ITEM_AMOUNT;
1759 while ((top_function = TopTypeStack(ITEM_FUNCTION)) &&
1760 top_function->s_item_data.item_func_data.item_precedence >=
1761 run_precedence) {
1762
1763 return_value = 1;
1764
1765 if ((top_item = PopStack())->s_item_type != ITEM_AMOUNT){
1766 KMessageBox::error( 0, "Stack processing error - right_op");
1767
1768 }
1769 right_op = top_item->s_item_data.item_amount;
1770
1771 if (!((top_item = PopStack()) &&
1772 top_item->s_item_type == ITEM_FUNCTION)) {
1773 KMessageBox::error( 0, "Stack processing error - function");
1774
1775 }
1776 op_function =
1777 top_item->s_item_data.item_func_data.item_function;
1778
1779 if (!((top_item = PopStack()) &&
1780 top_item->s_item_type == ITEM_AMOUNT)) {
1781 KMessageBox::error( 0, "Stack processing error - left_op");
1782 }
1783 left_op = top_item->s_item_data.item_amount;
1784
1785 new_item.s_item_data.item_amount =
1786 (Arith_ops[op_function])(left_op, right_op);
1787 PushStack(&new_item);
1788
1789 }
1790 if (return_value &&
1791 percent_mode &&
1792 !display_error &&
1793 Prcnt_ops[op_function] != NULL){
1794 new_item.s_item_data.item_amount =
1795 (Prcnt_ops[op_function])(left_op,
1796 right_op,
1797 new_item.s_item_data.item_amount);
1798 PushStack(&new_item);
1799 }
1800 if (return_value)
1801 DISPLAY_AMOUNT = new_item.s_item_data.item_amount;
1802
1803 return return_value;
1804}
1805
1806int isoddint(CALCAMNT input)
1807{
1808 CALCAMNT dummy;
1809 /*
1810 * Routine to check if CALCAMNT is an Odd integer
1811 */
1812 return (MODF(input, &dummy) == 0.0 &&
1813 MODF(input/2, &dummy) == 0.5);
1814}
1815
1816CALCAMNT ExecOr(CALCAMNT left_op, CALCAMNT right_op)
1817{
1818 // printf("ExecOr\n");
1819 CALCAMNT boh_work_d;
1820 long boh_work_l, boh_work_r;
1821
1822 MODF(left_op, &boh_work_d);
1823 if (FABS(boh_work_d) > LONG_MAX) {
1824 display_error = 1;
1825 return 0;
1826 }
1827 boh_work_l = (long int)boh_work_d;
1828 MODF(right_op, &boh_work_d);
1829 if (FABS(boh_work_d) > LONG_MAX) {
1830 display_error = 1;
1831 return 0;
1832 }
1833 boh_work_r = (long int) boh_work_d;
1834 return (boh_work_l | boh_work_r);
1835}
1836
1837CALCAMNT ExecXor(CALCAMNT left_op, CALCAMNT right_op)
1838{
1839 // printf("ExecXOr\n");
1840 CALCAMNT boh_work_d;
1841 long boh_work_l, boh_work_r;
1842
1843 MODF(left_op, &boh_work_d);
1844 if (FABS(boh_work_d) > LONG_MAX) {
1845 display_error = 1;
1846 return 0;
1847 }
1848 boh_work_l = (long int) boh_work_d;
1849 MODF(right_op, &boh_work_d);
1850 if (FABS(boh_work_d) > LONG_MAX) {
1851 display_error = 1;
1852 return 0;
1853 }
1854 boh_work_r = (long int) boh_work_d;
1855 return (boh_work_l ^ boh_work_r);
1856}
1857
1858CALCAMNT ExecAnd(CALCAMNT left_op, CALCAMNT right_op)
1859{
1860 // printf("ExecAnd\n");
1861 CALCAMNT boh_work_d;
1862 long boh_work_l, boh_work_r;
1863
1864 MODF(left_op, &boh_work_d);
1865 if (FABS(boh_work_d) > LONG_MAX) {
1866 display_error = 1;
1867 return 0;
1868 }
1869 boh_work_l = (long int ) boh_work_d;
1870 MODF(right_op, &boh_work_d);
1871 if (FABS(boh_work_d) > LONG_MAX) {
1872 display_error = 1;
1873 return 0;
1874 }
1875 boh_work_r = (long int ) boh_work_d;
1876 return (boh_work_l & boh_work_r);
1877}
1878
1879CALCAMNT ExecLsh(CALCAMNT left_op, CALCAMNT right_op)
1880{
1881 // printf("ExecLsh\n");
1882 CALCAMNT boh_work_d;
1883 long boh_work_l, boh_work_r;
1884
1885 MODF(left_op, &boh_work_d);
1886 if (FABS(boh_work_d) > LONG_MAX) {
1887 display_error = 1;
1888 return 0;
1889 }
1890 boh_work_l = (long int) boh_work_d;
1891 MODF(right_op, &boh_work_d);
1892 if (FABS(boh_work_d) > LONG_MAX) {
1893 display_error = 1;
1894 return 0;
1895 }
1896 boh_work_r = (long int ) boh_work_d;
1897 return (boh_work_l << boh_work_r);
1898}
1899
1900CALCAMNT ExecRsh(CALCAMNT left_op, CALCAMNT right_op)
1901{
1902 // printf("ExecRsh\n");
1903 CALCAMNT boh_work_d;
1904 long boh_work_l, boh_work_r;
1905
1906 MODF(left_op, &boh_work_d);
1907 if (FABS(boh_work_d) > LONG_MAX) {
1908 display_error = 1;
1909 return 0;
1910 }
1911 boh_work_l = (long int ) boh_work_d;
1912 MODF(right_op, &boh_work_d);
1913 if (FABS(boh_work_d) > LONG_MAX) {
1914 display_error = 1;
1915 return 0;
1916 }
1917 boh_work_r = ( long int ) boh_work_d;
1918 return (boh_work_l >> boh_work_r);
1919}
1920
1921CALCAMNT ExecAdd(CALCAMNT left_op, CALCAMNT right_op)
1922{
1923 // printf("ExecAdd\n");
1924 return left_op + right_op;
1925}
1926
1927CALCAMNT ExecSubtract(CALCAMNT left_op, CALCAMNT right_op)
1928{
1929 // printf("ExecSubtract\n");
1930 return left_op - right_op;
1931}
1932
1933CALCAMNT ExecMultiply(CALCAMNT left_op, CALCAMNT right_op)
1934{
1935 // printf("ExecMulti\n");
1936 return left_op * right_op;
1937}
1938
1939CALCAMNT ExecDivide(CALCAMNT left_op, CALCAMNT right_op)
1940{
1941 // printf("ExecDivide\n");
1942 if (right_op == 0) {
1943 display_error = 1;
1944 return 0L;
1945 } else
1946 return left_op / right_op;
1947}
1948
1949CALCAMNT ExecMod(CALCAMNT left_op, CALCAMNT right_op)
1950{
1951 // printf("ExecMod\n");
1952 CALCAMNT temp =0.0;
1953
1954 if (right_op == 0) {
1955 display_error = 1;
1956 return 0L;
1957 } else {
1958
1959 // x mod y should be the same as x mod -y, thus:
1960 right_op = FABS(right_op);
1961
1962 temp = FMOD(left_op, right_op);
1963
1964 // let's make sure that -7 mod 3 = 2 and NOT -1.
1965 // In other words we wand x mod 3 to be a _positive_ number
1966 // that is 0,1 or 2.
1967
1968 if( temp < 0 ) temp = right_op + temp;
1969 temp = FABS(temp);
1970
1971 return temp;
1972 }
1973}
1974
1975CALCAMNT ExecIntDiv(CALCAMNT left_op, CALCAMNT right_op)
1976{
1977 // printf("IndDiv\n");
1978 if (right_op == 0) {
1979 display_error = 1;
1980 return 0L;
1981 } else {
1982 MODF(left_op / right_op, &left_op);
1983 return left_op;
1984 }
1985}
1986
1987CALCAMNT ExecPower(CALCAMNT left_op, CALCAMNT right_op)
1988{
1989
1990 // printf("ExecPowser %g left_op, %g right_op\n",left_op, right_op);
1991 if (right_op == 0)
1992 return 1L;
1993 if (left_op < 0 && isoddint(1/right_op))
1994 left_op = -1L * POW((-1L * left_op), right_op);
1995 else
1996 left_op = POW(left_op, right_op);
1997 if (errno == EDOM || errno == ERANGE) {
1998 display_error = 1;
1999 return 0;
2000 } else
2001 return left_op;
2002}
2003
2004CALCAMNT ExecPwrRoot(CALCAMNT left_op, CALCAMNT right_op)
2005{
2006
2007 // printf("ExecPwrRoot %g left_op, %g right_op\n", left_op, right_op);
2008 if (right_op == 0) {
2009 display_error = 1;
2010 return 0L;
2011 }
2012 if (left_op < 0 && isoddint(right_op))
2013 left_op = -1L * POW((-1L * left_op), (1L)/right_op);
2014 else
2015 left_op = POW(left_op, (1L)/right_op);
2016 if (errno == EDOM || errno == ERANGE) {
2017 display_error = 1;
2018 return 0;
2019 }
2020 else
2021 return left_op;
2022}
2023
2024
2025CALCAMNT ExecAddSubP(CALCAMNT left_op, CALCAMNT right_op, CALCAMNT result)
2026{
2027 // printf("ExecAddsubP\n");
2028 (void) left_op;
2029
2030 if (result == 0) {
2031 display_error = 1;
2032 return 0;
2033 } else
2034 return (result * 100L) / right_op;
2035}
2036
2037CALCAMNT ExecMultiplyP(CALCAMNT left_op, CALCAMNT right_op, CALCAMNT result)
2038{
2039 // printf("ExecMultiplyP\n");
2040 (void) left_op;
2041 (void) right_op;
2042
2043 return (result / 100L);
2044}
2045
2046CALCAMNT ExecDivideP(CALCAMNT left_op, CALCAMNT right_op, CALCAMNT result)
2047{
2048 // printf("ExecDivideP\n");
2049 (void) left_op;
2050 (void) right_op;
2051
2052 return (result * 100L);
2053}
2054
2055CALCAMNT ExecPowerP(CALCAMNT left_op, CALCAMNT right_op, CALCAMNT result)
2056{
2057 // printf("ExecPowerP\n");
2058 (void) result;
2059 return ExecPower(left_op, (right_op / 100L));
2060}
2061
2062CALCAMNT ExecPwrRootP(CALCAMNT left_op, CALCAMNT right_op, CALCAMNT result)
2063{
2064 // printf("ExePwrRootP\n");
2065 (void) result;
2066
2067 if (right_op == 0) {
2068 display_error = 1;
2069 return 0;
2070 } else
2071 return ExecPower(left_op, (100L / right_op));
2072}
2073
2074
2075
2076stack_ptr AllocStackItem (void) {
2077
2078 if (stack_next <= stack_last) {
2079
2080 process_stack[stack_next].prior_item = NULL;
2081 process_stack[stack_next].prior_type = NULL;
2082 return &process_stack[stack_next++];
2083 }
2084
2085 KMessageBox::error( 0, "Stack Error !");
2086 return &process_stack[stack_next];
2087}
2088
2089void UnAllocStackItem (stack_ptr return_item) {
2090
2091 if (return_item != &process_stack[--stack_next]) {
2092
2093 KMessageBox::error( 0, "Stack Error !");
2094 }
2095
2096}
2097void PushStack(item_contents *add_item)
2098{
2099 /*
2100 * Add an item to the stack
2101 */
2102
2103 stack_ptr new_item = top_of_stack;
2104
2105 if (!(new_item &&
2106 new_item->item_value.s_item_type == add_item->s_item_type)) {
2107
2108 new_item = AllocStackItem(); /* Get a new item */
2109
2110 /*
2111 * Chain new item to existing stacks
2112 */
2113
2114 new_item->prior_item = top_of_stack;
2115 top_of_stack = new_item;
2116 new_item->prior_type = top_type_stack[add_item->s_item_type];
2117 top_type_stack[add_item->s_item_type] = new_item;
2118 }
2119
2120 new_item->item_value = *add_item; /* assign contents*/
2121
2122}
2123
2124item_contents *PopStack(void)
2125{
2126 /*
2127 * Remove and return the top item in the stack
2128 */
2129
2130 static item_contents return_item;
2131 item_contents *return_item_ptr = NULL;
2132 stack_ptr return_stack_ptr;
2133
2134 if ((return_stack_ptr = top_of_stack)) {
2135 return_item = top_of_stack->item_value;
2136
2137 top_type_stack[return_item.s_item_type]
2138 = top_of_stack->prior_type;
2139 top_of_stack = top_of_stack->prior_item;
2140
2141 UnAllocStackItem(return_stack_ptr);
2142 return_item_ptr = &return_item;
2143 }
2144
2145 return return_item_ptr;
2146}
2147
2148item_contents *TopOfStack(void)
2149{
2150 /*
2151 * Return the top item in the stack without removing
2152 */
2153
2154 item_contents *return_item_ptr = NULL;
2155
2156 if (top_of_stack) {
2157 return_item_ptr = &top_of_stack->item_value;
2158 }
2159
2160 return return_item_ptr;
2161}
2162
2163item_contents *TopTypeStack(item_type rqstd_type)
2164{
2165 /*
2166 * Return the top item in the stack without removing
2167 */
2168
2169 item_contents *return_item_ptr = NULL;
2170
2171 if (top_type_stack[rqstd_type]) {
2172 return_item_ptr = &top_type_stack[rqstd_type]->item_value;
2173 }
2174
2175 return return_item_ptr;
2176}
2177
2178
2179/*
2180 * Stack storage management Data and Functions
2181 */
2182
2183
2184
2185void InitStack (void) {
2186
2187 stack_next = 0;
2188 stack_last = STACK_SIZE - 1;
2189 top_of_stack = top_type_stack[0] = top_type_stack[1] = NULL;
2190}
2191
2192