' This program  is free  software;  you can redistribute  it and/or modify it
' under the terms of the GNU General  Public License as published by the Free
' Software Foundation;  either version 2 of the License,  or (at your option)
' any later version.
'
' This program is distributed in the hope that it will be useful, but WITHOUT
' ANY  WARRANTY;  without  even the  implied warranty  of MERCHANTABILITY  or
' FITNESS FOR  A PARTICULAR  PURPOSE.  See the GNU General Public License for
' more details.
'
' You should  have received  a copy  of the  GNU General Public License along
' with this  program;  if not,  write to the Free Software Foundation,  Inc.,
' 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
'
'-------------------------------------------------------------------
' FoxCalc v0.92
'
' Author: Mateusz Viste "Fox" ([email protected])
' Compiled with FreeBASIC v0.18.3, using the GMP and MTFR libraries
' Homepage at http://mateusz.viste.free.fr/dos
'-------------------------------------------------------------------
'
#INCLUDE ONCE "VBCOMPAT.BI" ' Required by: FORMAT()
#INCLUDE ONCE "DOS\DPMI.BI" ' Required by: GetCurrentCodePage
#INCLUDE ONCE "GMP.BI"      ' Required by: MPFR.BI
#INCLUDE ONCE "MPFR.BI"     ' Required by: Calculus
#INCLUDE ONCE "COUNTRY.BI"  ' Required by: PrintWork


CONST pVer AS STRING = "0.92"
CONST pDate AS STRING = "2007"

TYPE BOOL AS BYTE        ' Creating the BOOL type, as it
CONST TRUE AS BOOL = 1   ' is not supported natively by
CONST FALSE AS BOOL = 0  ' the FreeBASIC compiler.

DECLARE SUB About()
DECLARE SUB PrintMsg(Komunikat AS STRING)
DECLARE SUB MouseRefresh(x AS INTEGER, y AS INTEGER, Forcing AS BOOL = FALSE)
DECLARE SUB Compute()
DECLARE SUB DrawButton(n AS UBYTE, Stan AS UBYTE)
DECLARE SUB PrintWork(WorkN AS STRING)
DECLARE SUB Quit()
DECLARE SUB DrawBackground(ShortCut AS BOOL)
DECLARE SUB Bip()
DECLARE SUB KeybFlush()
DECLARE SUB SoundQ(ByVal freq AS UINTEGER, dur AS UINTEGER)
DECLARE SUB GetCountrySysSettings()
DECLARE FUNCTION GetCurrentCodePage() AS USHORT
DECLARE FUNCTION Calculus(Numb1 AS STRING, Numb2 AS STRING, Oper AS STRING) AS STRING

DIM SHARED ClickMap(0 TO 24, 0 TO 79) AS BYTE
DIM SHARED AS BOOL Snd, MouseSupport, ResetTrigger, ShortCutList, ForceRefresh
DIM SHARED AS STRING Operation, TempString, WorkNumber, Result, Memory, DecSep, ThousSep
DIM SHARED MousePosition(1 TO 3) AS INTEGER
DIM SHARED AsciiButton(1 TO 4) AS STRING * 3
DIM SHARED AS BYTE InitialLocate
DIM SHARED AS INTEGER SavedMouseX, SavedMouseY
DIM AS INTEGER xPos, yPos, Buttons
DIM AS BYTE x, ClickedButton
Snd = TRUE
ResetTrigger = FALSE
MouseSupport = TRUE
Result = "0"
Memory = "0"
WorkNumber = "0"

ClickMap(10,25) = 1 : ClickMap(10,26) = 1 : ClickMap(10,27) = 1
ClickMap(10,29) = 2 : ClickMap(10,30) = 2 : ClickMap(10,31) = 2
ClickMap(10,33) = 3 : ClickMap(10,34) = 3 : ClickMap(10,35) = 3
ClickMap(10,37) = 4 : ClickMap(10,38) = 4 : ClickMap(10,39) = 4
ClickMap(10,41) = 5 : ClickMap(10,42) = 5 : ClickMap(10,43) = 5
ClickMap(12,25) = 6 : ClickMap(12,26) = 6 : ClickMap(12,27) = 6
ClickMap(12,29) = 7 : ClickMap(12,30) = 7 : ClickMap(12,31) = 7
ClickMap(12,33) = 8 : ClickMap(12,34) = 8 : ClickMap(12,35) = 8
ClickMap(12,37) = 9 : ClickMap(12,38) = 9 : ClickMap(12,39) = 9
ClickMap(12,41) = 10: ClickMap(12,42) = 10: ClickMap(12,43) = 10: ClickMap(13,41) = 10: ClickMap(13,42) = 10: ClickMap(13,43) = 10: ClickMap(14,41) = 10: ClickMap(14,42) = 10: ClickMap(14,43) = 10
ClickMap(14,25) = 11: ClickMap(14,26) = 11: ClickMap(14,27) = 11
ClickMap(14,29) = 12: ClickMap(14,30) = 12: ClickMap(14,31) = 12
ClickMap(14,33) = 13: ClickMap(14,34) = 13: ClickMap(14,35) = 13
ClickMap(14,37) = 14: ClickMap(14,38) = 14: ClickMap(14,39) = 14
ClickMap(16,25) = 15: ClickMap(16,26) = 15: ClickMap(16,27) = 15
ClickMap(16,29) = 16: ClickMap(16,30) = 16: ClickMap(16,31) = 16
ClickMap(16,33) = 17: ClickMap(16,34) = 17: ClickMap(16,35) = 17
ClickMap(16,37) = 18: ClickMap(16,38) = 18: ClickMap(16,39) = 18
ClickMap(16,41) = 19: ClickMap(16,42) = 19: ClickMap(16,43) = 19: ClickMap(17,41) = 19: ClickMap(17,42) = 19: ClickMap(17,43) = 19: ClickMap(18,41) = 19: ClickMap(18,42) = 19: ClickMap(18,43) = 19
ClickMap(18,25) = 20: ClickMap(18,26) = 20: ClickMap(18,27) = 20
ClickMap(18,29) = 21: ClickMap(18,30) = 21: ClickMap(18,31) = 21: ClickMap(18,32) = 21: ClickMap(18,33) = 21: ClickMap(18,34) = 21: ClickMap(18,35) = 21
ClickMap(18,37) = 22: ClickMap(18,38) = 22: ClickMap(18,39) = 22
ClickMap(10,48) = 23: ClickMap(10,49) = 23: ClickMap(10,50) = 23
ClickMap(10,52) = 24: ClickMap(10,53) = 24: ClickMap(10,54) = 24
ClickMap(12,48) = 25: ClickMap(12,49) = 25: ClickMap(12,50) = 25
ClickMap(12,52) = 26: ClickMap(12,53) = 26: ClickMap(12,54) = 26
ClickMap(14,48) = 27: ClickMap(14,49) = 27: ClickMap(14,50) = 27
ClickMap(14,52) = 28: ClickMap(14,53) = 28: ClickMap(14,54) = 28
ClickMap(16,48) = 29: ClickMap(16,49) = 29: ClickMap(16,50) = 29
ClickMap(16,52) = 30: ClickMap(16,53) = 30: ClickMap(16,54) = 30
ClickMap(18,48) = 31: ClickMap(18,49) = 31: ClickMap(18,50) = 31
ClickMap(18,52) = 32: ClickMap(18,53) = 32: ClickMap(18,54) = 32

IF SETMOUSE(1, 1, 1) <> 0 THEN PRINT "Mouse init failed - Please check if you loaded a mouse driver!": MouseSupport = FALSE: SLEEP 1000

GetCountrySysSettings

PCOPY(0, 1)            ' Saving the initial video page
InitialLocate = CSRLIN ' Saving initial cursor position

IF MouseSupport = TRUE THEN
   ShortCutList = FALSE
   GETMOUSE(xPos, yPos,, Buttons)
   MousePosition(1) = xPos+1
   MousePosition(2) = yPos+1
   MousePosition(3) = SCREEN(yPos+1, xPos+1, 1)
   MouseRefresh(xPos+1, yPos+1, TRUE)
 ELSE
   ShortCutList = TRUE
END IF
AsciiButton(1) = " / ": AsciiButton(2) = "SQR": AsciiButton(3) = "x^n": AsciiButton(4) = "x^2"
SELECT CASE GetCurrentCodePage
  CASE 437, 860, 861, 863, 865, 737, 790, 991
     AsciiButton(1) = " � ": AsciiButton(2) = " � ": AsciiButton(3) = " x�": AsciiButton(4) = " x�":
  CASE 775, 850, 857, 858
     AsciiButton(1) = " � ": AsciiButton(2) = "SQR": AsciiButton(3) = "x^n": AsciiButton(4) = " x�":
  CASE 852
     AsciiButton(1) = " � ": AsciiButton(2) = "SQR": AsciiButton(3) = "x^n": AsciiButton(4) = "x^2":
  CASE 866
     AsciiButton(1) = " / ": AsciiButton(2) = " � ": AsciiButton(3) = "x^n": AsciiButton(4) = "x^2":
END SELECT

LOCATE ,,0   ' Hiding the blinking text cursor

DrawBackground(ShortCutList)
PrintWork(Result)
FOR x = 1 TO 32
  DrawButton(x, 0)
NEXT x


DO
 SELECT CASE INKEY
    CASE ""
       REM It's here just to speed up the program if no key pressed.
    CASE "1"
       ClickedButton = 16
    CASE "2"
       ClickedButton = 17
    CASE "3"
       ClickedButton = 18
    CASE "4"
       ClickedButton = 12
    CASE "5"
       ClickedButton = 13
    CASE "6"
       ClickedButton = 14
    CASE "7"
       ClickedButton = 7
    CASE "8"
       ClickedButton = 8
    CASE "9"
       ClickedButton = 9
    CASE "0"
       ClickedButton = 21
    CASE CHR(13), "=" 'ENTER
       ClickedButton = 19
    CASE "*"
       ClickedButton = 4
    CASE "+"
       ClickedButton = 10
    CASE "-"
       ClickedButton = 5
    CASE ".", ","
       ClickedButton = 22
       KeybFlush
    CASE CHR(27)    'ESC
       ClickedButton = 24
    CASE CHR(8)     'BackSPC
       ClickedButton = 28
    CASE CHR(255) + "S" 'DEL
       ClickedButton = 26
    CASE "!"
       ClickedButton = 15
    CASE "s"
       ClickedButton = 30
    CASE "?"
       ClickedButton = 32
    CASE "%"
       ClickedButton = 2
    CASE "/"
       ClickedButton = 3
    CASE "\"
       ClickedButton = 31
    CASE "m"
       ClickedButton = 23
    CASE "M"
       ClickedButton = 25
    CASE "r"
       ClickedButton = 27
    CASE "c"
       ClickedButton = 29
    CASE "^"
       ClickedButton = 11
    CASE ":"
       ClickedButton = 20
    CASE "["
       ClickedButton = 6
    CASE "]"
       ClickedButton = 1
    CASE CHR(255)+";"   ' F1 pressed
       ClickedButton = 127
 END SELECT
 IF ClickedButton > 0 THEN
     DrawButton(ClickedButton, 2)
     IF Snd = TRUE THEN Bip ELSE SLEEP 50
     KeybFlush
     ClickedButton = 0 - ClickedButton
 END IF
 IF ResetTrigger = TRUE THEN ClickedButton = -26: ResetTrigger = FALSE
 IF MouseSupport = TRUE THEN
     GETMOUSE(xPos, yPos,, Buttons)
     IF ClickedButton >= 0 THEN MouseRefresh(xPos+1, yPos+1, ForceRefresh)
     ForceRefresh = FALSE
 END IF

 IF (Buttons AND 1) AND (ClickedButton = 0) THEN
    ClickedButton = ClickMap(yPos, xPos)
    DrawButton(ClickedButton, 2)
    SavedMouseX = xPos
    SavedMouseY = yPos
    IF Snd = TRUE AND ClickedButton > 0 THEN Bip
    ClickedButton = 0 - ClickedButton
 END IF
 IF Buttons = 0 AND ClickedButton < 0 THEN
    ForceRefresh = TRUE
    ClickedButton = ABS(ClickedButton)
    xPos = SavedMouseX     ' Here I am restoring the mouse position,
    yPos = SavedMouseY     ' that is the position of the mouse before
    SETMOUSE xPos, yPos    ' the click.
    DrawButton(ClickedButton, 0)
    SELECT CASE ClickedButton
      CASE 1   ' SQRT Button
        Compute
        Operation = "SQR"
        Compute
      CASE 2
        IF Operation = "-" OR Operation = "+" THEN WorkNumber = Calculus(WorkNumber, Result, "*")
        WorkNumber = Calculus(WorkNumber, "100", "/")
        Compute
      CASE 3
        Compute
        Operation = "/"
      CASE 4
        Compute
        Operation = "*"
      CASE 5
        Compute
        Operation = "-"
      CASE 6
        Compute
        WorkNumber = Result
        Operation = "*"
        Compute
      CASE 7
        SELECT CASE WorkNumber
          CASE "0"
            WorkNumber = "7"
          CASE "-0"
            WorkNumber = "-7"
          CASE ELSE
            IF (INSTR(WorkNumber, ".") = 0 AND LEN(WorkNumber) < 12) OR (INSTR(WorkNumber, ".") > 0 AND LEN(WorkNumber)-INSTR(WorkNumber, ".") < 10) THEN WorkNumber = WorkNumber + "7"
        END SELECT
        PrintWork(WorkNumber)
      CASE 8
        SELECT CASE WorkNumber
          CASE "0"
            WorkNumber = "8"
          CASE "-0"
            WorkNumber = "-8"
          CASE ELSE
            IF (INSTR(WorkNumber, ".") = 0 AND LEN(WorkNumber) < 12) OR (INSTR(WorkNumber, ".") > 0 AND LEN(WorkNumber)-INSTR(WorkNumber, ".") < 10) THEN WorkNumber = WorkNumber + "8"
        END SELECT
        PrintWork(WorkNumber)
      CASE 9
        SELECT CASE WorkNumber
          CASE "0"
            WorkNumber = "9"
          CASE "-0"
            WorkNumber = "-9"
          CASE ELSE
            IF (INSTR(WorkNumber, ".") = 0 AND LEN(WorkNumber) < 12) OR (INSTR(WorkNumber, ".") > 0 AND LEN(WorkNumber)-INSTR(WorkNumber, ".") < 10) THEN WorkNumber = WorkNumber + "9"
        END SELECT
        PrintWork(WorkNumber)
      CASE 10
        Compute
        Operation = "+"
      CASE 11
        Compute
        Operation = "xn"
      CASE 12
        SELECT CASE WorkNumber
          CASE "0"
            WorkNumber = "4"
          CASE "-0"
            WorkNumber = "-4"
          CASE ELSE
            IF (INSTR(WorkNumber, ".") = 0 AND LEN(WorkNumber) < 12) OR (INSTR(WorkNumber, ".") > 0 AND LEN(WorkNumber)-INSTR(WorkNumber, ".") < 10) THEN WorkNumber = WorkNumber + "4"
        END SELECT
        PrintWork(WorkNumber)
      CASE 13
        SELECT CASE WorkNumber
          CASE "0"
            WorkNumber = "5"
          CASE "-0"
            WorkNumber = "-5"
          CASE ELSE
            IF (INSTR(WorkNumber, ".") = 0 AND LEN(WorkNumber) < 12) OR (INSTR(WorkNumber, ".") > 0 AND LEN(WorkNumber)-INSTR(WorkNumber, ".") < 10) THEN WorkNumber = WorkNumber + "5"
        END SELECT
        PrintWork(WorkNumber)
      CASE 14
        SELECT CASE WorkNumber
          CASE "0"
            WorkNumber = "6"
          CASE "-0"
            WorkNumber = "-6"
          CASE ELSE
            IF (INSTR(WorkNumber, ".") = 0 AND LEN(WorkNumber) < 12) OR (INSTR(WorkNumber, ".") > 0 AND LEN(WorkNumber)-INSTR(WorkNumber, ".") < 10) THEN WorkNumber = WorkNumber + "6"
        END SELECT
        PrintWork(WorkNumber)
      CASE 15
        Compute
        Operation = "x!"
        Compute
      CASE 16
        SELECT CASE WorkNumber
          CASE "0"
            WorkNumber = "1"
          CASE "-0"
            WorkNumber = "-1"
          CASE ELSE
            IF (INSTR(WorkNumber, ".") = 0 AND LEN(WorkNumber) < 12) OR (INSTR(WorkNumber, ".") > 0 AND LEN(WorkNumber)-INSTR(WorkNumber, ".") < 10) THEN WorkNumber = WorkNumber + "1"
        END SELECT
        PrintWork(WorkNumber)
      CASE 17
        SELECT CASE WorkNumber
          CASE "0"
            WorkNumber = "2"
          CASE "-0"
            WorkNumber = "-2"
          CASE ELSE
            IF (INSTR(WorkNumber, ".") = 0 AND LEN(WorkNumber) < 12) OR (INSTR(WorkNumber, ".") > 0 AND LEN(WorkNumber)-INSTR(WorkNumber, ".") < 10) THEN WorkNumber = WorkNumber + "2"
        END SELECT
        PrintWork(WorkNumber)
      CASE 18
        SELECT CASE WorkNumber
          CASE "0"
            WorkNumber = "3"
          CASE "-0"
            WorkNumber = "-3"
          CASE ELSE
            IF (INSTR(WorkNumber, ".") = 0 AND LEN(WorkNumber) < 12) OR (INSTR(WorkNumber, ".") > 0 AND LEN(WorkNumber)-INSTR(WorkNumber, ".") < 10) THEN WorkNumber = WorkNumber + "3"
        END SELECT
        PrintWork(WorkNumber)
      CASE 19
        Compute
      CASE 20
        Compute
        Operation = "MOD"
      CASE 21   ' "0" button
        IF WorkNumber <> "0" AND WorkNumber <> "-0" THEN
            IF (INSTR(WorkNumber, ".") = 0 AND LEN(WorkNumber) < 12) OR (INSTR(WorkNumber, ".") > 0 AND LEN(WorkNumber)-INSTR(WorkNumber, ".") < 10) THEN WorkNumber = WorkNumber + "0"
        END IF
        PrintWork(WorkNumber)
      CASE 22  ' "." button
        IF INSTR(WorkNumber, ".") = 0 THEN WorkNumber = WorkNumber + "."
        PrintWork(WorkNumber)
      CASE 23
        Compute
        Memory = Calculus(Memory, Result, "+")
        DrawButton(27,0)
      CASE 24
        Quit
      CASE 25
        Compute
        Memory = Calculus(Memory, Result, "-")
        DrawButton(27,0)
      CASE 26     '  "AC" Button or ResetTrigger
        Memory = "0"
        DrawButton(27,0)
        WorkNumber = "0"
        Operation = ""
        Result = "0"
        Compute
      CASE 27
        WorkNumber = Memory
        PrintWork(WorkNumber)
      CASE 28   ' BackSpace
        IF WorkNumber <> "0" THEN
            WorkNumber = MID(WorkNumber, 1, LEN(WorkNumber) - 1)
            IF WorkNumber = "" THEN WorkNumber = "0"
            PrintWork(WorkNumber)
          ELSE
            Result = "0"
            WorkNumber = "0"
            Operation = ""
            Compute
        END IF
      CASE 29   ' MC button
        Memory = "0"
        DrawButton(27, 0)
      CASE 30
        IF Snd = TRUE THEN Snd = FALSE ELSE Snd = TRUE
        DrawButton(30, 0)
        IF ClickMap(yPos, xPos) = 30 THEN MousePosition(3) = SCREEN(yPos+1, xPos+1, 1)
        MouseRefresh(xPos+1, yPos+1, TRUE)
      CASE 31  ' +/- button
        IF MID(WorkNumber,1,1) = "-" THEN WorkNumber = MID(WorkNumber, 2, LEN(WorkNumber)-1) ELSE WorkNumber = "-" + WorkNumber
        PrintWork(WorkNumber)
      CASE 32
        About
      CASE 127
        TempString = ""
        FOR x = 1 TO 30
          TempString += CHR(SCREEN(8, 25+x))
        NEXT x
        PCOPY(1, 0)
        IF ShortCutList = FALSE THEN ShortCutList = TRUE ELSE ShortCutList = FALSE
        DrawBackground(ShortCutList)
        FOR x = 1 TO 32
           DrawButton(x, 0)
        NEXT x
        COLOR 10, 0: LOCATE 8, 26: PRINT TempString;
        COLOR 7,0
    END SELECT
    IF ClickedButton > 0 THEN ClickedButton = 0
 END IF

LOOP


'***  PROGRAM'S END  ***  HERE STARTS ALL SUB PROCEDURE & FUNCTIONS  ***


SUB DrawBackground(ShortCut AS BOOL)
 COLOR 7, 1
 LOCATE  5, 22: PRINT "������������������������������������ͻ";
 LOCATE  6, 22: PRINT "�                                    �";
 LOCATE  7, 22: PRINT "�  ������������������������������Ŀ  �";
 LOCATE  8, 22: PRINT "�  �                              �  �";
 LOCATE  9, 22: PRINT "�  ��������������������������������  �";
 LOCATE 10, 22: PRINT "�                                    �";
 LOCATE 11, 22: PRINT "�                                    �";
 LOCATE 12, 22: PRINT "�                                    �";
 LOCATE 13, 22: PRINT "�                                    �";
 LOCATE 14, 22: PRINT "�                                    �";
 LOCATE 15, 22: PRINT "�                                    �";
 LOCATE 16, 22: PRINT "�                                    �";
 LOCATE 17, 22: PRINT "�                                    �";
 LOCATE 18, 22: PRINT "�                                    �";
 LOCATE 19, 22: PRINT "�                                    �";
 LOCATE 20, 22: PRINT "�                                    �";
 LOCATE 21, 22: PRINT "������������������������������������ͼ";

 IF ShortCut = TRUE THEN
     LOCATE  1, 62: PRINT "�������������[F1]�";
     LOCATE  2, 62: PRINT "� KEY SHORTCUTS: �";
     LOCATE  3, 62: PRINT "� -------------- �";
     LOCATE  4, 62: PRINT "� ]   - SQR      �";
     LOCATE  5, 62: PRINT "� %   - Percent  �";
     LOCATE  6, 62: PRINT "� /   - Division �";
     LOCATE  7, 62: PRINT "� *   - Multip.  �";
     LOCATE  8, 62: PRINT "� -   - Subtrac. �";
     LOCATE  9, 62: PRINT "� [   - x^2      �";
     LOCATE 10, 62: PRINT "� ^   - x^y      �";
     LOCATE 11, 62: PRINT "� !   - Factor.  �";
     LOCATE 12, 62: PRINT "� :   - MOD      �";
     LOCATE 13, 62: PRINT "� +   - Addition �";
     LOCATE 14, 62: PRINT "� =   - Compute  �";
     LOCATE 15, 62: PRINT "� m   - M+       �";
     LOCATE 16, 62: PRINT "� M   - M-       �";
     LOCATE 17, 62: PRINT "� r   - MR       �";
     LOCATE 18, 62: PRINT "� c   - MC       �";
     LOCATE 19, 62: PRINT "� \   - +/-      �";
     LOCATE 20, 62: PRINT "� DEL - AC       �";
     LOCATE 21, 62: PRINT "� Bck - C        �";
     LOCATE 22, 62: PRINT "� s   - Snd      �";
     LOCATE 23, 62: PRINT "� ?   - About    �";
     LOCATE 24, 62: PRINT "� ESC - OFF      �";
     LOCATE 25, 62: PRINT "������������������";
 END IF
 COLOR 7, 0
END SUB


SUB Quit
 SETMOUSE(0, 0, 0)
 CLS
 PCOPY(1, 0) ' Restore initial screen
 LOCATE InitialLocate, 1
 END
END SUB


SUB PrintWork(WorkN AS STRING)
 DIM AS STRING DisplayMe, IntegerPart, DecimalPart, Signum, IntegerPartSep, LastVisibleNum
 DIM AS INTEGER x
 IF Calculus(WorkN, "0", "CMP") = "-1" THEN Signum = "-" ELSE Signum = ""
 IF INSTR(WorkN, ".") = 0 THEN
     IntegerPart = MID(WorkN, LEN(Signum) + 1, LEN(WorkN) - LEN(Signum))
   ELSE
     IntegerPart = MID(WorkN, LEN(Signum) + 1, INSTR(WorkN, ".") - 1 - LEN(Signum))
     IF INSTR(WorkN, ".") < LEN(WorkN) THEN DecimalPart = MID(WorkN, INSTR(WorkN, ".") + 1, LEN(WorkN) - INSTR(WorkN, "."))
 END IF
REM ----- Inserting thousand separators to the integer -----
 x = LEN(IntegerPart)
 WHILE x > 3
   IntegerPartSep = ThousSep + MID(IntegerPart, x - 2, 3) + IntegerPartSep
   x -= 3
 WEND
 IntegerPartSep = MID(IntegerPart, 1, x) + IntegerPartSep
REM ----- Thousand separators inserted -----
 DisplayMe = Signum + IntegerPartSep
 IF LEN(DisplayMe) > 30 THEN
     PrintMsg("#001")   ' #001 means "Number too big"
   ELSE
     IF INSTR(WorkN, ".") > 0 THEN DisplayMe += DecSep + DecimalPart
     IF LEN(DisplayMe) > 30 THEN DisplayMe = LEFT(DisplayMe, 30)
     COLOR 10, 0
     LOCATE 8, 26
     PRINT SPACE(30 - LEN(DisplayMe)); DisplayMe;
     COLOR 7, 0
 END IF
END SUB


SUB DrawButton(n AS UBYTE, Stan AS UBYTE)
 SELECT CASE Stan
   CASE 0
     COLOR 7, 6
     IF n = 30 AND Snd = TRUE THEN COLOR 14, 6
     IF n = 27 AND Memory <> "0" THEN COLOR 14, 6
   CASE 2
     COLOR 15, 4
 END SELECT

 SELECT CASE n
   CASE 1
     LOCATE 11, 26: PRINT AsciiButton(2);
   CASE 2
     LOCATE 11, 30: PRINT " % ";
   CASE 3
     LOCATE 11, 34: PRINT AsciiButton(1);
   CASE 4
     LOCATE 11, 38: PRINT " * ";
   CASE 5
     LOCATE 11, 42: PRINT " - ";
   CASE 6
     LOCATE 13, 26: PRINT AsciiButton(4);
   CASE 7
     LOCATE 13, 30: PRINT " 7 ";
   CASE 8
     LOCATE 13, 34: PRINT " 8 ";
   CASE 9
     LOCATE 13, 38: PRINT " 9 ";
   CASE 10
     LOCATE 13, 42: PRINT "   ";
     LOCATE 14, 42: PRINT " + ";
     LOCATE 15, 42: PRINT "   ";
   CASE 11
     LOCATE 15, 26: PRINT AsciiButton(3);
   CASE 12
     LOCATE 15, 30: PRINT " 4 ";
   CASE 13
     LOCATE 15, 34: PRINT " 5 ";
   CASE 14
     LOCATE 15, 38: PRINT " 6 ";
   CASE 15
     LOCATE 17, 26: PRINT " x!";
   CASE 16
     LOCATE 17, 30: PRINT " 1 ";
   CASE 17
     LOCATE 17, 34: PRINT " 2 ";
   CASE 18
     LOCATE 17, 38: PRINT " 3 ";
   CASE 19
     LOCATE 17, 42: PRINT "   ";
     LOCATE 18, 42: PRINT " = ";
     LOCATE 19, 42: PRINT "   ";
   CASE 20
     LOCATE 19, 26: PRINT "MOD";
   CASE 21
     LOCATE 19, 30: PRINT "   0   ";
   CASE 22
     LOCATE 19, 38: PRINT " . ";
   CASE 23
     LOCATE 11, 49: PRINT " M+";
   CASE 24
     LOCATE 11, 53: PRINT "OFF";
   CASE 25
     LOCATE 13, 49: PRINT " M-";
   CASE 26
     LOCATE 13, 53: PRINT " AC";
   CASE 27
     LOCATE 15, 49: PRINT " MR";
   CASE 28
     LOCATE 15, 53: PRINT " C ";
   CASE 29
     LOCATE 17, 49: PRINT " MC";
   CASE 30
     LOCATE 17, 53: PRINT "  ";
   CASE 31
     LOCATE 19, 49: PRINT "+/-";
   CASE 32
     LOCATE 19, 53: PRINT " ? ";
 END SELECT
 COLOR 7, 0
END SUB


SUB Bip
  SoundQ(800, 60)
END SUB


SUB Compute
 SELECT CASE Operation
   CASE ""
     IF WorkNumber <> "0" THEN Result = WorkNumber
   CASE "+"
     Result = Calculus(Result, WorkNumber, "+")
   CASE "-"
     Result = Calculus(Result, WorkNumber, "-")
   CASE "/"
     IF Calculus(WorkNumber, "0", "CMP") = "0" THEN PrintMsg("#003") ELSE Result = Calculus(Result, WorkNumber, "/")   ' #003 = "ERROR: DIV BY ZERO"
   CASE "*"
     Result = Calculus(Result, WorkNumber, "*")
   CASE "xn"
     IF Calculus(Result, "0", "CMP") = "0" AND Calculus(WorkNumber, "0", "CMP") = "-1" THEN    ' If you try to exponent 0 to a negative exponent (0^-x)...
         PrintMsg("#003")   ' 003 means "Div by zero"
       ELSEIF VAL(Calculus(Calculus(Result, "0", "ln"), WorkNumber, "*")) > 70 THEN ' That a hint submited by srvaldez: if (ln(x)*y) > ln() then do the exponentiation
         PrintMsg("#001")    ' 001 means "Number too big!"
       ELSEIF Calculus(WorkNumber, "0", "INT?") = "0" AND Calculus(Result, "0", "CMP") = "-1" THEN    ' If you try to exponent a negative number to a floating point exponent...
         PrintMsg("#002")  ' 002 means "Not allowed"
       ELSE
         Result = Calculus(Result, WorkNumber, "^")
     END IF
   CASE "x!"
     IF Calculus(Result, "0", "INT?") = "0" OR Calculus(Result, "0", "CMP") = "-1" THEN
         PrintMsg("#002")   ' #002 means "Not allowed"
       ELSEIF Calculus(Result, "29", "CMP") = "1" THEN
         PrintMsg("#001") ' 001 means "Number too big! Sorry."
       ELSE
         Result = Calculus(Result, "0", "x!")
     END IF
   CASE "SQR"
     IF Calculus(Result, "0", "CMP") = "-1" THEN PrintMsg("#002") ELSE Result = Calculus(Result, "0", "SQR")   ' #002 means "Not allowed"
   CASE "MOD"
     IF Calculus(WorkNumber, "0", "CMP") = "0" THEN
        PrintMsg("#003")
      ELSEIF Calculus(Result, "0", "INT?") = "0" OR Calculus(WorkNumber, "0", "INT?") = "0" THEN
        PrintMsg("#002")   ' 002 means "Not allowed"
      ELSEIF Calculus(WorkNumber, "0", "CMP") = "1" THEN  ' If result is positive
        Result = Calculus(Result, WorkNumber, "MOD")
        IF Calculus(Result, "0", "CMP") = "-1" THEN Result = Calculus(Calculus(WorkNumber, "0", "ABS"), Result, "+") ' Because MTFR gives weird values sometimes (eg. 18 mod 5 = -2...)
      ELSEIF Calculus(WorkNumber, "0", "CMP") = "-1" THEN ' If result is negative
        Result = Calculus(Result, WorkNumber, "MOD")
        IF Calculus(Result, "0", "CMP") = "1" THEN Result = Calculus("0", Calculus(Calculus(WorkNumber, "0", "ABS"), Result, "-"), "-") ' Because MTFR gives weird values sometimes (eg. -18 mod 5 = 2...)
     END IF
 END SELECT
 ON ERROR GOTO 0
 Operation = ""
 WorkNumber = "0"
 PrintWork(Result)
END SUB


SUB About
 DIM Text AS STRING
 DIM x AS UBYTE = 0
 Text = SPACE(31) + "FoxCalc v" + pVer + " - Copyright (C) Mateusz Viste " + CHR(34) + "Fox" + CHR(34) + " " + pDate + " - email: [email protected]" + SPACE(31)
 ResetTrigger = TRUE
 COLOR 10, 0
 FOR x = 1 TO LEN(Text) - 30
    LOCATE 8, 26
    PRINT MID(Text, x, 30);
    SLEEP 80
 NEXT x
 PrintWork(WorkNumber)
 KeybFlush
END SUB


SUB KeybFlush
 DO: LOOP UNTIL INKEY = ""
END SUB


SUB PrintMsg(Komunikat AS STRING) ' It's used to display error messages.
    SELECT CASE Komunikat
      CASE "#001"
        Komunikat = "Number too big! Sorry."
      CASE "#002"
        Komunikat = "NOT ALLOWED"
      CASE "#003"
        Komunikat = "ERROR: DIV BY ZERO"
    END SELECT
    LOCATE 8, 26: COLOR 4, 0
    PRINT SPACE(30 - LEN(Komunikat)) + Komunikat;
    COLOR 7, 0
    IF snd = TRUE THEN SoundQ(200, 500): ELSE SLEEP 500
    SLEEP 1500
    ResetTrigger = TRUE
    KeybFlush
END SUB


SUB MouseRefresh(x AS INTEGER, y AS INTEGER, Forcing AS BOOL = FALSE)
 IF (x > 0 AND y > 0 AND (x <> MousePosition(1) OR y <> MousePosition(2))) OR Forcing = TRUE THEN
    LOCATE MousePosition(2), MousePosition(1)                 ' Erasing the
    COLOR MousePosition(3) AND &HF, MousePosition(3) SHR 4    ' previous
    PRINT CHR(SCREEN(MousePosition(2), MousePosition(1), 0)); ' cursor.
    MousePosition(1) = x                       ' Saving the current's
    MousePosition(2) = y                       ' cursor position and
    MousePosition(3) = SCREEN(y, x, 1)         ' colors.
    LOCATE y, x
    IF MousePosition(3) SHR 4 <> 0 THEN COLOR 15, 0 ELSE COLOR 0, 8
    PRINT CHR(SCREEN(y, x, 0));
    COLOR 7, 0
 END IF
END SUB


SUB SoundQ(ByVal freq AS UINTEGER, dur AS UINTEGER)
  DIM t AS DOUBLE, f1 AS USHORT
  IF freq > 0 THEN
     f1 = 1193181 \ freq
     OUT &H61, INP(&H61) OR 3
     OUT &H43, &HB6
     OUT &H42, lobyte(f1)
     OUT &H42, hibyte(f1)
  END IF
  t = TIMER
  WHILE ((TIMER - t) * 1000) < dur
     SLEEP 0, 1
  WEND
  IF freq > 0 THEN
     OUT &H61, INP(&H61) AND &HFC
  END IF
END SUB


FUNCTION GetCurrentCodePage() AS USHORT
       CONST CF = 1
       DIM regs AS __dpmi_regs
       regs.x.ax = &h6601
       IF __dpmi_int(&h21, @regs) = 0 AND (regs.x.flags And CF) = 0 THEN
               RETURN regs.x.bx
       ELSE
               RETURN 0
       END IF
END FUNCTION


FUNCTION Calculus(Numb1 AS STRING, Numb2 AS STRING, Oper AS STRING) AS STRING
 REM ----- Initializing MPFR variables -----
  DIM AS mpfr_ptr mpfresult = allocate(len(__mpfr_struct))
  DIM AS mpfr_ptr mpfvar1 = allocate(len(__mpfr_struct))
  DIM AS mpfr_ptr mpfvar2 = allocate(len(__mpfr_struct))
  mpfr_set_default_prec(256)  ' Set the precision to 256 bits (default is 64)
  mpfr_set_default_rounding_mode(GMP_RNDN)  ' Set the default rounding mode to "nearest"
  mpfr_init(mpfresult)
  mpfr_init(mpfvar1)
  mpfr_init(mpfvar2)
  mpfr_set_str(mpfvar1, Numb1, 10)
  mpfr_set_str(mpfvar2, Numb2, 10)
 REM ----- Initializing other variables -----
  DIM AS STRING Rezultat

  SELECT CASE Oper
    CASE "+"
      mpfr_add(mpfresult, mpfvar1, mpfvar2, GMP_RNDN)
    CASE "-"
      mpfr_sub(mpfresult, mpfvar1, mpfvar2, GMP_RNDN)
    CASE "*"
      mpfr_mul(mpfresult, mpfvar1, mpfvar2, GMP_RNDN)
    CASE "/"
      mpfr_div(mpfresult, mpfvar1, mpfvar2, GMP_RNDN)
    CASE "SQR"
      mpfr_sqrt(mpfresult, mpfvar1, GMP_RNDN)
    CASE "x!"
      mpfr_fac_ui(mpfresult, mpfr_get_ui(mpfvar1, GMP_RNDN), GMP_RNDN)
    CASE "MOD"
      mpfr_remainder(mpfresult, mpfvar1, mpfvar2, GMP_RNDN)
    CASE "^"
      mpfr_pow(mpfresult, mpfvar1, mpfvar2, GMP_RNDN)
    CASE "CMP"   ' It's used for internal comparisions
      mpfr_set_str(mpfresult, STR(mpfr_cmp(mpfvar1, mpfvar2)), 10)
    CASE "ln"   ' It's used for internal overflow checking in x^y operations
      mpfr_log(mpfresult, mpfvar1, GMP_RNDN)
    CASE "INT?"   ' It's used for internal checking.
      mpfr_set_str(mpfresult, STR(mpfr_integer_p(mpfvar1)), 10)
    CASE "ABS"   ' It's used for internal checking.
      mpfr_abs(mpfresult, mpfvar1, GMP_RNDN)
  END SELECT

 REM ----- Here begins the MPFR -> STRING conversion -----
  DIM AS ZSTRING PTR s
  DIM AS mp_exp_t PTR exppn = allocate(len(mp_exp_t))
  DIM AS INTEGER Exponent
  s = mpfr_get_str(0, exppn, 10, 60, mpfresult, GMP_RNDN)
  Rezultat = *s
  Exponent = *exppn
  IF mpfr_cmp_si(mpfresult, 0) < 0 THEN Exponent += 1  ' That's for the additional byte (the "-" sign)
  IF Exponent < 0 THEN Rezultat = STRING(ABS(Exponent), "0") + Rezultat: Exponent = 0
  IF Exponent > LEN(Rezultat) THEN Rezultat += STRING(Exponent - LEN(Rezultat), "0")
  IF Exponent < LEN(Rezultat) THEN Rezultat = MID(Rezultat, 1, Exponent) + "." + MID(Rezultat, Exponent + 1, LEN(Rezultat) - Exponent)
  deallocate(exppn)
  deallocate(s)
 REM ----- Preformatting the output -----
  IF Rezultat = "" AND Exponent = 0 THEN Rezultat = "0"
  IF MID(Rezultat, 1, 1) = "." THEN Rezultat = "0" + Rezultat
  IF MID(Rezultat, 1, 2) = "-." THEN Rezultat = "-0" + MID(Rezultat, 2, LEN(Rezultat) - 1)
  IF INSTR(Rezultat, ".") <> 0 AND RIGHT(Rezultat, 1) = "0" THEN
     DO: Rezultat = MID(Rezultat, 1, LEN(Rezultat) - 1)
     LOOP UNTIL RIGHT(Rezultat, 1) <> "0"
  END IF
  IF RIGHT(Rezultat, 1) = "." THEN Rezultat = MID(Rezultat, 1, LEN(Rezultat) - 1)
 REM ----- Clearing all unneeded MPFR variables -----
  mpfr_clear(mpfresult)   '  Clearing unneeded variables,
  mpfr_clear(mpfvar1)     '  as they are still occuping
  mpfr_clear(mpfvar2)     '  memory. [floating point op.]

  RETURN Rezultat
END FUNCTION

SUB GetCountrySysSettings()
 DIM ci AS COUNTRYINFO
 IF GetCountryInfo(@ci) = 0 THEN
     ThousSep = ci.ciThousands
     DecSep = ci.ciDecimal
   ELSE
     ThousSep = "'"
     DecSep = "."
 END IF
 'DecSep = FORMAT(0.5, ".#")  ' That was the old way to get the decimal separator.
END SUB