PageRenderTime 54ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/Classes/common-42s/core_globals.cc

https://bitbucket.org/byronvf/42x
C++ | 3488 lines | 3466 code | 6 blank | 16 comment | 0 complexity | f95c7bc6f32c9f486f19b1de23ead199 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*****************************************************************************
  2. * Free42 -- an HP-42S calculator simulator
  3. * Copyright (C) 2004-2011 Thomas Okken
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License, version 2,
  7. * as published by the Free Software Foundation.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, see http://www.gnu.org/licenses/.
  16. *****************************************************************************/
  17. #include <stdlib.h>
  18. #include "core_globals.h"
  19. #include "core_commands2.h"
  20. #include "core_commands4.h"
  21. #include "core_display.h"
  22. #include "core_helpers.h"
  23. #include "core_main.h"
  24. #include "core_math1.h"
  25. #include "core_tables.h"
  26. #include "core_variables.h"
  27. #include "undo.h"
  28. #include "shell.h"
  29. error_spec errors[] = {
  30. { /* NONE */ NULL, 0 },
  31. { /* ALPHA_DATA_IS_INVALID */ "Alpha Data Is Invalid", 21 },
  32. { /* INSUFFICIENT_MEMORY */ "Insufficient Memory", 19 },
  33. { /* NOT_YET_IMPLEMENTED */ "Not Yet Implemented", 19 },
  34. { /* OUT_OF_RANGE */ "Out of Range", 12 },
  35. { /* DIVIDE_BY_0 */ "Divide by 0", 11 },
  36. { /* INVALID_TYPE */ "Invalid Type", 12 },
  37. { /* INVALID_DATA */ "Invalid Data", 12 },
  38. { /* DIMENSION_ERROR */ "Dimension Error", 15 },
  39. { /* SIZE_ERROR */ "Size Error", 10 },
  40. { /* INTERNAL_ERROR */ "Internal Error", 14 },
  41. { /* NONEXISTENT */ "Nonexistent", 11 },
  42. { /* RESTRICTED_OPERATION */ "Restricted Operation", 20 },
  43. { /* YES */ "Yes", 3 },
  44. { /* NO */ "No", 2 },
  45. { /* STOP */ NULL, 0 },
  46. { /* LABEL_NOT_FOUND */ "Label Not Found", 15 },
  47. { /* NO_REAL_VARIABLES */ "No Real Variables", 17 },
  48. { /* NO_COMPLEX_VARIABLES */ "No Complex Variables", 20 },
  49. { /* NO_MATRIX_VARIABLES */ "No Matrix Variables", 19 },
  50. { /* NO_MENU_VARIABLES */ "No Menu Variables", 17 },
  51. { /* STAT_MATH_ERROR */ "Stat Math Error", 15 },
  52. { /* INVALID_FORECAST_MODEL */ "Invalid Forecast Model", 22 },
  53. { /* SOLVE_INTEG_RTN_LOST */ "Solve/Integ RTN Lost", 20 },
  54. { /* SINGULAR_MATRIX */ "Singular Matrix", 15 },
  55. { /* SOLVE_SOLVE */ "Solve(Solve)", 12 },
  56. { /* INTEG_INTEG */ "Integ(Integ)", 12 },
  57. { /* RUN */ NULL, 0 },
  58. { /* INTERRUPTED */ "Interrupted", 11 },
  59. { /* PRINTING_IS_DISABLED */ "Printing Is Disabled", 20 },
  60. { /* INTERRUPTIBLE */ NULL, 0 },
  61. { /* NO_VARIABLES */ "No Variables", 12 }
  62. };
  63. menu_spec menus[] = {
  64. { /* MENU_ALPHA1 */ MENU_NONE, MENU_ALPHA2, MENU_ALPHA2,
  65. { { MENU_ALPHA_ABCDE1, 5, "ABCDE" },
  66. { MENU_ALPHA_FGHI, 4, "FGHI" },
  67. { MENU_ALPHA_JKLM, 4, "JKLM" },
  68. { MENU_ALPHA_NOPQ1, 4, "NOPQ" },
  69. { MENU_ALPHA_RSTUV1, 5, "RSTUV" },
  70. { MENU_ALPHA_WXYZ, 4, "WXYZ" } } },
  71. { /* MENU_ALPHA2 */ MENU_NONE, MENU_ALPHA1, MENU_ALPHA1,
  72. { { MENU_ALPHA_PAREN, 5, "( [ {" },
  73. { MENU_ALPHA_ARROW, 3, "\020^\016" },
  74. { MENU_ALPHA_COMP, 5, "< = >" },
  75. { MENU_ALPHA_MATH, 4, "MATH" },
  76. { MENU_ALPHA_PUNC1, 4, "PUNC" },
  77. { MENU_ALPHA_MISC1, 4, "MISC" } } },
  78. { /* MENU_ALPHA_ABCDE1 */ MENU_ALPHA1, MENU_ALPHA_ABCDE2, MENU_ALPHA_ABCDE2,
  79. { { MENU_NONE, 1, "A" },
  80. { MENU_NONE, 1, "B" },
  81. { MENU_NONE, 1, "C" },
  82. { MENU_NONE, 1, "D" },
  83. { MENU_NONE, 1, "E" },
  84. { MENU_NONE, 1, " " } } },
  85. { /* MENU_ALPHA_ABCDE2 */ MENU_ALPHA1, MENU_ALPHA_ABCDE1, MENU_ALPHA_ABCDE1,
  86. { { MENU_NONE, 1, "\026" },
  87. { MENU_NONE, 1, "\024" },
  88. { MENU_NONE, 1, "\031" },
  89. { MENU_NONE, 1, " " },
  90. { MENU_NONE, 1, " " },
  91. { MENU_NONE, 1, " " } } },
  92. { /* MENU_ALPHA_FGHI */ MENU_ALPHA1, MENU_NONE, MENU_NONE,
  93. { { MENU_NONE, 1, "F" },
  94. { MENU_NONE, 1, "G" },
  95. { MENU_NONE, 1, "H" },
  96. { MENU_NONE, 1, "I" },
  97. { MENU_NONE, 1, " " },
  98. { MENU_NONE, 1, " " } } },
  99. { /* MENU_ALPHA_JKLM */ MENU_ALPHA1, MENU_NONE, MENU_NONE,
  100. { { MENU_NONE, 1, "J" },
  101. { MENU_NONE, 1, "K" },
  102. { MENU_NONE, 1, "L" },
  103. { MENU_NONE, 1, "M" },
  104. { MENU_NONE, 1, " " },
  105. { MENU_NONE, 1, " " } } },
  106. { /* MENU_ALPHA_NOPQ1 */ MENU_ALPHA1, MENU_ALPHA_NOPQ2, MENU_ALPHA_NOPQ2,
  107. { { MENU_NONE, 1, "N" },
  108. { MENU_NONE, 1, "O" },
  109. { MENU_NONE, 1, "P" },
  110. { MENU_NONE, 1, "Q" },
  111. { MENU_NONE, 1, " " },
  112. { MENU_NONE, 1, " " } } },
  113. { /* MENU_ALPHA_NOPQ2 */ MENU_ALPHA1, MENU_ALPHA_NOPQ1, MENU_ALPHA_NOPQ1,
  114. { { MENU_NONE, 1, "\025" },
  115. { MENU_NONE, 1, "\034" },
  116. { MENU_NONE, 1, " " },
  117. { MENU_NONE, 1, " " },
  118. { MENU_NONE, 1, " " },
  119. { MENU_NONE, 1, " " } } },
  120. { /* MENU_ALPHA_RSTUV1 */ MENU_ALPHA1, MENU_ALPHA_RSTUV2, MENU_ALPHA_RSTUV2,
  121. { { MENU_NONE, 1, "R" },
  122. { MENU_NONE, 1, "S" },
  123. { MENU_NONE, 1, "T" },
  124. { MENU_NONE, 1, "U" },
  125. { MENU_NONE, 1, "V" },
  126. { MENU_NONE, 1, " " } } },
  127. { /* MENU_ALPHA_RSTUV2 */ MENU_ALPHA1, MENU_ALPHA_RSTUV1, MENU_ALPHA_RSTUV1,
  128. { { MENU_NONE, 1, " " },
  129. { MENU_NONE, 1, " " },
  130. { MENU_NONE, 1, " " },
  131. { MENU_NONE, 1, "\035" },
  132. { MENU_NONE, 1, " " },
  133. { MENU_NONE, 1, " " } } },
  134. { /* MENU_ALPHA_WXYZ */ MENU_ALPHA1, MENU_NONE, MENU_NONE,
  135. { { MENU_NONE, 1, "W" },
  136. { MENU_NONE, 1, "X" },
  137. { MENU_NONE, 1, "Y" },
  138. { MENU_NONE, 1, "Z" },
  139. { MENU_NONE, 1, " " },
  140. { MENU_NONE, 1, " " } } },
  141. { /* MENU_ALPHA_PAREN */ MENU_ALPHA2, MENU_NONE, MENU_NONE,
  142. { { MENU_NONE, 1, "(" },
  143. { MENU_NONE, 1, ")" },
  144. { MENU_NONE, 1, "[" },
  145. { MENU_NONE, 1, "]" },
  146. { MENU_NONE, 1, "{" },
  147. { MENU_NONE, 1, "}" } } },
  148. { /* MENU_ALPHA_ARROW */ MENU_ALPHA2, MENU_NONE, MENU_NONE,
  149. { { MENU_NONE, 1, "\020" },
  150. { MENU_NONE, 1, "^" },
  151. { MENU_NONE, 1, "\016" },
  152. { MENU_NONE, 1, "\017" },
  153. { MENU_NONE, 1, " " },
  154. { MENU_NONE, 1, " " } } },
  155. { /* MENU_ALPHA_COMP */ MENU_ALPHA2, MENU_NONE, MENU_NONE,
  156. { { MENU_NONE, 1, "=" },
  157. { MENU_NONE, 1, "\014" },
  158. { MENU_NONE, 1, "<" },
  159. { MENU_NONE, 1, ">" },
  160. { MENU_NONE, 1, "\011" },
  161. { MENU_NONE, 1, "\013" } } },
  162. { /* MENU_ALPHA_MATH */ MENU_ALPHA2, MENU_NONE, MENU_NONE,
  163. { { MENU_NONE, 1, "\005" },
  164. { MENU_NONE, 1, "\003" },
  165. { MENU_NONE, 1, "\002" },
  166. { MENU_NONE, 1, "\027" },
  167. { MENU_NONE, 1, "\023" },
  168. { MENU_NONE, 1, "\021" } } },
  169. { /* MENU_ALPHA_PUNC1 */ MENU_ALPHA2, MENU_ALPHA_PUNC2, MENU_ALPHA_PUNC2,
  170. { { MENU_NONE, 1, "," },
  171. { MENU_NONE, 1, ";" },
  172. { MENU_NONE, 1, ":" },
  173. { MENU_NONE, 1, "!" },
  174. { MENU_NONE, 1, "?" },
  175. { MENU_NONE, 1, "\"" } } },
  176. { /* MENU_ALPHA_PUNC2 */ MENU_ALPHA2, MENU_ALPHA_PUNC1, MENU_ALPHA_PUNC1,
  177. { { MENU_NONE, 1, "\032" },
  178. { MENU_NONE, 1, "_" },
  179. { MENU_NONE, 1, "`" },
  180. { MENU_NONE, 1, "'" },
  181. { MENU_NONE, 1, "\010" },
  182. { MENU_NONE, 1, "\012" } } },
  183. { /* MENU_ALPHA_MISC1 */ MENU_ALPHA2, MENU_ALPHA_MISC2, MENU_ALPHA_MISC2,
  184. { { MENU_NONE, 1, "$" },
  185. { MENU_NONE, 1, "*" },
  186. { MENU_NONE, 1, "#" },
  187. { MENU_NONE, 1, "/" },
  188. { MENU_NONE, 1, "\037" },
  189. { MENU_NONE, 1, " " } } },
  190. { /* MENU_ALPHA_MISC2 */ MENU_ALPHA2, MENU_ALPHA_MISC1, MENU_ALPHA_MISC1,
  191. { { MENU_NONE, 1, "\022" },
  192. { MENU_NONE, 1, "&" },
  193. { MENU_NONE, 1, "@" },
  194. { MENU_NONE, 1, "\\" },
  195. { MENU_NONE, 1, "~" },
  196. { MENU_NONE, 1, "|" } } },
  197. { /* MENU_ST */ MENU_NONE, MENU_NONE, MENU_NONE,
  198. { { MENU_NONE, 4, "ST L" },
  199. { MENU_NONE, 4, "ST X" },
  200. { MENU_NONE, 4, "ST Y" },
  201. { MENU_NONE, 4, "ST Z" },
  202. { MENU_NONE, 4, "ST T" },
  203. { MENU_NONE, 0, "" } } },
  204. { /* MENU_IND_ST */ MENU_NONE, MENU_NONE, MENU_NONE,
  205. { { MENU_NONE, 3, "IND" },
  206. { MENU_NONE, 4, "ST L" },
  207. { MENU_NONE, 4, "ST X" },
  208. { MENU_NONE, 4, "ST Y" },
  209. { MENU_NONE, 4, "ST Z" },
  210. { MENU_NONE, 4, "ST T" } } },
  211. { /* MENU_IND */ MENU_NONE, MENU_NONE, MENU_NONE,
  212. { { MENU_NONE, 3, "IND" },
  213. { MENU_NONE, 0, "" },
  214. { MENU_NONE, 0, "" },
  215. { MENU_NONE, 0, "" },
  216. { MENU_NONE, 0, "" },
  217. { MENU_NONE, 0, "" } } },
  218. { /* MENU_MODES1 */ MENU_NONE, MENU_MODES2, MENU_MODES2,
  219. { { 0x2000 + CMD_DEG, 0, "" },
  220. { 0x2000 + CMD_RAD, 0, "" },
  221. { 0x2000 + CMD_GRAD, 0, "" },
  222. { 0x1000 + CMD_NULL, 0, "" },
  223. { 0x2000 + CMD_RECT, 0, "" },
  224. { 0x2000 + CMD_POLAR, 0, "" } } },
  225. { /* MENU_MODES2 */ MENU_NONE, MENU_MODES1, MENU_MODES1,
  226. { { 0x1000 + CMD_SIZE, 0, "" },
  227. { 0x2000 + CMD_QUIET, 0, "" },
  228. { 0x2000 + CMD_CPXRES, 0, "" },
  229. { 0x2000 + CMD_REALRES, 0, "" },
  230. { 0x2000 + CMD_KEYASN, 0, "" },
  231. { 0x2000 + CMD_LCLBL, 0, "" } } },
  232. { /* MENU_DISP */ MENU_NONE, MENU_NONE, MENU_NONE,
  233. { { 0x2000 + CMD_FIX, 0, "" },
  234. { 0x2000 + CMD_SCI, 0, "" },
  235. { 0x2000 + CMD_ENG, 0, "" },
  236. { 0x2000 + CMD_ALL, 0, "" },
  237. { 0x2000 + CMD_RDXDOT, 0, "" },
  238. { 0x2000 + CMD_RDXCOMMA, 0, "" } } },
  239. #ifdef BIGSTACK
  240. { /* MENU_CLEAR1 */ MENU_NONE, MENU_CLEAR2, MENU_CLEAR3,
  241. #else
  242. { /* MENU_CLEAR1 */ MENU_NONE, MENU_CLEAR2, MENU_CLEAR2,
  243. #endif
  244. { { 0x1000 + CMD_CLSIGMA, 0, "" },
  245. { 0x1000 + CMD_CLP, 0, "" },
  246. { 0x1000 + CMD_CLV, 0, "" },
  247. { 0x1000 + CMD_CLST, 0, "" },
  248. { 0x1000 + CMD_CLA, 0, "" },
  249. { 0x1000 + CMD_CLX, 0, "" } } },
  250. #ifdef BIGSTACK
  251. { /* MENU_CLEAR2 */ MENU_NONE, MENU_CLEAR3, MENU_CLEAR1,
  252. #else
  253. { /* MENU_CLEAR2 */ MENU_NONE, MENU_CLEAR1, MENU_CLEAR1,
  254. #endif
  255. { { 0x1000 + CMD_CLRG, 0, "" },
  256. { 0x1000 + CMD_DEL, 0, "" },
  257. { 0x1000 + CMD_CLKEYS, 0, "" },
  258. { 0x1000 + CMD_CLLCD, 0, "" },
  259. { 0x1000 + CMD_CLMENU, 0, "" },
  260. { 0x1000 + CMD_CLALLa, 0, "" } } },
  261. { /* MENU_CONVERT1 */ MENU_NONE, MENU_CONVERT2, MENU_CONVERT4,
  262. { { 0, 0, "" },
  263. { 0, 0, "" },
  264. { 0, 0, "" },
  265. { 0, 0, "" },
  266. { 0, 0, "" },
  267. { 0, 0, "" } } },
  268. { /* MENU_CONVERT2 */ MENU_NONE, MENU_CONVERT3, MENU_CONVERT1,
  269. { { 0 , 0, "" },
  270. { 0, 0, "" },
  271. { 0, 0, "" },
  272. { 0, 0, "" },
  273. { 0, 0, "" },
  274. { 0, 0, "" } } },
  275. { /* MENU_FLAGS */ MENU_NONE, MENU_NONE, MENU_NONE,
  276. { { 0x1000 + CMD_SF, 0, "" },
  277. { 0x1000 + CMD_CF, 0, "" },
  278. { 0x1000 + CMD_FS_T, 0, "" },
  279. { 0x1000 + CMD_FC_T, 0, "" },
  280. { 0x1000 + CMD_FSC_T, 0, "" },
  281. { 0x1000 + CMD_FCC_T, 0, "" } } },
  282. { /* MENU_PROB */ MENU_NONE, MENU_NONE, MENU_NONE,
  283. { { 0x1000 + CMD_COMB, 0, "" },
  284. { 0x1000 + CMD_PERM, 0, "" },
  285. { 0x1000 + CMD_FACT, 0, "" },
  286. { 0x1000 + CMD_GAMMA, 0, "" },
  287. { 0x1000 + CMD_RAN, 0, "" },
  288. { 0x1000 + CMD_SEED, 0, "" } } },
  289. { /* MENU_CUSTOM1 */ MENU_NONE, MENU_CUSTOM2, MENU_CUSTOM3,
  290. { { 0, 0, "" },
  291. { 0, 0, "" },
  292. { 0, 0, "" },
  293. { 0, 0, "" },
  294. { 0, 0, "" },
  295. { 0, 0, "" } } },
  296. { /* MENU_CUSTOM2 */ MENU_NONE, MENU_CUSTOM3, MENU_CUSTOM1,
  297. { { 0, 0, "" },
  298. { 0, 0, "" },
  299. { 0, 0, "" },
  300. { 0, 0, "" },
  301. { 0, 0, "" },
  302. { 0, 0, "" } } },
  303. { /* MENU_CUSTOM3 */ MENU_NONE, MENU_CUSTOM1, MENU_CUSTOM2,
  304. { { 0, 0, "" },
  305. { 0, 0, "" },
  306. { 0, 0, "" },
  307. { 0, 0, "" },
  308. { 0, 0, "" },
  309. { 0, 0, "" } } },
  310. { /* MENU_PGM_FCN1 */ MENU_NONE, MENU_PGM_FCN2, MENU_PGM_FCN4,
  311. { { 0x1000 + CMD_LBL, 0, "" },
  312. { 0x1000 + CMD_RTN, 0, "" },
  313. { 0x1000 + CMD_INPUT, 0, "" },
  314. { 0x1000 + CMD_VIEW, 0, "" },
  315. { 0x1000 + CMD_AVIEW, 0, "" },
  316. { 0x1000 + CMD_XEQ, 0, "" } } },
  317. { /* MENU_PGM_FCN2 */ MENU_NONE, MENU_PGM_FCN3, MENU_PGM_FCN1,
  318. { { MENU_PGM_XCOMP0, 3, "X?0" },
  319. { MENU_PGM_XCOMPY, 3, "X?Y" },
  320. { 0x1000 + CMD_PROMPT, 0, "" },
  321. { 0x1000 + CMD_PSE, 0, "" },
  322. { 0x1000 + CMD_ISG, 0, "" },
  323. { 0x1000 + CMD_DSE, 0, "" } } },
  324. { /* MENU_PGM_FCN3 */ MENU_NONE, MENU_PGM_FCN4, MENU_PGM_FCN2,
  325. { { 0x1000 + CMD_AIP, 0, "" },
  326. { 0x1000 + CMD_XTOA, 0, "" },
  327. { 0x1000 + CMD_AGRAPH, 0, "" },
  328. { 0x1000 + CMD_PIXEL, 0, "" },
  329. { 0x1000 + CMD_BEEP, 0, "" },
  330. { 0x1000 + CMD_TONE, 0, "" } } },
  331. { /* MENU_PGM_FCN4 */ MENU_NONE, MENU_PGM_FCN1, MENU_PGM_FCN3,
  332. { { 0x1000 + CMD_MVAR, 0, "" },
  333. { 0x1000 + CMD_VARMENU, 0, "" },
  334. { 0x1000 + CMD_GETKEY, 0, "" },
  335. { 0x1000 + CMD_MENU, 0, "" },
  336. { 0x1000 + CMD_KEYG, 0, "" },
  337. { 0x1000 + CMD_KEYX, 0, "" } } },
  338. { /* MENU_PGM_XCOMP0 */ MENU_PGM_FCN2, MENU_NONE, MENU_NONE,
  339. { { 0x1000 + CMD_X_EQ_0, 0, "" },
  340. { 0x1000 + CMD_X_NE_0, 0, "" },
  341. { 0x1000 + CMD_X_LT_0, 0, "" },
  342. { 0x1000 + CMD_X_GT_0, 0, "" },
  343. { 0x1000 + CMD_X_LE_0, 0, "" },
  344. { 0x1000 + CMD_X_GE_0, 0, "" } } },
  345. { /* MENU_PGM_XCOMPY */ MENU_PGM_FCN2, MENU_NONE, MENU_NONE,
  346. { { 0x1000 + CMD_X_EQ_Y, 0, "" },
  347. { 0x1000 + CMD_X_NE_Y, 0, "" },
  348. { 0x1000 + CMD_X_LT_Y, 0, "" },
  349. { 0x1000 + CMD_X_GT_Y, 0, "" },
  350. { 0x1000 + CMD_X_LE_Y, 0, "" },
  351. { 0x1000 + CMD_X_GE_Y, 0, "" } } },
  352. { /* MENU_PRINT1 */ MENU_NONE, MENU_PRINT2, MENU_PRINT3,
  353. { { 0x1000 + CMD_PRSIGMA, 0, "" },
  354. { 0x1000 + CMD_PRP, 0, "" },
  355. { 0x1000 + CMD_PRV, 0, "" },
  356. { 0x1000 + CMD_PRSTK, 0, "" },
  357. { 0x1000 + CMD_PRA, 0, "" },
  358. { 0x1000 + CMD_PRX, 0, "" } } },
  359. { /* MENU_PRINT2 */ MENU_NONE, MENU_PRINT3, MENU_PRINT1,
  360. { { 0x1000 + CMD_PRUSR, 0, "" },
  361. { 0x1000 + CMD_LIST, 0, "" },
  362. { 0x1000 + CMD_ADV, 0, "" },
  363. { 0x1000 + CMD_PRLCD, 0, "" },
  364. { 0x1000 + CMD_NULL, 0, "" },
  365. { 0x1000 + CMD_DELAY, 0, "" } } },
  366. { /* MENU_PRINT3 */ MENU_NONE, MENU_PRINT1, MENU_PRINT2,
  367. { { 0x2000 + CMD_PON, 0, "" },
  368. { 0x2000 + CMD_POFF, 0, "" },
  369. { 0x1000 + CMD_NULL, 0, "" },
  370. { 0x2000 + CMD_MAN, 0, "" },
  371. { 0x2000 + CMD_NORM, 0, "" },
  372. { 0x2000 + CMD_TRACE, 0, "" } } },
  373. { /* MENU_TOP_FCN */ MENU_NONE, MENU_NONE, MENU_NONE,
  374. { { 0x1000 + CMD_SIGMAADD, 0, "" },
  375. { 0x1000 + CMD_INV, 0, "" },
  376. { 0x1000 + CMD_SQRT, 0, "" },
  377. { 0x1000 + CMD_LOG, 0, "" },
  378. { 0x1000 + CMD_LN, 0, "" },
  379. { 0x1000 + CMD_XEQ, 0, "" } } },
  380. { /* MENU_CATALOG */ MENU_NONE, MENU_NONE, MENU_NONE,
  381. { { 0, 0, "" },
  382. { 0, 0, "" },
  383. { 0, 0, "" },
  384. { 0, 0, "" },
  385. { 0, 0, "" },
  386. { 0, 0, "" } } },
  387. { /* MENU_BLANK */ MENU_NONE, MENU_NONE, MENU_NONE,
  388. { { 0, 0, "" },
  389. { 0, 0, "" },
  390. { 0, 0, "" },
  391. { 0, 0, "" },
  392. { 0, 0, "" },
  393. { 0, 0, "" } } },
  394. { /* MENU_PROGRAMMABLE */ MENU_NONE, MENU_NONE, MENU_NONE,
  395. { { 0, 0, "" },
  396. { 0, 0, "" },
  397. { 0, 0, "" },
  398. { 0, 0, "" },
  399. { 0, 0, "" },
  400. { 0, 0, "" } } },
  401. { /* MENU_VARMENU */ MENU_NONE, MENU_NONE, MENU_NONE,
  402. { { 0, 0, "" },
  403. { 0, 0, "" },
  404. { 0, 0, "" },
  405. { 0, 0, "" },
  406. { 0, 0, "" },
  407. { 0, 0, "" } } },
  408. { /* MENU_STAT1 */ MENU_NONE, MENU_STAT2, MENU_STAT2,
  409. { { 0x1000 + CMD_SIGMAADD, 0, "" },
  410. { 0x1000 + CMD_SUM, 0, "" },
  411. { 0x1000 + CMD_MEAN, 0, "" },
  412. { 0x1000 + CMD_WMEAN, 0, "" },
  413. { 0x1000 + CMD_SDEV, 0, "" },
  414. { MENU_STAT_CFIT, 4, "CFIT" } } },
  415. { /* MENU_STAT2 */ MENU_NONE, MENU_STAT1, MENU_STAT1,
  416. { { 0x2000 + CMD_ALLSIGMA, 0, "" },
  417. { 0x2000 + CMD_LINSIGMA, 0, "" },
  418. { 0x1000 + CMD_NULL, 0, "" },
  419. { 0x1000 + CMD_NULL, 0, "" },
  420. { 0x1000 + CMD_SIGMAREG, 0, "" },
  421. { 0x1000 + CMD_SIGMAREG_T, 0, "" } } },
  422. { /* MENU_STAT_CFIT */ MENU_STAT1, MENU_NONE, MENU_NONE,
  423. { { 0x1000 + CMD_FCSTX, 0, "" },
  424. { 0x1000 + CMD_FCSTY, 0, "" },
  425. { 0x1000 + CMD_SLOPE, 0, "" },
  426. { 0x1000 + CMD_YINT, 0, "" },
  427. { 0x1000 + CMD_CORR, 0, "" },
  428. { MENU_STAT_MODL, 4, "MODL" } } },
  429. { /* MENU_STAT_MODL */ MENU_STAT_CFIT, MENU_NONE, MENU_NONE,
  430. { { 0x2000 + CMD_LINF, 0, "" },
  431. { 0x2000 + CMD_LOGF, 0, "" },
  432. { 0x2000 + CMD_EXPF, 0, "" },
  433. { 0x2000 + CMD_PWRF, 0, "" },
  434. { 0x1000 + CMD_NULL, 0, "" },
  435. { 0x1000 + CMD_BEST, 0, "" } } },
  436. { /* MENU_MATRIX1 */ MENU_NONE, MENU_MATRIX2, MENU_MATRIX3,
  437. { { 0x1000 + CMD_NEWMAT, 0, "" },
  438. { 0x1000 + CMD_INVRT, 0, "" },
  439. { 0x1000 + CMD_DET, 0, "" },
  440. { 0x1000 + CMD_TRANS, 0, "" },
  441. { 0x1000 + CMD_SIMQ, 0, "" },
  442. { 0x1000 + CMD_EDIT, 0, "" } } },
  443. { /* MENU_MATRIX2 */ MENU_NONE, MENU_MATRIX3, MENU_MATRIX1,
  444. { { 0x1000 + CMD_DOT, 0, "" },
  445. { 0x1000 + CMD_CROSS, 0, "" },
  446. { 0x1000 + CMD_UVEC, 0, "" },
  447. { 0x1000 + CMD_DIM, 0, "" },
  448. { 0x1000 + CMD_INDEX, 0, "" },
  449. { 0x1000 + CMD_EDITN, 0, "" } } },
  450. { /* MENU_MATRIX3 */ MENU_NONE, MENU_MATRIX1, MENU_MATRIX2,
  451. { { 0x1000 + CMD_STOIJ, 0, "" },
  452. { 0x1000 + CMD_RCLIJ, 0, "" },
  453. { 0x1000 + CMD_STOEL, 0, "" },
  454. { 0x1000 + CMD_RCLEL, 0, "" },
  455. { 0x1000 + CMD_PUTM, 0, "" },
  456. { 0x1000 + CMD_GETM, 0, "" } } },
  457. { /* MENU_MATRIX_SIMQ */ MENU_MATRIX1, MENU_NONE, MENU_NONE,
  458. { { 0x1000 + CMD_MATA, 0, "" },
  459. { 0x1000 + CMD_MATB, 0, "" },
  460. { 0x1000 + CMD_MATX, 0, "" },
  461. { 0x1000 + CMD_NULL, 0, "" },
  462. { 0x1000 + CMD_NULL, 0, "" },
  463. { 0x1000 + CMD_NULL, 0, "" } } },
  464. { /* MENU_MATRIX_EDIT1 */ MENU_NONE, MENU_MATRIX_EDIT2, MENU_MATRIX_EDIT2,
  465. { { 0x1000 + CMD_LEFT, 0, "" },
  466. { 0x1000 + CMD_OLD, 0, "" },
  467. { 0x1000 + CMD_UP, 0, "" },
  468. { 0x1000 + CMD_DOWN, 0, "" },
  469. { 0x1000 + CMD_GOTOROW, 0, "" },
  470. { 0x1000 + CMD_RIGHT, 0, "" } } },
  471. { /* MENU_MATRIX_EDIT2 */ MENU_NONE, MENU_MATRIX_EDIT1, MENU_MATRIX_EDIT1,
  472. { { 0x1000 + CMD_INSR, 0, "" },
  473. { 0x1000 + CMD_NULL, 0, "" },
  474. { 0x1000 + CMD_DELR, 0, "" },
  475. { 0x1000 + CMD_NULL, 0, "" },
  476. { 0x2000 + CMD_WRAP, 0, "" },
  477. { 0x2000 + CMD_GROW, 0, "" } } },
  478. { /* MENU_BASE */ MENU_NONE, MENU_NONE, MENU_NONE,
  479. { { 0x1000 + CMD_A_THRU_F, 0, "" },
  480. { 0x2000 + CMD_HEXM, 0, "" },
  481. { 0x2000 + CMD_DECM, 0, "" },
  482. { 0x2000 + CMD_OCTM, 0, "" },
  483. { 0x2000 + CMD_BINM, 0, "" },
  484. { MENU_BASE_LOGIC, 5, "LOGIC" } } },
  485. { /* MENU_BASE_A_THRU_F */ MENU_BASE, MENU_NONE, MENU_NONE,
  486. { { 0x4000, 1, "A" },
  487. { 0x4000, 1, "B" },
  488. { 0x4000, 1, "C" },
  489. { 0x4000, 1, "D" },
  490. { 0x4000, 1, "E" },
  491. { 0x4000, 1, "F" } } },
  492. { /* MENU_BASE_LOGIC */ MENU_BASE, MENU_NONE, MENU_NONE,
  493. { { 0x1000 + CMD_AND, 0, "" },
  494. { 0x1000 + CMD_OR, 0, "" },
  495. { 0x1000 + CMD_XOR, 0, "" },
  496. { 0x1000 + CMD_NOT, 0, "" },
  497. { 0x1000 + CMD_BIT_T, 0, "" },
  498. { 0x1000 + CMD_ROTXY, 0, "" } } },
  499. { /* MENU_SOLVE */ MENU_NONE, MENU_NONE, MENU_NONE,
  500. { { 0x1000 + CMD_MVAR, 0, "" },
  501. { 0x1000 + CMD_NULL, 0, "" },
  502. { 0x1000 + CMD_NULL, 0, "" },
  503. { 0x1000 + CMD_NULL, 0, "" },
  504. { 0x1000 + CMD_PGMSLV, 0, "" },
  505. { 0x1000 + CMD_SOLVE, 0, "" } } },
  506. { /* MENU_INTEG */ MENU_NONE, MENU_NONE, MENU_NONE,
  507. { { 0x1000 + CMD_MVAR, 0, "" },
  508. { 0x1000 + CMD_NULL, 0, "" },
  509. { 0x1000 + CMD_NULL, 0, "" },
  510. { 0x1000 + CMD_NULL, 0, "" },
  511. { 0x1000 + CMD_PGMINT, 0, "" },
  512. { 0x1000 + CMD_INTEG, 0, "" } } },
  513. { /* MENU_INTEG_PARAMS */ MENU_NONE, MENU_NONE, MENU_NONE,
  514. { { 0, 4, "LLIM" },
  515. { 0, 4, "ULIM" },
  516. { 0, 3, "ACC" },
  517. { 0x1000 + CMD_NULL, 0, "" },
  518. { 0x1000 + CMD_NULL, 0, "" },
  519. { 0, 1, "\003" } } },
  520. #ifdef BIGSTACK
  521. { /* MENU_CLEAR3 */ MENU_NONE, MENU_CLEAR1, MENU_CLEAR2,
  522. { { 0x1000 + CMD_DROP, 0, "" },
  523. { 0x1000 + CMD_UNDO, 0, "" },
  524. { 0x1000 + CMD_REDO, 0, "" },
  525. { 0x1000 + CMD_NULL, 0, "" },
  526. { 0x1000 + CMD_NULL, 0, "" },
  527. { 0x1000 + CMD_NULL, 0, "" } } },
  528. { /* MENU_CONVERT3 */ MENU_NONE, MENU_CONVERT4, MENU_CONVERT2,
  529. { { 0x1000 + CMD_TO_DEG, 0, "" },
  530. { 0x1000 + CMD_TO_RAD, 0, "" },
  531. { 0x1000 + CMD_TO_HR, 0, "" },
  532. { 0x1000 + CMD_TO_HMS, 0, "" },
  533. { 0x1000 + CMD_TO_REC, 0, "" },
  534. { 0x1000 + CMD_TO_POL, 0, "" } } },
  535. { /* MENU_CONVERT4 */ MENU_NONE, MENU_CONVERT1, MENU_CONVERT3,
  536. { { 0x1000 + CMD_IP, 0, "" },
  537. { 0x1000 + CMD_FP, 0, "" },
  538. { 0x1000 + CMD_RND, 0, "" },
  539. { 0x1000 + CMD_ABS, 0, "" },
  540. { 0x1000 + CMD_SIGN, 0, "" },
  541. { 0x1000 + CMD_MOD, 0, "" } } },
  542. { /* MENU_UNITS */ MENU_NONE, MENU_NONE, MENU_NONE,
  543. { { 0 , 0, "" },
  544. { 0, 0, "" },
  545. { 0, 0, "" },
  546. { 0, 0, "" },
  547. { 0, 0, "" },
  548. { 0, 0, "" } } },
  549. #endif
  550. };
  551. /* By how much do the variables, programs, and labels
  552. * arrays grow when they are full
  553. */
  554. #define VARS_INCREMENT 25
  555. #define PRGMS_INCREMENT 10
  556. #define LABELS_INCREMENT 10
  557. /* Registers */
  558. vartype *reg_x = NULL;
  559. vartype *reg_y = NULL;
  560. vartype *reg_z = NULL;
  561. vartype *reg_t = NULL;
  562. vartype *reg_lastx = NULL;
  563. int reg_alpha_length = 0;
  564. char reg_alpha[44];
  565. /* Flags */
  566. flags_struct flags;
  567. /* Variables */
  568. int vars_capacity = 0;
  569. int vars_count = 0;
  570. var_struct *vars = NULL;
  571. /* Programs */
  572. int prgms_capacity = 0;
  573. int prgms_count = 0;
  574. prgm_struct *prgms = NULL;
  575. int labels_capacity = 0;
  576. int labels_count = 0;
  577. label_struct *labels = NULL;
  578. int current_prgm = -1;
  579. int4 pc;
  580. int prgm_highlight_row = 0;
  581. int varmenu_length;
  582. char varmenu[7];
  583. int varmenu_rows;
  584. int varmenu_row;
  585. int varmenu_labellength[6];
  586. char varmenu_labeltext[6][7];
  587. int varmenu_role;
  588. bool mode_clall;
  589. int (*mode_interruptible)(int) = NULL;
  590. bool mode_stoppable;
  591. bool mode_command_entry;
  592. bool mode_number_entry;
  593. bool mode_alpha_entry;
  594. bool mode_shift;
  595. int mode_appmenu;
  596. int mode_plainmenu;
  597. bool mode_plainmenu_sticky;
  598. int mode_transientmenu;
  599. int mode_alphamenu;
  600. int mode_commandmenu;
  601. bool mode_running;
  602. bool mode_getkey;
  603. bool mode_pause = false;
  604. bool mode_disable_stack_lift; /* transient */
  605. bool mode_varmenu;
  606. bool mode_updown;
  607. int4 mode_sigma_reg;
  608. int mode_goose;
  609. bool mode_time_clktd;
  610. bool mode_time_clk24;
  611. bool mode_time_dmy;
  612. #if BIGSTACK
  613. stack_item *bigstack_head = NULL;
  614. /* True if we are currently operating with the extended stack */
  615. bool mode_rpl_enter = false;
  616. int stacksize = 4; /* stack size is always at least 4 */
  617. int last_pending_command = CMD_NONE;
  618. /* Keep track of what the stack type was before solve or integration */
  619. int orig_stack_type_before_solve = 0;
  620. #endif
  621. bool cllcd_cmd = false;
  622. phloat entered_number;
  623. int entered_string_length;
  624. char entered_string[15];
  625. int pending_command;
  626. arg_struct pending_command_arg;
  627. int xeq_invisible;
  628. /* Multi-keystroke commands -- edit state */
  629. /* Relevant when mode_command_entry != 0 */
  630. int incomplete_command;
  631. int incomplete_ind;
  632. int incomplete_alpha;
  633. int incomplete_length;
  634. int incomplete_maxdigits;
  635. int incomplete_argtype;
  636. int incomplete_num;
  637. char incomplete_str[7];
  638. int4 incomplete_saved_pc;
  639. int4 incomplete_saved_highlight_row;
  640. /* Command line handling temporaries */
  641. char cmdline[100];
  642. int cmdline_length;
  643. int cmdline_row;
  644. /* Matrix editor / matrix indexing */
  645. int matedit_mode; /* 0=off, 1=index, 2=edit, 3=editn */
  646. char matedit_name[7];
  647. int matedit_length;
  648. vartype *matedit_x;
  649. int4 matedit_i;
  650. int4 matedit_j;
  651. int matedit_prev_appmenu;
  652. /* INPUT */
  653. char input_name[11];
  654. int input_length;
  655. arg_struct input_arg;
  656. /* BASE application */
  657. int baseapp = 0;
  658. /* Random number generator */
  659. phloat random_number;
  660. /* NORM & TRACE mode: number waiting to be printed */
  661. int deferred_print = 0;
  662. /* Keystroke buffer - holds keystrokes received while
  663. * there is a program running.
  664. */
  665. int keybuf_head = 0;
  666. int keybuf_tail = 0;
  667. int keybuf[16];
  668. int remove_program_catalog = 0;
  669. bool bin_dec_mode_switch;
  670. bool state_file_has_old_bcd;
  671. /*******************/
  672. /* Private globals */
  673. /*******************/
  674. static bool state_bool_is_int;
  675. #define MAX_RTNS 8
  676. static int rtn_sp = 0;
  677. static int rtn_prgm[MAX_RTNS];
  678. static int4 rtn_pc[MAX_RTNS];
  679. typedef struct {
  680. int type;
  681. int4 rows;
  682. int4 columns;
  683. } matrix_persister;
  684. static int array_count;
  685. static int array_list_capacity;
  686. static void **array_list;
  687. static bool read_int(int *n) GLOBALS_SECT;
  688. static bool write_int(int n) GLOBALS_SECT;
  689. static bool read_int4(int4 *n) GLOBALS_SECT;
  690. static bool write_int4(int4 n) GLOBALS_SECT;
  691. static bool read_bool(bool *n) GLOBALS_SECT;
  692. static bool write_bool(bool n) GLOBALS_SECT;
  693. static bool array_list_grow() GLOBALS_SECT;
  694. static int array_list_search(void *array) GLOBALS_SECT;
  695. static bool persist_vartype(vartype *v) GLOBALS_SECT;
  696. static bool unpersist_vartype(vartype **v) GLOBALS_SECT;
  697. static void update_label_table(int prgm, int4 pc, int inserted) GLOBALS_SECT;
  698. static void invalidate_lclbls(int prgm_index) GLOBALS_SECT;
  699. static int pc_line_convert(int4 loc, int loc_is_pc) GLOBALS_SECT;
  700. static bool convert_programs() GLOBALS_SECT;
  701. #ifdef IPHONE
  702. static void convert_bigstack_drop() GLOBALS_SECT;
  703. static bool persist_undo() GLOBALS_SECT;
  704. static bool unpersist_undo() GLOBALS_SECT;
  705. #endif
  706. static bool array_list_grow() {
  707. if (array_count < array_list_capacity)
  708. return true;
  709. array_list_capacity += 10;
  710. void **p = (void **) realloc(array_list,
  711. array_list_capacity * sizeof(void *));
  712. if (p == NULL)
  713. return false;
  714. array_list = p;
  715. return true;
  716. }
  717. static int array_list_search(void *array) {
  718. for (int i = 0; i < array_count; i++)
  719. if (array_list[i] == array)
  720. return i;
  721. return -1;
  722. }
  723. static bool persist_vartype(vartype *v) {
  724. if (v == NULL) {
  725. int type = TYPE_NULL;
  726. return shell_write_saved_state(&type, sizeof(int));
  727. }
  728. switch (v->type) {
  729. case TYPE_REAL:
  730. return shell_write_saved_state(v, sizeof(vartype_real));
  731. case TYPE_COMPLEX:
  732. return shell_write_saved_state(v, sizeof(vartype_complex));
  733. case TYPE_STRING:
  734. return shell_write_saved_state(v, sizeof(vartype_string));
  735. case TYPE_REALMATRIX: {
  736. matrix_persister mp;
  737. vartype_realmatrix *rm = (vartype_realmatrix *) v;
  738. mp.type = rm->type;
  739. mp.rows = rm->rows;
  740. mp.columns = rm->columns;
  741. int4 size = mp.rows * mp.columns;
  742. bool must_write = true;
  743. if (rm->array->refcount > 1) {
  744. int n = array_list_search(rm->array);
  745. if (n == -1) {
  746. // A negative row count signals a new shared matrix
  747. mp.rows = -mp.rows;
  748. if (!array_list_grow())
  749. return false;
  750. array_list[array_count++] = rm->array;
  751. } else {
  752. // A zero row count means this matrix shares its data
  753. // with a previously written matrix
  754. mp.rows = 0;
  755. mp.columns = n;
  756. must_write = false;
  757. }
  758. }
  759. if (!shell_write_saved_state(&mp, sizeof(matrix_persister)))
  760. return false;
  761. if (must_write) {
  762. if (!shell_write_saved_state(rm->array->data,
  763. size * sizeof(phloat)))
  764. return false;
  765. if (!shell_write_saved_state(rm->array->is_string, size))
  766. return false;
  767. }
  768. return true;
  769. }
  770. case TYPE_COMPLEXMATRIX: {
  771. matrix_persister mp;
  772. vartype_complexmatrix *cm = (vartype_complexmatrix *) v;
  773. mp.type = cm->type;
  774. mp.rows = cm->rows;
  775. mp.columns = cm->columns;
  776. int4 size = mp.rows * mp.columns;
  777. bool must_write = true;
  778. if (cm->array->refcount > 1) {
  779. int n = array_list_search(cm->array);
  780. if (n == -1) {
  781. // A negative row count signals a new shared matrix
  782. mp.rows = -mp.rows;
  783. if (!array_list_grow())
  784. return false;
  785. array_list[array_count++] = cm->array;
  786. } else {
  787. // A zero row count means this matrix shares its data
  788. // with a previously written matrix
  789. mp.rows = 0;
  790. mp.columns = n;
  791. must_write = false;
  792. }
  793. }
  794. if (!shell_write_saved_state(&mp, sizeof(matrix_persister)))
  795. return false;
  796. if (must_write) {
  797. if (!shell_write_saved_state(cm->array->data,
  798. 2 * size * sizeof(phloat)))
  799. return false;
  800. }
  801. return true;
  802. }
  803. default:
  804. /* Should not happen */
  805. return true;
  806. }
  807. }
  808. // A few declarations to help unpersist_vartype get the offsets right,
  809. // in the case it needs to convert the state file.
  810. struct fake_bcd {
  811. short d_[P+1];
  812. };
  813. struct bin_real {
  814. int type;
  815. double x;
  816. };
  817. struct bin_complex {
  818. int type;
  819. double re, im;
  820. };
  821. struct dec_real {
  822. int type;
  823. fake_bcd x;
  824. };
  825. struct dec_complex {
  826. int type;
  827. fake_bcd re, im;
  828. };
  829. static bool unpersist_vartype(vartype **v) {
  830. int type;
  831. if (shell_read_saved_state(&type, sizeof(int)) != sizeof(int))
  832. return false;
  833. switch (type) {
  834. case TYPE_NULL: {
  835. *v = NULL;
  836. return true;
  837. }
  838. case TYPE_REAL: {
  839. vartype_real *r = (vartype_real *) new_real(0);
  840. if (r == NULL)
  841. return false;
  842. if (bin_dec_mode_switch) {
  843. #ifdef BCD_MATH
  844. int n = sizeof(bin_real) - sizeof(int);
  845. bin_real br;
  846. if (shell_read_saved_state(&br.type + 1, n) != n) {
  847. free_vartype((vartype *) r);
  848. return false;
  849. }
  850. r->x = br.x;
  851. #else
  852. int n = sizeof(dec_real) - sizeof(int);
  853. dec_real dr;
  854. if (shell_read_saved_state(&dr.type + 1, n) != n) {
  855. free_vartype((vartype *) r);
  856. return false;
  857. }
  858. r->x = bcd2double(dr.x.d_, state_file_has_old_bcd);
  859. #endif
  860. } else {
  861. int n = sizeof(vartype_real) - sizeof(int);
  862. if (shell_read_saved_state(&r->type + 1, n) != n) {
  863. free_vartype((vartype *) r);
  864. return false;
  865. }
  866. #ifdef BCD_MATH
  867. if (state_file_has_old_bcd)
  868. bcdfloat_old2new(r->x.bcd.d_);
  869. #endif
  870. }
  871. *v = (vartype *) r;
  872. return true;
  873. }
  874. case TYPE_COMPLEX: {
  875. vartype_complex *c = (vartype_complex *) new_complex(0, 0);
  876. if (c == NULL)
  877. return false;
  878. if (bin_dec_mode_switch) {
  879. #ifdef BCD_MATH
  880. int n = sizeof(bin_complex) - sizeof(int);
  881. bin_complex bc;
  882. if (shell_read_saved_state(&bc.type + 1, n) != n) {
  883. free_vartype((vartype *) c);
  884. return false;
  885. }
  886. c->re = bc.re;
  887. c->im = bc.im;
  888. #else
  889. int n = sizeof(dec_complex) - sizeof(int);
  890. dec_complex dc;
  891. if (shell_read_saved_state(&dc.type + 1, n) != n) {
  892. free_vartype((vartype *) c);
  893. return false;
  894. }
  895. c->re = bcd2double(dc.re.d_, state_file_has_old_bcd);
  896. c->im = bcd2double(dc.im.d_, state_file_has_old_bcd);
  897. #endif
  898. } else {
  899. int n = sizeof(vartype_complex) - sizeof(int);
  900. if (shell_read_saved_state(&c->type + 1, n) != n) {
  901. free_vartype((vartype *) c);
  902. return false;
  903. }
  904. #ifdef BCD_MATH
  905. if (state_file_has_old_bcd) {
  906. bcdfloat_old2new(c->re.bcd.d_);
  907. bcdfloat_old2new(c->im.bcd.d_);
  908. }
  909. #endif
  910. }
  911. *v = (vartype *) c;
  912. return true;
  913. }
  914. case TYPE_STRING: {
  915. vartype_string *s = (vartype_string *) new_string("", 0);
  916. int n = sizeof(vartype_string) - sizeof(int);
  917. if (s == NULL)
  918. return false;
  919. if (shell_read_saved_state(&s->type + 1, n) != n) {
  920. free_vartype((vartype *) s);
  921. return false;
  922. } else {
  923. *v = (vartype *) s;
  924. return true;
  925. }
  926. }
  927. case TYPE_REALMATRIX: {
  928. matrix_persister mp;
  929. int n = sizeof(matrix_persister) - sizeof(int);
  930. if (shell_read_saved_state(&mp.type + 1, n) != n)
  931. return false;
  932. if (mp.rows == 0) {
  933. // Shared matrix
  934. vartype *m = new_matrix_alias((vartype *) array_list[mp.columns]);
  935. if (m == NULL)
  936. return false;
  937. else {
  938. *v = m;
  939. return true;
  940. }
  941. }
  942. bool shared = mp.rows < 0;
  943. if (shared)
  944. mp.rows = -mp.rows;
  945. vartype_realmatrix *rm = (vartype_realmatrix *) new_realmatrix(mp.rows, mp.columns);
  946. if (rm == NULL)
  947. return false;
  948. if (bin_dec_mode_switch) {
  949. int4 size = mp.rows * mp.columns;
  950. #ifdef BCD_MATH
  951. int phsz = sizeof(double);
  952. #else
  953. int phsz = sizeof(fake_bcd);
  954. #endif
  955. int4 tsz = size * phsz;
  956. char *temp = (char *) malloc(tsz);
  957. if (temp == NULL) {
  958. free_vartype((vartype *) rm);
  959. return false;
  960. }
  961. if (shell_read_saved_state(temp, tsz) != tsz) {
  962. free(temp);
  963. free_vartype((vartype *) rm);
  964. return false;
  965. }
  966. if (shell_read_saved_state(rm->array->is_string, size) != size) {
  967. free(temp);
  968. free_vartype((vartype *) rm);
  969. return false;
  970. }
  971. #ifdef BCD_MATH
  972. for (int4 i = 0; i < size; i++) {
  973. if (rm->array->is_string[i]) {
  974. char *src = temp + i * phsz;
  975. char *dst = (char *) (rm->array->data + i);
  976. for (int j = 0; j < 7; j++)
  977. *dst++ = *src++;
  978. } else {
  979. rm->array->data[i] = ((double *) temp)[i];
  980. }
  981. }
  982. #else
  983. for (int4 i = 0; i < size; i++) {
  984. if (rm->array->is_string[i]) {
  985. char *src = temp + i * phsz;
  986. char *dst = (char *) (rm->array->data + i);
  987. for (int j = 0; j < 7; j++)
  988. *dst++ = *src++;
  989. } else {
  990. rm->array->data[i] = bcd2double((short *) (temp + phsz * i), state_file_has_old_bcd);
  991. }
  992. }
  993. #endif
  994. free(temp);
  995. } else {
  996. int4 size = mp.rows * mp.columns * sizeof(phloat);
  997. if (shell_read_saved_state(rm->array->data, size) != size) {
  998. free_vartype((vartype *) rm);
  999. return false;
  1000. }
  1001. size = mp.rows * mp.columns;
  1002. if (shell_read_saved_state(rm->array->is_string, size) != size) {
  1003. free_vartype((vartype *) rm);
  1004. return false;
  1005. }
  1006. #ifdef BCD_MATH
  1007. if (state_file_has_old_bcd)
  1008. for (int4 i = 0; i < size; i++)
  1009. if (!rm->array->is_string[i])
  1010. bcdfloat_old2new(rm->array->data[i].bcd.d_);
  1011. #endif
  1012. }
  1013. if (shared) {
  1014. if (!array_list_grow()) {
  1015. free_vartype((vartype *) rm);
  1016. return false;
  1017. }
  1018. array_list[array_count++] = rm;
  1019. }
  1020. *v = (vartype *) rm;
  1021. return true;
  1022. }
  1023. case TYPE_COMPLEXMATRIX: {
  1024. matrix_persister mp;
  1025. int n = sizeof(matrix_persister) - sizeof(int);
  1026. if (shell_read_saved_state(&mp.type + 1, n) != n)
  1027. return false;
  1028. if (mp.rows == 0) {
  1029. // Shared matrix
  1030. vartype *m = new_matrix_alias((vartype *) array_list[mp.columns]);
  1031. if (m == NULL)
  1032. return false;
  1033. else {
  1034. *v = m;
  1035. return true;
  1036. }
  1037. }
  1038. bool shared = mp.rows < 0;
  1039. if (shared)
  1040. mp.rows = -mp.rows;
  1041. vartype_complexmatrix *cm = (vartype_complexmatrix *)
  1042. new_complexmatrix(mp.rows, mp.columns);
  1043. if (cm == NULL)
  1044. return false;
  1045. if (bin_dec_mode_switch) {
  1046. int4 size = 2 * mp.rows * mp.columns;
  1047. for (int4 i = 0; i < size; i++)
  1048. if (!read_phloat(cm->array->data + i)) {
  1049. free_vartype((vartype *) cm);
  1050. return false;
  1051. }
  1052. } else {
  1053. int4 size = 2 * mp.rows * mp.columns * sizeof(phloat);
  1054. if (shell_read_saved_state(cm->array->data, size) != size) {
  1055. free_vartype((vartype *) cm);
  1056. return false;
  1057. }
  1058. #ifdef BCD_MATH
  1059. if (state_file_has_old_bcd)
  1060. for (int4 i = 0; i < size; i++)
  1061. bcdfloat_old2new(cm->array->data[i].bcd.d_);
  1062. #endif
  1063. }
  1064. if (shared) {
  1065. if (!array_list_grow()) {
  1066. free_vartype((vartype *) cm);
  1067. return false;
  1068. }
  1069. array_list[array_count++] = cm;
  1070. }
  1071. *v = (vartype *) cm;
  1072. return true;
  1073. }
  1074. default:
  1075. return false;
  1076. }
  1077. }
  1078. static bool persist_globals() GLOBALS_SECT;
  1079. static bool persist_globals() {
  1080. int i;
  1081. array_count = 0;
  1082. array_list_capacity = 0;
  1083. array_list = NULL;
  1084. bool ret = false;
  1085. #if BIGSTACK
  1086. stack_item *si = bigstack_head;
  1087. #endif
  1088. if (!persist_vartype(reg_x))
  1089. goto done;
  1090. if (!persist_vartype(reg_y))
  1091. goto done;
  1092. if (!persist_vartype(reg_z))
  1093. goto done;
  1094. if (!persist_vartype(reg_t))
  1095. goto done;
  1096. if (!persist_vartype(reg_lastx))
  1097. goto done;
  1098. #if BIGSTACK
  1099. if (!write_bool(true)) /* Yes, big stack block exists */
  1100. goto done;
  1101. persist_undo();
  1102. if (!write_int(stacksize))
  1103. goto done;
  1104. while (si != NULL) {
  1105. if (!persist_vartype(si->var))
  1106. goto done;
  1107. si = si->next;
  1108. }
  1109. if (!write_bool(mode_rpl_enter))
  1110. goto done;
  1111. #else
  1112. if (!write_bool(false)) /* No, big stack block does not exist */
  1113. goto done;
  1114. #endif
  1115. if (!write_int(reg_alpha_length))
  1116. goto done;
  1117. if (!shell_write_saved_state(reg_alpha, 44))
  1118. goto done;
  1119. if (!write_int4(mode_sigma_reg))
  1120. goto done;
  1121. if (!write_int(mode_goose))
  1122. goto done;
  1123. if (!write_bool(mode_time_clktd))
  1124. goto done;
  1125. if (!write_bool(mode_time_clk24))
  1126. goto done;
  1127. if (!write_bool(mode_time_dmy))
  1128. goto done;
  1129. if (!shell_write_saved_state(&flags, sizeof(flags_struct)))
  1130. goto done;
  1131. if (!write_int(vars_count))
  1132. goto done;
  1133. if (!shell_write_saved_state(vars, vars_count * sizeof(var_struct)))
  1134. goto done;
  1135. for (i = 0; i < vars_count; i++)
  1136. if (!persist_vartype(vars[i].value))
  1137. goto done;
  1138. if (!write_int(prgms_count))
  1139. goto done;
  1140. if (!shell_write_saved_state(prgms, prgms_count * sizeof(prgm_struct)))
  1141. goto done;
  1142. for (i = 0; i < prgms_count; i++)
  1143. if (!shell_write_saved_state(prgms[i].text, prgms[i].size))
  1144. goto done;
  1145. if (!write_int(current_prgm))
  1146. goto done;
  1147. if (!write_int4(pc))
  1148. goto done;
  1149. if (!write_int(prgm_highlight_row))
  1150. goto done;
  1151. if (!write_int(varmenu_length))
  1152. goto done;
  1153. if (!shell_write_saved_state(varmenu, 7))
  1154. goto done;
  1155. if (!write_int(varmenu_rows))
  1156. goto done;
  1157. if (!write_int(varmenu_row))
  1158. goto done;
  1159. if (!shell_write_saved_state(varmenu_labellength, 6 * sizeof(int)))
  1160. goto done;
  1161. if (!shell_write_saved_state(varmenu_labeltext, 42))
  1162. goto done;
  1163. if (!write_int(varmenu_role))
  1164. goto done;
  1165. if (!write_int(rtn_sp))
  1166. goto done;
  1167. if (!shell_write_saved_state(&rtn_prgm, MAX_RTNS * sizeof(int)))
  1168. goto done;
  1169. if (!shell_write_saved_state(&rtn_pc, MAX_RTNS * sizeof(int4)))
  1170. goto done;
  1171. ret = true;
  1172. done:
  1173. free(array_list);
  1174. return ret;
  1175. }
  1176. static bool unpersist_globals(int4 ver) GLOBALS_SECT;
  1177. static bool unpersist_globals(int4 ver) {
  1178. int4 n;
  1179. int i;
  1180. array_count = 0;
  1181. array_list_capacity = 0;
  1182. array_list = NULL;
  1183. bool ret = false;
  1184. bool bigstack = false;
  1185. free_vartype(reg_x);
  1186. if (!unpersist_vartype(&reg_x))
  1187. goto done;
  1188. free_vartype(reg_y);
  1189. if (!unpersist_vartype(&reg_y))
  1190. goto done;
  1191. free_vartype(reg_z);
  1192. if (!unpersist_vartype(&reg_z))
  1193. goto done;
  1194. free_vartype(reg_t);
  1195. if (!unpersist_vartype(&reg_t))
  1196. goto done;
  1197. free_vartype(reg_lastx);
  1198. if (!unpersist_vartype(&reg_lastx))
  1199. goto done;
  1200. if (ver >= 12) {
  1201. /* we are on atleast version 12, so this block exists */
  1202. if (!read_bool(&bigstack))
  1203. goto done;
  1204. }
  1205. #ifdef BIGSTACK
  1206. if (bigstack)
  1207. {
  1208. if (ver >= 17) {
  1209. unpersist_undo();
  1210. }
  1211. stacksize = 20; /* backward compatible pre version 13 big stack */
  1212. if (ver >= 13) {
  1213. if (!read_int(&stacksize))
  1214. goto done;
  1215. while(bigstack_head != NULL)
  1216. {
  1217. shift_big_stack_down();
  1218. free_vartype(reg_t);
  1219. }
  1220. }
  1221. int i = stacksize - 4;
  1222. stack_item *lastsi = NULL;
  1223. while (i-- > 0) {
  1224. vartype *v = NULL;
  1225. if (!unpersist_vartype(&v))
  1226. goto done;
  1227. stack_item *si = new_stack_item(v);
  1228. si->next = NULL;
  1229. if (lastsi == NULL)
  1230. bigstack_head = si;
  1231. else
  1232. lastsi->next = si;
  1233. lastsi = si;
  1234. }
  1235. if (!read_bool(&mode_rpl_enter))
  1236. goto done;
  1237. }
  1238. #endif
  1239. if (!read_int(&reg_alpha_length)) {
  1240. reg_alpha_length = 0;
  1241. goto done;
  1242. }
  1243. if (shell_read_saved_state(reg_alpha, 44) != 44) {
  1244. reg_alpha_length = 0;
  1245. goto done;
  1246. }
  1247. if (!read_int4(&mode_sigma_reg)) {
  1248. mode_sigma_reg = 11;
  1249. goto done;
  1250. }
  1251. if (!read_int(&mode_goose)) {
  1252. mode_goose = -1;
  1253. goto done;
  1254. }
  1255. if (ver >= 16) {
  1256. if (!read_bool(&mode_time_clktd)) {
  1257. mode_time_clktd = false;
  1258. goto done;
  1259. }
  1260. if (!read_bool(&mode_time_clk24)) {
  1261. mode_time_clk24 = false;
  1262. goto done;
  1263. }
  1264. if (!read_bool(&mode_time_dmy)) {
  1265. mode_time_dmy = false;
  1266. goto done;
  1267. }
  1268. }
  1269. if (shell_read_saved_state(&flags, sizeof(flags_struct))
  1270. != sizeof(flags_struct))
  1271. goto done;
  1272. vars_capacity = 0;
  1273. if (vars != NULL) {
  1274. free(vars);
  1275. vars = NULL;
  1276. }
  1277. if (!read_int(&vars_count)) {
  1278. vars_count = 0;
  1279. goto done;
  1280. }
  1281. n = vars_count * sizeof(var_struct);
  1282. vars = (var_struct *) malloc(n);
  1283. if (vars == NULL) {
  1284. vars_count = 0;
  1285. goto done;
  1286. }
  1287. if (shell_read_saved_state(vars, n) != n) {
  1288. free(vars);
  1289. vars = NULL;
  1290. vars_count = 0;
  1291. goto done;
  1292. }
  1293. vars_capacity = vars_count;
  1294. for (i = 0; i < vars_count; i++)
  1295. vars[i].value = NULL;
  1296. for (i = 0; i < vars_count; i++)
  1297. if (!unpersist_vartype(&vars[i].value)) {
  1298. purge_all_vars();
  1299. goto done;
  1300. }
  1301. prgms_capacity = 0;
  1302. if (prgms != NULL) {
  1303. free(prgms);
  1304. prgms = NULL;
  1305. }
  1306. if (!read_int(&prgms_count)) {
  1307. prgms_count = 0;
  1308. goto done;
  1309. }
  1310. n = prgms_count * sizeof(prgm_struct);
  1311. prgms = (prgm_struct *) malloc(n);
  1312. if (prgms == NULL) {
  1313. prgms_count = 0;
  1314. goto done;
  1315. }
  1316. if (shell_read_saved_state(prgms, n) != n) {
  1317. free(prgms);
  1318. prgms = NULL;
  1319. prgms_count = 0;
  1320. goto done;
  1321. }
  1322. prgms_capacity = prgms_count;
  1323. for (i = 0; i < prgms_count; i++) {
  1324. prgms[i].capacity = prgms[i].size;
  1325. prgms[i].text = (unsigned char *) malloc(prgms[i].size);
  1326. // TODO - handle memory allocation failure
  1327. }
  1328. for (i = 0; i < prgms_count; i++) {
  1329. if (shell_read_saved_state(prgms[i].text, prgms[i].size)
  1330. != prgms[i].size) {
  1331. clear_all_prgms();
  1332. goto done;
  1333. }
  1334. }
  1335. if (!read_int(&current_prgm)) {
  1336. current_prgm = 0;
  1337. goto done;
  1338. }
  1339. if (!read_int4(&pc)) {
  1340. pc = -1;
  1341. goto done;
  1342. }
  1343. if (!read_int(&prgm_highlight_row)) {
  1344. prgm_highlight_row = 0;
  1345. goto done;
  1346. }
  1347. if (!read_int(&varmenu_length)) {
  1348. varmenu_length = 0;
  1349. goto done;
  1350. }
  1351. if (shell_read_saved_state(varmenu, 7) != 7) {
  1352. varmenu_length = 0;
  1353. goto done;
  1354. }
  1355. if (!read_int(&varmenu_rows)) {
  1356. varmenu_length = 0;
  1357. goto done;
  1358. }
  1359. if (!read_int(&varmenu_row)) {
  1360. varmenu_length = 0;
  1361. goto done;
  1362. }
  1363. if (shell_read_saved_state(varmenu_labellength, 6 * sizeof(int))
  1364. != 6 * sizeof(int))
  1365. goto done;
  1366. if (shell_read_saved_state(varmenu_labeltext, 42) != 42)
  1367. goto done;
  1368. if (!read_int(&varmenu_role))
  1369. goto done;
  1370. if (!read_int(&rtn_sp))
  1371. goto done;
  1372. if (shell_read_saved_state(rtn_prgm, MAX_RTNS * sizeof(int))
  1373. != MAX_RTNS * sizeof(int))
  1374. goto done;
  1375. if (shell_read_saved_state(rtn_pc, MAX_RTNS * sizeof(int4))
  1376. != MAX_RTNS * sizeof(int4))
  1377. goto done;
  1378. if (bin_dec_mode_switch)
  1379. if (!convert_programs()) {
  1380. clear_all_prgms();
  1381. goto done;
  1382. }
  1383. #ifdef IPHONE
  1384. if (ver == 12 || ver == 13) {
  1385. // CMD_DROP redefined from 315 to 329, to resolve clash with
  1386. // Underhill's COPAN extensions.
  1387. convert_bigstack_drop();
  1388. }
  1389. #endif
  1390. rebuild_label_table();
  1391. ret = true;
  1392. done:
  1393. free(array_list);
  1394. return ret;
  1395. }
  1396. void clear_all_prgms() {
  1397. if (prgms != NULL) {
  1398. int i;
  1399. for (i = 0; i < prgms_count; i++)
  1400. if (prgms[i].text != NULL)
  1401. free(prgms[i].text);
  1402. free(prgms);
  1403. }
  1404. prgms = NULL;
  1405. prgms_capacity = 0;
  1406. prgms_count = 0;
  1407. if (labels != NULL)
  1408. free(labels);
  1409. labels = NULL;
  1410. labels_capacity = 0;
  1411. labels_count = 0;
  1412. }
  1413. int clear_prgm(const arg_struct *arg) {
  1414. int prgm_index = NULL;
  1415. int i, j;
  1416. if (arg->type == ARGTYPE_LBLINDEX)
  1417. prgm_index = labels[arg->val.num].prgm;
  1418. else if (arg->type == ARGTYPE_STR) {
  1419. if (arg->length == 0) {
  1420. if (current_prgm < 0 || current_prgm >= prgms_count)
  1421. return ERR_INTERNAL_ERROR;
  1422. prgm_index = current_prgm;
  1423. } else {
  1424. int i;
  1425. for (i = labels_count - 1; i >= 0; i--)
  1426. if (string_equals(arg->val.text, arg->length,
  1427. labels[i].name, labels[i].length))
  1428. goto found;
  1429. return ERR_LABEL_NOT_FOUND;
  1430. found:
  1431. prgm_index = labels[i].prgm;
  1432. }
  1433. }
  1434. clear_all_rtns();
  1435. if (prgm_index == current_prgm)
  1436. pc = -1;
  1437. else if (current_prgm > prgm_index)
  1438. current_prgm--;
  1439. free(prgms[prgm_index].text);
  1440. for (i = prgm_index; i < prgms_count - 1; i++)
  1441. prgms[i] = prgms[i + 1];
  1442. prgms_count--;
  1443. i = j = 0;
  1444. while (j < labels_count) {
  1445. if (j > i)
  1446. labels[i] = labels[j];
  1447. j++;
  1448. if (labels[i].prgm > prgm_index) {
  1449. labels[i].prgm--;
  1450. i++;
  1451. } else if (labels[i].prgm < prgm_index)
  1452. i++;
  1453. }
  1454. labels_count = i;
  1455. if (prgms_count == 0 || prgm_index == prgms_count) {
  1456. int saved_prgm = current_prgm;
  1457. int saved_pc = pc;
  1458. goto_dot_dot();
  1459. current_prgm = saved_prgm;
  1460. pc = saved_pc;
  1461. }
  1462. update_catalog();
  1463. return ERR_NONE;
  1464. }
  1465. void clear_prgm_lines(int4 count) {
  1466. int4 frompc, deleted, i, j;
  1467. if (pc == -1)
  1468. pc = 0;
  1469. frompc = pc;
  1470. while (count > 0) {
  1471. int command;
  1472. arg_struct arg;
  1473. get_next_command(&pc, &command, &arg, 0);
  1474. if (command == CMD_END) {
  1475. pc -= 2;
  1476. break;
  1477. }
  1478. count--;
  1479. }
  1480. deleted = pc - frompc;
  1481. for (i = pc; i < prgms[current_prgm].size; i++)
  1482. prgms[current_prgm].text[i - deleted] = prgms[current_prgm].text[i];
  1483. prgms[current_prgm].size -= deleted;
  1484. pc = frompc;
  1485. i = j = 0;
  1486. while (j < labels_count) {
  1487. if (j > i)
  1488. labels[i] = labels[j];
  1489. j++;
  1490. if (labels[i].prgm == current_prgm) {
  1491. if (labels[i].pc < frompc)
  1492. i++;
  1493. else if (labels[i].pc >= frompc + deleted) {
  1494. labels[i].pc -= deleted;
  1495. i++;
  1496. }
  1497. } else
  1498. i++;
  1499. }
  1500. labels_count = i;
  1501. invalidate_lclbls(current_prgm);
  1502. clear_all_rtns();
  1503. }
  1504. void goto_dot_dot() {
  1505. int command;
  1506. arg_struct arg;
  1507. if (prgms_count != 0) {
  1508. /* Check if last program is empty */
  1509. pc = 0;
  1510. current_prgm = prgms_count - 1;
  1511. get_next_command(&pc, &command, &arg, 0);
  1512. if (command == CMD_END) {
  1513. pc = -1;
  1514. return;
  1515. }
  1516. }
  1517. if (prgms_count == prgms_capacity) {
  1518. prgm_struct *newprgms;
  1519. int i;
  1520. prgms_capacity += 10;
  1521. newprgms = (prgm_struct *) malloc(prgms_capacity * sizeof(prgm_struct));
  1522. // TODO - handle memory allocation failure
  1523. for (i = 0; i < prgms_count; i++)
  1524. newprgms[i] = prgms[i];
  1525. if (prgms != NULL)
  1526. free(prgms);
  1527. prgms = newprgms;
  1528. }
  1529. current_prgm = prgms_count++;
  1530. prgms[current_prgm].capacity = 0;
  1531. prgms[current_prgm].size = 0;
  1532. prgms[current_prgm].lclbl_invalid = 1;
  1533. prgms[current_prgm].text = NULL;
  1534. command = CMD_END;
  1535. arg.type = ARGTYPE_NONE;
  1536. store_command(0, command, &arg);
  1537. pc = -1;
  1538. }
  1539. int mvar_prgms_exist() {
  1540. int i;
  1541. for (i = 0; i < labels_count; i++)
  1542. if (label_has_mvar(i))
  1543. return 1;
  1544. return 0;
  1545. }
  1546. int label_has_mvar(int lblindex) {
  1547. int saved_prgm;
  1548. int4 pc;
  1549. int command;
  1550. arg_struct arg;
  1551. if (labels[lblindex].length == 0)
  1552. return 0;
  1553. saved_prgm = current_prgm;
  1554. current_prgm = labels[lblindex].prgm;
  1555. pc = labels[lblindex].pc;
  1556. pc += get_command_length(current_prgm, pc);
  1557. get_next_command(&pc, &command, &arg, 0);
  1558. current_prgm = saved_prgm;
  1559. return command == CMD_MVAR;
  1560. }
  1561. int get_command_length(int prgm_index, int4 pc) {
  1562. prgm_struct *prgm = prgms + prgm_index;
  1563. int4 pc2 = pc;
  1564. int command = prgm->text[pc2++];
  1565. int argtype = prgm->text[pc2++];
  1566. command |= (argtype & 240) << 4;
  1567. argtype &= 15;
  1568. if (command == CMD_CONVERT) pc2 += 2;
  1569. if ((command == CMD_GTO || command == CMD_XEQ)
  1570. && (argtype == ARGTYPE_NUM || argtype == ARGTYPE_LCLBL))
  1571. pc2 += 4;
  1572. switch (argtype) {
  1573. case ARGTYPE_NUM:
  1574. case ARGTYPE_NEG_NUM:
  1575. case ARGTYPE_IND_NUM: {
  1576. while ((prgm->text[pc2++] & 128) == 0);
  1577. break;
  1578. }
  1579. case ARGTYPE_STK:
  1580. case ARGTYPE_IND_STK:
  1581. case ARGTYPE_COMMAND:
  1582. case ARGTYPE_LCLBL:
  1583. pc2++;
  1584. break;
  1585. case ARGTYPE_STR:
  1586. case ARGTYPE_IND_STR: {
  1587. pc2 += prgm->text[pc2] + 1;
  1588. break;
  1589. }
  1590. case ARGTYPE_DOUBLE:
  1591. pc2 += sizeof(phloat);
  1592. break;
  1593. }
  1594. return pc2 - pc;
  1595. }
  1596. void get_next_command(int4 *pc, int *command, arg_struct *arg, int find_target){
  1597. prgm_struct *prgm = prgms + current_prgm;
  1598. int i;
  1599. int4 target_pc;
  1600. int4 orig_pc = *pc;
  1601. *command = prgm->text[(*pc)++];
  1602. arg->type = prgm->text[(*pc)++];
  1603. *command |= (arg->type & 240) << 4;
  1604. arg->type &= 15;
  1605. if ((*command == CMD_GTO || *command == CMD_XEQ)
  1606. && (arg->type == ARGTYPE_NUM
  1607. || arg->type == ARGTYPE_LCLBL)) {
  1608. if (find_target) {
  1609. target_pc = 0;
  1610. for (i = 0; i < 4; i++)
  1611. target_pc = (target_pc << 8) | prgm->text[(*pc)++];
  1612. if (target_pc != -1) {
  1613. arg->target = target_pc;
  1614. find_target = 0;
  1615. }
  1616. } else
  1617. (*pc) += 4;
  1618. } else {
  1619. find_target = 0;
  1620. arg->target = -1;
  1621. }
  1622. switch (arg->type) {
  1623. case ARGTYPE_NUM:
  1624. case ARGTYPE_NEG_NUM:
  1625. case ARGTYPE_IND_NUM: {
  1626. int4 num = 0;
  1627. unsigned char c;
  1628. do {
  1629. c = prgm->text[(*pc)++];
  1630. num = (num << 7) | (c & 127);
  1631. } while ((c & 128) == 0);
  1632. if (arg->type == ARGTYPE_NEG_NUM) {
  1633. arg->type = ARGTYPE_NUM;
  1634. num = -num;
  1635. }
  1636. arg->val.num = num;
  1637. break;
  1638. }
  1639. case ARGTYPE_STK:
  1640. case ARGTYPE_IND_STK:
  1641. arg->val.stk = prgm->text[(*pc)++];
  1642. break;
  1643. case ARGTYPE_COMMAND:
  1644. arg->val.cmd = prgm->text[(*pc)++];
  1645. break;
  1646. case ARGTYPE_LCLBL:
  1647. arg->val.lclbl = prgm->text[(*pc)++];
  1648. break;
  1649. case ARGTYPE_STR:
  1650. case ARGTYPE_IND_STR: {
  1651. arg->length = prgm->text[(*pc)++];
  1652. for (i = 0; i < arg->length; i++)
  1653. arg->val.text[i] = prgm->text[(*pc)++];
  1654. break;
  1655. }
  1656. case ARGTYPE_DOUBLE: {
  1657. unsigned char *b = (unsigned char *) &arg->val_d;
  1658. for (int i = 0; i < (int) sizeof(phloat); i++)
  1659. *b++ = prgm->text[(*pc)++];
  1660. break;
  1661. }
  1662. }
  1663. if (*command == CMD_NUMBER && arg->type != ARGTYPE_DOUBLE) {
  1664. /* argtype is ARGTYPE_NUM; convert to phloat */
  1665. arg->val_d = arg->val.num;
  1666. arg->type = ARGTYPE_DOUBLE;
  1667. }
  1668. if (find_target) {
  1669. target_pc = find_local_label(arg);
  1670. arg->target = target_pc;
  1671. for (i = 5; i >= 2; i--) {
  1672. prgm->text[orig_pc + i] = target_pc;
  1673. target_pc >>= 8;
  1674. }
  1675. prgm->lclbl_invalid = 0;
  1676. }
  1677. if (*command == CMD_CONVERT)
  1678. {
  1679. arg->val.num = prgm->text[(*pc)++];
  1680. arg->val.num |= prgm->text[(*pc)++] << 8;
  1681. }
  1682. }
  1683. void rebuild_label_table() {
  1684. /* TODO -- this is *not* efficient; inserting and deleting ENDs and
  1685. * global LBLs should not cause every single program to get rescanned!
  1686. * But, I don't feel like dealing with that at the moment, so just
  1687. * this ugly brute force approach for now.
  1688. */
  1689. int prgm_index;
  1690. int4 pc;
  1691. labels_count = 0;
  1692. for (prgm_index = 0; prgm_index < prgms_count; prgm_index++) {
  1693. prgm_struct *prgm = prgms + prgm_index;
  1694. pc = 0;
  1695. while (pc < prgm->size) {
  1696. int command = prgm->text[pc];
  1697. int argtype = prgm->text[pc + 1];
  1698. command |= (argtype & 240) << 4;
  1699. argtype &= 15;
  1700. if (command == CMD_END
  1701. || (command == CMD_LBL && argtype == ARGTYPE_STR)) {
  1702. label_struct *newlabel;
  1703. if (labels_count == labels_capacity) {
  1704. label_struct *newlabels;
  1705. int i;
  1706. labels_capacity += 50;
  1707. newlabels = (label_struct *)
  1708. malloc(labels_capacity * sizeof(label_struct));
  1709. // TODO - handle memory allocation failure
  1710. for (i = 0; i < labels_count; i++)
  1711. newlabels[i] = labels[i];
  1712. if (labels != NULL)
  1713. free(labels);
  1714. labels = newlabels;
  1715. }
  1716. newlabel = labels + labels_count++;
  1717. if (command == CMD_END)
  1718. newlabel->length = 0;
  1719. else {
  1720. int i;
  1721. newlabel->length = prgm->text[pc + 2];
  1722. for (i = 0; i < newlabel->length; i++)
  1723. newlabel->name[i] = prgm->text[pc + 3 + i];
  1724. }
  1725. newlabel->prgm = prgm_index;
  1726. newlabel->pc = pc;
  1727. }
  1728. pc += get_command_length(prgm_index, pc);
  1729. }
  1730. }
  1731. }
  1732. static void update_label_table(int prgm, int4 pc, int inserted) {
  1733. int i;
  1734. for (i = 0; i < labels_count; i++) {
  1735. if (labels[i].prgm > prgm)
  1736. return;
  1737. if (labels[i].prgm == prgm && labels[i].pc >= pc)
  1738. labels[i].pc += inserted;
  1739. }
  1740. }
  1741. static void invalidate_lclbls(int prgm_index) {
  1742. prgm_struct *prgm = prgms + prgm_index;
  1743. if (!prgm->lclbl_invalid) {
  1744. int4 pc2 = 0;
  1745. while (pc2 < prgm->size) {
  1746. int command = prgm->text[pc2];
  1747. int argtype = prgm->text[pc2 + 1];
  1748. command |= (argtype & 240) << 4;
  1749. argtype &= 15;
  1750. if ((command == CMD_GTO || command == CMD_XEQ)
  1751. && (argtype == ARGTYPE_NUM || argtype == ARGTYPE_LCLBL)) {
  1752. /* A dest_pc value of -1 signals 'unknown',
  1753. * -2 means 'nonexistent', and anything else is
  1754. * the pc where the destination label is found.
  1755. */
  1756. int4 pos;
  1757. for (pos = pc2 + 2; pos < pc2 + 6; pos++)
  1758. prgm->text[pos] = 255;
  1759. }
  1760. pc2 += get_command_length(prgm_index, pc2);
  1761. }
  1762. prgm->lclbl_invalid = 1;
  1763. }
  1764. }
  1765. void delete_command(int4 pc) {
  1766. prgm_struct *prgm = prgms + current_prgm;
  1767. int command = prgm->text[pc];
  1768. int argtype = prgm->text[pc + 1];
  1769. int length = get_command_length(current_prgm, pc);
  1770. int4 pos;
  1771. command |= (argtype & 240) << 4;
  1772. argtype &= 15;
  1773. if (command == CMD_END) {
  1774. int4 newsize;
  1775. prgm_struct *nextprgm;
  1776. if (current_prgm == prgms_count - 1)
  1777. /* Don't allow deletion of last program's END. */
  1778. return;
  1779. nextprgm = prgm + 1;
  1780. prgm->size -= 2;
  1781. newsize = prgm->size + nextprgm->size;
  1782. if (newsize > prgm->capacity) {
  1783. int4 newcapacity = (newsize + 511) & ~511;
  1784. unsigned char *newtext = (unsigned char *) malloc(newcapacity);
  1785. // TODO - handle memory allocation failure
  1786. for (pos = 0; pos < prgm->size; pos++)
  1787. newtext[pos] = prgm->text[pos];
  1788. free(prgm->text);
  1789. prgm->text = newtext;
  1790. prgm->capacity = newcapacity;
  1791. }
  1792. for (pos = 0; pos < nextprgm->size; pos++)
  1793. prgm->text[prgm->size++] = nextprgm->text[pos];
  1794. free(nextprgm->text);
  1795. for (pos = current_prgm + 1; pos < prgms_count - 1; pos++)
  1796. prgms[pos] = prgms[pos + 1];
  1797. prgms_count--;
  1798. rebuild_label_table();
  1799. invalidate_lclbls(current_prgm);
  1800. clear_all_rtns();
  1801. draw_varmenu();
  1802. return;
  1803. }
  1804. for (pos = pc; pos < prgm->size - length; pos++)
  1805. prgm->text[pos] = prgm->text[pos + length];
  1806. prgm->size -= length;
  1807. if (command == CMD_LBL && argtype == ARGTYPE_STR)
  1808. rebuild_label_table();
  1809. else
  1810. update_label_table(current_prgm, pc, -length);
  1811. invalidate_lclbls(current_prgm);
  1812. clear_all_rtns();
  1813. draw_varmenu();
  1814. }
  1815. void store_command(int4 pc, int command, arg_struct *arg) {
  1816. unsigned char buf[100];
  1817. int bufptr = 0;
  1818. int i;
  1819. int4 pos;
  1820. prgm_struct *prgm = prgms + current_prgm;
  1821. /* We should never be called with pc = -1, but just to be safe... */
  1822. if (pc == -1)
  1823. pc = 0;
  1824. if (arg->type == ARGTYPE_NUM && arg->val.num < 0) {
  1825. arg->type = ARGTYPE_NEG_NUM;
  1826. arg->val.num = -arg->val.num;
  1827. } else if (command == CMD_NUMBER) {
  1828. /* arg.type is always ARGTYPE_DOUBLE for CMD_NUMBER, but for storage
  1829. * efficiency, we handle integers specially and store them as
  1830. * ARGTYPE_NUM or ARGTYPE_NEG_NUM instead.
  1831. */
  1832. int4 n = to_int4(arg->val_d);
  1833. if (n == arg->val_d && n != (int4) 0x80000000) {
  1834. if (n >= 0) {
  1835. arg->val.num = n;
  1836. arg->type = ARGTYPE_NUM;
  1837. } else {
  1838. arg->val.num = -n;
  1839. arg->type = ARGTYPE_NEG_NUM;
  1840. }
  1841. }
  1842. } else if (arg->type == ARGTYPE_LBLINDEX) {
  1843. int li = arg->val.num;
  1844. arg->length = labels[li].length;
  1845. for (i = 0; i < arg->length; i++)
  1846. arg->val.text[i] = labels[li].name[i];
  1847. arg->type = ARGTYPE_STR;
  1848. }
  1849. buf[bufptr++] = command & 255;
  1850. buf[bufptr++] = arg->type | ((command & ~255) >> 4);
  1851. /* If the program is nonempty, it must already contain an END,
  1852. * since that's the very first thing that gets stored in any new
  1853. * program. In this case, we need to split the program.
  1854. */
  1855. if (command == CMD_END && prgm->size > 0) {
  1856. prgm_struct *new_prgm;
  1857. if (prgms_count == prgms_capacity) {
  1858. prgm_struct *new_prgms;
  1859. int i;
  1860. prgms_capacity += 10;
  1861. new_prgms = (prgm_struct *)
  1862. malloc(prgms_capacity * sizeof(prgm_struct));
  1863. // TODO - handle memory allocation failure
  1864. for (i = 0; i <= current_prgm; i++)
  1865. new_prgms[i] = prgms[i];
  1866. for (i = current_prgm + 1; i < prgms_count; i++)
  1867. new_prgms[i + 1] = prgms[i];
  1868. free(prgms);
  1869. prgms = new_prgms;
  1870. prgm = prgms + current_prgm;
  1871. } else {
  1872. for (i = prgms_count - 1; i > current_prgm; i--)
  1873. prgms[i + 1] = prgms[i];
  1874. }
  1875. prgms_count++;
  1876. new_prgm = prgm + 1;
  1877. new_prgm->size = prgm->size - pc;
  1878. new_prgm->capacity = (new_prgm->size + 511) & ~511;
  1879. new_prgm->text = (unsigned char *) malloc(new_prgm->capacity);
  1880. // TODO - handle memory allocation failure
  1881. for (i = pc; i < prgm->size; i++)
  1882. new_prgm->text[i - pc] = prgm->text[i];
  1883. current_prgm++;
  1884. /* Truncate the previously 'current' program and append an END.
  1885. * No need to check the size against the capacity and grow the
  1886. * program; since it contained an END before, it still has the
  1887. * capacity for one now;
  1888. */
  1889. prgm->size = pc;
  1890. prgm->text[prgm->size++] = CMD_END;
  1891. prgm->text[prgm->size++] = ARGTYPE_NONE;
  1892. if (flags.f.trace_print || flags.f.normal_print)
  1893. print_program_line(current_prgm - 1, pc);
  1894. rebuild_label_table();
  1895. invalidate_lclbls(current_prgm);
  1896. invalidate_lclbls(current_prgm - 1);
  1897. clear_all_rtns();
  1898. draw_varmenu();
  1899. return;
  1900. }
  1901. if ((command == CMD_GTO || command == CMD_XEQ)
  1902. && (arg->type == ARGTYPE_NUM || arg->type == ARGTYPE_LCLBL))
  1903. for (i = 0; i < 4; i++)
  1904. buf[bufptr++] = 255;
  1905. switch (arg->type) {
  1906. case ARGTYPE_NUM:
  1907. case ARGTYPE_NEG_NUM:
  1908. case ARGTYPE_IND_NUM: {
  1909. int4 num = arg->val.num;
  1910. char tmpbuf[5];
  1911. int tmplen = 0;
  1912. while (num > 127) {
  1913. tmpbuf[tmplen++] = num & 127;
  1914. num >>= 7;
  1915. }
  1916. tmpbuf[tmplen++] = num;
  1917. tmpbuf[0] |= 128;
  1918. while (--tmplen >= 0)
  1919. buf[bufptr++] = tmpbuf[tmplen];
  1920. break;
  1921. }
  1922. case ARGTYPE_STK:
  1923. case ARGTYPE_IND_STK:
  1924. buf[bufptr++] = arg->val.stk;
  1925. break;
  1926. case ARGTYPE_STR:
  1927. case ARGTYPE_IND_STR: {
  1928. buf[bufptr++] = arg->length;
  1929. for (i = 0; i < arg->length; i++)
  1930. buf[bufptr++] = arg->val.text[i];
  1931. break;
  1932. }
  1933. case ARGTYPE_LCLBL:
  1934. buf[bufptr++] = arg->val.lclbl;
  1935. break;
  1936. case ARGTYPE_DOUBLE: {
  1937. unsigned char *b = (unsigned char *) &arg->val_d;
  1938. for (int i = 0; i < (int) sizeof(phloat); i++)
  1939. buf[bufptr++] = *b++;
  1940. break;
  1941. }
  1942. }
  1943. if (command == CMD_CONVERT)
  1944. {
  1945. buf[bufptr++] = arg->val.num&0xFF;
  1946. buf[bufptr++] = ((arg->val.num) >> 8)&0xFF;
  1947. }
  1948. if (bufptr + prgm->size > prgm->capacity) {
  1949. unsigned char *newtext;
  1950. prgm->capacity += 512;
  1951. newtext = (unsigned char *) malloc(prgm->capacity);
  1952. // TODO - handle memory allocation failure
  1953. for (pos = 0; pos < pc; pos++)
  1954. newtext[pos] = prgm->text[pos];
  1955. for (pos = pc; pos < prgm->size; pos++)
  1956. newtext[pos + bufptr] = prgm->text[pos];
  1957. if (prgm->text != NULL)
  1958. free(prgm->text);
  1959. prgm->text = newtext;
  1960. } else {
  1961. for (pos = prgm->size - 1; pos >= pc; pos--)
  1962. prgm->text[pos + bufptr] = prgm->text[pos];
  1963. }
  1964. for (pos = 0; pos < bufptr; pos++)
  1965. prgm->text[pc + pos] = buf[pos];
  1966. prgm->size += bufptr;
  1967. if (command != CMD_END && (flags.f.trace_print || flags.f.normal_print))
  1968. print_program_line(current_prgm, pc);
  1969. if (command == CMD_END ||
  1970. (command == CMD_LBL && arg->type == ARGTYPE_STR))
  1971. rebuild_label_table();
  1972. else
  1973. update_label_table(current_prgm, pc, bufptr);
  1974. invalidate_lclbls(current_prgm);
  1975. clear_all_rtns();
  1976. draw_varmenu();
  1977. }
  1978. void store_command_after(int4 *pc, int command, arg_struct *arg) {
  1979. if (*pc == -1)
  1980. *pc = 0;
  1981. else if (prgms[current_prgm].text[*pc] != CMD_END)
  1982. *pc += get_command_length(current_prgm, *pc);
  1983. store_command(*pc, command, arg);
  1984. }
  1985. static int pc_line_convert(int4 loc, int loc_is_pc) {
  1986. int4 pc = 0;
  1987. int4 line = 1;
  1988. prgm_struct *prgm = prgms + current_prgm;
  1989. while (1) {
  1990. if (loc_is_pc) {
  1991. if (pc >= loc)
  1992. return line;
  1993. } else {
  1994. if (line >= loc)
  1995. return pc;
  1996. }
  1997. if (prgm->text[pc] == CMD_END)
  1998. return loc_is_pc ? line : pc;
  1999. pc += get_command_length(current_prgm, pc);
  2000. line++;
  2001. }
  2002. }
  2003. int4 pc2line(int4 pc) {
  2004. if (pc == -1)
  2005. return 0;
  2006. else
  2007. return pc_line_convert(pc, 1);
  2008. }
  2009. int4 line2pc(int4 line) {
  2010. if (line == 0)
  2011. return -1;
  2012. else
  2013. return pc_line_convert(line, 0);
  2014. }
  2015. int4 find_local_label(const arg_struct *arg) {
  2016. int4 orig_pc = pc;
  2017. int4 search_pc;
  2018. int wrapped = 0;
  2019. prgm_struct *prgm = prgms + current_prgm;
  2020. if (orig_pc == -1)
  2021. orig_pc = 0;
  2022. search_pc = orig_pc;
  2023. while (!wrapped || search_pc < orig_pc) {
  2024. int command, argtype;
  2025. if (search_pc >= prgm->size - 2) {
  2026. if (orig_pc == 0)
  2027. break;
  2028. search_pc = 0;
  2029. wrapped = 1;
  2030. }
  2031. command = prgm->text[search_pc];
  2032. argtype = prgm->text[search_pc + 1];
  2033. command |= (argtype & 240) << 4;
  2034. argtype &= 15;
  2035. if (command == CMD_LBL && argtype == arg->type) {
  2036. if (argtype == ARGTYPE_NUM) {
  2037. int num = 0;
  2038. unsigned char c;
  2039. int pos = search_pc + 2;
  2040. do {
  2041. c = prgm->text[pos++];
  2042. num = (num << 7) | (c & 127);
  2043. } while ((c & 128) == 0);
  2044. if (num == arg->val.num)
  2045. return search_pc;
  2046. } else {
  2047. char lclbl = prgm->text[search_pc + 2];
  2048. if (lclbl == arg->val.lclbl)
  2049. return search_pc;
  2050. }
  2051. }
  2052. search_pc += get_command_length(current_prgm, search_pc);
  2053. }
  2054. return -2;
  2055. }
  2056. // Created a wrapper method to this function so it is easier to call from
  2057. // MenuView to determine if we should display variable values for a cusomt menu
  2058. int find_global_label(const char *name, int namelen, int *prgm, int4 *pc) {
  2059. int i;
  2060. for (i = labels_count - 1; i >= 0; i--) {
  2061. int j;
  2062. char *labelname;
  2063. if (labels[i].length != namelen)
  2064. continue;
  2065. labelname = labels[i].name;
  2066. for (j = 0; j < namelen; j++)
  2067. if (labelname[j] != name[j])
  2068. goto nomatch;
  2069. *prgm = labels[i].prgm;
  2070. *pc = labels[i].pc;
  2071. return 1;
  2072. nomatch:;
  2073. }
  2074. return 0;
  2075. }
  2076. // Wrapper method for above find_global_label
  2077. int find_global_label(const arg_struct *arg, int *prgm, int4 *pc) {
  2078. return find_global_label(arg->val.text, arg->length, prgm, pc);
  2079. }
  2080. int push_rtn_addr(int prgm, int4 pc) {
  2081. int err = ERR_NONE;
  2082. if (rtn_sp == MAX_RTNS) {
  2083. int i;
  2084. if (rtn_prgm[0] == -2 || rtn_prgm[0] == -3)
  2085. err = ERR_SOLVE_INTEG_RTN_LOST;
  2086. for (i = 0; i < MAX_RTNS - 1; i++) {
  2087. rtn_prgm[i] = rtn_prgm[i + 1];
  2088. rtn_pc[i] = rtn_pc[i + 1];
  2089. }
  2090. rtn_sp--;
  2091. }
  2092. rtn_prgm[rtn_sp] = prgm;
  2093. rtn_pc[rtn_sp] = pc;
  2094. rtn_sp++;
  2095. return err;
  2096. }
  2097. void pop_rtn_addr(int *prgm, int4 *pc) {
  2098. if (rtn_sp == 0) {
  2099. *prgm = -1;
  2100. *pc = -1;
  2101. } else {
  2102. rtn_sp--;
  2103. *prgm = rtn_prgm[rtn_sp];
  2104. *pc = rtn_pc[rtn_sp];
  2105. }
  2106. }
  2107. void clear_all_rtns() {
  2108. rtn_sp = 0;
  2109. }
  2110. void setup_bigstack_for_solve_integ()
  2111. {
  2112. orig_stack_type_before_solve = flags.f.f32;
  2113. if (!orig_stack_type_before_solve)
  2114. return;
  2115. push_var_on_stack(new_real(0));
  2116. push_var_on_stack(new_real(0));
  2117. push_var_on_stack(new_real(0));
  2118. push_var_on_stack(new_real(0));
  2119. flags.f.f32 = FALSE; // Force size 4 stack mode for solving
  2120. }
  2121. // If are in bigstack mode, then change the stack mode back to bigstack
  2122. // and shift the stack back down so that only the result is the X register.
  2123. // Set restore_all to true to restore the entire stack.
  2124. void restore_bigstack_for_solve_integ(bool restore_all)
  2125. {
  2126. if (!orig_stack_type_before_solve)
  2127. return;
  2128. flags.f.f32 = TRUE;
  2129. vartype* tmp = reg_t;
  2130. reg_t = reg_x;
  2131. reg_x = tmp;
  2132. pop_var_off_stack();
  2133. pop_var_off_stack();
  2134. pop_var_off_stack();
  2135. if (restore_all)
  2136. pop_var_off_stack();
  2137. }
  2138. bool solve_active() {
  2139. int i;
  2140. for (i = 0; i < rtn_sp; i++)
  2141. if (rtn_prgm[i] == -2)
  2142. return true;
  2143. return false;
  2144. }
  2145. bool integ_active() {
  2146. int i;
  2147. for (i = 0; i < rtn_sp; i++)
  2148. if (rtn_prgm[i] == -3)
  2149. return true;
  2150. return false;
  2151. }
  2152. void unwind_stack_until_solve() {
  2153. while (rtn_prgm[--rtn_sp] != -2);
  2154. }
  2155. static bool read_int(int *n) {
  2156. return shell_read_saved_state(n, sizeof(int)) == sizeof(int);
  2157. }
  2158. static bool write_int(int n) {
  2159. return shell_write_saved_state(&n, sizeof(int));
  2160. }
  2161. static bool read_int4(int4 *n) {
  2162. return shell_read_saved_state(n, sizeof(int4)) == sizeof(int4);
  2163. }
  2164. static bool write_int4(int4 n) {
  2165. return shell_write_saved_state(&n, sizeof(int4));
  2166. }
  2167. static bool read_chars(char *c, int maxsize)
  2168. {
  2169. int readsize = 0;
  2170. do {
  2171. readsize++;
  2172. if (readsize > maxsize)
  2173. return false;
  2174. shell_read_saved_state(c, sizeof(char));
  2175. }
  2176. while(*c++ != 0);
  2177. return true;
  2178. }
  2179. static bool write_chars(char *c) {
  2180. do {
  2181. if (!shell_write_saved_state(c, sizeof(char)))
  2182. return false;
  2183. }
  2184. while (*c++ != 0);
  2185. return true;
  2186. }
  2187. static bool read_bool(bool *b) {
  2188. if (state_bool_is_int) {
  2189. int t;
  2190. if (!read_int(&t))
  2191. return false;
  2192. if (t != 0 && t != 1)
  2193. return false;
  2194. *b = t != 0;
  2195. return true;
  2196. } else {
  2197. return shell_read_saved_state(b, sizeof(bool)) == sizeof(bool);
  2198. }
  2199. }
  2200. static bool write_bool(bool b) {
  2201. return shell_write_saved_state(&b, sizeof(bool));
  2202. }
  2203. bool read_phloat(phloat *d) {
  2204. if (bin_dec_mode_switch) {
  2205. #ifdef BCD_MATH
  2206. double dbl;
  2207. if (shell_read_saved_state(&dbl, sizeof(double)) != sizeof(double))
  2208. return false;
  2209. *d = dbl;
  2210. return true;
  2211. #else
  2212. short bcd[P + 1];
  2213. if (shell_read_saved_state(bcd, (P + 1) * sizeof(short))
  2214. != (P + 1) * sizeof(short))
  2215. return false;
  2216. *d = bcd2double(bcd, state_file_has_old_bcd);
  2217. return true;
  2218. #endif
  2219. } else {
  2220. if (shell_read_saved_state(d, sizeof(phloat)) != sizeof(phloat))
  2221. return false;
  2222. #ifdef BCD_MATH
  2223. if (state_file_has_old_bcd)
  2224. bcdfloat_old2new(d->bcd.d_);
  2225. #endif
  2226. return true;
  2227. }
  2228. }
  2229. bool write_phloat(phloat d) {
  2230. return shell_write_saved_state(&d, sizeof(phloat));
  2231. }
  2232. bool load_state(int4 ver) {
  2233. int4 magic;
  2234. int4 version;
  2235. /* The shell has verified the initial magic and version numbers,
  2236. * and loaded the shell state, before we got called.
  2237. */
  2238. state_bool_is_int = ver < 9;
  2239. #ifdef BCD_MATH
  2240. if (ver < 9) {
  2241. bin_dec_mode_switch = true;
  2242. state_file_has_old_bcd = false;
  2243. } else {
  2244. bool state_is_decimal;
  2245. if (!read_bool(&state_is_decimal)) return false;
  2246. bin_dec_mode_switch = !state_is_decimal;
  2247. state_file_has_old_bcd = state_is_decimal && ver < 12;
  2248. }
  2249. #else
  2250. if (ver < 9) {
  2251. bin_dec_mode_switch = false;
  2252. state_file_has_old_bcd = false;
  2253. } else {
  2254. bool state_is_decimal;
  2255. if (!read_bool(&state_is_decimal)) return false;
  2256. bin_dec_mode_switch = state_is_decimal;
  2257. state_file_has_old_bcd = state_is_decimal && ver < 12;
  2258. }
  2259. #endif
  2260. if (ver < 2) {
  2261. core_settings.matrix_singularmatrix = false;
  2262. core_settings.matrix_outofrange = false;
  2263. } else {
  2264. if (!read_bool(&core_settings.matrix_singularmatrix)) return false;
  2265. if (!read_bool(&core_settings.matrix_outofrange)) return false;
  2266. if (ver < 9) {
  2267. int dummy;
  2268. if (!read_int(&dummy)) return false;
  2269. }
  2270. }
  2271. if (ver < 5)
  2272. core_settings.raw_text = false;
  2273. else {
  2274. if (!read_bool(&core_settings.raw_text)) return false;
  2275. if (ver < 8) {
  2276. int dummy;
  2277. if (!read_int(&dummy)) return false;
  2278. }
  2279. }
  2280. if (ver < 11)
  2281. core_settings.auto_repeat = true;
  2282. else
  2283. if (!read_bool(&core_settings.auto_repeat)) return false;
  2284. if (ver < 15) {
  2285. #if defined(COPAN)
  2286. core_settings.enable_ext_copan = true;
  2287. #else
  2288. core_settings.enable_ext_copan = false;
  2289. #endif
  2290. #if defined(BIGSTACK)
  2291. core_settings.enable_ext_bigstack = true;
  2292. #else
  2293. core_settings.enable_ext_bigstack = false;
  2294. #endif
  2295. #if defined(ANDROID) || defined(IPHONE)
  2296. core_settings.enable_ext_accel = true;
  2297. core_settings.enable_ext_locat = true;
  2298. core_settings.enable_ext_heading = true;
  2299. #else
  2300. core_settings.enable_ext_accel = false;
  2301. core_settings.enable_ext_locat = false;
  2302. core_settings.enable_ext_heading = false;
  2303. #endif
  2304. core_settings.enable_ext_time = true;
  2305. } else {
  2306. if (!read_bool(&core_settings.enable_ext_copan)) return false;
  2307. if (!read_bool(&core_settings.enable_ext_bigstack)) return false;
  2308. if (!read_bool(&core_settings.enable_ext_accel)) return false;
  2309. if (!read_bool(&core_settings.enable_ext_locat)) return false;
  2310. if (!read_bool(&core_settings.enable_ext_heading)) return false;
  2311. if (!read_bool(&core_settings.enable_ext_time)) return false;
  2312. }
  2313. if (!read_bool(&mode_clall)) return false;
  2314. if (!read_bool(&mode_command_entry)) return false;
  2315. if (!read_bool(&mode_number_entry)) return false;
  2316. if (!read_bool(&mode_alpha_entry)) return false;
  2317. if (!read_bool(&mode_shift)) return false;
  2318. if (!read_int(&mode_appmenu)) return false;
  2319. if (!read_int(&mode_plainmenu)) return false;
  2320. if (!read_bool(&mode_plainmenu_sticky)) return false;
  2321. if (!read_int(&mode_transientmenu)) return false;
  2322. if (!read_int(&mode_alphamenu)) return false;
  2323. if (!read_int(&mode_commandmenu)) return false;
  2324. if (!read_bool(&mode_running)) return false;
  2325. if (!read_bool(&mode_varmenu)) return false;
  2326. if (!read_bool(&mode_updown)) return false;
  2327. if (ver < 6)
  2328. mode_getkey = false;
  2329. else if (!read_bool(&mode_getkey))
  2330. return false;
  2331. if (!read_phloat(&entered_number)) return false;
  2332. if (!read_int(&entered_string_length)) return false;
  2333. if (shell_read_saved_state(entered_string, 15) != 15) return false;
  2334. if (!read_int(&pending_command)) return false;
  2335. if (!read_arg(&pending_command_arg, ver < 9)) return false;
  2336. if (!read_int(&xeq_invisible)) return false;
  2337. if (!read_int(&incomplete_command)) return false;
  2338. if (!read_int(&incomplete_ind)) return false;
  2339. if (!read_int(&incomplete_alpha)) return false;
  2340. if (!read_int(&incomplete_length)) return false;
  2341. if (!read_int(&incomplete_maxdigits)) return false;
  2342. if (!read_int(&incomplete_argtype)) return false;
  2343. if (!read_int(&incomplete_num)) return false;
  2344. if (shell_read_saved_state(incomplete_str, 7) != 7) return false;
  2345. if (!read_int4(&incomplete_saved_pc)) return false;
  2346. if (!read_int4(&incomplete_saved_highlight_row)) return false;
  2347. if (shell_read_saved_state(cmdline, 100) != 100) return false;
  2348. if (!read_int(&cmdline_length)) return false;
  2349. if (!read_int(&cmdline_row)) return false;
  2350. if (!read_int(&matedit_mode)) return false;
  2351. if (shell_read_saved_state(matedit_name, 7) != 7) return false;
  2352. if (!read_int(&matedit_length)) return false;
  2353. if (!unpersist_vartype(&matedit_x)) return false;
  2354. if (!read_int4(&matedit_i)) return false;
  2355. if (!read_int4(&matedit_j)) return false;
  2356. if (!read_int(&matedit_prev_appmenu)) return false;
  2357. if (shell_read_saved_state(input_name, 11) != 11) return false;
  2358. if (!read_int(&input_length)) return false;
  2359. if (!read_arg(&input_arg, ver < 9)) return false;
  2360. if (!read_int(&baseapp)) return false;
  2361. if (!read_phloat(&random_number))
  2362. return false;
  2363. if (ver < 3) {
  2364. deferred_print = 0;
  2365. } else {
  2366. if (!read_int(&deferred_print)) return false;
  2367. }
  2368. if (!read_int(&keybuf_head)) return false;
  2369. if (!read_int(&keybuf_tail)) return false;
  2370. if (shell_read_saved_state(keybuf, 16 * sizeof(int))
  2371. != 16 * sizeof(int))
  2372. return false;
  2373. if (!unpersist_display(ver))
  2374. return false;
  2375. if (!unpersist_globals(ver))
  2376. return false;
  2377. if (ver < 4) {
  2378. /* Before state file version 4, I used to save the BCD table in the
  2379. * state file. As of state file version 4, the Unix and Windows
  2380. * versions don't do that any more because they don't need to
  2381. * (generating the table on startup is fast enough); the PalmOS version
  2382. * now persists the BCD table in a database, which is faster because it
  2383. * doesn't need to be loaded and saved each time the application is
  2384. * started and stopped.
  2385. * This code is to skip the saved BCD table in state versions up to
  2386. * and including version 3.
  2387. */
  2388. int min_pow2, max_pow2;
  2389. uint4 n1, n2, n3, n4, n;
  2390. char dummy[1024];
  2391. if (!read_int(&min_pow2))
  2392. return false;
  2393. if (!read_int(&max_pow2))
  2394. return false;
  2395. n1 = 16 * (max_pow2 + 1); /* size of pos_pow2mant table */
  2396. n2 = sizeof(int) * (max_pow2 + 1); /* size of pos_pow2exp table */
  2397. n3 = 16 * (-min_pow2); /* size of neg_pow2mant table */
  2398. n4 = sizeof(int) * (-min_pow2); /* size of neg_pow2exp table */
  2399. n = n1 + n2 + n3 + n4; /* total number of bytes to skip */
  2400. while (n > 0) {
  2401. int count = n < 1024 ? n : 1024;
  2402. if (shell_read_saved_state(dummy, count) != count)
  2403. return false;
  2404. n -= count;
  2405. }
  2406. }
  2407. if (!unpersist_math(bin_dec_mode_switch))
  2408. return false;
  2409. if (!read_int4(&magic)) return false;
  2410. if (magic != FREE42_MAGIC)
  2411. return false;
  2412. if (!read_int4(&version)) return false;
  2413. if (version != ver)
  2414. return false;
  2415. return true;
  2416. }
  2417. void save_state() {
  2418. /* The shell has written the initial magic and version numbers,
  2419. * and the shell state, before we got called.
  2420. */
  2421. #ifdef BCD_MATH
  2422. if (!write_bool(true)) return;
  2423. #else
  2424. if (!write_bool(false)) return;
  2425. #endif
  2426. if (!write_bool(core_settings.matrix_singularmatrix)) return;
  2427. if (!write_bool(core_settings.matrix_outofrange)) return;
  2428. if (!write_bool(core_settings.raw_text)) return;
  2429. if (!write_bool(core_settings.auto_repeat)) return;
  2430. if (!write_bool(core_settings.enable_ext_copan)) return;
  2431. if (!write_bool(core_settings.enable_ext_bigstack)) return;
  2432. if (!write_bool(core_settings.enable_ext_accel)) return;
  2433. if (!write_bool(core_settings.enable_ext_locat)) return;
  2434. if (!write_bool(core_settings.enable_ext_heading)) return;
  2435. if (!write_bool(core_settings.enable_ext_time)) return;
  2436. if (!write_bool(mode_clall)) return;
  2437. if (!write_bool(mode_command_entry)) return;
  2438. if (!write_bool(mode_number_entry)) return;
  2439. if (!write_bool(mode_alpha_entry)) return;
  2440. if (!write_bool(mode_shift)) return;
  2441. if (!write_int(mode_appmenu)) return;
  2442. if (!write_int(mode_plainmenu)) return;
  2443. if (!write_bool(mode_plainmenu_sticky)) return;
  2444. if (!write_int(mode_transientmenu)) return;
  2445. if (!write_int(mode_alphamenu)) return;
  2446. if (!write_int(mode_commandmenu)) return;
  2447. if (!write_bool(mode_running)) return;
  2448. if (!write_bool(mode_varmenu)) return;
  2449. if (!write_bool(mode_updown)) return;
  2450. if (!write_bool(mode_getkey)) return;
  2451. if (!write_phloat(entered_number)) return;
  2452. if (!write_int(entered_string_length)) return;
  2453. if (!shell_write_saved_state(entered_string, 15)) return;
  2454. if (!write_int(pending_command)) return;
  2455. if (!shell_write_saved_state(&pending_command_arg, sizeof(arg_struct))) return;
  2456. if (!write_int(xeq_invisible)) return;
  2457. if (!write_int(incomplete_command)) return;
  2458. if (!write_int(incomplete_ind)) return;
  2459. if (!write_int(incomplete_alpha)) return;
  2460. if (!write_int(incomplete_length)) return;
  2461. if (!write_int(incomplete_maxdigits)) return;
  2462. if (!write_int(incomplete_argtype)) return;
  2463. if (!write_int(incomplete_num)) return;
  2464. if (!shell_write_saved_state(incomplete_str, 7)) return;
  2465. if (!write_int4(incomplete_saved_pc)) return;
  2466. if (!write_int4(incomplete_saved_highlight_row)) return;
  2467. if (!shell_write_saved_state(cmdline, 100)) return;
  2468. if (!write_int(cmdline_length)) return;
  2469. if (!write_int(cmdline_row)) return;
  2470. if (!write_int(matedit_mode)) return;
  2471. if (!shell_write_saved_state(matedit_name, 7)) return;
  2472. if (!write_int(matedit_length)) return;
  2473. if (!persist_vartype(matedit_x)) return;
  2474. if (!write_int4(matedit_i)) return;
  2475. if (!write_int4(matedit_j)) return;
  2476. if (!write_int(matedit_prev_appmenu)) return;
  2477. if (!shell_write_saved_state(input_name, 11)) return;
  2478. if (!write_int(input_length)) return;
  2479. if (!shell_write_saved_state(&input_arg, sizeof(arg_struct))) return;
  2480. if (!write_int(baseapp)) return;
  2481. if (!write_phloat(random_number)) return;
  2482. if (!write_int(deferred_print)) return;
  2483. if (!write_int(keybuf_head)) return;
  2484. if (!write_int(keybuf_tail)) return;
  2485. if (!shell_write_saved_state(keybuf, 16 * sizeof(int))) return;
  2486. if (!persist_display())
  2487. return;
  2488. if (!persist_globals())
  2489. return;
  2490. if (!persist_math())
  2491. return;
  2492. if (!write_int4(FREE42_MAGIC)) return;
  2493. if (!write_int4(FREE42_VERSION)) return;
  2494. }
  2495. void hard_reset(int bad_state_file) {
  2496. vartype *regs;
  2497. /* Clear stack */
  2498. free_vartype(reg_x);
  2499. free_vartype(reg_y);
  2500. free_vartype(reg_z);
  2501. free_vartype(reg_t);
  2502. #ifdef BIGSTACK
  2503. while(bigstack_head != NULL)
  2504. {
  2505. shift_big_stack_down();
  2506. free_vartype(reg_t);
  2507. }
  2508. #endif
  2509. free_vartype(reg_lastx);
  2510. reg_x = new_real(0);
  2511. reg_y = new_real(0);
  2512. reg_z = new_real(0);
  2513. reg_t = new_real(0);
  2514. reg_lastx = new_real(0);
  2515. /* Clear alpha */
  2516. reg_alpha_length = 0;
  2517. /* Clear variables */
  2518. purge_all_vars();
  2519. regs = new_realmatrix(25, 1);
  2520. store_var("REGS", 4, regs);
  2521. /* Clear programs */
  2522. if (prgms != NULL) {
  2523. free(prgms);
  2524. prgms = NULL;
  2525. prgms_capacity = 0;
  2526. prgms_count = 0;
  2527. }
  2528. if (labels != NULL) {
  2529. free(labels);
  2530. labels = NULL;
  2531. labels_capacity = 0;
  2532. labels_count = 0;
  2533. }
  2534. goto_dot_dot();
  2535. pending_command = CMD_NONE;
  2536. matedit_mode = 0;
  2537. input_length = 0;
  2538. baseapp = 0;
  2539. random_number = shell_random_seed();
  2540. flags.f.f00 = flags.f.f01 = flags.f.f02 = flags.f.f03 = flags.f.f04 = 0;
  2541. flags.f.f05 = flags.f.f06 = flags.f.f07 = flags.f.f08 = flags.f.f09 = 0;
  2542. flags.f.f10 = 0;
  2543. flags.f.auto_exec = 0;
  2544. flags.f.double_wide_print = 0;
  2545. flags.f.lowercase_print = 0;
  2546. flags.f.f14 = 0;
  2547. flags.f.trace_print = 0;
  2548. flags.f.normal_print = 0;
  2549. flags.f.f17 = flags.f.f18 = flags.f.f19 = flags.f.f20 = 0;
  2550. flags.f.printer_enable = 1; // HP-42S sets this to 0 on hard reset
  2551. flags.f.numeric_data_input = 0;
  2552. flags.f.alpha_data_input = 0;
  2553. flags.f.range_error_ignore = 0;
  2554. flags.f.error_ignore = 0;
  2555. flags.f.audio_enable = 1;
  2556. /* flags.f.VIRTUAL_custom_menu = 0; */
  2557. flags.f.decimal_point = 1;
  2558. flags.f.thousands_separators = 1;
  2559. flags.f.stack_lift_disable = 0;
  2560. flags.f.f31 = flags.f.f32 = flags.f.f33 = 0;
  2561. flags.f.agraph_control1 = 0;
  2562. flags.f.agraph_control0 = 0;
  2563. flags.f.digits_bit3 = 0;
  2564. flags.f.digits_bit2 = 1;
  2565. flags.f.digits_bit1 = 0;
  2566. flags.f.digits_bit0 = 0;
  2567. flags.f.fix_or_all = 1;
  2568. flags.f.eng_or_all = 1;
  2569. flags.f.grad = 0;
  2570. flags.f.rad = 0;
  2571. flags.f.continuous_on = 0;
  2572. /* flags.f.VIRTUAL_solving = 0; */
  2573. /* flags.f.VIRTUAL_integrating = 0; */
  2574. /* flags.f.VIRTUAL_variable_menu = 0; */
  2575. flags.f.alpha_mode = 0;
  2576. /* flags.f.VIRTUAL_low_battery = 0; */
  2577. flags.f.message = 1;
  2578. flags.f.two_line_message = 0;
  2579. flags.f.prgm_mode = 0;
  2580. /* flags.f.VIRTUAL_input = 0; */
  2581. flags.f.f54 = 0;
  2582. flags.f.printer_exists = 1; // HP-42S sets this to 0 on hard reset
  2583. flags.f.lin_fit = 1;
  2584. flags.f.log_fit = 0;
  2585. flags.f.exp_fit = 0;
  2586. flags.f.pwr_fit = 0;
  2587. flags.f.all_sigma = 1;
  2588. flags.f.log_fit_invalid = 0;
  2589. flags.f.exp_fit_invalid = 0;
  2590. flags.f.pwr_fit_invalid = 0;
  2591. flags.f.f64 = 0;
  2592. /* flags.f.VIRTUAL_matrix_editor = 0; */
  2593. flags.f.grow = 0;
  2594. flags.f.f67 = 0;
  2595. flags.f.base_bit0 = 0;
  2596. flags.f.base_bit1 = 0;
  2597. flags.f.base_bit2 = 0;
  2598. flags.f.base_bit3 = 0;
  2599. flags.f.local_label = 0;
  2600. flags.f.polar = 0;
  2601. flags.f.real_result_only = 0;
  2602. /* flags.f.VIRTUAL_programmable_menu = 0; */
  2603. flags.f.matrix_edge_wrap = 0;
  2604. flags.f.matrix_end_wrap = 0;
  2605. flags.f.f78 = flags.f.f79 = flags.f.f80 = flags.f.f81 = flags.f.f82 = 0;
  2606. flags.f.f83 = flags.f.f84 = flags.f.f85 = flags.f.f86 = flags.f.f87 = 0;
  2607. flags.f.f88 = flags.f.f89 = flags.f.f90 = flags.f.f91 = flags.f.f92 = 0;
  2608. flags.f.f93 = flags.f.f94 = flags.f.f95 = flags.f.f96 = flags.f.f97 = 0;
  2609. flags.f.f98 = flags.f.f99 = 0;
  2610. mode_clall = false;
  2611. mode_command_entry = false;
  2612. mode_number_entry = false;
  2613. mode_alpha_entry = false;
  2614. mode_shift = false;
  2615. mode_commandmenu = MENU_NONE;
  2616. mode_alphamenu = MENU_NONE;
  2617. mode_transientmenu = MENU_NONE;
  2618. mode_plainmenu = MENU_NONE;
  2619. mode_appmenu = MENU_NONE;
  2620. mode_running = false;
  2621. mode_getkey = false;
  2622. mode_pause = false;
  2623. mode_varmenu = false;
  2624. prgm_highlight_row = 0;
  2625. varmenu_length = 0;
  2626. mode_updown = false;
  2627. mode_sigma_reg = 11;
  2628. mode_goose = -1;
  2629. mode_time_clktd = false;
  2630. mode_time_clk24 = false;
  2631. mode_time_dmy = false;
  2632. core_settings.auto_repeat = true;
  2633. #if defined(COPAN)
  2634. core_settings.enable_ext_copan = true;
  2635. #else
  2636. core_settings.enable_ext_copan = false;
  2637. #endif
  2638. #if defined(BIGSTACK)
  2639. core_settings.enable_ext_bigstack = true;
  2640. #else
  2641. core_settings.enable_ext_bigstack = false;
  2642. #endif
  2643. #if defined(ANDROID) || defined(IPHONE)
  2644. core_settings.enable_ext_accel = true;
  2645. core_settings.enable_ext_locat = true;
  2646. core_settings.enable_ext_heading = true;
  2647. #else
  2648. core_settings.enable_ext_accel = false;
  2649. core_settings.enable_ext_locat = false;
  2650. core_settings.enable_ext_heading = false;
  2651. #endif
  2652. core_settings.enable_ext_time = true;
  2653. reset_math();
  2654. clear_display();
  2655. clear_custom_menu();
  2656. clear_prgm_menu();
  2657. if (bad_state_file)
  2658. draw_string(0, 0, "State File Corrupt", 18);
  2659. else
  2660. draw_string(0, 0, "Memory Clear", 12);
  2661. display_x(1);
  2662. flush_display();
  2663. }
  2664. struct dec_arg_struct {
  2665. unsigned char type;
  2666. unsigned char length;
  2667. int4 target;
  2668. union {
  2669. int4 num;
  2670. char text[15];
  2671. char stk;
  2672. int cmd;
  2673. char lclbl;
  2674. } val;
  2675. fake_bcd val_d;
  2676. };
  2677. struct bin_arg_struct {
  2678. unsigned char type;
  2679. unsigned char length;
  2680. int4 target;
  2681. union {
  2682. int4 num;
  2683. char text[15];
  2684. char stk;
  2685. int cmd;
  2686. char lclbl;
  2687. } val;
  2688. double val_d;
  2689. };
  2690. bool read_arg(arg_struct *arg, bool old) {
  2691. if (old) {
  2692. // Prior to core state version 9, the arg_struct type saved a bit of
  2693. // by using a union to hold the argument value.
  2694. // In version 9, we switched from using 'double' as our main numeric
  2695. // data type to 'phloat' -- but since 'phloat' is a class, with a
  2696. // constructor, it cannot be a member of a union.
  2697. // So, I had to change the 'val' member from a union to a struct.
  2698. // Of course, this means that the arg_struct layout is now different,
  2699. // and when deserializing a pre-9 state file, I must make sure to
  2700. // deserialize an old-stype arg_struct and then convert it to a
  2701. // new one.
  2702. struct {
  2703. unsigned char type;
  2704. unsigned char length;
  2705. int4 target;
  2706. union {
  2707. int4 num;
  2708. char text[15];
  2709. char stk;
  2710. int cmd; /* For backward compatibility only! */
  2711. char lclbl;
  2712. double d;
  2713. } val;
  2714. } old_arg;
  2715. if (shell_read_saved_state(&old_arg, sizeof(old_arg))
  2716. != sizeof(old_arg))
  2717. return false;
  2718. arg->type = old_arg.type;
  2719. arg->length = old_arg.length;
  2720. arg->target = old_arg.target;
  2721. char *d = (char *) &arg->val;
  2722. char *s = (char *) &old_arg.val;
  2723. for (unsigned int i = 0; i < sizeof(old_arg.val); i++)
  2724. *d++ = *s++;
  2725. arg->val_d = old_arg.val.d;
  2726. return true;
  2727. } else if (bin_dec_mode_switch) {
  2728. #ifdef BCD_MATH
  2729. bin_arg_struct ba;
  2730. if (shell_read_saved_state(&ba, sizeof(bin_arg_struct))
  2731. != sizeof(bin_arg_struct))
  2732. return false;
  2733. arg->type = ba.type;
  2734. arg->length = ba.length;
  2735. arg->target = ba.target;
  2736. char *d = (char *) &arg->val;
  2737. char *s = (char *) &ba.val;
  2738. for (unsigned int i = 0; i < sizeof(ba.val); i++)
  2739. *d++ = *s++;
  2740. arg->val_d = ba.val_d;
  2741. #else
  2742. dec_arg_struct da;
  2743. if (shell_read_saved_state(&da, sizeof(dec_arg_struct))
  2744. != sizeof(dec_arg_struct))
  2745. return false;
  2746. arg->type = da.type;
  2747. arg->length = da.length;
  2748. arg->target = da.target;
  2749. char *d = (char *) &arg->val;
  2750. char *s = (char *) &da.val;
  2751. for (unsigned int i = 0; i < sizeof(da.val); i++)
  2752. *d++ = *s++;
  2753. arg->val_d = bcd2double(da.val_d.d_, state_file_has_old_bcd);
  2754. #endif
  2755. return true;
  2756. } else {
  2757. return shell_read_saved_state(arg, sizeof(arg_struct))
  2758. == sizeof(arg_struct);
  2759. }
  2760. }
  2761. static bool convert_programs() {
  2762. // This function is called if the setting of mode_decimal recorded in the
  2763. // state file does not match the current setting (i.e., if we're a binary
  2764. // Free42 and the state file was written by the decimal version, or vice
  2765. // versa).
  2766. // This function looks for floating-point number literals (command =
  2767. // CMD_NUMBER with arg.type = ARGTYPE_DOUBLE) and converts them from double
  2768. // to Phloat or the other way around.
  2769. int saved_prgm = current_prgm;
  2770. int4 saved_pc = pc;
  2771. int i;
  2772. // Since converting programs can cause instructions to move, I have to
  2773. // update all stored PC values to correct for this. PCs are stored in the
  2774. // 'pc' and 'rtn_pc[]' globals. I copy those values into a local array,
  2775. // which I then sort by program index and pc; this allows me to do the
  2776. // updates very efficiently later on.
  2777. int mod_prgm[MAX_RTNS + 2];
  2778. int4 mod_pc[MAX_RTNS + 2];
  2779. int mod_sp[MAX_RTNS + 2];
  2780. int mod_count = 0;
  2781. for (i = 0; i < rtn_sp; i++) {
  2782. int prgm = rtn_prgm[i];
  2783. if (prgm == -2 || prgm == -3) {
  2784. // Return-to-solve and return-to-integ
  2785. // On a binary/decimal mode switch, unpersist_math() discards all
  2786. // the SOLVE and INTEG state. If SOLVE or INTEG are actually
  2787. // active, we have to clear the RTN stack, too.
  2788. rtn_sp = 0;
  2789. mod_count = 0;
  2790. break;
  2791. }
  2792. mod_prgm[mod_count] = prgm;
  2793. mod_pc[mod_count] = rtn_pc[i];
  2794. mod_sp[mod_count] = i;
  2795. mod_count++;
  2796. }
  2797. if (saved_pc > 0) {
  2798. mod_prgm[mod_count] = current_prgm;
  2799. mod_pc[mod_count] = saved_pc;
  2800. mod_sp[mod_count] = -1;
  2801. mod_count++;
  2802. }
  2803. if (incomplete_saved_pc > 0) {
  2804. mod_prgm[mod_count] = current_prgm;
  2805. mod_pc[mod_count] = incomplete_saved_pc;
  2806. mod_sp[mod_count] = -2;
  2807. mod_count++;
  2808. }
  2809. mod_count--;
  2810. for (i = 0; i < mod_count; i++)
  2811. for (int j = i + 1; j <= mod_count; j++)
  2812. if (mod_prgm[i] < mod_prgm[j]
  2813. || (mod_prgm[i] == mod_prgm[j] && mod_pc[i] < mod_pc[j])) {
  2814. int tmp = mod_prgm[i];
  2815. mod_prgm[i] = mod_prgm[j];
  2816. mod_prgm[j] = tmp;
  2817. int4 tmp4 = mod_pc[i];
  2818. mod_pc[i] = mod_pc[j];
  2819. mod_pc[j] = tmp4;
  2820. tmp = mod_sp[i];
  2821. mod_sp[i] = mod_sp[j];
  2822. mod_sp[j] = tmp;
  2823. }
  2824. for (i = 0; i < prgms_count; i++) {
  2825. current_prgm = i;
  2826. pc = 0;
  2827. int4 oldpc = 0;
  2828. prgm_struct *prgm = prgms + i;
  2829. prgm->lclbl_invalid = 1;
  2830. while (true) {
  2831. while (mod_count >= 0 && current_prgm == mod_prgm[mod_count]
  2832. && oldpc >= mod_pc[mod_count]) {
  2833. // oldpc should never be greater than mod_pc[mod_count]; this
  2834. // means that something is out of whack, because we have an old
  2835. // PC value that does not actually coincide with the beginning
  2836. // of an instruction.
  2837. int s = mod_sp[mod_count];
  2838. if (s == -1)
  2839. saved_pc = pc;
  2840. else if (s == -2)
  2841. incomplete_saved_pc = pc;
  2842. else
  2843. rtn_pc[s] = pc;
  2844. mod_count--;
  2845. }
  2846. int4 prevpc = pc;
  2847. int command = prgm->text[pc++];
  2848. int argtype = prgm->text[pc++];
  2849. command |= (argtype & 240) << 4;
  2850. argtype &= 15;
  2851. if (command == CMD_END)
  2852. break;
  2853. if ((command == CMD_GTO || command == CMD_XEQ)
  2854. && (argtype == ARGTYPE_NUM || argtype == ARGTYPE_LCLBL)) {
  2855. // Invalidate local label offsets
  2856. prgm->text[pc++] = 255;
  2857. prgm->text[pc++] = 255;
  2858. prgm->text[pc++] = 255;
  2859. prgm->text[pc++] = 255;
  2860. }
  2861. switch (argtype) {
  2862. case ARGTYPE_NUM:
  2863. case ARGTYPE_NEG_NUM:
  2864. case ARGTYPE_IND_NUM: {
  2865. while ((prgm->text[pc++] & 128) == 0);
  2866. break;
  2867. }
  2868. case ARGTYPE_STK:
  2869. case ARGTYPE_IND_STK:
  2870. case ARGTYPE_COMMAND:
  2871. case ARGTYPE_LCLBL:
  2872. pc++;
  2873. break;
  2874. case ARGTYPE_STR:
  2875. case ARGTYPE_IND_STR: {
  2876. pc += prgm->text[pc] + 1;
  2877. break;
  2878. }
  2879. case ARGTYPE_DOUBLE:
  2880. #ifdef BCD_MATH
  2881. double d;
  2882. int j;
  2883. unsigned char *b = (unsigned char *) &d;
  2884. for (j = 0; j < (int) sizeof(double); j++)
  2885. *b++ = prgm->text[pc++];
  2886. pc -= sizeof(double);
  2887. int growth = sizeof(phloat) - sizeof(double);
  2888. int4 pos;
  2889. if (prgm->size + growth > prgm->capacity) {
  2890. unsigned char *newtext;
  2891. prgm->capacity += 512;
  2892. newtext = (unsigned char *) malloc(prgm->capacity);
  2893. if (newtext == NULL)
  2894. // Failed to grow program; abort.
  2895. return false;
  2896. for (pos = 0; pos < pc; pos++)
  2897. newtext[pos] = prgm->text[pos];
  2898. for (pos = pc; pos < prgm->size; pos++)
  2899. newtext[pos + growth] = prgm->text[pos];
  2900. if (prgm->text != NULL)
  2901. free(prgm->text);
  2902. prgm->text = newtext;
  2903. } else {
  2904. for (pos = prgm->size - 1; pos >= pc; pos--)
  2905. prgm->text[pos + growth] = prgm->text[pos];
  2906. }
  2907. prgm->size += growth;
  2908. oldpc -= growth;
  2909. phloat p;
  2910. p.bcd = double2bcd(d, true);
  2911. b = (unsigned char *) &p;
  2912. for (j = 0; j < (int) sizeof(phloat); j++)
  2913. prgm->text[pc++] = *b++;
  2914. #else
  2915. fake_bcd bcd;
  2916. int j;
  2917. unsigned char *b = (unsigned char *) &bcd;
  2918. for (j = 0; j < (int) sizeof(fake_bcd); j++)
  2919. *b++ = prgm->text[pc++];
  2920. double dbl = bcd2double(bcd.d_, state_file_has_old_bcd);
  2921. int inf = isinf(dbl);
  2922. if (inf > 0)
  2923. dbl = POS_HUGE_PHLOAT;
  2924. else if (inf < 0)
  2925. dbl = NEG_HUGE_PHLOAT;
  2926. else if (dbl == 0) {
  2927. if (bcd.d_[0] != 0)
  2928. if ((bcd.d_[P] & 0x8000) == 0)
  2929. dbl = POS_TINY_PHLOAT;
  2930. else
  2931. dbl = NEG_TINY_PHLOAT;
  2932. }
  2933. pc -= sizeof(fake_bcd);
  2934. b = (unsigned char *) &dbl;
  2935. for (j = 0; j < (int) sizeof(double); j++)
  2936. prgm->text[pc++] = *b++;
  2937. int shrinkage = sizeof(fake_bcd) - sizeof(double);
  2938. prgm->size -= shrinkage;
  2939. for (int4 pos = pc; pos < prgm->size; pos++)
  2940. prgm->text[pos] = prgm->text[pos + shrinkage];
  2941. oldpc += shrinkage;
  2942. #endif
  2943. break;
  2944. }
  2945. oldpc += pc - prevpc;
  2946. }
  2947. }
  2948. current_prgm = saved_prgm;
  2949. pc = saved_pc;
  2950. return true;
  2951. }
  2952. #ifdef BIGSTACK
  2953. static stack_item* stack_item_pool = NULL;
  2954. static int MAX_STACK_SIZE = 40;
  2955. stack_item* new_stack_item(vartype* v) {
  2956. stack_item* si = NULL;
  2957. if (stack_item_pool == NULL)
  2958. si = (stack_item*)malloc(sizeof(stack_item));
  2959. else {
  2960. si = stack_item_pool;
  2961. stack_item_pool = si->next;
  2962. }
  2963. si->var = v;
  2964. si->next = NULL;
  2965. return si;
  2966. }
  2967. void free_stack_item(stack_item* si) {
  2968. si->next = stack_item_pool;
  2969. stack_item_pool = si;
  2970. si->var = NULL;
  2971. }
  2972. /* Debug method to verify the integrity of the stack */
  2973. int big_stack_verify() {
  2974. stack_item *si = bigstack_head;
  2975. int size = 0;
  2976. while (si != NULL) {
  2977. si = si->next;
  2978. size++;
  2979. /* If size is crazy big then we are probably in an infinite loop. */
  2980. if (size > MAX_STACK_SIZE*10) {
  2981. return 1;
  2982. }
  2983. }
  2984. if (size > 0 && size + 4 != stacksize) {
  2985. return 2;
  2986. }
  2987. if (stacksize > MAX_STACK_SIZE) {
  2988. return 3;
  2989. }
  2990. if (stacksize < 3) {
  2991. return 5;
  2992. }
  2993. return 0;
  2994. }
  2995. void push_var_on_stack(vartype *var)
  2996. {
  2997. if (flags.f.f32)
  2998. shift_big_stack_up();
  2999. else
  3000. free_vartype(reg_t);
  3001. reg_t = reg_z;
  3002. reg_z = reg_y;
  3003. reg_y = reg_x;
  3004. reg_x = var;
  3005. }
  3006. void pop_var_off_stack()
  3007. {
  3008. free_vartype(reg_x);
  3009. reg_x = reg_y;
  3010. reg_y = reg_z;
  3011. reg_z = reg_t;
  3012. if (flags.f.f32)
  3013. shift_big_stack_down();
  3014. else
  3015. reg_t = dup_vartype(reg_t);
  3016. }
  3017. void shift_big_stack_up() {
  3018. stacksize++;
  3019. if (stacksize > 4) {
  3020. stack_item* si = new_stack_item(reg_t);
  3021. si->next = bigstack_head;
  3022. bigstack_head = si;
  3023. if (stacksize > MAX_STACK_SIZE) {
  3024. /* Stack has grown too big, so remove last element, not
  3025. the most efficient method, but well behaving programs
  3026. should not trash the stack either */
  3027. si = bigstack_head;
  3028. while (si->next->next != NULL)
  3029. si = si->next;
  3030. free_vartype(si->next->var);
  3031. free_stack_item(si->next);
  3032. si->next = NULL;
  3033. stacksize--;
  3034. assert(stacksize == MAX_STACK_SIZE);
  3035. }
  3036. }
  3037. else {
  3038. if (stacksize == 4 && reg_z->type == TYPE_REAL && ((vartype_real*)reg_z)->x == 0)
  3039. stacksize --;
  3040. assert(stacksize == 3 || stacksize == 4);
  3041. /* We can't move reg_t into the extended stack so we free it
  3042. here, calling code depends on this behavior */
  3043. free_vartype(reg_t);
  3044. }
  3045. assert(big_stack_verify() == 0);
  3046. }
  3047. void shift_big_stack_down() {
  3048. stacksize--;
  3049. if (bigstack_head == NULL) {
  3050. reg_t = new_real(0);
  3051. if (stacksize < 3) stacksize = 3;
  3052. }
  3053. else {
  3054. assert(stacksize >= 4);
  3055. reg_t = bigstack_head->var;
  3056. stack_item* si = bigstack_head;
  3057. bigstack_head = si->next;
  3058. free_stack_item(si);
  3059. }
  3060. assert(big_stack_verify() == 0);
  3061. }
  3062. void clean_stack_item_pool() {
  3063. while (stack_item_pool != NULL)
  3064. {
  3065. stack_item *si = stack_item_pool;
  3066. stack_item_pool = stack_item_pool->next;
  3067. free(si);
  3068. }
  3069. }
  3070. #endif
  3071. #ifdef IPHONE
  3072. static void convert_bigstack_drop() {
  3073. // This function is called when we've read an iPhone version state file
  3074. // with version number 12 or 13. In those two versions, the DROP command
  3075. // was at index 315 of the commands table, but that conflicted with
  3076. // Underhill's COPAN extensions. In version 14 and later, I moved DROP
  3077. // to index 329 to fix this clash. This will allow all extensions to
  3078. // coexist in the future, should someone want to merge them all into one
  3079. // build at some point -- and even if that never happens, at least now
  3080. // all programs in all versions are encoded identically.
  3081. for (int i = 0; i < prgms_count; i++) {
  3082. int pc = 0;
  3083. prgm_struct *prgm = prgms + i;
  3084. while (true) {
  3085. int command = prgm->text[pc++];
  3086. int argtype = prgm->text[pc++];
  3087. command |= (argtype & 240) << 4;
  3088. argtype &= 15;
  3089. if (command == CMD_END)
  3090. break;
  3091. if (command == 315) { // Pre-version-14 value of CMD_DROP
  3092. prgm->text[pc - 2] = (unsigned char) CMD_DROP;
  3093. prgm->text[pc - 1] = (unsigned char) ((CMD_DROP & 0xF00) >> 4 | argtype);
  3094. }
  3095. if ((command == CMD_GTO || command == CMD_XEQ)
  3096. && (argtype == ARGTYPE_NUM || argtype == ARGTYPE_LCLBL)) {
  3097. pc += 4;
  3098. }
  3099. switch (argtype) {
  3100. case ARGTYPE_NUM:
  3101. case ARGTYPE_NEG_NUM:
  3102. case ARGTYPE_IND_NUM: {
  3103. while ((prgm->text[pc++] & 128) == 0);
  3104. break;
  3105. }
  3106. case ARGTYPE_STK:
  3107. case ARGTYPE_IND_STK:
  3108. case ARGTYPE_COMMAND:
  3109. case ARGTYPE_LCLBL:
  3110. pc++;
  3111. break;
  3112. case ARGTYPE_STR:
  3113. case ARGTYPE_IND_STR: {
  3114. pc += prgm->text[pc] + 1;
  3115. break;
  3116. }
  3117. case ARGTYPE_DOUBLE:
  3118. pc += sizeof(phloat);
  3119. break;
  3120. }
  3121. }
  3122. }
  3123. }
  3124. static bool persist_undo() {
  3125. if (!write_int(snapshot_count))
  3126. return false;
  3127. if (!write_int(undo_pos))
  3128. return false;
  3129. snapshot *snap = snapshot_head;
  3130. while (snap != NULL)
  3131. {
  3132. if (!write_chars(snap->describe))
  3133. return false;
  3134. stack_item *si = snap->stack_item_head;
  3135. int size = 0;
  3136. // get stack size
  3137. while (si != NULL) {
  3138. size++;
  3139. si = si->next;
  3140. }
  3141. if (!write_int(size))
  3142. return false;
  3143. si = snap->stack_item_head;
  3144. while (si != NULL) {
  3145. if (!persist_vartype(si->var))
  3146. return false;
  3147. si = si->next;
  3148. }
  3149. snap = snap->next;
  3150. }
  3151. return true;
  3152. }
  3153. static bool unpersist_undo() {
  3154. snapshot_head = NULL;
  3155. if (!read_int(&snapshot_count))
  3156. return false;
  3157. if (!read_int(&undo_pos))
  3158. return false;
  3159. int count = 0;
  3160. snapshot *snap = NULL;
  3161. while (count < snapshot_count) {
  3162. if (count == 0) {
  3163. snapshot_head = (snapshot*)malloc(sizeof(snapshot));
  3164. snap = snapshot_head;
  3165. }
  3166. else {
  3167. snap->next = (snapshot*)malloc(sizeof(snapshot));
  3168. snap = snap->next;
  3169. }
  3170. snap->next = NULL;
  3171. snap->stack_item_head = NULL;
  3172. if (!read_chars(snap->describe, DESC_SIZE))
  3173. return false;
  3174. int size = 0;
  3175. // stack size of this snapshot
  3176. if (!read_int(&size))
  3177. return false;
  3178. stack_item *last_si = NULL;
  3179. while (size-- > 0)
  3180. {
  3181. vartype *v = NULL;
  3182. if (!unpersist_vartype(&v))
  3183. return false;
  3184. stack_item *si = new_stack_item(v);
  3185. si->next = NULL;
  3186. if (last_si == NULL) {
  3187. snap->stack_item_head = si;
  3188. }
  3189. else {
  3190. last_si->next = si;
  3191. }
  3192. last_si = si;
  3193. }
  3194. count++;
  3195. }
  3196. return true;
  3197. }
  3198. #endif
  3199. #ifdef ANDROID
  3200. void reinitialize_globals() {
  3201. /* The Android version may call core_init() after core_quit(), in other
  3202. * words, the globals may live for more than one session. This caused
  3203. * crashes in the initial builds, because of course global initializers
  3204. * are only invoked once, and core_quit() did not bother to clean things
  3205. * up so that core_init() would be able to run safely.
  3206. * In my defense, this wasn't sloppy coding; core_quit() does deallocate
  3207. * everything -- I've tested Free42 for memory leaks using POSE many
  3208. * times, and it is solid in that regard. The dangling pointers left
  3209. * by core_quit() are never a problem as long as core_init() and
  3210. * core_quit() are only called once per process.
  3211. * Anyway: the following are re-initializations of some globals that
  3212. * could cause double-free() memory corruption, or other (less fatal, but
  3213. * still annoying) misbehaviors if left as they are.
  3214. */
  3215. reg_x = NULL;
  3216. reg_y = NULL;
  3217. reg_z = NULL;
  3218. reg_t = NULL;
  3219. reg_lastx = NULL;
  3220. reg_alpha_length = 0;
  3221. vars_capacity = 0;
  3222. vars_count = 0;
  3223. vars = NULL;
  3224. prgms_capacity = 0;
  3225. prgms_count = 0;
  3226. prgms = NULL;
  3227. labels_capacity = 0;
  3228. labels_count = 0;
  3229. labels = NULL;
  3230. current_prgm = -1;
  3231. prgm_highlight_row = 0;
  3232. mode_interruptible = NULL;
  3233. mode_pause = false;
  3234. baseapp = 0;
  3235. deferred_print = 0;
  3236. keybuf_head = 0;
  3237. keybuf_tail = 0;
  3238. remove_program_catalog = 0;
  3239. rtn_sp = 0;
  3240. }
  3241. #endif