kspread Library API Documentation

kcalc_core.cpp

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