PageRenderTime 67ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/free42/common/core_globals.cc

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