/Classes/common-42s/core_globals.cc
C++ | 3488 lines | 3466 code | 6 blank | 16 comment | 0 complexity | f95c7bc6f32c9f486f19b1de23ead199 MD5 | raw file
Possible License(s): GPL-2.0
- /*****************************************************************************
- * Free42 -- an HP-42S calculator simulator
- * Copyright (C) 2004-2011 Thomas Okken
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License, version 2,
- * as published by the Free Software Foundation.
- *
- * 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, see http://www.gnu.org/licenses/.
- *****************************************************************************/
- #include <stdlib.h>
- #include "core_globals.h"
- #include "core_commands2.h"
- #include "core_commands4.h"
- #include "core_display.h"
- #include "core_helpers.h"
- #include "core_main.h"
- #include "core_math1.h"
- #include "core_tables.h"
- #include "core_variables.h"
- #include "undo.h"
- #include "shell.h"
- error_spec errors[] = {
- { /* NONE */ NULL, 0 },
- { /* ALPHA_DATA_IS_INVALID */ "Alpha Data Is Invalid", 21 },
- { /* INSUFFICIENT_MEMORY */ "Insufficient Memory", 19 },
- { /* NOT_YET_IMPLEMENTED */ "Not Yet Implemented", 19 },
- { /* OUT_OF_RANGE */ "Out of Range", 12 },
- { /* DIVIDE_BY_0 */ "Divide by 0", 11 },
- { /* INVALID_TYPE */ "Invalid Type", 12 },
- { /* INVALID_DATA */ "Invalid Data", 12 },
- { /* DIMENSION_ERROR */ "Dimension Error", 15 },
- { /* SIZE_ERROR */ "Size Error", 10 },
- { /* INTERNAL_ERROR */ "Internal Error", 14 },
- { /* NONEXISTENT */ "Nonexistent", 11 },
- { /* RESTRICTED_OPERATION */ "Restricted Operation", 20 },
- { /* YES */ "Yes", 3 },
- { /* NO */ "No", 2 },
- { /* STOP */ NULL, 0 },
- { /* LABEL_NOT_FOUND */ "Label Not Found", 15 },
- { /* NO_REAL_VARIABLES */ "No Real Variables", 17 },
- { /* NO_COMPLEX_VARIABLES */ "No Complex Variables", 20 },
- { /* NO_MATRIX_VARIABLES */ "No Matrix Variables", 19 },
- { /* NO_MENU_VARIABLES */ "No Menu Variables", 17 },
- { /* STAT_MATH_ERROR */ "Stat Math Error", 15 },
- { /* INVALID_FORECAST_MODEL */ "Invalid Forecast Model", 22 },
- { /* SOLVE_INTEG_RTN_LOST */ "Solve/Integ RTN Lost", 20 },
- { /* SINGULAR_MATRIX */ "Singular Matrix", 15 },
- { /* SOLVE_SOLVE */ "Solve(Solve)", 12 },
- { /* INTEG_INTEG */ "Integ(Integ)", 12 },
- { /* RUN */ NULL, 0 },
- { /* INTERRUPTED */ "Interrupted", 11 },
- { /* PRINTING_IS_DISABLED */ "Printing Is Disabled", 20 },
- { /* INTERRUPTIBLE */ NULL, 0 },
- { /* NO_VARIABLES */ "No Variables", 12 }
- };
- menu_spec menus[] = {
- { /* MENU_ALPHA1 */ MENU_NONE, MENU_ALPHA2, MENU_ALPHA2,
- { { MENU_ALPHA_ABCDE1, 5, "ABCDE" },
- { MENU_ALPHA_FGHI, 4, "FGHI" },
- { MENU_ALPHA_JKLM, 4, "JKLM" },
- { MENU_ALPHA_NOPQ1, 4, "NOPQ" },
- { MENU_ALPHA_RSTUV1, 5, "RSTUV" },
- { MENU_ALPHA_WXYZ, 4, "WXYZ" } } },
- { /* MENU_ALPHA2 */ MENU_NONE, MENU_ALPHA1, MENU_ALPHA1,
- { { MENU_ALPHA_PAREN, 5, "( [ {" },
- { MENU_ALPHA_ARROW, 3, "\020^\016" },
- { MENU_ALPHA_COMP, 5, "< = >" },
- { MENU_ALPHA_MATH, 4, "MATH" },
- { MENU_ALPHA_PUNC1, 4, "PUNC" },
- { MENU_ALPHA_MISC1, 4, "MISC" } } },
- { /* MENU_ALPHA_ABCDE1 */ MENU_ALPHA1, MENU_ALPHA_ABCDE2, MENU_ALPHA_ABCDE2,
- { { MENU_NONE, 1, "A" },
- { MENU_NONE, 1, "B" },
- { MENU_NONE, 1, "C" },
- { MENU_NONE, 1, "D" },
- { MENU_NONE, 1, "E" },
- { MENU_NONE, 1, " " } } },
- { /* MENU_ALPHA_ABCDE2 */ MENU_ALPHA1, MENU_ALPHA_ABCDE1, MENU_ALPHA_ABCDE1,
- { { MENU_NONE, 1, "\026" },
- { MENU_NONE, 1, "\024" },
- { MENU_NONE, 1, "\031" },
- { MENU_NONE, 1, " " },
- { MENU_NONE, 1, " " },
- { MENU_NONE, 1, " " } } },
- { /* MENU_ALPHA_FGHI */ MENU_ALPHA1, MENU_NONE, MENU_NONE,
- { { MENU_NONE, 1, "F" },
- { MENU_NONE, 1, "G" },
- { MENU_NONE, 1, "H" },
- { MENU_NONE, 1, "I" },
- { MENU_NONE, 1, " " },
- { MENU_NONE, 1, " " } } },
- { /* MENU_ALPHA_JKLM */ MENU_ALPHA1, MENU_NONE, MENU_NONE,
- { { MENU_NONE, 1, "J" },
- { MENU_NONE, 1, "K" },
- { MENU_NONE, 1, "L" },
- { MENU_NONE, 1, "M" },
- { MENU_NONE, 1, " " },
- { MENU_NONE, 1, " " } } },
- { /* MENU_ALPHA_NOPQ1 */ MENU_ALPHA1, MENU_ALPHA_NOPQ2, MENU_ALPHA_NOPQ2,
- { { MENU_NONE, 1, "N" },
- { MENU_NONE, 1, "O" },
- { MENU_NONE, 1, "P" },
- { MENU_NONE, 1, "Q" },
- { MENU_NONE, 1, " " },
- { MENU_NONE, 1, " " } } },
- { /* MENU_ALPHA_NOPQ2 */ MENU_ALPHA1, MENU_ALPHA_NOPQ1, MENU_ALPHA_NOPQ1,
- { { MENU_NONE, 1, "\025" },
- { MENU_NONE, 1, "\034" },
- { MENU_NONE, 1, " " },
- { MENU_NONE, 1, " " },
- { MENU_NONE, 1, " " },
- { MENU_NONE, 1, " " } } },
- { /* MENU_ALPHA_RSTUV1 */ MENU_ALPHA1, MENU_ALPHA_RSTUV2, MENU_ALPHA_RSTUV2,
- { { MENU_NONE, 1, "R" },
- { MENU_NONE, 1, "S" },
- { MENU_NONE, 1, "T" },
- { MENU_NONE, 1, "U" },
- { MENU_NONE, 1, "V" },
- { MENU_NONE, 1, " " } } },
- { /* MENU_ALPHA_RSTUV2 */ MENU_ALPHA1, MENU_ALPHA_RSTUV1, MENU_ALPHA_RSTUV1,
- { { MENU_NONE, 1, " " },
- { MENU_NONE, 1, " " },
- { MENU_NONE, 1, " " },
- { MENU_NONE, 1, "\035" },
- { MENU_NONE, 1, " " },
- { MENU_NONE, 1, " " } } },
- { /* MENU_ALPHA_WXYZ */ MENU_ALPHA1, MENU_NONE, MENU_NONE,
- { { MENU_NONE, 1, "W" },
- { MENU_NONE, 1, "X" },
- { MENU_NONE, 1, "Y" },
- { MENU_NONE, 1, "Z" },
- { MENU_NONE, 1, " " },
- { MENU_NONE, 1, " " } } },
- { /* MENU_ALPHA_PAREN */ MENU_ALPHA2, MENU_NONE, MENU_NONE,
- { { MENU_NONE, 1, "(" },
- { MENU_NONE, 1, ")" },
- { MENU_NONE, 1, "[" },
- { MENU_NONE, 1, "]" },
- { MENU_NONE, 1, "{" },
- { MENU_NONE, 1, "}" } } },
- { /* MENU_ALPHA_ARROW */ MENU_ALPHA2, MENU_NONE, MENU_NONE,
- { { MENU_NONE, 1, "\020" },
- { MENU_NONE, 1, "^" },
- { MENU_NONE, 1, "\016" },
- { MENU_NONE, 1, "\017" },
- { MENU_NONE, 1, " " },
- { MENU_NONE, 1, " " } } },
- { /* MENU_ALPHA_COMP */ MENU_ALPHA2, MENU_NONE, MENU_NONE,
- { { MENU_NONE, 1, "=" },
- { MENU_NONE, 1, "\014" },
- { MENU_NONE, 1, "<" },
- { MENU_NONE, 1, ">" },
- { MENU_NONE, 1, "\011" },
- { MENU_NONE, 1, "\013" } } },
- { /* MENU_ALPHA_MATH */ MENU_ALPHA2, MENU_NONE, MENU_NONE,
- { { MENU_NONE, 1, "\005" },
- { MENU_NONE, 1, "\003" },
- { MENU_NONE, 1, "\002" },
- { MENU_NONE, 1, "\027" },
- { MENU_NONE, 1, "\023" },
- { MENU_NONE, 1, "\021" } } },
- { /* MENU_ALPHA_PUNC1 */ MENU_ALPHA2, MENU_ALPHA_PUNC2, MENU_ALPHA_PUNC2,
- { { MENU_NONE, 1, "," },
- { MENU_NONE, 1, ";" },
- { MENU_NONE, 1, ":" },
- { MENU_NONE, 1, "!" },
- { MENU_NONE, 1, "?" },
- { MENU_NONE, 1, "\"" } } },
- { /* MENU_ALPHA_PUNC2 */ MENU_ALPHA2, MENU_ALPHA_PUNC1, MENU_ALPHA_PUNC1,
- { { MENU_NONE, 1, "\032" },
- { MENU_NONE, 1, "_" },
- { MENU_NONE, 1, "`" },
- { MENU_NONE, 1, "'" },
- { MENU_NONE, 1, "\010" },
- { MENU_NONE, 1, "\012" } } },
- { /* MENU_ALPHA_MISC1 */ MENU_ALPHA2, MENU_ALPHA_MISC2, MENU_ALPHA_MISC2,
- { { MENU_NONE, 1, "$" },
- { MENU_NONE, 1, "*" },
- { MENU_NONE, 1, "#" },
- { MENU_NONE, 1, "/" },
- { MENU_NONE, 1, "\037" },
- { MENU_NONE, 1, " " } } },
- { /* MENU_ALPHA_MISC2 */ MENU_ALPHA2, MENU_ALPHA_MISC1, MENU_ALPHA_MISC1,
- { { MENU_NONE, 1, "\022" },
- { MENU_NONE, 1, "&" },
- { MENU_NONE, 1, "@" },
- { MENU_NONE, 1, "\\" },
- { MENU_NONE, 1, "~" },
- { MENU_NONE, 1, "|" } } },
- { /* MENU_ST */ MENU_NONE, MENU_NONE, MENU_NONE,
- { { MENU_NONE, 4, "ST L" },
- { MENU_NONE, 4, "ST X" },
- { MENU_NONE, 4, "ST Y" },
- { MENU_NONE, 4, "ST Z" },
- { MENU_NONE, 4, "ST T" },
- { MENU_NONE, 0, "" } } },
- { /* MENU_IND_ST */ MENU_NONE, MENU_NONE, MENU_NONE,
- { { MENU_NONE, 3, "IND" },
- { MENU_NONE, 4, "ST L" },
- { MENU_NONE, 4, "ST X" },
- { MENU_NONE, 4, "ST Y" },
- { MENU_NONE, 4, "ST Z" },
- { MENU_NONE, 4, "ST T" } } },
- { /* MENU_IND */ MENU_NONE, MENU_NONE, MENU_NONE,
- { { MENU_NONE, 3, "IND" },
- { MENU_NONE, 0, "" },
- { MENU_NONE, 0, "" },
- { MENU_NONE, 0, "" },
- { MENU_NONE, 0, "" },
- { MENU_NONE, 0, "" } } },
- { /* MENU_MODES1 */ MENU_NONE, MENU_MODES2, MENU_MODES2,
- { { 0x2000 + CMD_DEG, 0, "" },
- { 0x2000 + CMD_RAD, 0, "" },
- { 0x2000 + CMD_GRAD, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x2000 + CMD_RECT, 0, "" },
- { 0x2000 + CMD_POLAR, 0, "" } } },
- { /* MENU_MODES2 */ MENU_NONE, MENU_MODES1, MENU_MODES1,
- { { 0x1000 + CMD_SIZE, 0, "" },
- { 0x2000 + CMD_QUIET, 0, "" },
- { 0x2000 + CMD_CPXRES, 0, "" },
- { 0x2000 + CMD_REALRES, 0, "" },
- { 0x2000 + CMD_KEYASN, 0, "" },
- { 0x2000 + CMD_LCLBL, 0, "" } } },
- { /* MENU_DISP */ MENU_NONE, MENU_NONE, MENU_NONE,
- { { 0x2000 + CMD_FIX, 0, "" },
- { 0x2000 + CMD_SCI, 0, "" },
- { 0x2000 + CMD_ENG, 0, "" },
- { 0x2000 + CMD_ALL, 0, "" },
- { 0x2000 + CMD_RDXDOT, 0, "" },
- { 0x2000 + CMD_RDXCOMMA, 0, "" } } },
- #ifdef BIGSTACK
- { /* MENU_CLEAR1 */ MENU_NONE, MENU_CLEAR2, MENU_CLEAR3,
- #else
- { /* MENU_CLEAR1 */ MENU_NONE, MENU_CLEAR2, MENU_CLEAR2,
- #endif
- { { 0x1000 + CMD_CLSIGMA, 0, "" },
- { 0x1000 + CMD_CLP, 0, "" },
- { 0x1000 + CMD_CLV, 0, "" },
- { 0x1000 + CMD_CLST, 0, "" },
- { 0x1000 + CMD_CLA, 0, "" },
- { 0x1000 + CMD_CLX, 0, "" } } },
- #ifdef BIGSTACK
- { /* MENU_CLEAR2 */ MENU_NONE, MENU_CLEAR3, MENU_CLEAR1,
- #else
- { /* MENU_CLEAR2 */ MENU_NONE, MENU_CLEAR1, MENU_CLEAR1,
- #endif
- { { 0x1000 + CMD_CLRG, 0, "" },
- { 0x1000 + CMD_DEL, 0, "" },
- { 0x1000 + CMD_CLKEYS, 0, "" },
- { 0x1000 + CMD_CLLCD, 0, "" },
- { 0x1000 + CMD_CLMENU, 0, "" },
- { 0x1000 + CMD_CLALLa, 0, "" } } },
-
- { /* MENU_CONVERT1 */ MENU_NONE, MENU_CONVERT2, MENU_CONVERT4,
- { { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" } } },
-
- { /* MENU_CONVERT2 */ MENU_NONE, MENU_CONVERT3, MENU_CONVERT1,
- { { 0 , 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" } } },
-
- { /* MENU_FLAGS */ MENU_NONE, MENU_NONE, MENU_NONE,
- { { 0x1000 + CMD_SF, 0, "" },
- { 0x1000 + CMD_CF, 0, "" },
- { 0x1000 + CMD_FS_T, 0, "" },
- { 0x1000 + CMD_FC_T, 0, "" },
- { 0x1000 + CMD_FSC_T, 0, "" },
- { 0x1000 + CMD_FCC_T, 0, "" } } },
- { /* MENU_PROB */ MENU_NONE, MENU_NONE, MENU_NONE,
- { { 0x1000 + CMD_COMB, 0, "" },
- { 0x1000 + CMD_PERM, 0, "" },
- { 0x1000 + CMD_FACT, 0, "" },
- { 0x1000 + CMD_GAMMA, 0, "" },
- { 0x1000 + CMD_RAN, 0, "" },
- { 0x1000 + CMD_SEED, 0, "" } } },
- { /* MENU_CUSTOM1 */ MENU_NONE, MENU_CUSTOM2, MENU_CUSTOM3,
- { { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" } } },
- { /* MENU_CUSTOM2 */ MENU_NONE, MENU_CUSTOM3, MENU_CUSTOM1,
- { { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" } } },
- { /* MENU_CUSTOM3 */ MENU_NONE, MENU_CUSTOM1, MENU_CUSTOM2,
- { { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" } } },
- { /* MENU_PGM_FCN1 */ MENU_NONE, MENU_PGM_FCN2, MENU_PGM_FCN4,
- { { 0x1000 + CMD_LBL, 0, "" },
- { 0x1000 + CMD_RTN, 0, "" },
- { 0x1000 + CMD_INPUT, 0, "" },
- { 0x1000 + CMD_VIEW, 0, "" },
- { 0x1000 + CMD_AVIEW, 0, "" },
- { 0x1000 + CMD_XEQ, 0, "" } } },
- { /* MENU_PGM_FCN2 */ MENU_NONE, MENU_PGM_FCN3, MENU_PGM_FCN1,
- { { MENU_PGM_XCOMP0, 3, "X?0" },
- { MENU_PGM_XCOMPY, 3, "X?Y" },
- { 0x1000 + CMD_PROMPT, 0, "" },
- { 0x1000 + CMD_PSE, 0, "" },
- { 0x1000 + CMD_ISG, 0, "" },
- { 0x1000 + CMD_DSE, 0, "" } } },
- { /* MENU_PGM_FCN3 */ MENU_NONE, MENU_PGM_FCN4, MENU_PGM_FCN2,
- { { 0x1000 + CMD_AIP, 0, "" },
- { 0x1000 + CMD_XTOA, 0, "" },
- { 0x1000 + CMD_AGRAPH, 0, "" },
- { 0x1000 + CMD_PIXEL, 0, "" },
- { 0x1000 + CMD_BEEP, 0, "" },
- { 0x1000 + CMD_TONE, 0, "" } } },
- { /* MENU_PGM_FCN4 */ MENU_NONE, MENU_PGM_FCN1, MENU_PGM_FCN3,
- { { 0x1000 + CMD_MVAR, 0, "" },
- { 0x1000 + CMD_VARMENU, 0, "" },
- { 0x1000 + CMD_GETKEY, 0, "" },
- { 0x1000 + CMD_MENU, 0, "" },
- { 0x1000 + CMD_KEYG, 0, "" },
- { 0x1000 + CMD_KEYX, 0, "" } } },
- { /* MENU_PGM_XCOMP0 */ MENU_PGM_FCN2, MENU_NONE, MENU_NONE,
- { { 0x1000 + CMD_X_EQ_0, 0, "" },
- { 0x1000 + CMD_X_NE_0, 0, "" },
- { 0x1000 + CMD_X_LT_0, 0, "" },
- { 0x1000 + CMD_X_GT_0, 0, "" },
- { 0x1000 + CMD_X_LE_0, 0, "" },
- { 0x1000 + CMD_X_GE_0, 0, "" } } },
- { /* MENU_PGM_XCOMPY */ MENU_PGM_FCN2, MENU_NONE, MENU_NONE,
- { { 0x1000 + CMD_X_EQ_Y, 0, "" },
- { 0x1000 + CMD_X_NE_Y, 0, "" },
- { 0x1000 + CMD_X_LT_Y, 0, "" },
- { 0x1000 + CMD_X_GT_Y, 0, "" },
- { 0x1000 + CMD_X_LE_Y, 0, "" },
- { 0x1000 + CMD_X_GE_Y, 0, "" } } },
- { /* MENU_PRINT1 */ MENU_NONE, MENU_PRINT2, MENU_PRINT3,
- { { 0x1000 + CMD_PRSIGMA, 0, "" },
- { 0x1000 + CMD_PRP, 0, "" },
- { 0x1000 + CMD_PRV, 0, "" },
- { 0x1000 + CMD_PRSTK, 0, "" },
- { 0x1000 + CMD_PRA, 0, "" },
- { 0x1000 + CMD_PRX, 0, "" } } },
- { /* MENU_PRINT2 */ MENU_NONE, MENU_PRINT3, MENU_PRINT1,
- { { 0x1000 + CMD_PRUSR, 0, "" },
- { 0x1000 + CMD_LIST, 0, "" },
- { 0x1000 + CMD_ADV, 0, "" },
- { 0x1000 + CMD_PRLCD, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x1000 + CMD_DELAY, 0, "" } } },
- { /* MENU_PRINT3 */ MENU_NONE, MENU_PRINT1, MENU_PRINT2,
- { { 0x2000 + CMD_PON, 0, "" },
- { 0x2000 + CMD_POFF, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x2000 + CMD_MAN, 0, "" },
- { 0x2000 + CMD_NORM, 0, "" },
- { 0x2000 + CMD_TRACE, 0, "" } } },
- { /* MENU_TOP_FCN */ MENU_NONE, MENU_NONE, MENU_NONE,
- { { 0x1000 + CMD_SIGMAADD, 0, "" },
- { 0x1000 + CMD_INV, 0, "" },
- { 0x1000 + CMD_SQRT, 0, "" },
- { 0x1000 + CMD_LOG, 0, "" },
- { 0x1000 + CMD_LN, 0, "" },
- { 0x1000 + CMD_XEQ, 0, "" } } },
- { /* MENU_CATALOG */ MENU_NONE, MENU_NONE, MENU_NONE,
- { { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" } } },
- { /* MENU_BLANK */ MENU_NONE, MENU_NONE, MENU_NONE,
- { { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" } } },
- { /* MENU_PROGRAMMABLE */ MENU_NONE, MENU_NONE, MENU_NONE,
- { { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" } } },
- { /* MENU_VARMENU */ MENU_NONE, MENU_NONE, MENU_NONE,
- { { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" } } },
- { /* MENU_STAT1 */ MENU_NONE, MENU_STAT2, MENU_STAT2,
- { { 0x1000 + CMD_SIGMAADD, 0, "" },
- { 0x1000 + CMD_SUM, 0, "" },
- { 0x1000 + CMD_MEAN, 0, "" },
- { 0x1000 + CMD_WMEAN, 0, "" },
- { 0x1000 + CMD_SDEV, 0, "" },
- { MENU_STAT_CFIT, 4, "CFIT" } } },
- { /* MENU_STAT2 */ MENU_NONE, MENU_STAT1, MENU_STAT1,
- { { 0x2000 + CMD_ALLSIGMA, 0, "" },
- { 0x2000 + CMD_LINSIGMA, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x1000 + CMD_SIGMAREG, 0, "" },
- { 0x1000 + CMD_SIGMAREG_T, 0, "" } } },
- { /* MENU_STAT_CFIT */ MENU_STAT1, MENU_NONE, MENU_NONE,
- { { 0x1000 + CMD_FCSTX, 0, "" },
- { 0x1000 + CMD_FCSTY, 0, "" },
- { 0x1000 + CMD_SLOPE, 0, "" },
- { 0x1000 + CMD_YINT, 0, "" },
- { 0x1000 + CMD_CORR, 0, "" },
- { MENU_STAT_MODL, 4, "MODL" } } },
- { /* MENU_STAT_MODL */ MENU_STAT_CFIT, MENU_NONE, MENU_NONE,
- { { 0x2000 + CMD_LINF, 0, "" },
- { 0x2000 + CMD_LOGF, 0, "" },
- { 0x2000 + CMD_EXPF, 0, "" },
- { 0x2000 + CMD_PWRF, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x1000 + CMD_BEST, 0, "" } } },
- { /* MENU_MATRIX1 */ MENU_NONE, MENU_MATRIX2, MENU_MATRIX3,
- { { 0x1000 + CMD_NEWMAT, 0, "" },
- { 0x1000 + CMD_INVRT, 0, "" },
- { 0x1000 + CMD_DET, 0, "" },
- { 0x1000 + CMD_TRANS, 0, "" },
- { 0x1000 + CMD_SIMQ, 0, "" },
- { 0x1000 + CMD_EDIT, 0, "" } } },
- { /* MENU_MATRIX2 */ MENU_NONE, MENU_MATRIX3, MENU_MATRIX1,
- { { 0x1000 + CMD_DOT, 0, "" },
- { 0x1000 + CMD_CROSS, 0, "" },
- { 0x1000 + CMD_UVEC, 0, "" },
- { 0x1000 + CMD_DIM, 0, "" },
- { 0x1000 + CMD_INDEX, 0, "" },
- { 0x1000 + CMD_EDITN, 0, "" } } },
- { /* MENU_MATRIX3 */ MENU_NONE, MENU_MATRIX1, MENU_MATRIX2,
- { { 0x1000 + CMD_STOIJ, 0, "" },
- { 0x1000 + CMD_RCLIJ, 0, "" },
- { 0x1000 + CMD_STOEL, 0, "" },
- { 0x1000 + CMD_RCLEL, 0, "" },
- { 0x1000 + CMD_PUTM, 0, "" },
- { 0x1000 + CMD_GETM, 0, "" } } },
- { /* MENU_MATRIX_SIMQ */ MENU_MATRIX1, MENU_NONE, MENU_NONE,
- { { 0x1000 + CMD_MATA, 0, "" },
- { 0x1000 + CMD_MATB, 0, "" },
- { 0x1000 + CMD_MATX, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" } } },
- { /* MENU_MATRIX_EDIT1 */ MENU_NONE, MENU_MATRIX_EDIT2, MENU_MATRIX_EDIT2,
- { { 0x1000 + CMD_LEFT, 0, "" },
- { 0x1000 + CMD_OLD, 0, "" },
- { 0x1000 + CMD_UP, 0, "" },
- { 0x1000 + CMD_DOWN, 0, "" },
- { 0x1000 + CMD_GOTOROW, 0, "" },
- { 0x1000 + CMD_RIGHT, 0, "" } } },
- { /* MENU_MATRIX_EDIT2 */ MENU_NONE, MENU_MATRIX_EDIT1, MENU_MATRIX_EDIT1,
- { { 0x1000 + CMD_INSR, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x1000 + CMD_DELR, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x2000 + CMD_WRAP, 0, "" },
- { 0x2000 + CMD_GROW, 0, "" } } },
- { /* MENU_BASE */ MENU_NONE, MENU_NONE, MENU_NONE,
- { { 0x1000 + CMD_A_THRU_F, 0, "" },
- { 0x2000 + CMD_HEXM, 0, "" },
- { 0x2000 + CMD_DECM, 0, "" },
- { 0x2000 + CMD_OCTM, 0, "" },
- { 0x2000 + CMD_BINM, 0, "" },
- { MENU_BASE_LOGIC, 5, "LOGIC" } } },
- { /* MENU_BASE_A_THRU_F */ MENU_BASE, MENU_NONE, MENU_NONE,
- { { 0x4000, 1, "A" },
- { 0x4000, 1, "B" },
- { 0x4000, 1, "C" },
- { 0x4000, 1, "D" },
- { 0x4000, 1, "E" },
- { 0x4000, 1, "F" } } },
- { /* MENU_BASE_LOGIC */ MENU_BASE, MENU_NONE, MENU_NONE,
- { { 0x1000 + CMD_AND, 0, "" },
- { 0x1000 + CMD_OR, 0, "" },
- { 0x1000 + CMD_XOR, 0, "" },
- { 0x1000 + CMD_NOT, 0, "" },
- { 0x1000 + CMD_BIT_T, 0, "" },
- { 0x1000 + CMD_ROTXY, 0, "" } } },
- { /* MENU_SOLVE */ MENU_NONE, MENU_NONE, MENU_NONE,
- { { 0x1000 + CMD_MVAR, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x1000 + CMD_PGMSLV, 0, "" },
- { 0x1000 + CMD_SOLVE, 0, "" } } },
- { /* MENU_INTEG */ MENU_NONE, MENU_NONE, MENU_NONE,
- { { 0x1000 + CMD_MVAR, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x1000 + CMD_PGMINT, 0, "" },
- { 0x1000 + CMD_INTEG, 0, "" } } },
- { /* MENU_INTEG_PARAMS */ MENU_NONE, MENU_NONE, MENU_NONE,
- { { 0, 4, "LLIM" },
- { 0, 4, "ULIM" },
- { 0, 3, "ACC" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0, 1, "\003" } } },
- #ifdef BIGSTACK
- { /* MENU_CLEAR3 */ MENU_NONE, MENU_CLEAR1, MENU_CLEAR2,
- { { 0x1000 + CMD_DROP, 0, "" },
- { 0x1000 + CMD_UNDO, 0, "" },
- { 0x1000 + CMD_REDO, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" },
- { 0x1000 + CMD_NULL, 0, "" } } },
-
-
-
- { /* MENU_CONVERT3 */ MENU_NONE, MENU_CONVERT4, MENU_CONVERT2,
- { { 0x1000 + CMD_TO_DEG, 0, "" },
- { 0x1000 + CMD_TO_RAD, 0, "" },
- { 0x1000 + CMD_TO_HR, 0, "" },
- { 0x1000 + CMD_TO_HMS, 0, "" },
- { 0x1000 + CMD_TO_REC, 0, "" },
- { 0x1000 + CMD_TO_POL, 0, "" } } },
-
- { /* MENU_CONVERT4 */ MENU_NONE, MENU_CONVERT1, MENU_CONVERT3,
- { { 0x1000 + CMD_IP, 0, "" },
- { 0x1000 + CMD_FP, 0, "" },
- { 0x1000 + CMD_RND, 0, "" },
- { 0x1000 + CMD_ABS, 0, "" },
- { 0x1000 + CMD_SIGN, 0, "" },
- { 0x1000 + CMD_MOD, 0, "" } } },
-
- { /* MENU_UNITS */ MENU_NONE, MENU_NONE, MENU_NONE,
- { { 0 , 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" },
- { 0, 0, "" } } },
- #endif
- };
- /* By how much do the variables, programs, and labels
- * arrays grow when they are full
- */
- #define VARS_INCREMENT 25
- #define PRGMS_INCREMENT 10
- #define LABELS_INCREMENT 10
- /* Registers */
- vartype *reg_x = NULL;
- vartype *reg_y = NULL;
- vartype *reg_z = NULL;
- vartype *reg_t = NULL;
- vartype *reg_lastx = NULL;
- int reg_alpha_length = 0;
- char reg_alpha[44];
- /* Flags */
- flags_struct flags;
- /* Variables */
- int vars_capacity = 0;
- int vars_count = 0;
- var_struct *vars = NULL;
- /* Programs */
- int prgms_capacity = 0;
- int prgms_count = 0;
- prgm_struct *prgms = NULL;
- int labels_capacity = 0;
- int labels_count = 0;
- label_struct *labels = NULL;
- int current_prgm = -1;
- int4 pc;
- int prgm_highlight_row = 0;
- int varmenu_length;
- char varmenu[7];
- int varmenu_rows;
- int varmenu_row;
- int varmenu_labellength[6];
- char varmenu_labeltext[6][7];
- int varmenu_role;
- bool mode_clall;
- int (*mode_interruptible)(int) = NULL;
- bool mode_stoppable;
- bool mode_command_entry;
- bool mode_number_entry;
- bool mode_alpha_entry;
- bool mode_shift;
- int mode_appmenu;
- int mode_plainmenu;
- bool mode_plainmenu_sticky;
- int mode_transientmenu;
- int mode_alphamenu;
- int mode_commandmenu;
- bool mode_running;
- bool mode_getkey;
- bool mode_pause = false;
- bool mode_disable_stack_lift; /* transient */
- bool mode_varmenu;
- bool mode_updown;
- int4 mode_sigma_reg;
- int mode_goose;
- bool mode_time_clktd;
- bool mode_time_clk24;
- bool mode_time_dmy;
- #if BIGSTACK
- stack_item *bigstack_head = NULL;
- /* True if we are currently operating with the extended stack */
- bool mode_rpl_enter = false;
- int stacksize = 4; /* stack size is always at least 4 */
- int last_pending_command = CMD_NONE;
- /* Keep track of what the stack type was before solve or integration */
- int orig_stack_type_before_solve = 0;
- #endif
- bool cllcd_cmd = false;
- phloat entered_number;
- int entered_string_length;
- char entered_string[15];
- int pending_command;
- arg_struct pending_command_arg;
- int xeq_invisible;
- /* Multi-keystroke commands -- edit state */
- /* Relevant when mode_command_entry != 0 */
- int incomplete_command;
- int incomplete_ind;
- int incomplete_alpha;
- int incomplete_length;
- int incomplete_maxdigits;
- int incomplete_argtype;
- int incomplete_num;
- char incomplete_str[7];
- int4 incomplete_saved_pc;
- int4 incomplete_saved_highlight_row;
- /* Command line handling temporaries */
- char cmdline[100];
- int cmdline_length;
- int cmdline_row;
- /* Matrix editor / matrix indexing */
- int matedit_mode; /* 0=off, 1=index, 2=edit, 3=editn */
- char matedit_name[7];
- int matedit_length;
- vartype *matedit_x;
- int4 matedit_i;
- int4 matedit_j;
- int matedit_prev_appmenu;
- /* INPUT */
- char input_name[11];
- int input_length;
- arg_struct input_arg;
- /* BASE application */
- int baseapp = 0;
- /* Random number generator */
- phloat random_number;
- /* NORM & TRACE mode: number waiting to be printed */
- int deferred_print = 0;
- /* Keystroke buffer - holds keystrokes received while
- * there is a program running.
- */
- int keybuf_head = 0;
- int keybuf_tail = 0;
- int keybuf[16];
- int remove_program_catalog = 0;
- bool bin_dec_mode_switch;
- bool state_file_has_old_bcd;
- /*******************/
- /* Private globals */
- /*******************/
- static bool state_bool_is_int;
- #define MAX_RTNS 8
- static int rtn_sp = 0;
- static int rtn_prgm[MAX_RTNS];
- static int4 rtn_pc[MAX_RTNS];
- typedef struct {
- int type;
- int4 rows;
- int4 columns;
- } matrix_persister;
- static int array_count;
- static int array_list_capacity;
- static void **array_list;
- static bool read_int(int *n) GLOBALS_SECT;
- static bool write_int(int n) GLOBALS_SECT;
- static bool read_int4(int4 *n) GLOBALS_SECT;
- static bool write_int4(int4 n) GLOBALS_SECT;
- static bool read_bool(bool *n) GLOBALS_SECT;
- static bool write_bool(bool n) GLOBALS_SECT;
- static bool array_list_grow() GLOBALS_SECT;
- static int array_list_search(void *array) GLOBALS_SECT;
- static bool persist_vartype(vartype *v) GLOBALS_SECT;
- static bool unpersist_vartype(vartype **v) GLOBALS_SECT;
- static void update_label_table(int prgm, int4 pc, int inserted) GLOBALS_SECT;
- static void invalidate_lclbls(int prgm_index) GLOBALS_SECT;
- static int pc_line_convert(int4 loc, int loc_is_pc) GLOBALS_SECT;
- static bool convert_programs() GLOBALS_SECT;
- #ifdef IPHONE
- static void convert_bigstack_drop() GLOBALS_SECT;
- static bool persist_undo() GLOBALS_SECT;
- static bool unpersist_undo() GLOBALS_SECT;
- #endif
- static bool array_list_grow() {
- if (array_count < array_list_capacity)
- return true;
- array_list_capacity += 10;
- void **p = (void **) realloc(array_list,
- array_list_capacity * sizeof(void *));
- if (p == NULL)
- return false;
- array_list = p;
- return true;
- }
- static int array_list_search(void *array) {
- for (int i = 0; i < array_count; i++)
- if (array_list[i] == array)
- return i;
- return -1;
- }
- static bool persist_vartype(vartype *v) {
- if (v == NULL) {
- int type = TYPE_NULL;
- return shell_write_saved_state(&type, sizeof(int));
- }
- switch (v->type) {
- case TYPE_REAL:
- return shell_write_saved_state(v, sizeof(vartype_real));
- case TYPE_COMPLEX:
- return shell_write_saved_state(v, sizeof(vartype_complex));
- case TYPE_STRING:
- return shell_write_saved_state(v, sizeof(vartype_string));
- case TYPE_REALMATRIX: {
- matrix_persister mp;
- vartype_realmatrix *rm = (vartype_realmatrix *) v;
- mp.type = rm->type;
- mp.rows = rm->rows;
- mp.columns = rm->columns;
- int4 size = mp.rows * mp.columns;
- bool must_write = true;
- if (rm->array->refcount > 1) {
- int n = array_list_search(rm->array);
- if (n == -1) {
- // A negative row count signals a new shared matrix
- mp.rows = -mp.rows;
- if (!array_list_grow())
- return false;
- array_list[array_count++] = rm->array;
- } else {
- // A zero row count means this matrix shares its data
- // with a previously written matrix
- mp.rows = 0;
- mp.columns = n;
- must_write = false;
- }
- }
- if (!shell_write_saved_state(&mp, sizeof(matrix_persister)))
- return false;
- if (must_write) {
- if (!shell_write_saved_state(rm->array->data,
- size * sizeof(phloat)))
- return false;
- if (!shell_write_saved_state(rm->array->is_string, size))
- return false;
- }
- return true;
- }
- case TYPE_COMPLEXMATRIX: {
- matrix_persister mp;
- vartype_complexmatrix *cm = (vartype_complexmatrix *) v;
- mp.type = cm->type;
- mp.rows = cm->rows;
- mp.columns = cm->columns;
- int4 size = mp.rows * mp.columns;
- bool must_write = true;
- if (cm->array->refcount > 1) {
- int n = array_list_search(cm->array);
- if (n == -1) {
- // A negative row count signals a new shared matrix
- mp.rows = -mp.rows;
- if (!array_list_grow())
- return false;
- array_list[array_count++] = cm->array;
- } else {
- // A zero row count means this matrix shares its data
- // with a previously written matrix
- mp.rows = 0;
- mp.columns = n;
- must_write = false;
- }
- }
- if (!shell_write_saved_state(&mp, sizeof(matrix_persister)))
- return false;
- if (must_write) {
- if (!shell_write_saved_state(cm->array->data,
- 2 * size * sizeof(phloat)))
- return false;
- }
- return true;
- }
- default:
- /* Should not happen */
- return true;
- }
- }
- // A few declarations to help unpersist_vartype get the offsets right,
- // in the case it needs to convert the state file.
- struct fake_bcd {
- short d_[P+1];
- };
- struct bin_real {
- int type;
- double x;
- };
- struct bin_complex {
- int type;
- double re, im;
- };
- struct dec_real {
- int type;
- fake_bcd x;
- };
- struct dec_complex {
- int type;
- fake_bcd re, im;
- };
- static bool unpersist_vartype(vartype **v) {
- int type;
- if (shell_read_saved_state(&type, sizeof(int)) != sizeof(int))
- return false;
- switch (type) {
- case TYPE_NULL: {
- *v = NULL;
- return true;
- }
- case TYPE_REAL: {
- vartype_real *r = (vartype_real *) new_real(0);
- if (r == NULL)
- return false;
- if (bin_dec_mode_switch) {
- #ifdef BCD_MATH
- int n = sizeof(bin_real) - sizeof(int);
- bin_real br;
- if (shell_read_saved_state(&br.type + 1, n) != n) {
- free_vartype((vartype *) r);
- return false;
- }
- r->x = br.x;
- #else
- int n = sizeof(dec_real) - sizeof(int);
- dec_real dr;
- if (shell_read_saved_state(&dr.type + 1, n) != n) {
- free_vartype((vartype *) r);
- return false;
- }
- r->x = bcd2double(dr.x.d_, state_file_has_old_bcd);
- #endif
- } else {
- int n = sizeof(vartype_real) - sizeof(int);
- if (shell_read_saved_state(&r->type + 1, n) != n) {
- free_vartype((vartype *) r);
- return false;
- }
- #ifdef BCD_MATH
- if (state_file_has_old_bcd)
- bcdfloat_old2new(r->x.bcd.d_);
- #endif
- }
- *v = (vartype *) r;
- return true;
- }
- case TYPE_COMPLEX: {
- vartype_complex *c = (vartype_complex *) new_complex(0, 0);
- if (c == NULL)
- return false;
- if (bin_dec_mode_switch) {
- #ifdef BCD_MATH
- int n = sizeof(bin_complex) - sizeof(int);
- bin_complex bc;
- if (shell_read_saved_state(&bc.type + 1, n) != n) {
- free_vartype((vartype *) c);
- return false;
- }
- c->re = bc.re;
- c->im = bc.im;
- #else
- int n = sizeof(dec_complex) - sizeof(int);
- dec_complex dc;
- if (shell_read_saved_state(&dc.type + 1, n) != n) {
- free_vartype((vartype *) c);
- return false;
- }
- c->re = bcd2double(dc.re.d_, state_file_has_old_bcd);
- c->im = bcd2double(dc.im.d_, state_file_has_old_bcd);
- #endif
- } else {
- int n = sizeof(vartype_complex) - sizeof(int);
- if (shell_read_saved_state(&c->type + 1, n) != n) {
- free_vartype((vartype *) c);
- return false;
- }
- #ifdef BCD_MATH
- if (state_file_has_old_bcd) {
- bcdfloat_old2new(c->re.bcd.d_);
- bcdfloat_old2new(c->im.bcd.d_);
- }
- #endif
- }
- *v = (vartype *) c;
- return true;
- }
- case TYPE_STRING: {
- vartype_string *s = (vartype_string *) new_string("", 0);
- int n = sizeof(vartype_string) - sizeof(int);
- if (s == NULL)
- return false;
- if (shell_read_saved_state(&s->type + 1, n) != n) {
- free_vartype((vartype *) s);
- return false;
- } else {
- *v = (vartype *) s;
- return true;
- }
- }
- case TYPE_REALMATRIX: {
- matrix_persister mp;
- int n = sizeof(matrix_persister) - sizeof(int);
- if (shell_read_saved_state(&mp.type + 1, n) != n)
- return false;
- if (mp.rows == 0) {
- // Shared matrix
- vartype *m = new_matrix_alias((vartype *) array_list[mp.columns]);
- if (m == NULL)
- return false;
- else {
- *v = m;
- return true;
- }
- }
- bool shared = mp.rows < 0;
- if (shared)
- mp.rows = -mp.rows;
- vartype_realmatrix *rm = (vartype_realmatrix *) new_realmatrix(mp.rows, mp.columns);
- if (rm == NULL)
- return false;
- if (bin_dec_mode_switch) {
- int4 size = mp.rows * mp.columns;
- #ifdef BCD_MATH
- int phsz = sizeof(double);
- #else
- int phsz = sizeof(fake_bcd);
- #endif
- int4 tsz = size * phsz;
- char *temp = (char *) malloc(tsz);
- if (temp == NULL) {
- free_vartype((vartype *) rm);
- return false;
- }
- if (shell_read_saved_state(temp, tsz) != tsz) {
- free(temp);
- free_vartype((vartype *) rm);
- return false;
- }
- if (shell_read_saved_state(rm->array->is_string, size) != size) {
- free(temp);
- free_vartype((vartype *) rm);
- return false;
- }
- #ifdef BCD_MATH
- for (int4 i = 0; i < size; i++) {
- if (rm->array->is_string[i]) {
- char *src = temp + i * phsz;
- char *dst = (char *) (rm->array->data + i);
- for (int j = 0; j < 7; j++)
- *dst++ = *src++;
- } else {
- rm->array->data[i] = ((double *) temp)[i];
- }
- }
- #else
- for (int4 i = 0; i < size; i++) {
- if (rm->array->is_string[i]) {
- char *src = temp + i * phsz;
- char *dst = (char *) (rm->array->data + i);
- for (int j = 0; j < 7; j++)
- *dst++ = *src++;
- } else {
- rm->array->data[i] = bcd2double((short *) (temp + phsz * i), state_file_has_old_bcd);
- }
- }
- #endif
- free(temp);
- } else {
- int4 size = mp.rows * mp.columns * sizeof(phloat);
- if (shell_read_saved_state(rm->array->data, size) != size) {
- free_vartype((vartype *) rm);
- return false;
- }
- size = mp.rows * mp.columns;
- if (shell_read_saved_state(rm->array->is_string, size) != size) {
- free_vartype((vartype *) rm);
- return false;
- }
- #ifdef BCD_MATH
- if (state_file_has_old_bcd)
- for (int4 i = 0; i < size; i++)
- if (!rm->array->is_string[i])
- bcdfloat_old2new(rm->array->data[i].bcd.d_);
- #endif
- }
- if (shared) {
- if (!array_list_grow()) {
- free_vartype((vartype *) rm);
- return false;
- }
- array_list[array_count++] = rm;
- }
- *v = (vartype *) rm;
- return true;
- }
- case TYPE_COMPLEXMATRIX: {
- matrix_persister mp;
- int n = sizeof(matrix_persister) - sizeof(int);
- if (shell_read_saved_state(&mp.type + 1, n) != n)
- return false;
- if (mp.rows == 0) {
- // Shared matrix
- vartype *m = new_matrix_alias((vartype *) array_list[mp.columns]);
- if (m == NULL)
- return false;
- else {
- *v = m;
- return true;
- }
- }
- bool shared = mp.rows < 0;
- if (shared)
- mp.rows = -mp.rows;
- vartype_complexmatrix *cm = (vartype_complexmatrix *)
- new_complexmatrix(mp.rows, mp.columns);
- if (cm == NULL)
- return false;
- if (bin_dec_mode_switch) {
- int4 size = 2 * mp.rows * mp.columns;
- for (int4 i = 0; i < size; i++)
- if (!read_phloat(cm->array->data + i)) {
- free_vartype((vartype *) cm);
- return false;
- }
- } else {
- int4 size = 2 * mp.rows * mp.columns * sizeof(phloat);
- if (shell_read_saved_state(cm->array->data, size) != size) {
- free_vartype((vartype *) cm);
- return false;
- }
- #ifdef BCD_MATH
- if (state_file_has_old_bcd)
- for (int4 i = 0; i < size; i++)
- bcdfloat_old2new(cm->array->data[i].bcd.d_);
- #endif
- }
- if (shared) {
- if (!array_list_grow()) {
- free_vartype((vartype *) cm);
- return false;
- }
- array_list[array_count++] = cm;
- }
- *v = (vartype *) cm;
- return true;
- }
- default:
- return false;
- }
- }
- static bool persist_globals() GLOBALS_SECT;
- static bool persist_globals() {
- int i;
- array_count = 0;
- array_list_capacity = 0;
- array_list = NULL;
- bool ret = false;
- #if BIGSTACK
- stack_item *si = bigstack_head;
- #endif
- if (!persist_vartype(reg_x))
- goto done;
- if (!persist_vartype(reg_y))
- goto done;
- if (!persist_vartype(reg_z))
- goto done;
- if (!persist_vartype(reg_t))
- goto done;
- if (!persist_vartype(reg_lastx))
- goto done;
- #if BIGSTACK
- if (!write_bool(true)) /* Yes, big stack block exists */
- goto done;
-
- persist_undo();
-
- if (!write_int(stacksize))
- goto done;
- while (si != NULL) {
- if (!persist_vartype(si->var))
- goto done;
- si = si->next;
- }
- if (!write_bool(mode_rpl_enter))
- goto done;
- #else
- if (!write_bool(false)) /* No, big stack block does not exist */
- goto done;
- #endif
- if (!write_int(reg_alpha_length))
- goto done;
- if (!shell_write_saved_state(reg_alpha, 44))
- goto done;
- if (!write_int4(mode_sigma_reg))
- goto done;
- if (!write_int(mode_goose))
- goto done;
- if (!write_bool(mode_time_clktd))
- goto done;
- if (!write_bool(mode_time_clk24))
- goto done;
- if (!write_bool(mode_time_dmy))
- goto done;
- if (!shell_write_saved_state(&flags, sizeof(flags_struct)))
- goto done;
- if (!write_int(vars_count))
- goto done;
- if (!shell_write_saved_state(vars, vars_count * sizeof(var_struct)))
- goto done;
- for (i = 0; i < vars_count; i++)
- if (!persist_vartype(vars[i].value))
- goto done;
- if (!write_int(prgms_count))
- goto done;
- if (!shell_write_saved_state(prgms, prgms_count * sizeof(prgm_struct)))
- goto done;
- for (i = 0; i < prgms_count; i++)
- if (!shell_write_saved_state(prgms[i].text, prgms[i].size))
- goto done;
- if (!write_int(current_prgm))
- goto done;
- if (!write_int4(pc))
- goto done;
- if (!write_int(prgm_highlight_row))
- goto done;
- if (!write_int(varmenu_length))
- goto done;
- if (!shell_write_saved_state(varmenu, 7))
- goto done;
- if (!write_int(varmenu_rows))
- goto done;
- if (!write_int(varmenu_row))
- goto done;
- if (!shell_write_saved_state(varmenu_labellength, 6 * sizeof(int)))
- goto done;
- if (!shell_write_saved_state(varmenu_labeltext, 42))
- goto done;
- if (!write_int(varmenu_role))
- goto done;
- if (!write_int(rtn_sp))
- goto done;
- if (!shell_write_saved_state(&rtn_prgm, MAX_RTNS * sizeof(int)))
- goto done;
- if (!shell_write_saved_state(&rtn_pc, MAX_RTNS * sizeof(int4)))
- goto done;
- ret = true;
- done:
- free(array_list);
- return ret;
- }
- static bool unpersist_globals(int4 ver) GLOBALS_SECT;
- static bool unpersist_globals(int4 ver) {
- int4 n;
- int i;
- array_count = 0;
- array_list_capacity = 0;
- array_list = NULL;
- bool ret = false;
- bool bigstack = false;
- free_vartype(reg_x);
- if (!unpersist_vartype(®_x))
- goto done;
- free_vartype(reg_y);
- if (!unpersist_vartype(®_y))
- goto done;
- free_vartype(reg_z);
- if (!unpersist_vartype(®_z))
- goto done;
- free_vartype(reg_t);
- if (!unpersist_vartype(®_t))
- goto done;
- free_vartype(reg_lastx);
- if (!unpersist_vartype(®_lastx))
- goto done;
- if (ver >= 12) {
- /* we are on atleast version 12, so this block exists */
- if (!read_bool(&bigstack))
- goto done;
- }
-
- #ifdef BIGSTACK
- if (bigstack)
- {
-
- if (ver >= 17) {
- unpersist_undo();
- }
-
- stacksize = 20; /* backward compatible pre version 13 big stack */
-
- if (ver >= 13) {
- if (!read_int(&stacksize))
- goto done;
- while(bigstack_head != NULL)
- {
- shift_big_stack_down();
- free_vartype(reg_t);
- }
- }
- int i = stacksize - 4;
- stack_item *lastsi = NULL;
- while (i-- > 0) {
- vartype *v = NULL;
- if (!unpersist_vartype(&v))
- goto done;
- stack_item *si = new_stack_item(v);
- si->next = NULL;
- if (lastsi == NULL)
- bigstack_head = si;
- else
- lastsi->next = si;
- lastsi = si;
- }
- if (!read_bool(&mode_rpl_enter))
- goto done;
- }
- #endif
- if (!read_int(®_alpha_length)) {
- reg_alpha_length = 0;
- goto done;
- }
- if (shell_read_saved_state(reg_alpha, 44) != 44) {
- reg_alpha_length = 0;
- goto done;
- }
- if (!read_int4(&mode_sigma_reg)) {
- mode_sigma_reg = 11;
- goto done;
- }
- if (!read_int(&mode_goose)) {
- mode_goose = -1;
- goto done;
- }
- if (ver >= 16) {
- if (!read_bool(&mode_time_clktd)) {
- mode_time_clktd = false;
- goto done;
- }
- if (!read_bool(&mode_time_clk24)) {
- mode_time_clk24 = false;
- goto done;
- }
- if (!read_bool(&mode_time_dmy)) {
- mode_time_dmy = false;
- goto done;
- }
- }
- if (shell_read_saved_state(&flags, sizeof(flags_struct))
- != sizeof(flags_struct))
- goto done;
- vars_capacity = 0;
- if (vars != NULL) {
- free(vars);
- vars = NULL;
- }
- if (!read_int(&vars_count)) {
- vars_count = 0;
- goto done;
- }
- n = vars_count * sizeof(var_struct);
- vars = (var_struct *) malloc(n);
- if (vars == NULL) {
- vars_count = 0;
- goto done;
- }
- if (shell_read_saved_state(vars, n) != n) {
- free(vars);
- vars = NULL;
- vars_count = 0;
- goto done;
- }
- vars_capacity = vars_count;
- for (i = 0; i < vars_count; i++)
- vars[i].value = NULL;
- for (i = 0; i < vars_count; i++)
- if (!unpersist_vartype(&vars[i].value)) {
- purge_all_vars();
- goto done;
- }
- prgms_capacity = 0;
- if (prgms != NULL) {
- free(prgms);
- prgms = NULL;
- }
- if (!read_int(&prgms_count)) {
- prgms_count = 0;
- goto done;
- }
- n = prgms_count * sizeof(prgm_struct);
- prgms = (prgm_struct *) malloc(n);
- if (prgms == NULL) {
- prgms_count = 0;
- goto done;
- }
- if (shell_read_saved_state(prgms, n) != n) {
- free(prgms);
- prgms = NULL;
- prgms_count = 0;
- goto done;
- }
- prgms_capacity = prgms_count;
- for (i = 0; i < prgms_count; i++) {
- prgms[i].capacity = prgms[i].size;
- prgms[i].text = (unsigned char *) malloc(prgms[i].size);
- // TODO - handle memory allocation failure
- }
- for (i = 0; i < prgms_count; i++) {
- if (shell_read_saved_state(prgms[i].text, prgms[i].size)
- != prgms[i].size) {
- clear_all_prgms();
- goto done;
- }
- }
- if (!read_int(¤t_prgm)) {
- current_prgm = 0;
- goto done;
- }
- if (!read_int4(&pc)) {
- pc = -1;
- goto done;
- }
- if (!read_int(&prgm_highlight_row)) {
- prgm_highlight_row = 0;
- goto done;
- }
- if (!read_int(&varmenu_length)) {
- varmenu_length = 0;
- goto done;
- }
- if (shell_read_saved_state(varmenu, 7) != 7) {
- varmenu_length = 0;
- goto done;
- }
- if (!read_int(&varmenu_rows)) {
- varmenu_length = 0;
- goto done;
- }
- if (!read_int(&varmenu_row)) {
- varmenu_length = 0;
- goto done;
- }
- if (shell_read_saved_state(varmenu_labellength, 6 * sizeof(int))
- != 6 * sizeof(int))
- goto done;
- if (shell_read_saved_state(varmenu_labeltext, 42) != 42)
- goto done;
- if (!read_int(&varmenu_role))
- goto done;
- if (!read_int(&rtn_sp))
- goto done;
- if (shell_read_saved_state(rtn_prgm, MAX_RTNS * sizeof(int))
- != MAX_RTNS * sizeof(int))
- goto done;
- if (shell_read_saved_state(rtn_pc, MAX_RTNS * sizeof(int4))
- != MAX_RTNS * sizeof(int4))
- goto done;
- if (bin_dec_mode_switch)
- if (!convert_programs()) {
- clear_all_prgms();
- goto done;
- }
- #ifdef IPHONE
- if (ver == 12 || ver == 13) {
- // CMD_DROP redefined from 315 to 329, to resolve clash with
- // Underhill's COPAN extensions.
- convert_bigstack_drop();
- }
- #endif
- rebuild_label_table();
- ret = true;
- done:
- free(array_list);
- return ret;
- }
- void clear_all_prgms() {
- if (prgms != NULL) {
- int i;
- for (i = 0; i < prgms_count; i++)
- if (prgms[i].text != NULL)
- free(prgms[i].text);
- free(prgms);
- }
- prgms = NULL;
- prgms_capacity = 0;
- prgms_count = 0;
- if (labels != NULL)
- free(labels);
- labels = NULL;
- labels_capacity = 0;
- labels_count = 0;
- }
- int clear_prgm(const arg_struct *arg) {
- int prgm_index = NULL;
- int i, j;
- if (arg->type == ARGTYPE_LBLINDEX)
- prgm_index = labels[arg->val.num].prgm;
- else if (arg->type == ARGTYPE_STR) {
- if (arg->length == 0) {
- if (current_prgm < 0 || current_prgm >= prgms_count)
- return ERR_INTERNAL_ERROR;
- prgm_index = current_prgm;
- } else {
- int i;
- for (i = labels_count - 1; i >= 0; i--)
- if (string_equals(arg->val.text, arg->length,
- labels[i].name, labels[i].length))
- goto found;
- return ERR_LABEL_NOT_FOUND;
- found:
- prgm_index = labels[i].prgm;
- }
- }
- clear_all_rtns();
- if (prgm_index == current_prgm)
- pc = -1;
- else if (current_prgm > prgm_index)
- current_prgm--;
- free(prgms[prgm_index].text);
- for (i = prgm_index; i < prgms_count - 1; i++)
- prgms[i] = prgms[i + 1];
- prgms_count--;
- i = j = 0;
- while (j < labels_count) {
- if (j > i)
- labels[i] = labels[j];
- j++;
- if (labels[i].prgm > prgm_index) {
- labels[i].prgm--;
- i++;
- } else if (labels[i].prgm < prgm_index)
- i++;
- }
- labels_count = i;
- if (prgms_count == 0 || prgm_index == prgms_count) {
- int saved_prgm = current_prgm;
- int saved_pc = pc;
- goto_dot_dot();
- current_prgm = saved_prgm;
- pc = saved_pc;
- }
- update_catalog();
- return ERR_NONE;
- }
- void clear_prgm_lines(int4 count) {
- int4 frompc, deleted, i, j;
- if (pc == -1)
- pc = 0;
- frompc = pc;
- while (count > 0) {
- int command;
- arg_struct arg;
- get_next_command(&pc, &command, &arg, 0);
- if (command == CMD_END) {
- pc -= 2;
- break;
- }
- count--;
- }
- deleted = pc - frompc;
- for (i = pc; i < prgms[current_prgm].size; i++)
- prgms[current_prgm].text[i - deleted] = prgms[current_prgm].text[i];
- prgms[current_prgm].size -= deleted;
- pc = frompc;
- i = j = 0;
- while (j < labels_count) {
- if (j > i)
- labels[i] = labels[j];
- j++;
- if (labels[i].prgm == current_prgm) {
- if (labels[i].pc < frompc)
- i++;
- else if (labels[i].pc >= frompc + deleted) {
- labels[i].pc -= deleted;
- i++;
- }
- } else
- i++;
- }
- labels_count = i;
- invalidate_lclbls(current_prgm);
- clear_all_rtns();
- }
- void goto_dot_dot() {
- int command;
- arg_struct arg;
- if (prgms_count != 0) {
- /* Check if last program is empty */
- pc = 0;
- current_prgm = prgms_count - 1;
- get_next_command(&pc, &command, &arg, 0);
- if (command == CMD_END) {
- pc = -1;
- return;
- }
- }
- if (prgms_count == prgms_capacity) {
- prgm_struct *newprgms;
- int i;
- prgms_capacity += 10;
- newprgms = (prgm_struct *) malloc(prgms_capacity * sizeof(prgm_struct));
- // TODO - handle memory allocation failure
- for (i = 0; i < prgms_count; i++)
- newprgms[i] = prgms[i];
- if (prgms != NULL)
- free(prgms);
- prgms = newprgms;
- }
- current_prgm = prgms_count++;
- prgms[current_prgm].capacity = 0;
- prgms[current_prgm].size = 0;
- prgms[current_prgm].lclbl_invalid = 1;
- prgms[current_prgm].text = NULL;
- command = CMD_END;
- arg.type = ARGTYPE_NONE;
- store_command(0, command, &arg);
- pc = -1;
- }
- int mvar_prgms_exist() {
- int i;
- for (i = 0; i < labels_count; i++)
- if (label_has_mvar(i))
- return 1;
- return 0;
- }
- int label_has_mvar(int lblindex) {
- int saved_prgm;
- int4 pc;
- int command;
- arg_struct arg;
- if (labels[lblindex].length == 0)
- return 0;
- saved_prgm = current_prgm;
- current_prgm = labels[lblindex].prgm;
- pc = labels[lblindex].pc;
- pc += get_command_length(current_prgm, pc);
- get_next_command(&pc, &command, &arg, 0);
- current_prgm = saved_prgm;
- return command == CMD_MVAR;
- }
- int get_command_length(int prgm_index, int4 pc) {
- prgm_struct *prgm = prgms + prgm_index;
- int4 pc2 = pc;
- int command = prgm->text[pc2++];
- int argtype = prgm->text[pc2++];
- command |= (argtype & 240) << 4;
- argtype &= 15;
- if (command == CMD_CONVERT) pc2 += 2;
-
- if ((command == CMD_GTO || command == CMD_XEQ)
- && (argtype == ARGTYPE_NUM || argtype == ARGTYPE_LCLBL))
- pc2 += 4;
- switch (argtype) {
- case ARGTYPE_NUM:
- case ARGTYPE_NEG_NUM:
- case ARGTYPE_IND_NUM: {
- while ((prgm->text[pc2++] & 128) == 0);
- break;
- }
- case ARGTYPE_STK:
- case ARGTYPE_IND_STK:
- case ARGTYPE_COMMAND:
- case ARGTYPE_LCLBL:
- pc2++;
- break;
- case ARGTYPE_STR:
- case ARGTYPE_IND_STR: {
- pc2 += prgm->text[pc2] + 1;
- break;
- }
- case ARGTYPE_DOUBLE:
- pc2 += sizeof(phloat);
- break;
- }
- return pc2 - pc;
- }
- void get_next_command(int4 *pc, int *command, arg_struct *arg, int find_target){
- prgm_struct *prgm = prgms + current_prgm;
- int i;
- int4 target_pc;
- int4 orig_pc = *pc;
- *command = prgm->text[(*pc)++];
- arg->type = prgm->text[(*pc)++];
- *command |= (arg->type & 240) << 4;
- arg->type &= 15;
- if ((*command == CMD_GTO || *command == CMD_XEQ)
- && (arg->type == ARGTYPE_NUM
- || arg->type == ARGTYPE_LCLBL)) {
- if (find_target) {
- target_pc = 0;
- for (i = 0; i < 4; i++)
- target_pc = (target_pc << 8) | prgm->text[(*pc)++];
- if (target_pc != -1) {
- arg->target = target_pc;
- find_target = 0;
- }
- } else
- (*pc) += 4;
- } else {
- find_target = 0;
- arg->target = -1;
- }
-
- switch (arg->type) {
- case ARGTYPE_NUM:
- case ARGTYPE_NEG_NUM:
- case ARGTYPE_IND_NUM: {
- int4 num = 0;
- unsigned char c;
- do {
- c = prgm->text[(*pc)++];
- num = (num << 7) | (c & 127);
- } while ((c & 128) == 0);
- if (arg->type == ARGTYPE_NEG_NUM) {
- arg->type = ARGTYPE_NUM;
- num = -num;
- }
- arg->val.num = num;
- break;
- }
- case ARGTYPE_STK:
- case ARGTYPE_IND_STK:
- arg->val.stk = prgm->text[(*pc)++];
- break;
- case ARGTYPE_COMMAND:
- arg->val.cmd = prgm->text[(*pc)++];
- break;
- case ARGTYPE_LCLBL:
- arg->val.lclbl = prgm->text[(*pc)++];
- break;
- case ARGTYPE_STR:
- case ARGTYPE_IND_STR: {
- arg->length = prgm->text[(*pc)++];
- for (i = 0; i < arg->length; i++)
- arg->val.text[i] = prgm->text[(*pc)++];
- break;
- }
- case ARGTYPE_DOUBLE: {
- unsigned char *b = (unsigned char *) &arg->val_d;
- for (int i = 0; i < (int) sizeof(phloat); i++)
- *b++ = prgm->text[(*pc)++];
- break;
- }
- }
- if (*command == CMD_NUMBER && arg->type != ARGTYPE_DOUBLE) {
- /* argtype is ARGTYPE_NUM; convert to phloat */
- arg->val_d = arg->val.num;
- arg->type = ARGTYPE_DOUBLE;
- }
-
- if (find_target) {
- target_pc = find_local_label(arg);
- arg->target = target_pc;
- for (i = 5; i >= 2; i--) {
- prgm->text[orig_pc + i] = target_pc;
- target_pc >>= 8;
- }
- prgm->lclbl_invalid = 0;
- }
-
- if (*command == CMD_CONVERT)
- {
- arg->val.num = prgm->text[(*pc)++];
- arg->val.num |= prgm->text[(*pc)++] << 8;
- }
- }
- void rebuild_label_table() {
- /* TODO -- this is *not* efficient; inserting and deleting ENDs and
- * global LBLs should not cause every single program to get rescanned!
- * But, I don't feel like dealing with that at the moment, so just
- * this ugly brute force approach for now.
- */
- int prgm_index;
- int4 pc;
- labels_count = 0;
- for (prgm_index = 0; prgm_index < prgms_count; prgm_index++) {
- prgm_struct *prgm = prgms + prgm_index;
- pc = 0;
- while (pc < prgm->size) {
- int command = prgm->text[pc];
- int argtype = prgm->text[pc + 1];
- command |= (argtype & 240) << 4;
- argtype &= 15;
- if (command == CMD_END
- || (command == CMD_LBL && argtype == ARGTYPE_STR)) {
- label_struct *newlabel;
- if (labels_count == labels_capacity) {
- label_struct *newlabels;
- int i;
- labels_capacity += 50;
- newlabels = (label_struct *)
- malloc(labels_capacity * sizeof(label_struct));
- // TODO - handle memory allocation failure
- for (i = 0; i < labels_count; i++)
- newlabels[i] = labels[i];
- if (labels != NULL)
- free(labels);
- labels = newlabels;
- }
- newlabel = labels + labels_count++;
- if (command == CMD_END)
- newlabel->length = 0;
- else {
- int i;
- newlabel->length = prgm->text[pc + 2];
- for (i = 0; i < newlabel->length; i++)
- newlabel->name[i] = prgm->text[pc + 3 + i];
- }
- newlabel->prgm = prgm_index;
- newlabel->pc = pc;
- }
- pc += get_command_length(prgm_index, pc);
- }
- }
- }
- static void update_label_table(int prgm, int4 pc, int inserted) {
- int i;
- for (i = 0; i < labels_count; i++) {
- if (labels[i].prgm > prgm)
- return;
- if (labels[i].prgm == prgm && labels[i].pc >= pc)
- labels[i].pc += inserted;
- }
- }
- static void invalidate_lclbls(int prgm_index) {
- prgm_struct *prgm = prgms + prgm_index;
- if (!prgm->lclbl_invalid) {
- int4 pc2 = 0;
- while (pc2 < prgm->size) {
- int command = prgm->text[pc2];
- int argtype = prgm->text[pc2 + 1];
- command |= (argtype & 240) << 4;
- argtype &= 15;
- if ((command == CMD_GTO || command == CMD_XEQ)
- && (argtype == ARGTYPE_NUM || argtype == ARGTYPE_LCLBL)) {
- /* A dest_pc value of -1 signals 'unknown',
- * -2 means 'nonexistent', and anything else is
- * the pc where the destination label is found.
- */
- int4 pos;
- for (pos = pc2 + 2; pos < pc2 + 6; pos++)
- prgm->text[pos] = 255;
- }
- pc2 += get_command_length(prgm_index, pc2);
- }
- prgm->lclbl_invalid = 1;
- }
- }
- void delete_command(int4 pc) {
- prgm_struct *prgm = prgms + current_prgm;
- int command = prgm->text[pc];
- int argtype = prgm->text[pc + 1];
- int length = get_command_length(current_prgm, pc);
- int4 pos;
- command |= (argtype & 240) << 4;
- argtype &= 15;
- if (command == CMD_END) {
- int4 newsize;
- prgm_struct *nextprgm;
- if (current_prgm == prgms_count - 1)
- /* Don't allow deletion of last program's END. */
- return;
- nextprgm = prgm + 1;
- prgm->size -= 2;
- newsize = prgm->size + nextprgm->size;
- if (newsize > prgm->capacity) {
- int4 newcapacity = (newsize + 511) & ~511;
- unsigned char *newtext = (unsigned char *) malloc(newcapacity);
- // TODO - handle memory allocation failure
- for (pos = 0; pos < prgm->size; pos++)
- newtext[pos] = prgm->text[pos];
- free(prgm->text);
- prgm->text = newtext;
- prgm->capacity = newcapacity;
- }
- for (pos = 0; pos < nextprgm->size; pos++)
- prgm->text[prgm->size++] = nextprgm->text[pos];
- free(nextprgm->text);
- for (pos = current_prgm + 1; pos < prgms_count - 1; pos++)
- prgms[pos] = prgms[pos + 1];
- prgms_count--;
- rebuild_label_table();
- invalidate_lclbls(current_prgm);
- clear_all_rtns();
- draw_varmenu();
- return;
- }
- for (pos = pc; pos < prgm->size - length; pos++)
- prgm->text[pos] = prgm->text[pos + length];
- prgm->size -= length;
- if (command == CMD_LBL && argtype == ARGTYPE_STR)
- rebuild_label_table();
- else
- update_label_table(current_prgm, pc, -length);
- invalidate_lclbls(current_prgm);
- clear_all_rtns();
- draw_varmenu();
- }
- void store_command(int4 pc, int command, arg_struct *arg) {
- unsigned char buf[100];
- int bufptr = 0;
- int i;
- int4 pos;
- prgm_struct *prgm = prgms + current_prgm;
- /* We should never be called with pc = -1, but just to be safe... */
- if (pc == -1)
- pc = 0;
- if (arg->type == ARGTYPE_NUM && arg->val.num < 0) {
- arg->type = ARGTYPE_NEG_NUM;
- arg->val.num = -arg->val.num;
- } else if (command == CMD_NUMBER) {
- /* arg.type is always ARGTYPE_DOUBLE for CMD_NUMBER, but for storage
- * efficiency, we handle integers specially and store them as
- * ARGTYPE_NUM or ARGTYPE_NEG_NUM instead.
- */
- int4 n = to_int4(arg->val_d);
- if (n == arg->val_d && n != (int4) 0x80000000) {
- if (n >= 0) {
- arg->val.num = n;
- arg->type = ARGTYPE_NUM;
- } else {
- arg->val.num = -n;
- arg->type = ARGTYPE_NEG_NUM;
- }
- }
- } else if (arg->type == ARGTYPE_LBLINDEX) {
- int li = arg->val.num;
- arg->length = labels[li].length;
- for (i = 0; i < arg->length; i++)
- arg->val.text[i] = labels[li].name[i];
- arg->type = ARGTYPE_STR;
- }
- buf[bufptr++] = command & 255;
- buf[bufptr++] = arg->type | ((command & ~255) >> 4);
- /* If the program is nonempty, it must already contain an END,
- * since that's the very first thing that gets stored in any new
- * program. In this case, we need to split the program.
- */
- if (command == CMD_END && prgm->size > 0) {
- prgm_struct *new_prgm;
- if (prgms_count == prgms_capacity) {
- prgm_struct *new_prgms;
- int i;
- prgms_capacity += 10;
- new_prgms = (prgm_struct *)
- malloc(prgms_capacity * sizeof(prgm_struct));
- // TODO - handle memory allocation failure
- for (i = 0; i <= current_prgm; i++)
- new_prgms[i] = prgms[i];
- for (i = current_prgm + 1; i < prgms_count; i++)
- new_prgms[i + 1] = prgms[i];
- free(prgms);
- prgms = new_prgms;
- prgm = prgms + current_prgm;
- } else {
- for (i = prgms_count - 1; i > current_prgm; i--)
- prgms[i + 1] = prgms[i];
- }
- prgms_count++;
- new_prgm = prgm + 1;
- new_prgm->size = prgm->size - pc;
- new_prgm->capacity = (new_prgm->size + 511) & ~511;
- new_prgm->text = (unsigned char *) malloc(new_prgm->capacity);
- // TODO - handle memory allocation failure
- for (i = pc; i < prgm->size; i++)
- new_prgm->text[i - pc] = prgm->text[i];
- current_prgm++;
- /* Truncate the previously 'current' program and append an END.
- * No need to check the size against the capacity and grow the
- * program; since it contained an END before, it still has the
- * capacity for one now;
- */
- prgm->size = pc;
- prgm->text[prgm->size++] = CMD_END;
- prgm->text[prgm->size++] = ARGTYPE_NONE;
- if (flags.f.trace_print || flags.f.normal_print)
- print_program_line(current_prgm - 1, pc);
- rebuild_label_table();
- invalidate_lclbls(current_prgm);
- invalidate_lclbls(current_prgm - 1);
- clear_all_rtns();
- draw_varmenu();
- return;
- }
- if ((command == CMD_GTO || command == CMD_XEQ)
- && (arg->type == ARGTYPE_NUM || arg->type == ARGTYPE_LCLBL))
- for (i = 0; i < 4; i++)
- buf[bufptr++] = 255;
- switch (arg->type) {
- case ARGTYPE_NUM:
- case ARGTYPE_NEG_NUM:
- case ARGTYPE_IND_NUM: {
- int4 num = arg->val.num;
- char tmpbuf[5];
- int tmplen = 0;
- while (num > 127) {
- tmpbuf[tmplen++] = num & 127;
- num >>= 7;
- }
- tmpbuf[tmplen++] = num;
- tmpbuf[0] |= 128;
- while (--tmplen >= 0)
- buf[bufptr++] = tmpbuf[tmplen];
- break;
- }
- case ARGTYPE_STK:
- case ARGTYPE_IND_STK:
- buf[bufptr++] = arg->val.stk;
- break;
- case ARGTYPE_STR:
- case ARGTYPE_IND_STR: {
- buf[bufptr++] = arg->length;
- for (i = 0; i < arg->length; i++)
- buf[bufptr++] = arg->val.text[i];
- break;
- }
- case ARGTYPE_LCLBL:
- buf[bufptr++] = arg->val.lclbl;
- break;
- case ARGTYPE_DOUBLE: {
- unsigned char *b = (unsigned char *) &arg->val_d;
- for (int i = 0; i < (int) sizeof(phloat); i++)
- buf[bufptr++] = *b++;
- break;
- }
- }
- if (command == CMD_CONVERT)
- {
- buf[bufptr++] = arg->val.num&0xFF;
- buf[bufptr++] = ((arg->val.num) >> 8)&0xFF;
- }
-
- if (bufptr + prgm->size > prgm->capacity) {
- unsigned char *newtext;
- prgm->capacity += 512;
- newtext = (unsigned char *) malloc(prgm->capacity);
- // TODO - handle memory allocation failure
- for (pos = 0; pos < pc; pos++)
- newtext[pos] = prgm->text[pos];
- for (pos = pc; pos < prgm->size; pos++)
- newtext[pos + bufptr] = prgm->text[pos];
- if (prgm->text != NULL)
- free(prgm->text);
- prgm->text = newtext;
- } else {
- for (pos = prgm->size - 1; pos >= pc; pos--)
- prgm->text[pos + bufptr] = prgm->text[pos];
- }
- for (pos = 0; pos < bufptr; pos++)
- prgm->text[pc + pos] = buf[pos];
- prgm->size += bufptr;
- if (command != CMD_END && (flags.f.trace_print || flags.f.normal_print))
- print_program_line(current_prgm, pc);
-
- if (command == CMD_END ||
- (command == CMD_LBL && arg->type == ARGTYPE_STR))
- rebuild_label_table();
- else
- update_label_table(current_prgm, pc, bufptr);
- invalidate_lclbls(current_prgm);
- clear_all_rtns();
- draw_varmenu();
- }
- void store_command_after(int4 *pc, int command, arg_struct *arg) {
- if (*pc == -1)
- *pc = 0;
- else if (prgms[current_prgm].text[*pc] != CMD_END)
- *pc += get_command_length(current_prgm, *pc);
- store_command(*pc, command, arg);
- }
- static int pc_line_convert(int4 loc, int loc_is_pc) {
- int4 pc = 0;
- int4 line = 1;
- prgm_struct *prgm = prgms + current_prgm;
- while (1) {
- if (loc_is_pc) {
- if (pc >= loc)
- return line;
- } else {
- if (line >= loc)
- return pc;
- }
- if (prgm->text[pc] == CMD_END)
- return loc_is_pc ? line : pc;
- pc += get_command_length(current_prgm, pc);
- line++;
- }
- }
- int4 pc2line(int4 pc) {
- if (pc == -1)
- return 0;
- else
- return pc_line_convert(pc, 1);
- }
- int4 line2pc(int4 line) {
- if (line == 0)
- return -1;
- else
- return pc_line_convert(line, 0);
- }
- int4 find_local_label(const arg_struct *arg) {
- int4 orig_pc = pc;
- int4 search_pc;
- int wrapped = 0;
- prgm_struct *prgm = prgms + current_prgm;
- if (orig_pc == -1)
- orig_pc = 0;
- search_pc = orig_pc;
- while (!wrapped || search_pc < orig_pc) {
- int command, argtype;
- if (search_pc >= prgm->size - 2) {
- if (orig_pc == 0)
- break;
- search_pc = 0;
- wrapped = 1;
- }
- command = prgm->text[search_pc];
- argtype = prgm->text[search_pc + 1];
- command |= (argtype & 240) << 4;
- argtype &= 15;
- if (command == CMD_LBL && argtype == arg->type) {
- if (argtype == ARGTYPE_NUM) {
- int num = 0;
- unsigned char c;
- int pos = search_pc + 2;
- do {
- c = prgm->text[pos++];
- num = (num << 7) | (c & 127);
- } while ((c & 128) == 0);
- if (num == arg->val.num)
- return search_pc;
- } else {
- char lclbl = prgm->text[search_pc + 2];
- if (lclbl == arg->val.lclbl)
- return search_pc;
- }
- }
- search_pc += get_command_length(current_prgm, search_pc);
- }
- return -2;
- }
- // Created a wrapper method to this function so it is easier to call from
- // MenuView to determine if we should display variable values for a cusomt menu
- int find_global_label(const char *name, int namelen, int *prgm, int4 *pc) {
- int i;
- for (i = labels_count - 1; i >= 0; i--) {
- int j;
- char *labelname;
- if (labels[i].length != namelen)
- continue;
- labelname = labels[i].name;
- for (j = 0; j < namelen; j++)
- if (labelname[j] != name[j])
- goto nomatch;
- *prgm = labels[i].prgm;
- *pc = labels[i].pc;
- return 1;
- nomatch:;
- }
- return 0;
- }
- // Wrapper method for above find_global_label
- int find_global_label(const arg_struct *arg, int *prgm, int4 *pc) {
- return find_global_label(arg->val.text, arg->length, prgm, pc);
- }
- int push_rtn_addr(int prgm, int4 pc) {
- int err = ERR_NONE;
- if (rtn_sp == MAX_RTNS) {
- int i;
- if (rtn_prgm[0] == -2 || rtn_prgm[0] == -3)
- err = ERR_SOLVE_INTEG_RTN_LOST;
- for (i = 0; i < MAX_RTNS - 1; i++) {
- rtn_prgm[i] = rtn_prgm[i + 1];
- rtn_pc[i] = rtn_pc[i + 1];
- }
- rtn_sp--;
- }
- rtn_prgm[rtn_sp] = prgm;
- rtn_pc[rtn_sp] = pc;
- rtn_sp++;
- return err;
- }
- void pop_rtn_addr(int *prgm, int4 *pc) {
- if (rtn_sp == 0) {
- *prgm = -1;
- *pc = -1;
- } else {
- rtn_sp--;
- *prgm = rtn_prgm[rtn_sp];
- *pc = rtn_pc[rtn_sp];
- }
- }
- void clear_all_rtns() {
- rtn_sp = 0;
- }
- void setup_bigstack_for_solve_integ()
- {
- orig_stack_type_before_solve = flags.f.f32;
- if (!orig_stack_type_before_solve)
- return;
- push_var_on_stack(new_real(0));
- push_var_on_stack(new_real(0));
- push_var_on_stack(new_real(0));
- push_var_on_stack(new_real(0));
- flags.f.f32 = FALSE; // Force size 4 stack mode for solving
- }
- // If are in bigstack mode, then change the stack mode back to bigstack
- // and shift the stack back down so that only the result is the X register.
- // Set restore_all to true to restore the entire stack.
- void restore_bigstack_for_solve_integ(bool restore_all)
- {
- if (!orig_stack_type_before_solve)
- return;
- flags.f.f32 = TRUE;
- vartype* tmp = reg_t;
- reg_t = reg_x;
- reg_x = tmp;
- pop_var_off_stack();
- pop_var_off_stack();
- pop_var_off_stack();
-
- if (restore_all)
- pop_var_off_stack();
- }
-
- bool solve_active() {
- int i;
- for (i = 0; i < rtn_sp; i++)
- if (rtn_prgm[i] == -2)
- return true;
- return false;
- }
- bool integ_active() {
- int i;
- for (i = 0; i < rtn_sp; i++)
- if (rtn_prgm[i] == -3)
- return true;
- return false;
- }
- void unwind_stack_until_solve() {
- while (rtn_prgm[--rtn_sp] != -2);
- }
- static bool read_int(int *n) {
- return shell_read_saved_state(n, sizeof(int)) == sizeof(int);
- }
- static bool write_int(int n) {
- return shell_write_saved_state(&n, sizeof(int));
- }
- static bool read_int4(int4 *n) {
- return shell_read_saved_state(n, sizeof(int4)) == sizeof(int4);
- }
- static bool write_int4(int4 n) {
- return shell_write_saved_state(&n, sizeof(int4));
- }
- static bool read_chars(char *c, int maxsize)
- {
- int readsize = 0;
- do {
- readsize++;
- if (readsize > maxsize)
- return false;
- shell_read_saved_state(c, sizeof(char));
- }
- while(*c++ != 0);
- return true;
- }
-
- static bool write_chars(char *c) {
- do {
- if (!shell_write_saved_state(c, sizeof(char)))
- return false;
- }
- while (*c++ != 0);
- return true;
- }
-
- static bool read_bool(bool *b) {
- if (state_bool_is_int) {
- int t;
- if (!read_int(&t))
- return false;
- if (t != 0 && t != 1)
- return false;
- *b = t != 0;
- return true;
- } else {
- return shell_read_saved_state(b, sizeof(bool)) == sizeof(bool);
- }
- }
- static bool write_bool(bool b) {
- return shell_write_saved_state(&b, sizeof(bool));
- }
- bool read_phloat(phloat *d) {
- if (bin_dec_mode_switch) {
- #ifdef BCD_MATH
- double dbl;
- if (shell_read_saved_state(&dbl, sizeof(double)) != sizeof(double))
- return false;
- *d = dbl;
- return true;
- #else
- short bcd[P + 1];
- if (shell_read_saved_state(bcd, (P + 1) * sizeof(short))
- != (P + 1) * sizeof(short))
- return false;
- *d = bcd2double(bcd, state_file_has_old_bcd);
- return true;
- #endif
- } else {
- if (shell_read_saved_state(d, sizeof(phloat)) != sizeof(phloat))
- return false;
- #ifdef BCD_MATH
- if (state_file_has_old_bcd)
- bcdfloat_old2new(d->bcd.d_);
- #endif
- return true;
- }
- }
- bool write_phloat(phloat d) {
- return shell_write_saved_state(&d, sizeof(phloat));
- }
- bool load_state(int4 ver) {
- int4 magic;
- int4 version;
- /* The shell has verified the initial magic and version numbers,
- * and loaded the shell state, before we got called.
- */
- state_bool_is_int = ver < 9;
- #ifdef BCD_MATH
- if (ver < 9) {
- bin_dec_mode_switch = true;
- state_file_has_old_bcd = false;
- } else {
- bool state_is_decimal;
- if (!read_bool(&state_is_decimal)) return false;
- bin_dec_mode_switch = !state_is_decimal;
- state_file_has_old_bcd = state_is_decimal && ver < 12;
- }
- #else
- if (ver < 9) {
- bin_dec_mode_switch = false;
- state_file_has_old_bcd = false;
- } else {
- bool state_is_decimal;
- if (!read_bool(&state_is_decimal)) return false;
- bin_dec_mode_switch = state_is_decimal;
- state_file_has_old_bcd = state_is_decimal && ver < 12;
- }
- #endif
- if (ver < 2) {
- core_settings.matrix_singularmatrix = false;
- core_settings.matrix_outofrange = false;
- } else {
- if (!read_bool(&core_settings.matrix_singularmatrix)) return false;
- if (!read_bool(&core_settings.matrix_outofrange)) return false;
- if (ver < 9) {
- int dummy;
- if (!read_int(&dummy)) return false;
- }
- }
- if (ver < 5)
- core_settings.raw_text = false;
- else {
- if (!read_bool(&core_settings.raw_text)) return false;
- if (ver < 8) {
- int dummy;
- if (!read_int(&dummy)) return false;
- }
- }
- if (ver < 11)
- core_settings.auto_repeat = true;
- else
- if (!read_bool(&core_settings.auto_repeat)) return false;
- if (ver < 15) {
- #if defined(COPAN)
- core_settings.enable_ext_copan = true;
- #else
- core_settings.enable_ext_copan = false;
- #endif
- #if defined(BIGSTACK)
- core_settings.enable_ext_bigstack = true;
- #else
- core_settings.enable_ext_bigstack = false;
- #endif
- #if defined(ANDROID) || defined(IPHONE)
- core_settings.enable_ext_accel = true;
- core_settings.enable_ext_locat = true;
- core_settings.enable_ext_heading = true;
- #else
- core_settings.enable_ext_accel = false;
- core_settings.enable_ext_locat = false;
- core_settings.enable_ext_heading = false;
- #endif
- core_settings.enable_ext_time = true;
- } else {
- if (!read_bool(&core_settings.enable_ext_copan)) return false;
- if (!read_bool(&core_settings.enable_ext_bigstack)) return false;
- if (!read_bool(&core_settings.enable_ext_accel)) return false;
- if (!read_bool(&core_settings.enable_ext_locat)) return false;
- if (!read_bool(&core_settings.enable_ext_heading)) return false;
- if (!read_bool(&core_settings.enable_ext_time)) return false;
- }
- if (!read_bool(&mode_clall)) return false;
- if (!read_bool(&mode_command_entry)) return false;
- if (!read_bool(&mode_number_entry)) return false;
- if (!read_bool(&mode_alpha_entry)) return false;
- if (!read_bool(&mode_shift)) return false;
- if (!read_int(&mode_appmenu)) return false;
- if (!read_int(&mode_plainmenu)) return false;
- if (!read_bool(&mode_plainmenu_sticky)) return false;
- if (!read_int(&mode_transientmenu)) return false;
- if (!read_int(&mode_alphamenu)) return false;
- if (!read_int(&mode_commandmenu)) return false;
- if (!read_bool(&mode_running)) return false;
- if (!read_bool(&mode_varmenu)) return false;
- if (!read_bool(&mode_updown)) return false;
- if (ver < 6)
- mode_getkey = false;
- else if (!read_bool(&mode_getkey))
- return false;
- if (!read_phloat(&entered_number)) return false;
- if (!read_int(&entered_string_length)) return false;
- if (shell_read_saved_state(entered_string, 15) != 15) return false;
- if (!read_int(&pending_command)) return false;
- if (!read_arg(&pending_command_arg, ver < 9)) return false;
- if (!read_int(&xeq_invisible)) return false;
- if (!read_int(&incomplete_command)) return false;
- if (!read_int(&incomplete_ind)) return false;
- if (!read_int(&incomplete_alpha)) return false;
- if (!read_int(&incomplete_length)) return false;
- if (!read_int(&incomplete_maxdigits)) return false;
- if (!read_int(&incomplete_argtype)) return false;
- if (!read_int(&incomplete_num)) return false;
- if (shell_read_saved_state(incomplete_str, 7) != 7) return false;
- if (!read_int4(&incomplete_saved_pc)) return false;
- if (!read_int4(&incomplete_saved_highlight_row)) return false;
- if (shell_read_saved_state(cmdline, 100) != 100) return false;
- if (!read_int(&cmdline_length)) return false;
- if (!read_int(&cmdline_row)) return false;
- if (!read_int(&matedit_mode)) return false;
- if (shell_read_saved_state(matedit_name, 7) != 7) return false;
- if (!read_int(&matedit_length)) return false;
- if (!unpersist_vartype(&matedit_x)) return false;
- if (!read_int4(&matedit_i)) return false;
- if (!read_int4(&matedit_j)) return false;
- if (!read_int(&matedit_prev_appmenu)) return false;
- if (shell_read_saved_state(input_name, 11) != 11) return false;
- if (!read_int(&input_length)) return false;
- if (!read_arg(&input_arg, ver < 9)) return false;
- if (!read_int(&baseapp)) return false;
- if (!read_phloat(&random_number))
- return false;
- if (ver < 3) {
- deferred_print = 0;
- } else {
- if (!read_int(&deferred_print)) return false;
- }
- if (!read_int(&keybuf_head)) return false;
- if (!read_int(&keybuf_tail)) return false;
- if (shell_read_saved_state(keybuf, 16 * sizeof(int))
- != 16 * sizeof(int))
- return false;
- if (!unpersist_display(ver))
- return false;
- if (!unpersist_globals(ver))
- return false;
- if (ver < 4) {
- /* Before state file version 4, I used to save the BCD table in the
- * state file. As of state file version 4, the Unix and Windows
- * versions don't do that any more because they don't need to
- * (generating the table on startup is fast enough); the PalmOS version
- * now persists the BCD table in a database, which is faster because it
- * doesn't need to be loaded and saved each time the application is
- * started and stopped.
- * This code is to skip the saved BCD table in state versions up to
- * and including version 3.
- */
- int min_pow2, max_pow2;
- uint4 n1, n2, n3, n4, n;
- char dummy[1024];
- if (!read_int(&min_pow2))
- return false;
- if (!read_int(&max_pow2))
- return false;
- n1 = 16 * (max_pow2 + 1); /* size of pos_pow2mant table */
- n2 = sizeof(int) * (max_pow2 + 1); /* size of pos_pow2exp table */
- n3 = 16 * (-min_pow2); /* size of neg_pow2mant table */
- n4 = sizeof(int) * (-min_pow2); /* size of neg_pow2exp table */
- n = n1 + n2 + n3 + n4; /* total number of bytes to skip */
- while (n > 0) {
- int count = n < 1024 ? n : 1024;
- if (shell_read_saved_state(dummy, count) != count)
- return false;
- n -= count;
- }
- }
- if (!unpersist_math(bin_dec_mode_switch))
- return false;
- if (!read_int4(&magic)) return false;
- if (magic != FREE42_MAGIC)
- return false;
- if (!read_int4(&version)) return false;
- if (version != ver)
- return false;
- return true;
- }
- void save_state() {
- /* The shell has written the initial magic and version numbers,
- * and the shell state, before we got called.
- */
- #ifdef BCD_MATH
- if (!write_bool(true)) return;
- #else
- if (!write_bool(false)) return;
- #endif
- if (!write_bool(core_settings.matrix_singularmatrix)) return;
- if (!write_bool(core_settings.matrix_outofrange)) return;
- if (!write_bool(core_settings.raw_text)) return;
- if (!write_bool(core_settings.auto_repeat)) return;
- if (!write_bool(core_settings.enable_ext_copan)) return;
- if (!write_bool(core_settings.enable_ext_bigstack)) return;
- if (!write_bool(core_settings.enable_ext_accel)) return;
- if (!write_bool(core_settings.enable_ext_locat)) return;
- if (!write_bool(core_settings.enable_ext_heading)) return;
- if (!write_bool(core_settings.enable_ext_time)) return;
- if (!write_bool(mode_clall)) return;
- if (!write_bool(mode_command_entry)) return;
- if (!write_bool(mode_number_entry)) return;
- if (!write_bool(mode_alpha_entry)) return;
- if (!write_bool(mode_shift)) return;
- if (!write_int(mode_appmenu)) return;
- if (!write_int(mode_plainmenu)) return;
- if (!write_bool(mode_plainmenu_sticky)) return;
- if (!write_int(mode_transientmenu)) return;
- if (!write_int(mode_alphamenu)) return;
- if (!write_int(mode_commandmenu)) return;
- if (!write_bool(mode_running)) return;
- if (!write_bool(mode_varmenu)) return;
- if (!write_bool(mode_updown)) return;
- if (!write_bool(mode_getkey)) return;
- if (!write_phloat(entered_number)) return;
- if (!write_int(entered_string_length)) return;
- if (!shell_write_saved_state(entered_string, 15)) return;
- if (!write_int(pending_command)) return;
- if (!shell_write_saved_state(&pending_command_arg, sizeof(arg_struct))) return;
- if (!write_int(xeq_invisible)) return;
- if (!write_int(incomplete_command)) return;
- if (!write_int(incomplete_ind)) return;
- if (!write_int(incomplete_alpha)) return;
- if (!write_int(incomplete_length)) return;
- if (!write_int(incomplete_maxdigits)) return;
- if (!write_int(incomplete_argtype)) return;
- if (!write_int(incomplete_num)) return;
- if (!shell_write_saved_state(incomplete_str, 7)) return;
- if (!write_int4(incomplete_saved_pc)) return;
- if (!write_int4(incomplete_saved_highlight_row)) return;
- if (!shell_write_saved_state(cmdline, 100)) return;
- if (!write_int(cmdline_length)) return;
- if (!write_int(cmdline_row)) return;
- if (!write_int(matedit_mode)) return;
- if (!shell_write_saved_state(matedit_name, 7)) return;
- if (!write_int(matedit_length)) return;
- if (!persist_vartype(matedit_x)) return;
- if (!write_int4(matedit_i)) return;
- if (!write_int4(matedit_j)) return;
- if (!write_int(matedit_prev_appmenu)) return;
- if (!shell_write_saved_state(input_name, 11)) return;
- if (!write_int(input_length)) return;
- if (!shell_write_saved_state(&input_arg, sizeof(arg_struct))) return;
- if (!write_int(baseapp)) return;
- if (!write_phloat(random_number)) return;
- if (!write_int(deferred_print)) return;
- if (!write_int(keybuf_head)) return;
- if (!write_int(keybuf_tail)) return;
- if (!shell_write_saved_state(keybuf, 16 * sizeof(int))) return;
- if (!persist_display())
- return;
- if (!persist_globals())
- return;
- if (!persist_math())
- return;
- if (!write_int4(FREE42_MAGIC)) return;
- if (!write_int4(FREE42_VERSION)) return;
- }
- void hard_reset(int bad_state_file) {
- vartype *regs;
- /* Clear stack */
- free_vartype(reg_x);
- free_vartype(reg_y);
- free_vartype(reg_z);
- free_vartype(reg_t);
- #ifdef BIGSTACK
- while(bigstack_head != NULL)
- {
- shift_big_stack_down();
- free_vartype(reg_t);
- }
- #endif
- free_vartype(reg_lastx);
- reg_x = new_real(0);
- reg_y = new_real(0);
- reg_z = new_real(0);
- reg_t = new_real(0);
- reg_lastx = new_real(0);
- /* Clear alpha */
- reg_alpha_length = 0;
- /* Clear variables */
- purge_all_vars();
- regs = new_realmatrix(25, 1);
- store_var("REGS", 4, regs);
- /* Clear programs */
- if (prgms != NULL) {
- free(prgms);
- prgms = NULL;
- prgms_capacity = 0;
- prgms_count = 0;
- }
- if (labels != NULL) {
- free(labels);
- labels = NULL;
- labels_capacity = 0;
- labels_count = 0;
- }
- goto_dot_dot();
- pending_command = CMD_NONE;
- matedit_mode = 0;
- input_length = 0;
- baseapp = 0;
- random_number = shell_random_seed();
- flags.f.f00 = flags.f.f01 = flags.f.f02 = flags.f.f03 = flags.f.f04 = 0;
- flags.f.f05 = flags.f.f06 = flags.f.f07 = flags.f.f08 = flags.f.f09 = 0;
- flags.f.f10 = 0;
- flags.f.auto_exec = 0;
- flags.f.double_wide_print = 0;
- flags.f.lowercase_print = 0;
- flags.f.f14 = 0;
- flags.f.trace_print = 0;
- flags.f.normal_print = 0;
- flags.f.f17 = flags.f.f18 = flags.f.f19 = flags.f.f20 = 0;
- flags.f.printer_enable = 1; // HP-42S sets this to 0 on hard reset
- flags.f.numeric_data_input = 0;
- flags.f.alpha_data_input = 0;
- flags.f.range_error_ignore = 0;
- flags.f.error_ignore = 0;
- flags.f.audio_enable = 1;
- /* flags.f.VIRTUAL_custom_menu = 0; */
- flags.f.decimal_point = 1;
- flags.f.thousands_separators = 1;
- flags.f.stack_lift_disable = 0;
- flags.f.f31 = flags.f.f32 = flags.f.f33 = 0;
- flags.f.agraph_control1 = 0;
- flags.f.agraph_control0 = 0;
- flags.f.digits_bit3 = 0;
- flags.f.digits_bit2 = 1;
- flags.f.digits_bit1 = 0;
- flags.f.digits_bit0 = 0;
- flags.f.fix_or_all = 1;
- flags.f.eng_or_all = 1;
- flags.f.grad = 0;
- flags.f.rad = 0;
- flags.f.continuous_on = 0;
- /* flags.f.VIRTUAL_solving = 0; */
- /* flags.f.VIRTUAL_integrating = 0; */
- /* flags.f.VIRTUAL_variable_menu = 0; */
- flags.f.alpha_mode = 0;
- /* flags.f.VIRTUAL_low_battery = 0; */
- flags.f.message = 1;
- flags.f.two_line_message = 0;
- flags.f.prgm_mode = 0;
- /* flags.f.VIRTUAL_input = 0; */
- flags.f.f54 = 0;
- flags.f.printer_exists = 1; // HP-42S sets this to 0 on hard reset
- flags.f.lin_fit = 1;
- flags.f.log_fit = 0;
- flags.f.exp_fit = 0;
- flags.f.pwr_fit = 0;
- flags.f.all_sigma = 1;
- flags.f.log_fit_invalid = 0;
- flags.f.exp_fit_invalid = 0;
- flags.f.pwr_fit_invalid = 0;
- flags.f.f64 = 0;
- /* flags.f.VIRTUAL_matrix_editor = 0; */
- flags.f.grow = 0;
- flags.f.f67 = 0;
- flags.f.base_bit0 = 0;
- flags.f.base_bit1 = 0;
- flags.f.base_bit2 = 0;
- flags.f.base_bit3 = 0;
- flags.f.local_label = 0;
- flags.f.polar = 0;
- flags.f.real_result_only = 0;
- /* flags.f.VIRTUAL_programmable_menu = 0; */
- flags.f.matrix_edge_wrap = 0;
- flags.f.matrix_end_wrap = 0;
- flags.f.f78 = flags.f.f79 = flags.f.f80 = flags.f.f81 = flags.f.f82 = 0;
- flags.f.f83 = flags.f.f84 = flags.f.f85 = flags.f.f86 = flags.f.f87 = 0;
- flags.f.f88 = flags.f.f89 = flags.f.f90 = flags.f.f91 = flags.f.f92 = 0;
- flags.f.f93 = flags.f.f94 = flags.f.f95 = flags.f.f96 = flags.f.f97 = 0;
- flags.f.f98 = flags.f.f99 = 0;
- mode_clall = false;
- mode_command_entry = false;
- mode_number_entry = false;
- mode_alpha_entry = false;
- mode_shift = false;
- mode_commandmenu = MENU_NONE;
- mode_alphamenu = MENU_NONE;
- mode_transientmenu = MENU_NONE;
- mode_plainmenu = MENU_NONE;
- mode_appmenu = MENU_NONE;
- mode_running = false;
- mode_getkey = false;
- mode_pause = false;
- mode_varmenu = false;
- prgm_highlight_row = 0;
- varmenu_length = 0;
- mode_updown = false;
- mode_sigma_reg = 11;
- mode_goose = -1;
- mode_time_clktd = false;
- mode_time_clk24 = false;
- mode_time_dmy = false;
- core_settings.auto_repeat = true;
- #if defined(COPAN)
- core_settings.enable_ext_copan = true;
- #else
- core_settings.enable_ext_copan = false;
- #endif
- #if defined(BIGSTACK)
- core_settings.enable_ext_bigstack = true;
- #else
- core_settings.enable_ext_bigstack = false;
- #endif
- #if defined(ANDROID) || defined(IPHONE)
- core_settings.enable_ext_accel = true;
- core_settings.enable_ext_locat = true;
- core_settings.enable_ext_heading = true;
- #else
- core_settings.enable_ext_accel = false;
- core_settings.enable_ext_locat = false;
- core_settings.enable_ext_heading = false;
- #endif
- core_settings.enable_ext_time = true;
- reset_math();
- clear_display();
- clear_custom_menu();
- clear_prgm_menu();
- if (bad_state_file)
- draw_string(0, 0, "State File Corrupt", 18);
- else
- draw_string(0, 0, "Memory Clear", 12);
- display_x(1);
- flush_display();
- }
- struct dec_arg_struct {
- unsigned char type;
- unsigned char length;
- int4 target;
- union {
- int4 num;
- char text[15];
- char stk;
- int cmd;
- char lclbl;
- } val;
- fake_bcd val_d;
- };
- struct bin_arg_struct {
- unsigned char type;
- unsigned char length;
- int4 target;
- union {
- int4 num;
- char text[15];
- char stk;
- int cmd;
- char lclbl;
- } val;
- double val_d;
- };
- bool read_arg(arg_struct *arg, bool old) {
- if (old) {
- // Prior to core state version 9, the arg_struct type saved a bit of
- // by using a union to hold the argument value.
- // In version 9, we switched from using 'double' as our main numeric
- // data type to 'phloat' -- but since 'phloat' is a class, with a
- // constructor, it cannot be a member of a union.
- // So, I had to change the 'val' member from a union to a struct.
- // Of course, this means that the arg_struct layout is now different,
- // and when deserializing a pre-9 state file, I must make sure to
- // deserialize an old-stype arg_struct and then convert it to a
- // new one.
- struct {
- unsigned char type;
- unsigned char length;
- int4 target;
- union {
- int4 num;
- char text[15];
- char stk;
- int cmd; /* For backward compatibility only! */
- char lclbl;
- double d;
- } val;
- } old_arg;
- if (shell_read_saved_state(&old_arg, sizeof(old_arg))
- != sizeof(old_arg))
- return false;
- arg->type = old_arg.type;
- arg->length = old_arg.length;
- arg->target = old_arg.target;
- char *d = (char *) &arg->val;
- char *s = (char *) &old_arg.val;
- for (unsigned int i = 0; i < sizeof(old_arg.val); i++)
- *d++ = *s++;
- arg->val_d = old_arg.val.d;
- return true;
- } else if (bin_dec_mode_switch) {
- #ifdef BCD_MATH
- bin_arg_struct ba;
- if (shell_read_saved_state(&ba, sizeof(bin_arg_struct))
- != sizeof(bin_arg_struct))
- return false;
- arg->type = ba.type;
- arg->length = ba.length;
- arg->target = ba.target;
- char *d = (char *) &arg->val;
- char *s = (char *) &ba.val;
- for (unsigned int i = 0; i < sizeof(ba.val); i++)
- *d++ = *s++;
- arg->val_d = ba.val_d;
- #else
- dec_arg_struct da;
- if (shell_read_saved_state(&da, sizeof(dec_arg_struct))
- != sizeof(dec_arg_struct))
- return false;
- arg->type = da.type;
- arg->length = da.length;
- arg->target = da.target;
- char *d = (char *) &arg->val;
- char *s = (char *) &da.val;
- for (unsigned int i = 0; i < sizeof(da.val); i++)
- *d++ = *s++;
- arg->val_d = bcd2double(da.val_d.d_, state_file_has_old_bcd);
- #endif
- return true;
- } else {
- return shell_read_saved_state(arg, sizeof(arg_struct))
- == sizeof(arg_struct);
- }
- }
- static bool convert_programs() {
- // This function is called if the setting of mode_decimal recorded in the
- // state file does not match the current setting (i.e., if we're a binary
- // Free42 and the state file was written by the decimal version, or vice
- // versa).
- // This function looks for floating-point number literals (command =
- // CMD_NUMBER with arg.type = ARGTYPE_DOUBLE) and converts them from double
- // to Phloat or the other way around.
- int saved_prgm = current_prgm;
- int4 saved_pc = pc;
- int i;
- // Since converting programs can cause instructions to move, I have to
- // update all stored PC values to correct for this. PCs are stored in the
- // 'pc' and 'rtn_pc[]' globals. I copy those values into a local array,
- // which I then sort by program index and pc; this allows me to do the
- // updates very efficiently later on.
- int mod_prgm[MAX_RTNS + 2];
- int4 mod_pc[MAX_RTNS + 2];
- int mod_sp[MAX_RTNS + 2];
- int mod_count = 0;
- for (i = 0; i < rtn_sp; i++) {
- int prgm = rtn_prgm[i];
- if (prgm == -2 || prgm == -3) {
- // Return-to-solve and return-to-integ
- // On a binary/decimal mode switch, unpersist_math() discards all
- // the SOLVE and INTEG state. If SOLVE or INTEG are actually
- // active, we have to clear the RTN stack, too.
- rtn_sp = 0;
- mod_count = 0;
- break;
- }
- mod_prgm[mod_count] = prgm;
- mod_pc[mod_count] = rtn_pc[i];
- mod_sp[mod_count] = i;
- mod_count++;
- }
- if (saved_pc > 0) {
- mod_prgm[mod_count] = current_prgm;
- mod_pc[mod_count] = saved_pc;
- mod_sp[mod_count] = -1;
- mod_count++;
- }
- if (incomplete_saved_pc > 0) {
- mod_prgm[mod_count] = current_prgm;
- mod_pc[mod_count] = incomplete_saved_pc;
- mod_sp[mod_count] = -2;
- mod_count++;
- }
- mod_count--;
- for (i = 0; i < mod_count; i++)
- for (int j = i + 1; j <= mod_count; j++)
- if (mod_prgm[i] < mod_prgm[j]
- || (mod_prgm[i] == mod_prgm[j] && mod_pc[i] < mod_pc[j])) {
- int tmp = mod_prgm[i];
- mod_prgm[i] = mod_prgm[j];
- mod_prgm[j] = tmp;
- int4 tmp4 = mod_pc[i];
- mod_pc[i] = mod_pc[j];
- mod_pc[j] = tmp4;
- tmp = mod_sp[i];
- mod_sp[i] = mod_sp[j];
- mod_sp[j] = tmp;
- }
- for (i = 0; i < prgms_count; i++) {
- current_prgm = i;
- pc = 0;
- int4 oldpc = 0;
- prgm_struct *prgm = prgms + i;
- prgm->lclbl_invalid = 1;
- while (true) {
- while (mod_count >= 0 && current_prgm == mod_prgm[mod_count]
- && oldpc >= mod_pc[mod_count]) {
- // oldpc should never be greater than mod_pc[mod_count]; this
- // means that something is out of whack, because we have an old
- // PC value that does not actually coincide with the beginning
- // of an instruction.
- int s = mod_sp[mod_count];
- if (s == -1)
- saved_pc = pc;
- else if (s == -2)
- incomplete_saved_pc = pc;
- else
- rtn_pc[s] = pc;
- mod_count--;
- }
- int4 prevpc = pc;
- int command = prgm->text[pc++];
- int argtype = prgm->text[pc++];
- command |= (argtype & 240) << 4;
- argtype &= 15;
- if (command == CMD_END)
- break;
- if ((command == CMD_GTO || command == CMD_XEQ)
- && (argtype == ARGTYPE_NUM || argtype == ARGTYPE_LCLBL)) {
- // Invalidate local label offsets
- prgm->text[pc++] = 255;
- prgm->text[pc++] = 255;
- prgm->text[pc++] = 255;
- prgm->text[pc++] = 255;
- }
- switch (argtype) {
- case ARGTYPE_NUM:
- case ARGTYPE_NEG_NUM:
- case ARGTYPE_IND_NUM: {
- while ((prgm->text[pc++] & 128) == 0);
- break;
- }
- case ARGTYPE_STK:
- case ARGTYPE_IND_STK:
- case ARGTYPE_COMMAND:
- case ARGTYPE_LCLBL:
- pc++;
- break;
- case ARGTYPE_STR:
- case ARGTYPE_IND_STR: {
- pc += prgm->text[pc] + 1;
- break;
- }
- case ARGTYPE_DOUBLE:
- #ifdef BCD_MATH
- double d;
- int j;
- unsigned char *b = (unsigned char *) &d;
- for (j = 0; j < (int) sizeof(double); j++)
- *b++ = prgm->text[pc++];
- pc -= sizeof(double);
- int growth = sizeof(phloat) - sizeof(double);
- int4 pos;
- if (prgm->size + growth > prgm->capacity) {
- unsigned char *newtext;
- prgm->capacity += 512;
- newtext = (unsigned char *) malloc(prgm->capacity);
- if (newtext == NULL)
- // Failed to grow program; abort.
- return false;
- for (pos = 0; pos < pc; pos++)
- newtext[pos] = prgm->text[pos];
- for (pos = pc; pos < prgm->size; pos++)
- newtext[pos + growth] = prgm->text[pos];
- if (prgm->text != NULL)
- free(prgm->text);
- prgm->text = newtext;
- } else {
- for (pos = prgm->size - 1; pos >= pc; pos--)
- prgm->text[pos + growth] = prgm->text[pos];
- }
- prgm->size += growth;
- oldpc -= growth;
- phloat p;
- p.bcd = double2bcd(d, true);
- b = (unsigned char *) &p;
- for (j = 0; j < (int) sizeof(phloat); j++)
- prgm->text[pc++] = *b++;
- #else
- fake_bcd bcd;
- int j;
- unsigned char *b = (unsigned char *) &bcd;
- for (j = 0; j < (int) sizeof(fake_bcd); j++)
- *b++ = prgm->text[pc++];
- double dbl = bcd2double(bcd.d_, state_file_has_old_bcd);
- int inf = isinf(dbl);
- if (inf > 0)
- dbl = POS_HUGE_PHLOAT;
- else if (inf < 0)
- dbl = NEG_HUGE_PHLOAT;
- else if (dbl == 0) {
- if (bcd.d_[0] != 0)
- if ((bcd.d_[P] & 0x8000) == 0)
- dbl = POS_TINY_PHLOAT;
- else
- dbl = NEG_TINY_PHLOAT;
- }
- pc -= sizeof(fake_bcd);
- b = (unsigned char *) &dbl;
- for (j = 0; j < (int) sizeof(double); j++)
- prgm->text[pc++] = *b++;
- int shrinkage = sizeof(fake_bcd) - sizeof(double);
- prgm->size -= shrinkage;
- for (int4 pos = pc; pos < prgm->size; pos++)
- prgm->text[pos] = prgm->text[pos + shrinkage];
- oldpc += shrinkage;
- #endif
- break;
- }
- oldpc += pc - prevpc;
- }
- }
- current_prgm = saved_prgm;
- pc = saved_pc;
- return true;
- }
- #ifdef BIGSTACK
- static stack_item* stack_item_pool = NULL;
- static int MAX_STACK_SIZE = 40;
- stack_item* new_stack_item(vartype* v) {
- stack_item* si = NULL;
- if (stack_item_pool == NULL)
- si = (stack_item*)malloc(sizeof(stack_item));
- else {
- si = stack_item_pool;
- stack_item_pool = si->next;
- }
- si->var = v;
- si->next = NULL;
- return si;
- }
- void free_stack_item(stack_item* si) {
- si->next = stack_item_pool;
- stack_item_pool = si;
- si->var = NULL;
- }
- /* Debug method to verify the integrity of the stack */
- int big_stack_verify() {
- stack_item *si = bigstack_head;
- int size = 0;
- while (si != NULL) {
- si = si->next;
- size++;
- /* If size is crazy big then we are probably in an infinite loop. */
- if (size > MAX_STACK_SIZE*10) {
- return 1;
- }
- }
- if (size > 0 && size + 4 != stacksize) {
- return 2;
- }
- if (stacksize > MAX_STACK_SIZE) {
- return 3;
- }
- if (stacksize < 3) {
- return 5;
- }
-
- return 0;
- }
- void push_var_on_stack(vartype *var)
- {
- if (flags.f.f32)
- shift_big_stack_up();
- else
- free_vartype(reg_t);
-
- reg_t = reg_z;
- reg_z = reg_y;
- reg_y = reg_x;
- reg_x = var;
- }
-
- void pop_var_off_stack()
- {
- free_vartype(reg_x);
- reg_x = reg_y;
- reg_y = reg_z;
- reg_z = reg_t;
- if (flags.f.f32)
- shift_big_stack_down();
- else
- reg_t = dup_vartype(reg_t);
- }
-
- void shift_big_stack_up() {
- stacksize++;
- if (stacksize > 4) {
- stack_item* si = new_stack_item(reg_t);
- si->next = bigstack_head;
- bigstack_head = si;
-
- if (stacksize > MAX_STACK_SIZE) {
- /* Stack has grown too big, so remove last element, not
- the most efficient method, but well behaving programs
- should not trash the stack either */
- si = bigstack_head;
- while (si->next->next != NULL)
- si = si->next;
- free_vartype(si->next->var);
- free_stack_item(si->next);
- si->next = NULL;
- stacksize--;
- assert(stacksize == MAX_STACK_SIZE);
- }
- }
- else {
- if (stacksize == 4 && reg_z->type == TYPE_REAL && ((vartype_real*)reg_z)->x == 0)
- stacksize --;
- assert(stacksize == 3 || stacksize == 4);
- /* We can't move reg_t into the extended stack so we free it
- here, calling code depends on this behavior */
- free_vartype(reg_t);
- }
- assert(big_stack_verify() == 0);
- }
- void shift_big_stack_down() {
- stacksize--;
- if (bigstack_head == NULL) {
- reg_t = new_real(0);
- if (stacksize < 3) stacksize = 3;
- }
- else {
- assert(stacksize >= 4);
- reg_t = bigstack_head->var;
- stack_item* si = bigstack_head;
- bigstack_head = si->next;
- free_stack_item(si);
- }
- assert(big_stack_verify() == 0);
- }
- void clean_stack_item_pool() {
- while (stack_item_pool != NULL)
- {
- stack_item *si = stack_item_pool;
- stack_item_pool = stack_item_pool->next;
- free(si);
- }
- }
- #endif
- #ifdef IPHONE
- static void convert_bigstack_drop() {
- // This function is called when we've read an iPhone version state file
- // with version number 12 or 13. In those two versions, the DROP command
- // was at index 315 of the commands table, but that conflicted with
- // Underhill's COPAN extensions. In version 14 and later, I moved DROP
- // to index 329 to fix this clash. This will allow all extensions to
- // coexist in the future, should someone want to merge them all into one
- // build at some point -- and even if that never happens, at least now
- // all programs in all versions are encoded identically.
- for (int i = 0; i < prgms_count; i++) {
- int pc = 0;
- prgm_struct *prgm = prgms + i;
- while (true) {
- int command = prgm->text[pc++];
- int argtype = prgm->text[pc++];
- command |= (argtype & 240) << 4;
- argtype &= 15;
- if (command == CMD_END)
- break;
- if (command == 315) { // Pre-version-14 value of CMD_DROP
- prgm->text[pc - 2] = (unsigned char) CMD_DROP;
- prgm->text[pc - 1] = (unsigned char) ((CMD_DROP & 0xF00) >> 4 | argtype);
- }
- if ((command == CMD_GTO || command == CMD_XEQ)
- && (argtype == ARGTYPE_NUM || argtype == ARGTYPE_LCLBL)) {
- pc += 4;
- }
- switch (argtype) {
- case ARGTYPE_NUM:
- case ARGTYPE_NEG_NUM:
- case ARGTYPE_IND_NUM: {
- while ((prgm->text[pc++] & 128) == 0);
- break;
- }
- case ARGTYPE_STK:
- case ARGTYPE_IND_STK:
- case ARGTYPE_COMMAND:
- case ARGTYPE_LCLBL:
- pc++;
- break;
- case ARGTYPE_STR:
- case ARGTYPE_IND_STR: {
- pc += prgm->text[pc] + 1;
- break;
- }
- case ARGTYPE_DOUBLE:
- pc += sizeof(phloat);
- break;
- }
- }
- }
- }
-
-
- static bool persist_undo() {
-
- if (!write_int(snapshot_count))
- return false;
-
- if (!write_int(undo_pos))
- return false;
-
- snapshot *snap = snapshot_head;
- while (snap != NULL)
- {
- if (!write_chars(snap->describe))
- return false;
-
- stack_item *si = snap->stack_item_head;
-
- int size = 0;
- // get stack size
- while (si != NULL) {
- size++;
- si = si->next;
- }
-
- if (!write_int(size))
- return false;
-
- si = snap->stack_item_head;
- while (si != NULL) {
- if (!persist_vartype(si->var))
- return false;
- si = si->next;
- }
-
- snap = snap->next;
- }
-
- return true;
- }
-
- static bool unpersist_undo() {
-
- snapshot_head = NULL;
-
- if (!read_int(&snapshot_count))
- return false;
-
- if (!read_int(&undo_pos))
- return false;
-
- int count = 0;
- snapshot *snap = NULL;
- while (count < snapshot_count) {
-
- if (count == 0) {
- snapshot_head = (snapshot*)malloc(sizeof(snapshot));
- snap = snapshot_head;
- }
- else {
- snap->next = (snapshot*)malloc(sizeof(snapshot));
- snap = snap->next;
- }
-
- snap->next = NULL;
- snap->stack_item_head = NULL;
- if (!read_chars(snap->describe, DESC_SIZE))
- return false;
-
- int size = 0;
- // stack size of this snapshot
- if (!read_int(&size))
- return false;
- stack_item *last_si = NULL;
- while (size-- > 0)
- {
- vartype *v = NULL;
- if (!unpersist_vartype(&v))
- return false;
- stack_item *si = new_stack_item(v);
- si->next = NULL;
- if (last_si == NULL) {
- snap->stack_item_head = si;
- }
- else {
- last_si->next = si;
- }
-
- last_si = si;
- }
- count++;
- }
-
- return true;
- }
-
-
-
- #endif
- #ifdef ANDROID
- void reinitialize_globals() {
- /* The Android version may call core_init() after core_quit(), in other
- * words, the globals may live for more than one session. This caused
- * crashes in the initial builds, because of course global initializers
- * are only invoked once, and core_quit() did not bother to clean things
- * up so that core_init() would be able to run safely.
- * In my defense, this wasn't sloppy coding; core_quit() does deallocate
- * everything -- I've tested Free42 for memory leaks using POSE many
- * times, and it is solid in that regard. The dangling pointers left
- * by core_quit() are never a problem as long as core_init() and
- * core_quit() are only called once per process.
- * Anyway: the following are re-initializations of some globals that
- * could cause double-free() memory corruption, or other (less fatal, but
- * still annoying) misbehaviors if left as they are.
- */
- reg_x = NULL;
- reg_y = NULL;
- reg_z = NULL;
- reg_t = NULL;
- reg_lastx = NULL;
- reg_alpha_length = 0;
- vars_capacity = 0;
- vars_count = 0;
- vars = NULL;
- prgms_capacity = 0;
- prgms_count = 0;
- prgms = NULL;
- labels_capacity = 0;
- labels_count = 0;
- labels = NULL;
- current_prgm = -1;
- prgm_highlight_row = 0;
- mode_interruptible = NULL;
- mode_pause = false;
- baseapp = 0;
- deferred_print = 0;
- keybuf_head = 0;
- keybuf_tail = 0;
- remove_program_catalog = 0;
- rtn_sp = 0;
- }
- #endif