kspread

kcalc_core.cpp

00001 /*
00002     $Id: kcalc_core.cpp 541875 2006-05-17 14:42:51Z zander $
00003 
00004     kCalculator, a scientific calculator for the X window system using the
00005     Qt widget libraries, available at no cost at http://www.troll.no
00006 
00007     The stack engine conatined in this file was take from
00008     Martin Bartlett's xfrmcalc
00009 
00010     portions:   Copyright (C) 1996 Bernd Johannes Wuebben
00011                                    wuebben@math.cornell.edu
00012 
00013     portions:   Copyright (C) 1995 Martin Bartlett
00014 
00015     This program is free software; you can redistribute it and/or modify
00016     it under the terms of the GNU General Public License as published by
00017     the Free Software Foundation; either version 2 of the License, or
00018     (at your option) any later version.
00019 
00020     This program is distributed in the hope that it will be useful,
00021     but WITHOUT ANY WARRANTY; without even the implied warranty of
00022     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023     GNU General Public License for more details.
00024 
00025     You should have received a copy of the GNU General Public License
00026     along with this program; if not, write to the Free Software
00027     Foundation, Inc., 51 Franklin Street, Fifth Floor,
00028  * Boston, MA 02110-1301, USA.
00029 
00030 */
00031 
00032 #include <config.h>
00033 #include <assert.h>
00034 #include <stdio.h>
00035 #include <errno.h>
00036 #include <limits.h>
00037 #include <math.h>
00038 #include <signal.h>
00039 #include <klocale.h>
00040 #include <kmessagebox.h>
00041 #include <knotifyclient.h>
00042 
00043 #include "kcalc.h"
00044 
00045 //What's that?!? (Werner)
00046 //#define i18n( x ) x
00047 
00048 // Undefine HAVE_LONG_DOUBLE for Beta 4 since RedHat 5.0 comes with a borken
00049 // glibc
00050 
00051 #ifdef HAVE_LONG_DOUBLE
00052 #undef HAVE_LONG_DOUBLE
00053 #endif
00054 
00055 #ifndef HAVE_FUNC_ISINF
00056 #ifdef HAVE_IEEEFP_H
00057 #include <ieeefp.h>
00058 #else
00059 #include <math.h>
00060 #endif
00061 
00062 int isinf(double x) { return !finite(x) && x==x; }
00063 #endif
00064 
00065 extern QPtrList<CALCAMNT> temp_stack;
00066 last_input_type last_input;
00067 char            display_str[DSP_SIZE+1];
00068 
00069 stack_ptr       top_of_stack = NULL;
00070 stack_ptr       top_type_stack[2] = { NULL, NULL };
00071 int             stack_next, stack_last;
00072 stack_item      process_stack[STACK_SIZE];
00073 
00074 int             inverse = FALSE;
00075 int             precedence_base = 0;
00076 num_base        current_base = NB_DECIMAL;
00077 int             input_limit = 0;
00078 int             input_count = 0;
00079 
00080 //item_contents         display_data = { ITEM_AMOUNT, 0 };
00081 item_contents   display_data;
00082 
00083 int             display_size = DEC_SIZE;
00084 
00085 int             hyp_mode = 0;
00086 int             angle_mode = ANG_DEGREE;
00087 int             refresh_display; // if 1 we start a new number
00088 int             display_error = 0;
00089 int             decimal_point = 0;
00090 int             percent_mode = 0;
00091 bool            eestate = false; // if true then we are in ee input mode
00092 
00093 CALCAMNT        pi;
00094 CALCAMNT        memory_num = 0.0;
00095 
00096 int precedence[14] = { 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 7, 7, 6 };
00097 
00098     int         adjust_op[14][3] = {
00099                                 {FUNC_NULL,     FUNC_NULL,     FUNC_NULL},
00100                                 {FUNC_OR,       FUNC_OR,       FUNC_XOR },
00101                                 {FUNC_XOR,      FUNC_XOR,      FUNC_XOR },
00102                                 {FUNC_AND,      FUNC_AND,      FUNC_AND },
00103                                 {FUNC_LSH,      FUNC_LSH,      FUNC_RSH },
00104                                 {FUNC_RSH,      FUNC_RSH,      FUNC_RSH },
00105                                 {FUNC_ADD,      FUNC_ADD,      FUNC_ADD },
00106                                 {FUNC_SUBTRACT, FUNC_SUBTRACT, FUNC_SUBTRACT},
00107                                 {FUNC_MULTIPLY, FUNC_MULTIPLY, FUNC_MULTIPLY},
00108                                 {FUNC_DIVIDE,   FUNC_DIVIDE,   FUNC_DIVIDE},
00109                                 {FUNC_MOD,      FUNC_MOD,      FUNC_INTDIV },
00110                                 {FUNC_POWER,    FUNC_POWER,    FUNC_PWR_ROOT},
00111                                 {FUNC_PWR_ROOT, FUNC_PWR_ROOT, FUNC_PWR_ROOT},
00112                                 {FUNC_INTDIV,   FUNC_INTDIV,   FUNC_INTDIV},
00113     };
00114 /*
00115     char                *function_desc[] = {
00116 
00117       "Null",
00118       "Or",
00119       "Exclusive Or",
00120       "And",
00121       "Left Shift",
00122       "Right Shift",
00123       "Add",
00124       "Subtract",
00125       "Multiply",
00126       "Divide",
00127       "Modulus"
00128       "Power"
00129       "Reciprocal Power"
00130       "Integer Division"
00131     };
00132     */
00133     Arith       Arith_ops[14] = { NULL,
00134                                   ExecOr,
00135                                   ExecXor,
00136                                   ExecAnd,
00137                                   ExecLsh,
00138                                   ExecRsh,
00139                                   ExecAdd, ExecSubtract,
00140                                   ExecMultiply,
00141                                   ExecDivide, ExecMod,
00142                                   ExecPower, ExecPwrRoot,
00143                                   ExecIntDiv
00144     };
00145 
00146     Prcnt       Prcnt_ops[14] = { NULL,
00147                                   NULL,
00148                                   NULL,
00149                                   NULL,
00150                                   NULL,
00151                                   NULL,
00152                                   ExecAddSubP,  ExecAddSubP,
00153                                   ExecMultiplyP,
00154                                   ExecDivideP, ExecDivideP,
00155                                   ExecPowerP, ExecPwrRootP,
00156                                   ExecDivideP
00157     };
00158 
00159 
00160 void QtCalculator::InitializeCalculator(void) {
00161 
00162   //
00163   // Basic initialization involves initializing the calcultion
00164   // stack, forcing the display to refresh to zero, and setting
00165   // up the floating point excetion signal handler to trap the
00166   // errors that the code can/has not been written to trap.
00167   //
00168   // We also calculate pi as double the arc sine of 1.
00169   //
00170 
00171   display_data.s_item_type = ITEM_AMOUNT;
00172   display_data.s_item_data.item_amount = 0.0;
00173   display_data.s_item_data.item_func_data.item_function = 0;
00174   display_data.s_item_data.item_func_data.item_precedence = 0;
00175 
00176   void fpe_handler(int fpe_parm);
00177   struct sigaction  fpe_trap;
00178 
00179   fpe_trap.sa_handler = &fpe_handler;
00180 #ifdef SA_RESTART
00181   fpe_trap.sa_flags = SA_RESTART;
00182 #endif
00183 
00184   sigaction(SIGFPE, &fpe_trap, NULL);
00185 
00186   RefreshCalculator();
00187   pi = ASIN(1.0) * 2L;
00188 }
00189 
00190 void fpe_handler(int fpe_parm)
00191 {
00192   (void) fpe_parm;
00193 
00194   display_error = 1;
00195   DISPLAY_AMOUNT = 0L;
00196 
00197 }
00198 
00199 void QtCalculator::setData( const QRect& _range, const char *_sheet )
00200 {
00201   sheet_range = _range;
00202   sheet_name = _sheet;
00203 }
00204 
00205 void QtCalculator::setValue( double _value )
00206 {
00207   last_input = DIGIT;
00208   DISPLAY_AMOUNT = _value;
00209   decimal_point = 0;
00210   refresh_display = 1;
00211   input_count = 0;
00212 
00213   UpdateDisplay();
00214 }
00215 
00216 void QtCalculator::setLabel( const char *_text )
00217 {
00218   last_input = DIGIT;
00219   DISPLAY_AMOUNT = 0L;
00220   decimal_point = 0;
00221   refresh_display = 0;
00222   input_count = 0;
00223 
00224   calc_display->setText( _text );
00225 }
00226 
00227 void QtCalculator::RefreshCalculator(void)
00228 {
00229         InitStack();
00230         display_error = 0;
00231         DISPLAY_AMOUNT = 0L;
00232         inverse = FALSE;
00233         UpdateDisplay();
00234         last_input = DIGIT; // must set last to DIGIT after Update Display in order
00235                             // not to get a display holding e.g. 0.000
00236         input_count = 0;
00237         decimal_point = 0;
00238 }
00239 
00240 void QtCalculator::EnterDigit(int data)
00241 {
00242 
00243   if(eestate){
00244 
00245     QString string;
00246     string.setNum(data);
00247     strcat(display_str, string.latin1());
00248     DISPLAY_AMOUNT = (CALCAMNT) strtod(display_str,0);
00249     UpdateDisplay();
00250     return;
00251 
00252   }
00253 
00254   last_input = DIGIT;
00255   if (refresh_display) {
00256     DISPLAY_AMOUNT = 0L;
00257     decimal_point = 0;
00258     refresh_display = 0;
00259     input_count = 0;
00260   }
00261 
00262   if (!(input_limit && input_count >= input_limit))
00263     if (DISPLAY_AMOUNT < 0)
00264       DISPLAY_AMOUNT = decimal_point ?
00265         DISPLAY_AMOUNT - ((CALCAMNT)data /
00266                           POW((float)current_base, decimal_point++)) :
00267     (current_base * DISPLAY_AMOUNT) - data;
00268     else
00269       DISPLAY_AMOUNT = decimal_point ?
00270         DISPLAY_AMOUNT + ((CALCAMNT)data /
00271                           POW((float)current_base, decimal_point++)) :
00272     (current_base * DISPLAY_AMOUNT) + data;
00273 
00274   if (decimal_point){
00275     input_count ++;
00276 
00277 #ifdef MYDEBUG
00278     printf("EnterDigit() inc dec.point:%d\n",input_count);
00279 #endif
00280 
00281   }
00282   UpdateDisplay();
00283 }
00284 
00285 void QtCalculator::button0()
00286 {
00287   EnterDigit(0);
00288 }
00289 
00290 void QtCalculator::button1()
00291 {
00292   EnterDigit(1);
00293  }
00294 
00295 void QtCalculator::button2()
00296 {
00297   if (current_base == NB_BINARY)
00298     return;
00299   EnterDigit(2);
00300 }
00301 
00302 void QtCalculator::button3()
00303 {
00304   if (current_base == NB_BINARY)
00305     return;
00306   EnterDigit(3);
00307 }
00308 
00309 void QtCalculator::button4()
00310 {
00311   if (current_base == NB_BINARY)
00312     return;
00313   EnterDigit(4);
00314 }
00315 
00316 void QtCalculator::button5()
00317 {
00318   if (current_base == NB_BINARY)
00319     return;
00320   EnterDigit(5);
00321 }
00322 
00323 void QtCalculator::button6()
00324 {
00325   if (current_base == NB_BINARY)
00326     return;
00327   EnterDigit(6);
00328 }
00329 
00330 void QtCalculator::button7()
00331 {
00332   if (current_base == NB_BINARY)
00333     return;
00334   EnterDigit(7);
00335 }
00336 
00337 void QtCalculator::button8()
00338 {
00339   if ((current_base == NB_BINARY) || (current_base == NB_OCTAL))
00340     return;
00341   EnterDigit(8);
00342 }
00343 
00344 void QtCalculator::button9()
00345 {
00346   if ((current_base == NB_BINARY) || (current_base == NB_OCTAL))
00347     return;
00348   EnterDigit(9);
00349 }
00350 
00351 
00352 void QtCalculator::buttonA()
00353 {
00354   if ((current_base == NB_BINARY) || (current_base == NB_OCTAL)
00355       || (current_base == NB_DECIMAL))
00356     return;
00357   EnterDigit(10);
00358 }
00359 
00360 
00361 void QtCalculator::buttonB()
00362 {
00363   if ((current_base == NB_BINARY) || (current_base == NB_OCTAL)
00364       || (current_base == NB_DECIMAL))
00365     return;
00366   EnterDigit(11);
00367 }
00368 
00369 
00370 void QtCalculator::buttonC()
00371 {
00372    if ((current_base == NB_BINARY) || (current_base == NB_OCTAL)
00373       || (current_base == NB_DECIMAL))
00374     return;
00375   EnterDigit(12);
00376 }
00377 
00378 
00379 void QtCalculator::buttonD()
00380 {
00381    if ((current_base == NB_BINARY) || (current_base == NB_OCTAL)
00382       || (current_base == NB_DECIMAL))
00383     return;
00384   EnterDigit(13);
00385 }
00386 
00387 
00388 void QtCalculator::buttonE()
00389 {
00390    if ((current_base == NB_BINARY) || (current_base == NB_OCTAL)
00391       || (current_base == NB_DECIMAL))
00392     return;
00393   EnterDigit(14);
00394 }
00395 
00396 void QtCalculator::buttonF()
00397 {
00398    if ((current_base == NB_BINARY) || (current_base == NB_OCTAL)
00399       || (current_base == NB_DECIMAL))
00400     return;
00401   EnterDigit(15);
00402 }
00403 
00404 
00405 
00406 void QtCalculator::EnterDecimal()
00407 {
00408 
00409   if(eestate){
00410     KNotifyClient::beep();
00411     return;
00412   }
00413 
00414   decimal_point = 1;
00415   if (refresh_display) {
00416     DISPLAY_AMOUNT = 0L;
00417     refresh_display = 0;
00418     input_count = 0;
00419   }
00420 
00421   if (last_input == DIGIT && !strpbrk( display_str,".")){
00422 
00423     // if the last input was a DIGIT and we don't have already a period in our
00424     // display string then display a period
00425 
00426     calc_display->setText(strcat(display_str, "."));
00427   }
00428   else {
00429 
00430     // the last input wasn't a DIGIT so we are about to
00431     // input a new number in particular we neet do display a "0.".
00432 
00433     DISPLAY_AMOUNT = 0L;
00434     refresh_display = 0;
00435     //    decimal_point = 1;
00436     //    input_count = 1;
00437     strcpy(display_str, "0.");
00438     calc_display->setText(display_str);
00439   }
00440 }
00441 
00442 
00443 void QtCalculator::Or()
00444 {
00445   eestate = false;
00446   if (inverse){
00447     EnterStackFunction(2);   // XOR
00448     inverse = FALSE;
00449   }
00450   else {
00451     EnterStackFunction(1);   // OR
00452   }
00453   last_input = OPERATION;
00454 }
00455 
00456 void QtCalculator::And()
00457 {
00458   eestate = false;
00459   last_input = OPERATION;
00460   EnterStackFunction(3);
00461 }
00462 
00463 
00464 void QtCalculator::Shift()
00465 {
00466   eestate = false;
00467   last_input = OPERATION;
00468   if (inverse){
00469     EnterStackFunction(5);   // Rsh
00470     inverse = FALSE;
00471   }
00472   else {
00473     EnterStackFunction(4);   // Lsh
00474   }
00475 
00476 }
00477 
00478 void QtCalculator::Plus()
00479 {
00480   eestate = false;
00481   last_input = OPERATION;
00482   EnterStackFunction(6);
00483 }
00484 
00485 void QtCalculator::Minus()
00486 {
00487   eestate = false;
00488   last_input = OPERATION;
00489   EnterStackFunction(7);
00490 
00491 }
00492 
00493 void QtCalculator::Multiply()
00494 {
00495   eestate = false;
00496   last_input = OPERATION;
00497   EnterStackFunction(8);
00498 }
00499 
00500 void QtCalculator::Divide()
00501 {
00502   eestate = false;
00503   last_input = OPERATION;
00504   EnterStackFunction(9);
00505 }
00506 
00507 void QtCalculator::Mod()
00508 {
00509   eestate = false;
00510   last_input = OPERATION;
00511   if (inverse){
00512     EnterStackFunction(13);   // InvMod
00513     inverse = FALSE;
00514   }
00515   else {
00516     EnterStackFunction(10);   // Mod
00517   }
00518 }
00519 
00520 void QtCalculator::Power()
00521 {
00522   eestate = false;
00523   last_input = OPERATION;
00524   if (inverse){
00525     EnterStackFunction(12);   // InvPower
00526     inverse = FALSE;
00527   }
00528   else {
00529     EnterStackFunction(11);   // Power
00530   }
00531 
00532 }
00533 
00534 
00535 
00536 void QtCalculator::EnterStackFunction(int data)
00537 {
00538         item_contents   new_item;
00539         int             new_precedence;
00540         int             dummy;
00541 
00542         dummy = 0;
00543 
00544         /*
00545         if (inverse ) {
00546           dummy = 3;
00547           inverse = FALSE;
00548         }
00549         else {
00550           dummy = 1;
00551         }
00552         */
00553 
00554         //      printf("data %d dummy %d\n",data,dummy);
00555         data = adjust_op[data][dummy];
00556         //      printf("data %d \n",data );
00557 
00558         PushStack(&display_data);
00559 
00560         new_item.s_item_type = ITEM_FUNCTION;
00561         new_item.s_item_data.item_func_data.item_function = data;
00562         new_item.s_item_data.item_func_data.item_precedence =
00563                 new_precedence = precedence[data] + precedence_base;
00564 
00565         refresh_display = 1;
00566         if (UpdateStack(new_precedence))
00567                 UpdateDisplay();
00568         PushStack(&new_item);
00569 }
00570 
00571 void QtCalculator::EnterNegate()
00572 {
00573 
00574   if(eestate){
00575     QString string;
00576     string = display_str;
00577     int pos;
00578     pos = string.findRev('e',-1,false);
00579     if(pos == -1)
00580       return;
00581 
00582     if(display_str[pos+1] == '+')
00583       display_str[pos+1] = '-';
00584     else{
00585       if(display_str[pos+1] == '-')
00586         display_str[pos+1] = '+';
00587       else{
00588         string.insert(pos +1,'-');
00589         strncpy(display_str,string.latin1(),DSP_SIZE);
00590       }
00591     }
00592     DISPLAY_AMOUNT = (CALCAMNT)strtod(display_str,0);
00593     UpdateDisplay();
00594   }
00595   else{
00596     //    last_input = OPERATION;
00597     if (DISPLAY_AMOUNT != 0) {
00598       DISPLAY_AMOUNT *= -1;
00599       UpdateDisplay();
00600     }
00601   }
00602   last_input = DIGIT;
00603 }
00604 
00605 void QtCalculator::EnterOpenParen()
00606 {
00607   eestate = false;
00608         last_input = OPERATION;
00609         precedence_base += PRECEDENCE_INCR;
00610         refresh_display = 1;
00611 
00612 }
00613 
00614 void QtCalculator::EnterCloseParen()
00615 {
00616   eestate = false;
00617         last_input = OPERATION;
00618         PushStack(&display_data);
00619         refresh_display = 1;
00620         if (UpdateStack(precedence_base))
00621                 UpdateDisplay();
00622         if ((precedence_base -= PRECEDENCE_INCR) < 0)
00623                 precedence_base = 0;
00624 
00625 }
00626 
00627 void QtCalculator::EnterRecip()
00628 {
00629   eestate = false;
00630   last_input = OPERATION;
00631   DISPLAY_AMOUNT = 1 / DISPLAY_AMOUNT;
00632   refresh_display = 1;
00633   UpdateDisplay();
00634 }
00635 
00636 void QtCalculator::EnterInt()
00637 {
00638   eestate = false;
00639   CALCAMNT work_amount1 = 0.0, work_amount2 = 0.0;
00640 
00641         last_input = OPERATION;
00642         if (!inverse){
00643           work_amount2 = MODF(DISPLAY_AMOUNT, &work_amount1);
00644           DISPLAY_AMOUNT = work_amount2 ;
00645             }
00646         else {
00647           DISPLAY_AMOUNT = work_amount1;
00648           inverse = FALSE;
00649         }
00650 
00651         refresh_display = 1;
00652         UpdateDisplay();
00653 
00654 }
00655 
00656 void QtCalculator::EnterFactorial()
00657 {
00658   eestate = false;
00659         CALCAMNT work_amount1, work_amount2;
00660         int      incr;
00661 
00662         MODF(DISPLAY_AMOUNT, &work_amount1);
00663 
00664         incr = work_amount1 < 0 ? -1 : 1;
00665         work_amount2 = work_amount1 - incr;
00666         while (work_amount1 != 0 && work_amount2 != 0 && !display_error) {
00667                 work_amount1 *= work_amount2;
00668                 work_amount2 -= incr;
00669                 if(isinf(work_amount1)) {
00670                   display_error=1;
00671                    break;
00672                 }
00673         }
00674 
00675         if( work_amount1 == 0.0)
00676           work_amount1 = 1.0;
00677 
00678         DISPLAY_AMOUNT = work_amount1;
00679         refresh_display = 1;
00680         last_input = OPERATION;
00681         UpdateDisplay();
00682 
00683 }
00684 
00685 void QtCalculator::EnterSquare()
00686 {
00687   eestate = false;
00688         if (!inverse){
00689                 DISPLAY_AMOUNT *= DISPLAY_AMOUNT;
00690         }
00691         else if (DISPLAY_AMOUNT < 0)
00692         display_error = 1;
00693         else
00694                 DISPLAY_AMOUNT = SQRT(DISPLAY_AMOUNT);
00695         refresh_display = 1;
00696         inverse = FALSE;
00697         last_input = OPERATION;
00698         UpdateDisplay();
00699 
00700 }
00701 
00702 void QtCalculator::EnterNotCmp()
00703 {
00704   eestate = false;
00705         CALCAMNT        boh_work_d;
00706         long            boh_work;
00707 
00708         MODF(DISPLAY_AMOUNT, &boh_work_d);
00709         if (FABS(boh_work_d) > LONG_MAX)
00710                 display_error = 1;
00711                 else {
00712                 boh_work = (long int) boh_work_d;
00713                 DISPLAY_AMOUNT = ~boh_work;
00714                         }
00715         refresh_display = 1;
00716         last_input = OPERATION;
00717         UpdateDisplay();
00718 
00719 }
00720 
00721 void QtCalculator::EnterHyp()
00722 {
00723 
00724   switch(kcalcdefaults.style){
00725   case 2:
00726   case 1:{
00727     if ( !sheet_name.isEmpty() )
00728       useData();
00729 
00730     if(!inverse){
00731     eestate = false; // terminate ee input mode
00732     DISPLAY_AMOUNT =  stats.count();
00733     last_input = OPERATION;
00734     refresh_display = 1;
00735     UpdateDisplay();
00736     }
00737     else{
00738     inverse = false;
00739     eestate = false; // terminate ee input mode
00740     DISPLAY_AMOUNT =  stats.sum();
00741     last_input = OPERATION;
00742     refresh_display = 1;
00743     UpdateDisplay();
00744     }
00745 
00746     break;
00747   }
00748 
00749   case 0: {
00750     // toggle between hyperbolic and standart trig functions
00751     hyp_mode = !hyp_mode;
00752 
00753     if (hyp_mode){
00754       statusHYPLabel->setText("HYP");
00755     }
00756     else{
00757       statusHYPLabel->setText("");
00758     }
00759     break;
00760   }
00761   }
00762 }
00763 
00764 
00765 void QtCalculator::ExecSin(){
00766 
00767   switch(kcalcdefaults.style){
00768 
00769   case 0:{ // trig mode
00770 
00771     ComputeSin();
00772     break;
00773   }
00774 
00775   case 1:{ // stats mode
00776     if ( !sheet_name.isEmpty() )
00777       useData();
00778 
00779     ComputeMean();
00780     break;
00781   }
00782 
00783   case 2:{ // sheet mode
00784     if ( !sheet_name.isEmpty() )
00785       useData();
00786 
00787     ComputeMin();
00788     break;
00789   }
00790 
00791   }
00792 
00793 }
00794 
00795 void QtCalculator::ComputeSum()
00796 {
00797   inverse = false;
00798   eestate = false;
00799   DISPLAY_AMOUNT = stats.sum();
00800   if (stats.error())
00801       display_error = 1;
00802 
00803   refresh_display = 1;
00804   last_input = OPERATION;
00805   UpdateDisplay();
00806 }
00807 
00808 void QtCalculator::ComputeMul()
00809 {
00810   inverse = false;
00811   eestate = false;
00812   DISPLAY_AMOUNT = stats.mul();
00813   if (stats.error())
00814       display_error = 1;
00815 
00816   refresh_display = 1;
00817   last_input = OPERATION;
00818   UpdateDisplay();
00819 }
00820 
00821 void QtCalculator::ComputeMin()
00822 {
00823   inverse = false;
00824   eestate = false;
00825   DISPLAY_AMOUNT = stats.min();
00826   if (stats.error())
00827       display_error = 1;
00828 
00829   refresh_display = 1;
00830   last_input = OPERATION;
00831   UpdateDisplay();
00832 }
00833 
00834 void QtCalculator::ComputeMax()
00835 {
00836   inverse = false;
00837   eestate = false;
00838   DISPLAY_AMOUNT = stats.max();
00839   if (stats.error())
00840       display_error = 1;
00841 
00842   refresh_display = 1;
00843   last_input = OPERATION;
00844   UpdateDisplay();
00845 }
00846 
00847 void QtCalculator::ComputeMean(){
00848 
00849   if(!inverse){
00850     eestate = false;
00851     DISPLAY_AMOUNT = stats.mean();
00852     if (stats.error())
00853       display_error = 1;
00854 
00855     refresh_display = 1;
00856     last_input = OPERATION;
00857     UpdateDisplay();
00858   }
00859   else{
00860     inverse = false;
00861     eestate = false;
00862     DISPLAY_AMOUNT = stats.sum_of_squares();
00863     if (stats.error())
00864       display_error = 1;
00865     refresh_display = 1;
00866     last_input = OPERATION;
00867     UpdateDisplay();
00868 
00869   }
00870 
00871 }
00872 
00873 void QtCalculator::ComputeSin()
00874 {
00875   CALCAMNT      work_amount;
00876   eestate = false;
00877   work_amount = DISPLAY_AMOUNT;
00878 
00879   if (hyp_mode){
00880     // sinh or arcsinh
00881     if (!inverse){
00882       DISPLAY_AMOUNT = SINH( work_amount);
00883     }
00884     else {
00885       DISPLAY_AMOUNT = ASINH( work_amount);
00886       if (errno == EDOM || errno == ERANGE)
00887         display_error = 1;
00888       inverse = FALSE;       // reset the inverse flag
00889     }
00890   }
00891   else {
00892     // sine or arcsine
00893     if (!inverse){
00894       // sine
00895       switch (angle_mode) {
00896       case ANG_DEGREE:
00897         work_amount = DEG2RAD(DISPLAY_AMOUNT);
00898         break;
00899       case ANG_GRADIENT:
00900         work_amount = GRA2RAD(DISPLAY_AMOUNT);
00901         break;
00902       case ANG_RADIAN:
00903         work_amount = DISPLAY_AMOUNT;
00904         break;
00905       }
00906       DISPLAY_AMOUNT = SIN( work_amount);
00907     }
00908     else {
00909       // arcsine
00910       DISPLAY_AMOUNT = ASIN(work_amount);
00911             switch (angle_mode) {
00912       case ANG_DEGREE:
00913         work_amount = RAD2DEG(DISPLAY_AMOUNT);
00914         break;
00915       case ANG_GRADIENT:
00916         work_amount = RAD2GRA(DISPLAY_AMOUNT);
00917         break;
00918       case ANG_RADIAN:
00919         work_amount = DISPLAY_AMOUNT;
00920         break;
00921       }
00922       DISPLAY_AMOUNT = work_amount;
00923       if (errno == EDOM || errno == ERANGE)
00924         display_error = 1;
00925       inverse = FALSE;          // reset the inverse flag
00926     }
00927   }
00928 
00929 // Now a cheat to help the weird case of COS 90 degrees not being 0!!!
00930 
00931   if (DISPLAY_AMOUNT < POS_ZERO && DISPLAY_AMOUNT > NEG_ZERO)
00932     DISPLAY_AMOUNT=0;
00933   refresh_display = 1;
00934   last_input = OPERATION;
00935   UpdateDisplay();
00936 
00937 }
00938 
00939 void QtCalculator::ExecCos(){
00940 
00941   switch(kcalcdefaults.style){
00942 
00943   case 0:{ // trig mode
00944 
00945     ComputeCos();
00946     break;
00947   }
00948 
00949   case 1:{ // stats mode
00950       if ( !sheet_name.isEmpty() )
00951       useData();
00952 
00953     ComputeStd();
00954     break;
00955   }
00956 
00957   case 2:{ // sheet mode
00958       if ( !sheet_name.isEmpty() )
00959       useData();
00960 
00961     ComputeMax();
00962     break;
00963   }
00964 
00965   }
00966 
00967 }
00968 
00969 void QtCalculator::ComputeStd(){
00970 
00971   if(!inverse){ // std (n-1)
00972     inverse = false;
00973     eestate = false;
00974     DISPLAY_AMOUNT = stats.std();
00975 
00976     if (stats.error()){
00977       display_error = 1;
00978     }
00979 
00980     refresh_display = 1;
00981     last_input = OPERATION;
00982     UpdateDisplay();
00983   }
00984   else{ // std (n)
00985 
00986     inverse = false;
00987     eestate = false;
00988     DISPLAY_AMOUNT = stats.sample_std();
00989 
00990     if (stats.error())
00991       display_error = 1;
00992 
00993     refresh_display = 1;
00994     last_input = OPERATION;
00995     UpdateDisplay();
00996 
00997 
00998 
00999   }
01000 
01001 }
01002 
01003 void QtCalculator::ComputeCos()
01004 {
01005   CALCAMNT      work_amount;
01006   eestate = false;
01007   work_amount = DISPLAY_AMOUNT;
01008 
01009   if (hyp_mode){
01010     // cosh or arccosh
01011     if (!inverse){
01012       DISPLAY_AMOUNT = COSH( work_amount);
01013     }
01014     else {
01015       DISPLAY_AMOUNT = ACOSH( work_amount);
01016       if (errno == EDOM || errno == ERANGE)
01017         display_error = 1;
01018       inverse = FALSE;       // reset the inverse flag
01019     }
01020   }
01021   else {
01022     // cosine or arccosine
01023     if (!inverse){
01024       // sine
01025       switch (angle_mode) {
01026       case ANG_DEGREE:
01027         work_amount = DEG2RAD(DISPLAY_AMOUNT);
01028         break;
01029       case ANG_GRADIENT:
01030         work_amount = GRA2RAD(DISPLAY_AMOUNT);
01031         break;
01032       case ANG_RADIAN:
01033         work_amount = DISPLAY_AMOUNT;
01034         break;
01035       }
01036       DISPLAY_AMOUNT = COS( work_amount);
01037     }
01038     else {
01039       // arccosine
01040       DISPLAY_AMOUNT = ACOS(work_amount);
01041       switch (angle_mode) {
01042       case ANG_DEGREE:
01043         work_amount = RAD2DEG(DISPLAY_AMOUNT);
01044         break;
01045       case ANG_GRADIENT:
01046         work_amount = RAD2GRA(DISPLAY_AMOUNT);
01047         break;
01048       case ANG_RADIAN:
01049         work_amount = DISPLAY_AMOUNT;
01050         break;
01051       }
01052 
01053       DISPLAY_AMOUNT = work_amount;
01054 
01055       if (errno == EDOM || errno == ERANGE)
01056         display_error = 1;
01057       inverse = FALSE;          // reset the inverse flag
01058     }
01059   }
01060 
01061 // Now a cheat to help the weird case of COS 90 degrees not being 0!!!
01062 
01063 
01064   if (DISPLAY_AMOUNT < POS_ZERO && DISPLAY_AMOUNT > NEG_ZERO)
01065     DISPLAY_AMOUNT=0;
01066   refresh_display = 1;
01067   last_input = OPERATION;
01068   UpdateDisplay();
01069 
01070 }
01071 
01072 void QtCalculator::ExecTan(){
01073 
01074   switch(kcalcdefaults.style){
01075 
01076   case 0:{ // trig mode
01077 
01078     ComputeTan();
01079     break;
01080   }
01081 
01082   case 2:
01083   case 1:{ // stats mode
01084 
01085     if ( !sheet_name.isEmpty() )
01086       useData();
01087 
01088     ComputeMedean();
01089     break;
01090   }
01091 
01092   }
01093 
01094 }
01095 
01096 void QtCalculator::ComputeMedean(){
01097 
01098   if(!inverse){ // std (n-1)
01099     inverse = false;
01100     eestate = false;
01101     DISPLAY_AMOUNT = stats.median();
01102 
01103     if (stats.error()){
01104       display_error = 1;
01105     }
01106 
01107     refresh_display = 1;
01108     last_input = OPERATION;
01109     UpdateDisplay();
01110   }
01111   else{ // std (n)
01112 
01113     inverse = false;
01114     eestate = false;
01115     DISPLAY_AMOUNT = stats.median();
01116 
01117     if (stats.error())
01118       display_error = 1;
01119 
01120     refresh_display = 1;
01121     last_input = OPERATION;
01122     UpdateDisplay();
01123 
01124   }
01125 }
01126 
01127 
01128 void QtCalculator::ComputeTan()
01129 {
01130   CALCAMNT      work_amount;
01131   eestate = false;
01132   work_amount = DISPLAY_AMOUNT;
01133 
01134   if (hyp_mode){
01135     // tanh or arctanh
01136     if (!inverse){
01137       DISPLAY_AMOUNT = TANH( work_amount);
01138     }
01139     else {
01140       DISPLAY_AMOUNT = ATANH( work_amount);
01141       if (errno == EDOM || errno == ERANGE)
01142         display_error = 1;
01143       inverse = FALSE;       // reset the inverse flag
01144     }
01145   }
01146   else {
01147     // tan or arctan
01148     if (!inverse){
01149       // tan
01150       switch (angle_mode) {
01151       case ANG_DEGREE:
01152         work_amount = DEG2RAD(DISPLAY_AMOUNT);
01153         break;
01154       case ANG_GRADIENT:
01155         work_amount = GRA2RAD(DISPLAY_AMOUNT);
01156         break;
01157       case ANG_RADIAN:
01158         work_amount = DISPLAY_AMOUNT;
01159         break;
01160       }
01161       DISPLAY_AMOUNT = TAN( work_amount);
01162       if (errno == EDOM || errno == ERANGE)
01163         display_error = 1;
01164     }
01165     else {
01166       // arctan
01167       DISPLAY_AMOUNT = ATAN(work_amount);
01168       switch (angle_mode) {
01169       case ANG_DEGREE:
01170         work_amount = RAD2DEG(DISPLAY_AMOUNT);
01171         break;
01172       case ANG_GRADIENT:
01173         work_amount = RAD2GRA(DISPLAY_AMOUNT);
01174         break;
01175       case ANG_RADIAN:
01176         work_amount = DISPLAY_AMOUNT;
01177         break;
01178       }
01179 
01180       DISPLAY_AMOUNT = work_amount;
01181 
01182       if (errno == EDOM || errno == ERANGE)
01183         display_error = 1;
01184       inverse = FALSE;          // reset the inverse flag
01185     }
01186   }
01187 
01188 // Now a cheat to help the weird case of COS 90 degrees not being 0!!!
01189 
01190   if (DISPLAY_AMOUNT < POS_ZERO && DISPLAY_AMOUNT > NEG_ZERO)
01191     DISPLAY_AMOUNT=0;
01192   refresh_display = 1;
01193   last_input = OPERATION;
01194   UpdateDisplay();
01195 
01196 }
01197 
01198 
01199 void QtCalculator::EnterPercent()
01200 {
01201   eestate = false;
01202   last_input = OPERATION;
01203   percent_mode = 1;
01204   EnterEqual();
01205   percent_mode = 0;
01206 
01207 }
01208 
01209 void QtCalculator::EnterLogr()
01210 {
01211 
01212   switch(kcalcdefaults.style){
01213   case 2:
01214     {
01215       if ( !sheet_name.isEmpty() )
01216         useData();
01217 
01218       ComputeSum();
01219       break;
01220     }
01221   case 1:{
01222 
01223     if ( !sheet_name.isEmpty() )
01224       useData();
01225 
01226     if(!inverse){
01227       eestate = false; // terminate ee input mode
01228       stats.enterData(DISPLAY_AMOUNT);
01229       last_input = OPERATION;
01230       refresh_display = 1;
01231       DISPLAY_AMOUNT = stats.count();
01232       UpdateDisplay();
01233     }
01234     else{
01235       inverse = false;
01236       last_input = OPERATION;
01237       refresh_display = 1;
01238       stats.clearLast();
01239       setStatusLabel("Last stat item erased");
01240       DISPLAY_AMOUNT = stats.count();
01241       UpdateDisplay();
01242 
01243     }
01244 
01245     break;
01246   }
01247   case 0:{
01248 
01249     eestate = false;
01250     last_input = OPERATION;
01251 
01252     if (!inverse) {
01253       if (DISPLAY_AMOUNT <= 0)
01254         display_error = 1;
01255       else
01256         DISPLAY_AMOUNT = LOG_TEN(DISPLAY_AMOUNT);
01257       refresh_display = 1;
01258       UpdateDisplay();
01259     } else if (inverse) {
01260       DISPLAY_AMOUNT = POW(10, DISPLAY_AMOUNT);
01261       refresh_display = 1;
01262       inverse = FALSE;
01263       UpdateDisplay();
01264     }
01265     break;
01266   }
01267   }
01268 }
01269 
01270 void QtCalculator::EnterLogn()
01271 {
01272 
01273   switch(kcalcdefaults.style){
01274   case 2:{
01275 
01276     if ( !sheet_name.isEmpty() )
01277       useData();
01278 
01279     ComputeMul();
01280 
01281     break;
01282   }
01283   case 1:{
01284 
01285     if ( !sheet_name.isEmpty() )
01286       useData();
01287 
01288     if(!inverse){
01289 
01290       stats.clearAll();
01291       setStatusLabel(i18n("Stat mem cleared"));
01292 
01293     }
01294     else{
01295       inverse = false;
01296       UpdateDisplay();
01297     }
01298 
01299     break;
01300   }
01301   case 0:{
01302     eestate = false;
01303     last_input = OPERATION;
01304     if (!inverse) {
01305       if (DISPLAY_AMOUNT <= 0)
01306         display_error = 1;
01307       else
01308         DISPLAY_AMOUNT = LOG(DISPLAY_AMOUNT);
01309       refresh_display = 1;
01310       UpdateDisplay();
01311     } else if (inverse) {
01312       DISPLAY_AMOUNT = EXP(DISPLAY_AMOUNT);
01313       refresh_display = 1;
01314       inverse =FALSE;
01315       UpdateDisplay();
01316     }
01317     break;
01318   }
01319   }
01320 
01321 }
01322 
01323 
01324 void QtCalculator::base_selected(int number){
01325 
01326   switch(number){
01327   case 0:
01328     SetHex();
01329     break;
01330   case 1:
01331     SetDec();
01332     break;
01333   case 2:
01334     SetOct();
01335     break;
01336   case 3:
01337     SetBin();
01338     break;
01339   default: // we shouldn't ever end up here
01340     SetDec();
01341     }
01342 }
01343 
01344 
01345 void QtCalculator::angle_selected(int number){
01346 
01347   switch(number){
01348   case 0:
01349     SetDeg();
01350     break;
01351   case 1:
01352     SetRad();
01353     break;
01354   case 2:
01355     SetGra();
01356     break;
01357   default: // we shouldn't ever end up here
01358     SetRad();
01359     }
01360 }
01361 
01362 void QtCalculator::SetInverse(){
01363 
01364   inverse = ! inverse;
01365   if (inverse){
01366     statusINVLabel->setText("INV");
01367   }
01368   else{
01369     statusINVLabel->setText("NORM");
01370   }
01371 }
01372 
01373 
01374 void QtCalculator::SetDeg() {
01375         angle_mode = ANG_DEGREE;
01376 }
01377 
01378 void QtCalculator::SetGra() {
01379         angle_mode = ANG_GRADIENT;
01380 }
01381 
01382 void QtCalculator::SetRad() {
01383         angle_mode = ANG_RADIAN;
01384 
01385 }
01386 
01387 void QtCalculator::SetHex() {
01388         /*
01389          * Set Hex Mode
01390          */
01391 
01392         current_base = NB_HEX;
01393         display_size = BOH_SIZE;
01394         decimal_point = 0;
01395         input_limit = 8;
01396 
01397         UpdateDisplay();
01398 }
01399 
01400 void QtCalculator::SetOct() {
01401         /*
01402          * Set Oct Mode
01403          */
01404 
01405         current_base = NB_OCTAL;
01406         display_size = BOH_SIZE;
01407         decimal_point = 0;
01408         input_limit = 11;
01409 
01410         UpdateDisplay();
01411 }
01412 
01413 void QtCalculator::SetBin() {
01414         /*
01415          * Set Bin Mode
01416          */
01417 
01418         current_base = NB_BINARY;
01419         display_size = BOH_SIZE;
01420         decimal_point = 0;
01421         input_limit = 16;
01422 
01423         UpdateDisplay();
01424 }
01425 
01426 void QtCalculator::SetDec()
01427 {
01428         /*
01429          * Set Dec Mode
01430          */
01431 
01432         current_base = NB_DECIMAL;
01433         display_size = DEC_SIZE;
01434         input_limit = 0;
01435 
01436 
01437         UpdateDisplay();
01438 }
01439 
01440 
01441 void QtCalculator::EE()
01442 {
01443   if(inverse){
01444     DISPLAY_AMOUNT = pi;
01445     inverse = FALSE;
01446     UpdateDisplay();
01447   }
01448   else{
01449     if(eestate == true)
01450       eestate = false;
01451     else{
01452       eestate = true;
01453       strcat(display_str,"e");
01454     }
01455 
01456     UpdateDisplay();
01457   }
01458 
01459 }
01460 
01461 void QtCalculator::MR()
01462 {
01463   eestate = false;
01464   last_input = OPERATION;
01465   DISPLAY_AMOUNT = memory_num;
01466   refresh_display = 1;
01467   UpdateDisplay();
01468 
01469 }
01470 
01471 void QtCalculator::Mplusminus()
01472 {
01473 
01474   eestate = false;
01475   EnterEqual();
01476   if (!inverse)
01477     memory_num += DISPLAY_AMOUNT;
01478   else {
01479     memory_num -= DISPLAY_AMOUNT;
01480     inverse = FALSE;
01481   }
01482 }
01483 
01484 void QtCalculator::MC()
01485 {
01486 
01487         memory_num = 0;
01488         refresh_display = 1;
01489 }
01490 
01491 void QtCalculator::EnterEqual()
01492 {
01493   eestate = false;
01494         last_input = OPERATION;
01495         PushStack(&display_data);
01496         refresh_display = 1;
01497 
01498         /*      if (UpdateStack(0))*/
01499                     UpdateStack(0);
01500 
01501         UpdateDisplay();
01502         precedence_base = 0;
01503 
01504         CALCAMNT* number ;
01505 
01506         if(temp_stack.count() > TEMP_STACK_SIZE){
01507 
01508           number = temp_stack.getFirst();
01509           temp_stack.removeFirst();
01510 
01511           if(number)
01512             free(number);
01513         }
01514 
01515         number = (CALCAMNT*) malloc(sizeof(CALCAMNT));
01516         *number = DISPLAY_AMOUNT;
01517 
01518         //printf("appending %Lg\n",*number);
01519 
01520         temp_stack.append(number);
01521 
01522 
01523 }
01524 
01525 void QtCalculator::Clear(){
01526 
01527   eestate = false;
01528 
01529   input_count = 0;
01530   decimal_point = 0;
01531 
01532   if(last_input == OPERATION){
01533     //    printf("LAST_INPUT = OPERATION\n");
01534     last_input = DIGIT;
01535     PopStack();
01536   }
01537   else{
01538     //    printf("LAST_INPUT = DIGIT\n");
01539     last_input = DIGIT;
01540   }
01541 
01542 
01543   if( display_error){
01544     display_error = 0;
01545     refresh_display = 0;
01546   }
01547 
01548   if (!refresh_display) {
01549     DISPLAY_AMOUNT = 0L;
01550     UpdateDisplay();
01551   }
01552 
01553 }
01554 
01555 void QtCalculator::ClearAll()
01556 {
01557 
01558   eestate = false;
01559   // last_input = OPERATION;
01560   last_input = DIGIT;
01561   RefreshCalculator();
01562   refresh_display = 1;
01563 
01564 }
01565 
01566 
01567 
01568 void QtCalculator::UpdateDisplay()
01569 {
01570 
01571   // this needs to be rewritten based on whether we are currently
01572   // inputting a number so that the period and the 0 after a period
01573   // are correctly displayed.
01574 
01575         CALCAMNT        boh_work_d;
01576         long            boh_work = 0;
01577         int             str_size = 0;
01578 
01579         if(eestate && (current_base == NB_DECIMAL)){
01580 
01581                 calc_display->setText(display_str);
01582                 return;
01583         }
01584 
01585         if (current_base != NB_DECIMAL) {
01586                 MODF(DISPLAY_AMOUNT, &boh_work_d);
01587                 if (boh_work_d < LONG_MIN || boh_work_d > ULONG_MAX)
01588                 display_error = 1;
01589 
01590         /*
01591          * We may be in that never-never land where boh numbers
01592          * turn from positive to negative - if so then we do
01593          * just that, allowing boh negative numbers to be entered
01594          * as read (from dumps and the like!)
01595          */
01596                 else if (boh_work_d > LONG_MAX) {
01597                         DISPLAY_AMOUNT =
01598                                 LONG_MIN+(boh_work_d-LONG_MAX-1);
01599                         boh_work = (long)DISPLAY_AMOUNT;
01600                 }
01601                 else {
01602                         DISPLAY_AMOUNT = boh_work_d;
01603                         boh_work = (long) boh_work_d;
01604                 }
01605         }
01606 
01607         if (!display_error) {
01608 
01609                 if (current_base == NB_BINARY)
01610                         str_size = cvb(display_str,
01611                                        boh_work,
01612                                        BOH_SIZE);
01613                 else if (current_base == NB_OCTAL)
01614                         str_size = sprintf(display_str,
01615                                            "%lo",
01616                                            boh_work);
01617                 else if (current_base == NB_DECIMAL) {
01618 
01619                   if(!kcalcdefaults.fixed || last_input == DIGIT
01620                      || (DISPLAY_AMOUNT > 1.0e+16)){
01621 
01622                     // if I don't guard against the DISPLAY_AMOUNT being too large
01623                     // kcalc will segfault on larger amount. Such as from typing
01624                     // from 5*5*******
01625 
01626                     str_size = sprintf(display_str,
01627 
01628 #ifdef HAVE_LONG_DOUBLE
01629                                      "%.*Lg", // was *Lg
01630 
01631                                      kcalcdefaults.precision  +1,
01632 #else
01633                                            "%.*g",
01634 
01635                                      kcalcdefaults.precision  +1,
01636 #endif
01637                                              DISPLAY_AMOUNT);
01638                   }
01639                   else{//fixed
01640 
01641                   str_size = sprintf(display_str,
01642 
01643 #ifdef HAVE_LONG_DOUBLE
01644                                      "%.*Lf", // was *Lg
01645 
01646                                      kcalcdefaults.fixedprecision  ,
01647 #else
01648                                            "%.*f",
01649 
01650                                      kcalcdefaults.fixedprecision  ,
01651 #endif
01652                                              DISPLAY_AMOUNT);
01653 
01654                   }// fixed
01655 
01656                   if ( input_count > 0 && !strpbrk(display_str,"e") &&
01657                                            last_input == DIGIT   ) {
01658 
01659 #ifdef HAVE_LONG_DOUBLE
01660                     str_size = sprintf(display_str,
01661                                            "%.*Lf",
01662                             (kcalcdefaults.precision +1 > input_count)?
01663                              input_count : kcalcdefaults.precision ,
01664                              DISPLAY_AMOUNT);
01665 #else
01666                     str_size = sprintf(display_str,
01667                                            "%.*f",
01668                             (kcalcdefaults.precision +1 > input_count)?
01669                              input_count : kcalcdefaults.precision ,
01670                              DISPLAY_AMOUNT);
01671 #endif
01672                   }
01673 
01674                 }
01675                 else
01676                   if (current_base == NB_HEX)
01677                         str_size = sprintf(display_str,
01678                                            "%lX",
01679                                            boh_work);
01680                   else
01681                         display_error = 1;
01682               }
01683 
01684         if (display_error || str_size < 0) {
01685           display_error = 1;
01686           strcpy(display_str,"Error");
01687           if(kcalcdefaults.beep)
01688             KNotifyClient::beep();
01689         }
01690         calc_display->setText(display_str);
01691 
01692 
01693   if (inverse){
01694     statusINVLabel->setText("INV");
01695   }
01696   else{
01697     statusINVLabel->setText("NORM");
01698   }
01699 
01700   if (hyp_mode){
01701     statusHYPLabel->setText("HYP");
01702   }
01703   else{
01704     statusHYPLabel->setText("");
01705   }
01706 
01707 
01708 }
01709 
01710 int cvb(char *out_str, long amount, int max_digits)
01711 {
01712         /*
01713          * A routine that converts a long int to
01714          * binary display format
01715          */
01716 
01717         char            work_str[(sizeof(amount) * CHAR_BIT) + 1];
01718         int             work_char = 0,
01719                         lead_zero = 1,
01720                         lead_one = 1,
01721                         lead_one_count = 0,
01722                         work_size = sizeof(amount) * CHAR_BIT;
01723         unsigned long   bit_mask = (1 << ((sizeof(amount) * CHAR_BIT) - 1));
01724 
01725         while (bit_mask) {
01726 
01727                 if (amount & bit_mask) {
01728                         if (lead_one)
01729                                 lead_one_count++;
01730                         lead_zero = 0;
01731                         work_str[work_char++] = '1';
01732                 } else {
01733                         lead_one = 0;
01734                         if (!lead_zero)
01735                                 work_str[work_char++] = '0';
01736                 }
01737                 bit_mask >>= 1;
01738         }
01739         if (!work_char)
01740                 work_str[work_char++] = '0';
01741         work_str[work_char] = '\0';
01742 
01743         if (work_char-lead_one_count < max_digits)
01744                 return strlen(strcpy(out_str,
01745                                       &work_str[lead_one_count ?
01746                                       work_size - max_digits :
01747                                       0]));
01748         else
01749            return -1;
01750 }
01751 
01752 int UpdateStack(int run_precedence)
01753 {
01754         item_contents   new_item, *top_item , *top_function;
01755         CALCAMNT        left_op =0.0 , right_op =0.0;
01756         int             op_function= 0, return_value = 0;
01757 
01758         new_item.s_item_type = ITEM_AMOUNT;
01759         while ((top_function = TopTypeStack(ITEM_FUNCTION)) &&
01760         top_function->s_item_data.item_func_data.item_precedence >=
01761         run_precedence) {
01762 
01763                 return_value = 1;
01764 
01765                 if ((top_item = PopStack())->s_item_type != ITEM_AMOUNT){
01766                   KMessageBox::error( 0, "Stack processing error - right_op");
01767 
01768                 }
01769                 right_op = top_item->s_item_data.item_amount;
01770 
01771                 if (!((top_item = PopStack()) &&
01772                 top_item->s_item_type == ITEM_FUNCTION)) {
01773                   KMessageBox::error( 0, "Stack processing error - function");
01774 
01775                 }
01776                 op_function =
01777                         top_item->s_item_data.item_func_data.item_function;
01778 
01779                 if (!((top_item = PopStack()) &&
01780                 top_item->s_item_type == ITEM_AMOUNT)) {
01781                   KMessageBox::error( 0, "Stack processing error - left_op");
01782                 }
01783                 left_op = top_item->s_item_data.item_amount;
01784 
01785                 new_item.s_item_data.item_amount =
01786                         (Arith_ops[op_function])(left_op, right_op);
01787                 PushStack(&new_item);
01788 
01789         }
01790         if (return_value &&
01791             percent_mode &&
01792             !display_error &&
01793             Prcnt_ops[op_function] != NULL){
01794                 new_item.s_item_data.item_amount =
01795                         (Prcnt_ops[op_function])(left_op,
01796                                 right_op,
01797                                 new_item.s_item_data.item_amount);
01798                 PushStack(&new_item);
01799         }
01800         if (return_value)
01801                 DISPLAY_AMOUNT = new_item.s_item_data.item_amount;
01802 
01803         return return_value;
01804 }
01805 
01806 int isoddint(CALCAMNT input)
01807 {
01808         CALCAMNT        dummy;
01809         /*
01810          * Routine to check if CALCAMNT is an Odd integer
01811          */
01812         return (MODF(input, &dummy) == 0.0 &&
01813                 MODF(input/2, &dummy) == 0.5);
01814 }
01815 
01816 CALCAMNT ExecOr(CALCAMNT left_op, CALCAMNT right_op)
01817 {
01818   // printf("ExecOr\n");
01819         CALCAMNT        boh_work_d;
01820         long            boh_work_l, boh_work_r;
01821 
01822         MODF(left_op, &boh_work_d);
01823         if (FABS(boh_work_d) > LONG_MAX) {
01824                 display_error = 1;
01825                 return 0;
01826         }
01827         boh_work_l = (long int)boh_work_d;
01828         MODF(right_op, &boh_work_d);
01829         if (FABS(boh_work_d) > LONG_MAX) {
01830                 display_error = 1;
01831                 return 0;
01832         }
01833         boh_work_r = (long int) boh_work_d;
01834         return (boh_work_l | boh_work_r);
01835 }
01836 
01837 CALCAMNT ExecXor(CALCAMNT left_op, CALCAMNT right_op)
01838 {
01839   // printf("ExecXOr\n");
01840         CALCAMNT        boh_work_d;
01841         long            boh_work_l, boh_work_r;
01842 
01843         MODF(left_op, &boh_work_d);
01844         if (FABS(boh_work_d) > LONG_MAX) {
01845                 display_error = 1;
01846                 return 0;
01847         }
01848         boh_work_l = (long int) boh_work_d;
01849         MODF(right_op, &boh_work_d);
01850         if (FABS(boh_work_d) > LONG_MAX) {
01851                 display_error = 1;
01852                 return 0;
01853         }
01854         boh_work_r = (long int) boh_work_d;
01855         return (boh_work_l ^ boh_work_r);
01856 }
01857 
01858 CALCAMNT ExecAnd(CALCAMNT left_op, CALCAMNT right_op)
01859 {
01860   // printf("ExecAnd\n");
01861         CALCAMNT        boh_work_d;
01862         long            boh_work_l, boh_work_r;
01863 
01864         MODF(left_op, &boh_work_d);
01865         if (FABS(boh_work_d) > LONG_MAX) {
01866                 display_error = 1;
01867                 return 0;
01868         }
01869         boh_work_l = (long int ) boh_work_d;
01870         MODF(right_op, &boh_work_d);
01871         if (FABS(boh_work_d) > LONG_MAX) {
01872                 display_error = 1;
01873                 return 0;
01874         }
01875         boh_work_r = (long int ) boh_work_d;
01876         return (boh_work_l & boh_work_r);
01877 }
01878 
01879 CALCAMNT ExecLsh(CALCAMNT left_op, CALCAMNT right_op)
01880 {
01881   // printf("ExecLsh\n");
01882         CALCAMNT        boh_work_d;
01883         long            boh_work_l, boh_work_r;
01884 
01885         MODF(left_op, &boh_work_d);
01886         if (FABS(boh_work_d) > LONG_MAX) {
01887                 display_error = 1;
01888                 return 0;
01889         }
01890         boh_work_l = (long int) boh_work_d;
01891         MODF(right_op, &boh_work_d);
01892         if (FABS(boh_work_d) > LONG_MAX) {
01893                 display_error = 1;
01894                 return 0;
01895         }
01896         boh_work_r = (long int ) boh_work_d;
01897         return (boh_work_l << boh_work_r);
01898 }
01899 
01900 CALCAMNT ExecRsh(CALCAMNT left_op, CALCAMNT right_op)
01901 {
01902   // printf("ExecRsh\n");
01903         CALCAMNT        boh_work_d;
01904         long            boh_work_l, boh_work_r;
01905 
01906         MODF(left_op, &boh_work_d);
01907         if (FABS(boh_work_d) > LONG_MAX) {
01908                 display_error = 1;
01909                 return 0;
01910         }
01911         boh_work_l = (long int ) boh_work_d;
01912         MODF(right_op, &boh_work_d);
01913         if (FABS(boh_work_d) > LONG_MAX) {
01914                 display_error = 1;
01915                 return 0;
01916         }
01917         boh_work_r = ( long int ) boh_work_d;
01918         return (boh_work_l >> boh_work_r);
01919 }
01920 
01921 CALCAMNT ExecAdd(CALCAMNT left_op, CALCAMNT right_op)
01922 {
01923   // printf("ExecAdd\n");
01924         return left_op + right_op;
01925 }
01926 
01927 CALCAMNT ExecSubtract(CALCAMNT left_op, CALCAMNT right_op)
01928 {
01929   // printf("ExecSubtract\n");
01930         return left_op - right_op;
01931 }
01932 
01933 CALCAMNT ExecMultiply(CALCAMNT left_op, CALCAMNT right_op)
01934 {
01935   // printf("ExecMulti\n");
01936         return left_op * right_op;
01937 }
01938 
01939 CALCAMNT ExecDivide(CALCAMNT left_op, CALCAMNT right_op)
01940 {
01941   // printf("ExecDivide\n");
01942         if (right_op == 0) {
01943                 display_error = 1;
01944                 return 0L;
01945         } else
01946                 return left_op / right_op;
01947 }
01948 
01949 CALCAMNT ExecMod(CALCAMNT left_op, CALCAMNT right_op)
01950 {
01951   // printf("ExecMod\n");
01952   CALCAMNT temp =0.0;
01953 
01954   if (right_op == 0) {
01955     display_error = 1;
01956     return 0L;
01957   } else {
01958 
01959     // x mod y should be the same as x mod -y, thus:
01960     right_op = FABS(right_op);
01961 
01962     temp = FMOD(left_op, right_op);
01963 
01964     // let's make sure that -7 mod 3 = 2 and NOT -1.
01965     // In other words we wand x mod 3 to be a _positive_ number
01966     // that is 0,1 or 2.
01967 
01968     if( temp < 0 ) temp = right_op + temp;
01969     temp = FABS(temp);
01970 
01971     return temp;
01972   }
01973 }
01974 
01975 CALCAMNT ExecIntDiv(CALCAMNT left_op, CALCAMNT right_op)
01976 {
01977   // printf("IndDiv\n");
01978         if (right_op == 0) {
01979                 display_error = 1;
01980                 return 0L;
01981         } else {
01982                 MODF(left_op / right_op, &left_op);
01983                 return left_op;
01984         }
01985 }
01986 
01987 CALCAMNT ExecPower(CALCAMNT left_op, CALCAMNT right_op)
01988 {
01989 
01990        // printf("ExecPowser %g left_op, %g right_op\n",left_op, right_op);
01991         if (right_op == 0)
01992                 return 1L;
01993         if (left_op < 0 && isoddint(1/right_op))
01994                 left_op = -1L * POW((-1L * left_op), right_op);
01995         else
01996                 left_op = POW(left_op, right_op);
01997         if (errno == EDOM || errno == ERANGE) {
01998                 display_error = 1;
01999                 return 0;
02000         } else
02001                 return left_op;
02002 }
02003 
02004 CALCAMNT ExecPwrRoot(CALCAMNT left_op, CALCAMNT right_op)
02005 {
02006 
02007        // printf("ExecPwrRoot  %g left_op, %g right_op\n", left_op, right_op);
02008         if (right_op == 0) {
02009                 display_error = 1;
02010                 return 0L;
02011         }
02012         if (left_op < 0 && isoddint(right_op))
02013                 left_op = -1L * POW((-1L * left_op), (1L)/right_op);
02014         else
02015                 left_op = POW(left_op, (1L)/right_op);
02016         if (errno == EDOM || errno == ERANGE) {
02017           display_error = 1;
02018           return 0;
02019         }
02020         else
02021           return left_op;
02022 }
02023 
02024 
02025 CALCAMNT ExecAddSubP(CALCAMNT left_op, CALCAMNT right_op, CALCAMNT result)
02026 {
02027   // printf("ExecAddsubP\n");
02028   (void) left_op;
02029 
02030         if (result == 0) {
02031                 display_error = 1;
02032                 return 0;
02033         } else
02034                 return (result * 100L) / right_op;
02035 }
02036 
02037 CALCAMNT ExecMultiplyP(CALCAMNT left_op, CALCAMNT right_op, CALCAMNT result)
02038 {
02039   // printf("ExecMultiplyP\n");
02040   (void) left_op;
02041   (void) right_op;
02042 
02043         return (result / 100L);
02044 }
02045 
02046 CALCAMNT ExecDivideP(CALCAMNT left_op, CALCAMNT right_op, CALCAMNT result)
02047 {
02048   // printf("ExecDivideP\n");
02049   (void) left_op;
02050   (void) right_op;
02051 
02052         return (result * 100L);
02053 }
02054 
02055 CALCAMNT ExecPowerP(CALCAMNT left_op, CALCAMNT right_op, CALCAMNT result)
02056 {
02057   // printf("ExecPowerP\n");
02058   (void) result;
02059         return ExecPower(left_op, (right_op / 100L));
02060 }
02061 
02062 CALCAMNT ExecPwrRootP(CALCAMNT left_op, CALCAMNT right_op, CALCAMNT result)
02063 {
02064   // printf("ExePwrRootP\n");
02065   (void) result;
02066 
02067         if (right_op == 0) {
02068                 display_error = 1;
02069                 return 0;
02070         } else
02071                 return ExecPower(left_op, (100L / right_op));
02072 }
02073 
02074 
02075 
02076 stack_ptr AllocStackItem (void) {
02077 
02078         if (stack_next <= stack_last) {
02079 
02080                 process_stack[stack_next].prior_item = NULL;
02081                 process_stack[stack_next].prior_type = NULL;
02082                 return &process_stack[stack_next++];
02083         }
02084 
02085         KMessageBox::error( 0, "Stack Error !");
02086         return &process_stack[stack_next];
02087 }
02088 
02089 void UnAllocStackItem (stack_ptr return_item) {
02090 
02091         if (return_item != &process_stack[--stack_next]) {
02092 
02093           KMessageBox::error( 0, "Stack Error !");
02094         }
02095 
02096 }
02097 void PushStack(item_contents *add_item)
02098 {
02099         /*
02100          * Add an item to the stack
02101          */
02102 
02103         stack_ptr new_item = top_of_stack;
02104 
02105         if (!(new_item &&
02106         new_item->item_value.s_item_type == add_item->s_item_type)) {
02107 
02108                 new_item = AllocStackItem();    /* Get a new item    */
02109 
02110                 /*
02111                  * Chain new item to existing stacks
02112                  */
02113 
02114                 new_item->prior_item = top_of_stack;
02115                 top_of_stack         = new_item;
02116                 new_item->prior_type = top_type_stack[add_item->s_item_type];
02117                 top_type_stack[add_item->s_item_type] = new_item;
02118         }
02119 
02120         new_item->item_value  = *add_item;      /* assign contents*/
02121 
02122 }
02123 
02124 item_contents *PopStack(void)
02125 {
02126         /*
02127          * Remove and return the top item in the stack
02128          */
02129 
02130         static item_contents return_item;
02131         item_contents *return_item_ptr = NULL;
02132         stack_ptr return_stack_ptr;
02133 
02134         if ((return_stack_ptr = top_of_stack)) {
02135                 return_item = top_of_stack->item_value;
02136 
02137                 top_type_stack[return_item.s_item_type]
02138                              = top_of_stack->prior_type;
02139                 top_of_stack = top_of_stack->prior_item;
02140 
02141                 UnAllocStackItem(return_stack_ptr);
02142                 return_item_ptr = &return_item;
02143         }
02144 
02145         return return_item_ptr;
02146 }
02147 
02148 item_contents *TopOfStack(void)
02149 {
02150         /*
02151          * Return the top item in the stack without removing
02152          */
02153 
02154         item_contents *return_item_ptr = NULL;
02155 
02156         if (top_of_stack) {
02157                 return_item_ptr = &top_of_stack->item_value;
02158         }
02159 
02160         return return_item_ptr;
02161 }
02162 
02163 item_contents *TopTypeStack(item_type rqstd_type)
02164 {
02165         /*
02166          * Return the top item in the stack without removing
02167          */
02168 
02169         item_contents *return_item_ptr = NULL;
02170 
02171         if (top_type_stack[rqstd_type]) {
02172                 return_item_ptr = &top_type_stack[rqstd_type]->item_value;
02173         }
02174 
02175         return return_item_ptr;
02176 }
02177 
02178 
02179 /*
02180  * Stack storage management Data and Functions
02181  */
02182 
02183 
02184 
02185 void InitStack (void) {
02186 
02187         stack_next = 0;
02188         stack_last = STACK_SIZE - 1;
02189         top_of_stack = top_type_stack[0] = top_type_stack[1] = NULL;
02190 }
02191 
02192 
KDE Home | KDE Accessibility Home | Description of Access Keys