├── LICENSE ├── README.md ├── icon.png ├── includes_vizualizer ├── cinclude2dot.pl └── sh_vizualize_includes.sh ├── makefile ├── screenshots ├── EDB_error_message.png ├── editor_example.png └── main_menu.png └── src ├── asmutil.asm ├── asmutil.h ├── ccdbg ├── ccdbg.cpp └── ccdbg.h ├── cutil.c ├── cutil.h ├── defines.c ├── defines.h ├── editor.c ├── editor.h ├── gui.c ├── gui.h ├── hevat.c ├── hevat.h ├── keypad.c ├── keypad.h ├── list.c ├── list.h ├── main.c ├── main_gui.c ├── main_gui.h ├── main_hl.c ├── main_hl.h ├── tools.c └── tools.h /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2024, Caleb "Captain Calc" Arant 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | 3. Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HexaEdit CE 2 | 3 | HexaEdit CE is a powerful on-calc hex editor for the TI-84 Plus CE. It allows you to edit: 4 | 5 | * Any TI-OS variable (programs, appvars, equations, etc.) 6 | * RAM 7 | * "Ports" (0xE00000 - 0xFFFFFF) 8 | 9 | It also enables you to view, but not edit, the calculator's ROM. 10 | 11 | ![Screenshot showing the main menu.](screenshots/main_menu.png) 12 | 13 | ![Screenshot showing editor.](screenshots/editor_example.png) 14 | 15 | The GUI editor offers a wide array of features, such as: 16 | 17 | * Direct letter-and-digit input (Pressing "A" writes its ASCII code.) 18 | * Cut-copy-paste 19 | * Automatic decimal translation of up to three bytes allowing for little-endian storage 20 | * A Find function for looking up short strings 21 | * A quick Goto function 22 | * And, an undo function 23 | 24 | To find out more about HexaEdit CE, please visit its [Cemetech forum thread](https://www.cemetech.net/forum/viewtopic.php?t=16759). 25 | 26 | ## Installation 27 | 28 | After extracting the HexaEdit_CE.zip file, send the following file to your calculator using a computer-calculator link program, such as TI-Connect CE or TILP: 29 | 30 | * HEXAEDIT.8xp 31 | 32 | This program requires the latest C libraries produced by the CE-Programming team. 33 | 34 | ## Warning! 35 | HexaEdit is like Linux: it allows you to do almost anything you want, but it does not prevent you from making serious mistakes. Arbitrarily writing values to RAM, Ports, or TI-OS variables might make your calculator crash, or, in the worst case, it will irreversibly damage your device ("bricking"). 36 | 37 | As it states in the BSD-3 license, the author is not responsible for any damage that this program may inflict. 38 | 39 | **Make sure you know what you are doing before using this program!** 40 | 41 | ## Overview of the Main Menu 42 | 43 | The main menu displays a three-column interface that hierarchically categorizes each variable. The rightmost column shows important metadata about each variable, like size, VAT location, and memory location. The bottom toolbar provides easy access to HexaEdit's ROM viewer, RAM editor, and Ports editor. 44 | 45 | The main menu also shows the amount of free RAM and free ROM on the calculator in the lower right-hand corner. The amount of free RAM does not include what HexaEdit is using at run-time. Above the RAM and ROM fields is one called *EDB*, "**ED**it **B**uffer Size", and it shows the edit buffer's capacity, in bytes. You cannot edit a variable with a greater size than the *EDB*. To increase the *EDB*'s capacity, you can archive or delete other variables on the calculator. 46 | 47 | ![Screenshot showing EDB error message.](screenshots/EDB_error_message.png) 48 | 49 | ## Controls 50 | 51 | HexaEdit 3 changes a few keybindings from version 2.1.0, but most of them have remain the same. The dedicated "Exit" button on the far right of the tool bar is gone, and [clear] has been extended to make it the de facto standard for exiting submenus, editors, and so on. 52 | 53 | ### Main Menu 54 | 55 | ![Screenshot showing the main menu.](screenshots/main_menu.png) 56 | 57 | | Key | Description 58 | | -------------- | ----------- 59 | | [up]/[down] | Change vertical position of the list cursor. 60 | | [left]/[right] | Switch between the left-column list and middle-column lists. If the list cursor is in the middle-column list, pressing [right] will open the selected variable. 61 | | [2nd]/[Enter] | If the list cursor is in the middle-column list, open the selected variable. 62 | | [y=] | Open the ROM Viewer. 63 | | [window] | Open the RAM Editor. 64 | | [zoom] | Open the Ports Editor. 65 | | [graph] | Open the About dialog. 66 | | [clear] | Exit the program. 67 | 68 | If the list cursor is in the middle-column list, you can press a letter button, and the cursor will jump to the first variable that starts with that letter. For those familiar with the Cesium shell, this is exactly the same feature. It cannot be used in the Recents list because that list is sorted by how recently a variable was opened, not by alphabetical order. 69 | 70 | ### Editor/Viewer 71 | 72 | ![Screenshot showing editor.](screenshots/editor_example.png) 73 | 74 | The top bar of the editor gives the name of memory being edited, the memory's size, the editor's state variables, and the battery status. 75 | The editor's state variables are, in order: writing mode, the number of selected bytes (the selection size), and the size of the cut-copy buffer. 76 | 77 | The writing mode can be "x" (hexadecimal), "A" (uppercase letters), "a" (lowercase letters), "0" (digits). In hexadecimal, you can press the hexadecimal characters on the keypad and write nibbles (half-bytes). In the other modes, the ASCII value for uppercase letters, lowercase letters, and digits will be written. 78 | 79 | The Paste tool can only be used to overwrite bytes, so you must select a number of bytes equal to the size of the cut-copy buffer. In other words, if you wish to paste a sequence of bytes, the last two digits of the editor's state variables should be equal. 80 | 81 | If the name of a tool in the bottom bar is darkened, it cannot be used in the present context. It is highly recommended that custom colorschemes use the same graphical indication so that users are not confused by the inconsistency. 82 | 83 | Pressing a function button (the white buttons directly beneath the screen) will activate the corresponding tool if it is available. 84 | 85 | | Key | Description 86 | | ------------- | ----------- 87 | | [2nd]/[enter] | Toggle the multi-byte selection mode. 88 | | [mode] | Switch the left column between address-mode and offset-mode. 89 | | [del] | If the access mode is "i" and selection is inactive, deletes one byte; if the selection is active, it will delete all of the selected bytes. 90 | | [alpha] | If [up]/[down] is pressed, the accelerated scrolling feature is activated. 91 | | [graph] | The "wMODE" stands for writing mode. Switches the writing mode. 92 | | [clear] | Exits the editor. If changes have been made, a save prompt will appear. 93 | 94 | The input fields that appear for tools like Find and Goto have special keybindings. 95 | 96 | | Key | Description 97 | | ------- | ----------- 98 | | [del] | Deletes one character. 99 | | [alpha] | Switches the keymap. 100 | | [clear] | Press once to clear all input. Press twice to exit the field. 101 | 102 | The keymap indicator, shown at the far right of the field uses the same characters as the writing mode indicator, i.e. "x" (hexadecimal), "A" (uppercase letters), "a" (lowercase letters), and "0" (digits). You cannot mix hexadecimal characters with any of the other three character sets. For instance, if you enter a character from the hexadecimal keymap, HexaEdit will not allow you to switch to any other keymap. If you enter an uppercase letter, a lowercase letter, or a number, HexaEdit will remove the hexadecimal keymap from the list of options. However, you can mix uppercase letters, lowercase letters, and numbers. 103 | 104 | The Find function will not be available for variables/memory areas that have less than a screens-worth of data in them. The Find input field expects at least four characters in hexadecimal mode and at least two characters in any other mode. **Note:** When doing searches in RAM, a particular phrase may exist at the time the find function searches the memory, but it may not exist by the time the viewer starts. This is because HexaEdit runs in RAM, so it will alter memory contents as it executes. 105 | 106 | If you delete a selection of multiple bytes and press "Undo," HexaEdit will highlight the selection of undeleted bytes and put the program into multi-byte selection mode. To execute another undo, you must press `[2nd]` or `[enter]` to leave multi-byte selection mode before pressing "Undo" again. However, if you delete a single byte and press "Undo," you will not be put into multi-byte selection mode. This allows you to undo single byte deletes more quickly. 107 | 108 | ## Headless Start 109 | 110 | 111 | ``` 112 | // The Headless Start configuration is written to Ans using the following data structures. 113 | 114 | // HEADER 115 | // +----------------+-----------------+ 116 | // | Description | Size (in bytes) | 117 | // +----------------+-----------------+ 118 | // | Header | 8 | 119 | // | Flags | 1 | 120 | // +----------------+-----------------+ 121 | // Total | 9 | 122 | // +-----------------+ 123 | // 124 | 125 | // After writing the HEADER, you should either write the MEMORY EDITOR block or 126 | // the VARIABLE EDITOR block, but never both. 127 | 128 | // MEMORY EDITOR 129 | // 130 | // +----------------+-----------------+ 131 | // | Description | Size (in bytes) | 132 | // +----------------+-----------------+ 133 | // | Flag | 1 | 134 | // | Cursor offset | 3 | 135 | // +----------------+-----------------+ 136 | // Total | 4 | 137 | // +-----------------+ 138 | // 139 | 140 | // VARIABLE EDITOR 141 | // 142 | // +----------------+-----------------+ 143 | // | Description | Size (in bytes) | 144 | // +----------------+-----------------+ 145 | // | Name | 8 | 146 | // | Name length | 1 | 147 | // | Variable type | 1 | 148 | // | Cursor offset | 3 | 149 | // +----------------+-----------------+ 150 | // Total | 13 | 151 | // +-----------------+ 152 | // 153 | 154 | // After the last block, write the colorscheme (s_color) if you want a custom 155 | // colorscheme. 156 | 157 | 158 | // ============================================================================= 159 | // DATA STRUCTURES 160 | // ============================================================================= 161 | 162 | 163 | enum HEADER_FLAGS : uint8_t 164 | { 165 | COLORSCHEME_PRESENT = 1 << 0, 166 | MEMORY_EDITOR = 1 << 1, 167 | VARIABLE_EDITOR = 1 << 2, 168 | }; 169 | 170 | enum MEMORY_EDITOR_FLAGS : uint8_t 171 | { 172 | RAM_EDITOR = 0, 173 | PORTS_EDITOR, 174 | ROM_VIEWER 175 | }; 176 | 177 | typedef struct 178 | { 179 | char header[8]; 180 | uint8_t flags; 181 | } s_header; 182 | 183 | typedef struct 184 | { 185 | uint8_t flag; 186 | uint24_t cursor_offset; 187 | } s_mem_editor; 188 | 189 | typedef struct 190 | { 191 | char name[8]; 192 | uint8_t name_length; 193 | uint8_t type; 194 | uint24_t cursor_offset; 195 | } s_var_editor; 196 | 197 | 198 | typedef struct 199 | { 200 | uint8_t bar; 201 | uint8_t bar_text; 202 | 203 | // Used for unavailable tools in the editor toolbar. 204 | uint8_t bar_text_dark; 205 | 206 | uint8_t background; 207 | uint8_t editor_side_panel; 208 | uint8_t editor_cursor; 209 | uint8_t editor_text_normal; 210 | uint8_t editor_text_selected; 211 | uint8_t list_cursor; 212 | uint8_t list_text_normal; 213 | uint8_t list_text_selected; 214 | } s_color; 215 | 216 | 217 | // ============================================================================= 218 | // HELPER FUNCTIONS 219 | // ============================================================================= 220 | 221 | 222 | static void write_header(const uint8_t flags, const uint8_t handle) 223 | { 224 | ti_Write("HexaEdit", 8, 1, handle); 225 | ti_Write(&flags, 1, 1, handle); 226 | return; 227 | } 228 | 229 | 230 | static void write_mem_editor( 231 | const s_mem_editor* const mem_editor, const uint8_t handle 232 | ) 233 | { 234 | ti_Write(mem_editor, sizeof(s_mem_editor), 1, handle); 235 | return; 236 | } 237 | 238 | 239 | static void write_var_editor( 240 | const s_var_editor* const var_editor, const uint8_t handle 241 | ) 242 | { 243 | ti_Write(var_editor, sizeof(s_var_editor), 1, handle); 244 | return; 245 | } 246 | 247 | 248 | static void write_colorscheme( 249 | const s_color* const colorscheme, const uint8_t handle 250 | ) 251 | { 252 | ti_Write(colorscheme, sizeof(s_color), 1, handle); 253 | return; 254 | } 255 | 256 | 257 | // ============================================================================= 258 | // EXAMPLES 259 | // ============================================================================= 260 | 261 | 262 | // Opens a RAM editor at cursor offset 0 with a custom colorscheme. 263 | void mainhl_SetMemEditor(void) 264 | { 265 | uint8_t handle; 266 | s_mem_editor mem_editor = { 267 | .flag = RAM_EDITOR, 268 | .cursor_offset = 0 269 | }; 270 | s_color colorscheme = { 271 | .bar = 0, 272 | .bar_text = 127, 273 | .bar_text_dark = 130, 274 | .background = 200, 275 | .editor_side_panel = 130, 276 | .editor_cursor = 0x3d, 277 | .editor_text_normal = 0, 278 | .editor_text_selected = 127 279 | }; 280 | 281 | if ((handle = ti_OpenVar(OS_VAR_ANS, "w", OS_TYPE_STR))) 282 | { 283 | write_header(MEMORY_EDITOR | COLORSCHEME_PRESENT, handle); 284 | write_mem_editor(&mem_editor, handle); 285 | write_colorscheme(&colorscheme, handle); 286 | ti_Close(handle); 287 | } 288 | 289 | return; 290 | } 291 | 292 | 293 | // Opens the TI-OS list L1 at cursor offset 0. 294 | void mainhl_SetVarEditor(void) 295 | { 296 | uint8_t handle; 297 | s_var_editor var_editor = { 298 | .name = OS_VAR_L1, 299 | .name_length = 3, 300 | .type = OS_TYPE_REAL_LIST, 301 | .cursor_offset = 0 302 | }; 303 | 304 | if ((handle = ti_OpenVar(OS_VAR_ANS, "w", OS_TYPE_STR))) 305 | { 306 | write_header(VARIABLE_EDITOR, handle); 307 | write_var_editor(&var_editor, handle); 308 | ti_Close(handle); 309 | } 310 | } 311 | ``` 312 | 313 | ## Differences between v2.1.0 and v3.0.0 314 | 315 | Version 3 was designed as the last major iteration of HexaEdit CE, so the author wanted to make it as reliable as possible. This meant ruthlessly cutting features that added unnecessary complexity and bug potential to the program. Thus, several features were not carried over from v2.1.0. These include: 316 | 317 | * The file search bar (replaced by alphabetical quick jump) 318 | * Main menu alpha scrolling (also replaced by alphabetical quick jump) 319 | * Main menu shortcut to a variable's VAT location 320 | * The sprite viewer (originally an easter egg) 321 | * The clock in the top bar 322 | 323 | As was mentioned before, a few keybindings have also changed, some related to tools that no longer exist. 324 | 325 | Aside from the many new features that version 3 introduces, this release finally fixes the horrendously slow list cursor of the main menu. 326 | 327 | ## Technical Info 328 | 329 | * Platforms: 330 | * TI-84 Plus CE (tested on TI-OS 5.3.0, TI-OS 5.8.0) 331 | * TI-83 Premium CE (untested) 332 | * Language: C and eZ80 assembly 333 | * Latest Version: 3.1.3 334 | 335 | ## Change Log 336 | | Release Number | Git Branch | Description 337 | | --------------------- |:------------:| ----------- 338 | | v3.1.3 | master | Patched a bug that miscalculated the size of TI-OS matrices. 339 | | v3.1.2 | master | Altered the look of the main menu. Patched a bug in the name parsing of hidden variables. 340 | | v3.1.1 | master | Made HexaEdit compatible with TI-OS 5.8.0. Patched a bug in the undo function. 341 | | v3.1.0 | master | Improved key debouncing and user experience in low RAM scenarios. Rewrote Find function. 342 | | v3.0.0 | master | Complete rewrite. Reworked GUI. Editor now uses split-buffer design. Edit buffer is allocated once to prevent pointer inconsistencies while opening and closing files. Editor can now open any type of TI-OS variable. 343 | | v2.2.0 *(unreleased)* | improve-core | Added "Ports" memory editor. Added faster alpha scrolling alternative in editor. Switched Headless Start configuration from appvar to Ans. Introduced more robust editor setup checks. 344 | | v2.1.0 | improve-core | Replaced phrase search C algorithm with faster assembly algorithm. Removed user-specified phrase search range because the faster algorithm rendered it superfluous. Added [mode] key functionality to the main menu. Fixed main menu protected program bug. 345 | | v2.0.2 | improve-core | Simplified editor API and Headless Start configuration. 346 | | v2.0.1 *(unreleased)* | master | Fixed Headless Start bug. Added phrase search to editor. Modified input functions. 347 | | v2.0.0 | master | Complete rewrite. Added Headless Start. "Undo" action now works for more than one change. Reworked GUI. Increased file search range to all file types. 348 | | v1.2.1 | master | Added [Enter] key support for selection and submitting actions; Upgraded the sprite viewer to handle any sprite size 349 | | v1.2.0 | master | Fixed "Goto" and decimal translation bugs; Added alpha-scrolling to main menu and editor; When the selected nibble is the second part of the byte, pressing the left arrow now relocates the selected nibble instead of moving the cursor; Fixed perpetual AM clock; Added lowercase letters to file search routine 350 | | v1.1.0 | master | Fixed main menu scrolling, key fall-throughs, and battery status indicator; Added file search, selective cursor delay, and recent files deletion 351 | | v1.0.0 | master | First release 352 | -------------------------------------------------------------------------------- /icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captain-calc/HexaEdit-CE/d34b22afb1b8d52f8c6d7658f9bb10a4a9230cec/icon.png -------------------------------------------------------------------------------- /includes_vizualizer/cinclude2dot.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl -w 2 | use strict; 3 | 4 | sub help() 5 | { 6 | print < source.dot 17 | \$ neato -Tps source.dot > source.ps 18 | \$ gv source.ps 19 | 20 | You might like to try "dot" instead of "neato" as well. 21 | 22 | Get graphviz here: http://www.research.att.com/sw/tools/graphviz/ 23 | 24 | Command line options are: 25 | 26 | --debug Display various debug info 27 | --exclude Specify a regular expression of filenames to ignore 28 | For example, ignore your test harnesses. 29 | --merge Granularity of the diagram: 30 | file - the default, treats each file as separate 31 | module - merges .c/.cc/.cpp/.cxx and .h/.hpp/.hxx pairs 32 | directory - merges directories into one node 33 | --groups Cluster files or modules into directory groups 34 | --help Display this help page. 35 | --include Followed by a comma separated list of include search 36 | paths. 37 | --paths Leaves relative paths in displayed filenames. 38 | --quotetypes Select for parsing the files included by strip quotes or angle brackets: 39 | both - the default, parse all headers. 40 | angle - include only "system" headers included by anglebrackets (<>) 41 | quote - include only "user" headers included by strip quotes ("") 42 | --src Followed by a path to the source code, defaults to current directory 43 | 44 | END 45 | exit 0; 46 | } 47 | 48 | ########################################################################## 49 | # Version history: 50 | # 51 | # v0.1 2000-09-14 10:24 initial version 52 | # v0.2 2000-09-14 10:49 strip leading ./ off files 53 | # v0.3 2000-09-14 11:00 allow whitespace between "^#" and "include" 54 | # v0.4 2000-09-14 12:44 strip paths 55 | # v0.5 2000-09-14 12:57 strip paths unless -p 56 | # v0.6 2002-02-08 10:30 major changes by francis@flourish.org 57 | # v0.7 2002-05-10 01:00 changed from a fixed len=5 to dynamic overlap=scale (Darxus) 58 | # v0.8 2003-05-26 19:48 patch from Preston Bannister for use with cygwin 59 | # v0.9 2003-12-10 14:52 Solaris compatible "find" call from chatko 60 | # 2004-03-18 11:00 added "--quotetypes" options by Viktor Chyzhdzenka (chyzhdzenka@mail.ru) 61 | # v1.0 2004-04-13 00:11 use File::Find rather than the shell `find` for win32 compat 62 | # v1.1 2005-12-13 02:05 add --src and .C (by Matthijs den Besten) 63 | 64 | ########################################################################## 65 | # Ideas for improvements: 66 | # 67 | # - Change the %links hash to store a count, and weigh the link by how often 68 | # there was an include along that link. Thicker lines mean stronger 69 | # connections. 70 | # 71 | # - Add label to digraph, saying which program generated it, when and guess 72 | # at the name of the application which has been graphed. 73 | # 74 | # - Write links from the same node in one line, rather than several. 75 | # "putmpg.c" -> { "config.h" "global.h" "stdio.h" "stdio.h" } 76 | # 77 | 78 | use Getopt::Long; 79 | use File::Spec::Functions; 80 | use File::Basename; 81 | use File::Find; 82 | 83 | ########################################################################## 84 | # Read parameters 85 | 86 | my $paths = ''; 87 | my $help =''; 88 | my $debug = ''; 89 | my $groups = ''; 90 | my $exclude = ""; 91 | my $merge = "file"; 92 | my $includelist = ""; 93 | my $quotetypes = "both"; 94 | my $src = '.'; 95 | die if !GetOptions('paths' => \$paths, 'groups' => \$groups, 96 | 'exclude=s' => \$exclude, 'merge=s' => \$merge, 97 | 'include=s' => \$includelist, 'help' =>\$help, 98 | 'debug' => \$debug, 'quotetypes=s' => \$quotetypes, 99 | 'src=s' => \$src); 100 | my @includepaths = split(/,/,$includelist); 101 | help() if ($help); 102 | if ($merge ne "file" && $merge ne "module" && $merge ne "directory") 103 | { 104 | die "Cluster parameter must be one of file, module or directory"; 105 | } 106 | if ($quotetypes ne "both" && $quotetypes ne "angle" && $quotetypes ne "quote") 107 | { 108 | die "quotetypes parameter must be one of both, angle or quote"; 109 | } 110 | 111 | ########################################################################## 112 | # Tidies up a path or filename, removing excess ./ and ../ parts. 113 | # Parameters: 114 | # $_ - Path or filename to tidy 115 | sub tidypath { 116 | $_ = shift; 117 | $_ = canonpath($_); 118 | # Use only one type of slash 119 | s:\\:/:g; 120 | # Remove constructs like xyz/.. 121 | while (s:[^/]+?/\.\./::) {}; 122 | return $_; 123 | } 124 | 125 | ########################################################################## 126 | # Searches file include path, and returns exact filename of file 127 | # Parameters: 128 | # $inc - text from within the #include statement 129 | # $file - filename the include was from 130 | sub include_search { 131 | my ($inc, $file) = @_; 132 | warn "include_search scanning for $inc from $file" if $debug; 133 | 134 | # Try relative to the including file 135 | $_ = tidypath(dirname($file) . "/" . $inc); 136 | warn "include_search trying $_ (dirname " . dirname($file) . ")" if $debug; 137 | return $_ if (-e "$_"); 138 | 139 | # Try user-specified include paths 140 | my $item; 141 | foreach $item (@includepaths) 142 | { 143 | $_ = tidypath($item . "/" . $inc); 144 | warn "include_search trying $_" if $debug; 145 | return $_ if (-e "$_"); 146 | } 147 | 148 | # Try relative to current directory 149 | $_ = $inc; 150 | warn "include_search trying $_" if $debug; 151 | return $_ if (-e "$_"); 152 | 153 | warn "include_search failed for $inc from $file" if $debug; 154 | return undef; 155 | } 156 | 157 | ########################################################################## 158 | # Converts a filename to its display version 159 | # Parameters: 160 | # $_ - Filename for display 161 | sub file_display { 162 | $_ = shift; 163 | $_ = basename($_) unless $paths; 164 | if ($merge eq "module") 165 | { 166 | s/\.c$//; 167 | s/\.cc$//; 168 | s/\.cxx$//; 169 | s/\.cpp$//; 170 | s/\.C$//; 171 | s/\.h$//; 172 | s/\.hpp$//; 173 | s/\.hxx$//; 174 | } 175 | s:/:/\\n:g; 176 | return $_; 177 | } 178 | 179 | ########################################################################## 180 | # Main code 181 | 182 | my @files; 183 | find sub { push @files, $File::Find::name if /\.(c|cc|cxx|cpp|C|h|hpp|hxx)$/ }, $src; 184 | 185 | print <) 213 | { 214 | # if ($line =~ m#^\#\s*include\s(\S+)#) 215 | my $regexp_include_line = '^\#\s*include\s+(\S+)'; 216 | if ($quotetypes eq "angle") 217 | { $regexp_include_line = '^\#\s*include\s+<(\S+)>'; } 218 | elsif ($quotetypes eq "quote") 219 | { $regexp_include_line = '^\#\s*include\s+"(\S+)"'; } 220 | if ($line =~ m/$regexp_include_line/) 221 | { 222 | my $included = $1; 223 | 224 | # strip quotes & anglebrackets 225 | (my $rawincluded = $included) =~ s/[\<\>"]//g; 226 | my $includefile = include_search($rawincluded, $file); 227 | 228 | if (! defined $includefile) 229 | { 230 | $notfound{$included . " from " . $file} = 1; 231 | next; 232 | } 233 | 234 | if ($merge eq "directory") 235 | { 236 | my $from = dirname($file); 237 | my $to = dirname($includefile); 238 | $links{" \"$from\" -> \"$to\"\n"} = 1 unless $from eq $to; 239 | } 240 | else 241 | { 242 | my $includefile_display = file_display($includefile); 243 | my $file_display = file_display($file); 244 | 245 | if ($groups) 246 | { 247 | my $groupname = dirname($includefile); 248 | print < \"$includefile_display\"\n"} = 1; 266 | } 267 | } 268 | } 269 | } 270 | 271 | close INPUT; 272 | } 273 | 274 | # Print out the links (we used a hash to avoid repeats of the same link) 275 | my $item; 276 | foreach $item (keys %links) 277 | { 278 | print $item; 279 | } 280 | 281 | # Print names of not found files 282 | foreach $item (sort keys %notfound) 283 | { 284 | print STDERR "Include file not found: " . $item . "\n"; 285 | } 286 | 287 | print "}\n"; 288 | -------------------------------------------------------------------------------- /includes_vizualizer/sh_vizualize_includes.sh: -------------------------------------------------------------------------------- 1 | ( 2 | cd ../src/ 3 | perl ../includes_vizualizer/cinclude2dot.pl > in.dot 4 | dot -Tpng in.dot > out_includes_graph.png 5 | rm in.dot 6 | mv out_includes_graph.png ../includes_vizualizer 7 | ) 8 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # ---------------------------- 2 | # Makefile Options 3 | # ---------------------------- 4 | 5 | NAME = HEXAEDIT 6 | VERSION = "3.1.3" 7 | ICON = icon.png 8 | DESCRIPTION = "HexaEdit CE v"$(VERSION) 9 | COMPRESSED = YES 10 | COMPRESSED_MODE = zx0 11 | ARCHIVED = YES 12 | 13 | CFLAGS = -Wall -Wextra -Oz -DPROGRAM_VERSION=\"$(VERSION)\" 14 | CXXFLAGS = -Wall -Wextra -Oz -DPROGRAM_VERSION=\"$(VERSION)\" 15 | 16 | HAS_PRINTF = NO 17 | 18 | # ---------------------------- 19 | 20 | include $(shell cedev-config --makefile) 21 | -------------------------------------------------------------------------------- /screenshots/EDB_error_message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captain-calc/HexaEdit-CE/d34b22afb1b8d52f8c6d7658f9bb10a4a9230cec/screenshots/EDB_error_message.png -------------------------------------------------------------------------------- /screenshots/editor_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captain-calc/HexaEdit-CE/d34b22afb1b8d52f8c6d7658f9bb10a4a9230cec/screenshots/editor_example.png -------------------------------------------------------------------------------- /screenshots/main_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/captain-calc/HexaEdit-CE/d34b22afb1b8d52f8c6d7658f9bb10a4a9230cec/screenshots/main_menu.png -------------------------------------------------------------------------------- /src/asmutil.asm: -------------------------------------------------------------------------------- 1 | ; Name: Captain Calc 2 | ; File: asmutil.asm 3 | ; Purpose: Provides the definitions of the functions declared in asmutil.h. 4 | ; Also defines any internal routines used by the public functions. 5 | 6 | 7 | ; BSD 3-Clause License 8 | ; 9 | ; Copyright (c) 2024, Caleb "Captain Calc" Arant 10 | ; All rights reserved. 11 | ; 12 | ; Redistribution and use in source and binary forms, with or without 13 | ; modification, are permitted provided that the following conditions are met: 14 | ; 15 | ; 1. Redistributions of source code must retain the above copyright notice, this 16 | ; list of conditions and the following disclaimer. 17 | ; 18 | ; 2. Redistributions in binary form must reproduce the above copyright notice, 19 | ; this list of conditions and the following disclaimer in the documentation 20 | ; and/or other materials provided with the distribution. 21 | ; 22 | ; 3. Neither the name of the copyright holder nor the names of its 23 | ; contributors may be used to endorse or promote products derived from 24 | ; this software without specific prior written permission. 25 | ; 26 | ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | ; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | ; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | ; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 30 | ; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 | ; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 | ; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | ; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 34 | ; OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | ; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | 37 | 38 | assume ADL=1 39 | 40 | section .text 41 | 42 | 43 | public _asmutil_IsNamedVar 44 | _asmutil_IsNamedVar: 45 | ; Arguments: 46 | ; arg0 = variable type 47 | ; Returns: 48 | ; True if variable has an ASCII name. False otherwise. 49 | ; Destroys: 50 | ; A, DE, HL 51 | ; Notes: 52 | ; Table of variable types: 53 | ; https://wikiti.brandonw.net/index.php?title=83Plus:OS:System_Table 54 | 55 | 56 | pop de 57 | pop hl 58 | push hl 59 | push de 60 | ld a,l 61 | cp a,$05 ; PRGM 62 | ret z 63 | cp a,$06 ; PROT PRGM 64 | ret z 65 | cp a,$15 ; APPVAR 66 | ret z 67 | cp a,$17 ; GROUP 68 | ret z 69 | xor a,a 70 | ret 71 | 72 | ; ----------------------------------------------------------------------------- 73 | 74 | public _asmutil_CopyData 75 | _asmutil_CopyData: 76 | ; Arguments: 77 | ; arg0 == pointer to copy data from 78 | ; arg1 == pointer to copy data to 79 | ; arg2 == amount of data 80 | ; arg3 == copy direction (0 = copy data and DECREMENT offset) 81 | ; (1 = copy data and INCREMENT offset) 82 | ; Returns: 83 | ; None 84 | ; Destroys: 85 | ; A, BC, DE, HL, IY 86 | 87 | 88 | ld iy,0 89 | add iy,sp 90 | ld hl,(iy + 3) 91 | ld de,(iy + 6) 92 | ld bc,(iy + 9) 93 | push hl 94 | xor a,a 95 | ld hl,0 96 | sbc hl,bc 97 | jr nc,.bc_is_zero 98 | ld hl,(iy + 12) 99 | cp a,l 100 | pop hl 101 | jr z,.decrement 102 | ldir 103 | ret 104 | .decrement: 105 | lddr 106 | ret 107 | .bc_is_zero: 108 | pop hl 109 | ret 110 | 111 | ; ----------------------------------------------------------------------------- 112 | 113 | _find_phrase: 114 | ; Arguments: 115 | ; arg0 == start address 116 | ; arg1 == end address 117 | ; arg2 == phrase 118 | ; arg3 == phrase length 119 | ; Returns: 120 | ; HL == pointer to first match found 121 | ; Carry flag set if match found; reset if no match found 122 | ; Destroys: 123 | ; A, BC, DE, IY 124 | 125 | 126 | ld iy,0 127 | add iy,sp 128 | ld bc,(iy + 3) 129 | ld hl,(iy + 6) 130 | push hl 131 | 132 | ; If start > end, exit 133 | push hl 134 | xor a,a 135 | sbc hl,bc 136 | pop hl 137 | jr nc,.cont 138 | xor a,a ; Reset carry flag 139 | pop hl 140 | ret 141 | 142 | .cont: 143 | ld de,0 ; E = phrase offset 144 | 145 | .compare: 146 | ld a,(bc) 147 | ld hl,(iy + 9) 148 | add hl,de 149 | cp a,(hl) 150 | jr z,.match 151 | 152 | ; Comparison failed: 153 | ld e,0 ; Reset phrase offset 154 | 155 | ; If end of range reached, exit 156 | .endCheck: 157 | pop hl 158 | push hl 159 | xor a,a 160 | sbc hl,bc 161 | jr z,.exitFast ; Carry flag is still reset if Z is set 162 | 163 | inc bc ; Increment current address 164 | jr .compare 165 | 166 | .match: 167 | inc e ; Increment phrase offset counter 168 | ld a,(iy + 12) 169 | xor a,e 170 | jr nz,.endCheck 171 | 172 | ; Full match found: 173 | push bc 174 | pop hl 175 | dec e 176 | sbc hl,de ; Carry reset by XOR A,E 177 | scf ; We found a match 178 | .exitFast: 179 | pop bc ; Remove the stack local 180 | ret 181 | 182 | ; ----------------------------------------------------------------------------- 183 | 184 | public _asmutil_FindPhrase 185 | _asmutil_FindPhrase: 186 | ; Arguments: 187 | ; arg0 == start address 188 | ; arg1 == end address 189 | ; arg2 -> phrase 190 | ; arg3 == phrase length 191 | ; arg4 -> pointer array for match pointers 192 | ; arg5 == number of match pointers allowed 193 | ; Returns: 194 | ; A == number of matches found 195 | ; Destroys: 196 | ; BC, DE, HL, IY 197 | 198 | 199 | ld iy,0 200 | add iy,sp 201 | ld hl,(iy + 12) 202 | push hl 203 | ld hl,(iy + 9) 204 | push hl 205 | ld hl,(iy + 6) 206 | push hl 207 | 208 | ld hl,(iy + 15) ; HL -> match pointer array 209 | ld bc,0 210 | .lastMatchInArray:=$-3 211 | ld (.lastMatchInArray),hl 212 | ld bc,0 213 | ld c,(iy + 18) ; C == max number of match pointers 214 | ld b,3 ; 3 bytes is the size of a pointer 215 | mlt bc 216 | add hl,bc 217 | ld bc,0 218 | .endOfArray:=$-3 219 | ld (.endOfArray),hl 220 | ld a,0 221 | .numMatchesFound:=$-1 222 | xor a,a 223 | ld (.numMatchesFound),a 224 | 225 | ld hl,(iy + 3) 226 | 227 | .compare: 228 | push hl ; HL == start address 229 | call _find_phrase 230 | pop bc 231 | push hl 232 | 233 | ; If _find_phrase does not return a match, exit 234 | sbc hl,hl ; If carry flag is reset, this will not set it again 235 | jr nc,.finish 236 | 237 | ; Check for room in the match array 238 | ld hl,(.endOfArray) 239 | ld de,(.lastMatchInArray) 240 | xor a,a 241 | sbc hl,de 242 | jr z,.finish 243 | 244 | ; Increment numMatchesFound 245 | ld a,(.numMatchesFound) 246 | inc a 247 | ld (.numMatchesFound),a 248 | 249 | ; Write new match address to array 250 | ex de,hl 251 | pop de ; DE == _find_phrase return value 252 | ld (hl),de 253 | inc hl 254 | inc hl 255 | inc hl 256 | ld (.lastMatchInArray),hl 257 | 258 | ; Add phrase length to new match address to get new start address 259 | ld hl,0 260 | ld l,(iy + 12) 261 | add hl,de 262 | jr .compare 263 | 264 | .finish: 265 | pop hl ; _find_phrase return value 266 | pop hl ; phrase length 267 | pop hl ; phrase 268 | pop hl ; end address 269 | ld a,(.numMatchesFound) 270 | ret 271 | -------------------------------------------------------------------------------- /src/asmutil.h: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: asmutil.h 3 | // Purpose: asmutil provides common assembly routines used by more than one 4 | // file. 5 | 6 | 7 | /* 8 | BSD 3-Clause License 9 | 10 | Copyright (c) 2024, Caleb "Captain Calc" Arant 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 16 | 1. Redistributions of source code must retain the above copyright notice, this 17 | list of conditions and the following disclaimer. 18 | 19 | 2. Redistributions in binary form must reproduce the above copyright notice, 20 | this list of conditions and the following disclaimer in the documentation 21 | and/or other materials provided with the distribution. 22 | 23 | 3. Neither the name of the copyright holder nor the names of its 24 | contributors may be used to endorse or promote products derived from 25 | this software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 31 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 35 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | */ 38 | 39 | 40 | #ifndef ASMUTIL_H 41 | #define ASMUTIL_H 42 | 43 | 44 | #include // For uint8_t 45 | 46 | // ============================================================================ 47 | // PUBLIC FUNCTION DECLARATIONS 48 | // ============================================================================ 49 | 50 | 51 | // Description: asmutil_IsNamedVar() determines if a variable has an ASCII name 52 | // based on its type. 53 | // Pre: should be a valid variable type. 54 | // Post: If variable is named, true returned. 55 | // Otherwise, false returned. 56 | bool asmutil_IsNamedVar(const uint8_t var_type); 57 | 58 | 59 | // Description: asm_CopyData() copies bytes from to . 60 | // If == 0, the routine decrements the copy 61 | // address. If == 1, the routine increments the 62 | // copy address. 63 | // Pre: All of the memory from to +/- and from 64 | // to +/- must be write-access memory, 65 | // depending on . 66 | // Post: bytes copied from to in given 67 | // . 68 | void asmutil_CopyData( 69 | void *src, 70 | void *dest, 71 | uint24_t amount, 72 | uint8_t copy_direction 73 | ); 74 | 75 | 76 | // Description: Finds all occurances of in memory from to 77 | // . Pointers to the start of the match are written to 78 | // . When a match is found and recorded, searching 79 | // resumes from (pointer to match start) + . 80 | // Pre: and must be valid memory pointers. 81 | // must be greater than or equal to . 82 | // must be the length of phrase. 83 | // must be the size of the array. 84 | // Post: Number of matches found returned. 85 | // contains pointers to every occurance of 86 | // found between and , inclusive. 87 | uint8_t asmutil_FindPhrase( 88 | const uint8_t* start, 89 | const uint8_t* end, 90 | const uint8_t phrase[], 91 | const uint8_t length, 92 | uint24_t matches[], 93 | uint8_t max_matches 94 | ); 95 | 96 | 97 | #endif 98 | -------------------------------------------------------------------------------- /src/ccdbg/ccdbg.cpp: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: ccdbg.cpp 3 | // Purpose: ccdbg provides macros for pretty-printing variable values. 4 | // Version: 0.2.4 5 | 6 | 7 | /* 8 | BSD 3-Clause License 9 | 10 | Copyright (c) 2024, Caleb "Captain Calc" Arant 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 16 | 1. Redistributions of source code must retain the above copyright notice, this 17 | list of conditions and the following disclaimer. 18 | 19 | 2. Redistributions in binary form must reproduce the above copyright notice, 20 | this list of conditions and the following disclaimer in the documentation 21 | and/or other materials provided with the distribution. 22 | 23 | 3. Neither the name of the copyright holder nor the names of its 24 | contributors may be used to endorse or promote products derived from 25 | this software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 31 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 35 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | */ 38 | 39 | 40 | // NOTE 41 | // 42 | // Changing this file's extension from ".cpp" to ".c" breaks running 43 | // "make debug" in each of the test directories. According to the compiliation 44 | // record produced by make, "ccdbg.c" will not be compiled, but "ccdbg.cpp" 45 | // will be. 46 | // 47 | 48 | 49 | #include 50 | #include 51 | #include // For strlen() 52 | 53 | #include "ccdbg.h" 54 | 55 | 56 | #if USE_CCDBG 57 | 58 | unsigned int g_ccdbg_chkpt_indent = 0; 59 | 60 | 61 | void print_indent() 62 | { 63 | for (unsigned int idx = 0; idx < g_ccdbg_chkpt_indent; idx++) 64 | { 65 | if (idx && !(idx % BLOCK_INDENT)) 66 | sprintf(dbgout, "|"); 67 | else 68 | sprintf(dbgout, ""); 69 | 70 | sprintf(dbgout, " "); 71 | } 72 | 73 | sprintf(dbgout, "|"); 74 | return; 75 | } 76 | 77 | 78 | void CCDBG_BEGINBLOCK(const char* name) 79 | { 80 | print_indent(); 81 | sprintf(dbgout, "\n"); 82 | 83 | g_ccdbg_chkpt_indent += BLOCK_INDENT; 84 | print_indent(); 85 | 86 | sprintf(dbgout, " %s\n", name); 87 | print_indent(); 88 | 89 | for (unsigned int idx = VALUE_INDENT + 15; idx > 0; idx--) 90 | sprintf(dbgout, "-"); 91 | 92 | sprintf(dbgout, "\n"); 93 | 94 | return; 95 | } 96 | 97 | 98 | void CCDBG_ENDBLOCK() 99 | { 100 | print_indent(); 101 | 102 | for (int i = VALUE_INDENT + 15; i > 0; i--) 103 | sprintf(dbgout, "-"); 104 | 105 | sprintf(dbgout, "\n"); 106 | g_ccdbg_chkpt_indent -= BLOCK_INDENT; 107 | print_indent(); 108 | sprintf(dbgout, "\n"); 109 | return; 110 | } 111 | 112 | 113 | void CCDBG_PUTS(const char* s) 114 | { 115 | print_indent(); 116 | sprintf(dbgout, " %s\n", s); 117 | return; 118 | } 119 | 120 | 121 | void CCDBG_DUMP_STR_func(const char* varname, const char* var) 122 | { 123 | print_indent(); 124 | sprintf(dbgout, " %s", varname); 125 | 126 | for (int idx = VALUE_INDENT - strlen(varname); idx > 0; idx--) 127 | sprintf(dbgout, " "); 128 | 129 | sprintf(dbgout,"= %s\n", var); 130 | return; 131 | } 132 | 133 | 134 | void CCDBG_DUMP_PTR_func(const char* varname, const unsigned int var) 135 | { 136 | print_indent(); 137 | sprintf(dbgout, " %s", varname); 138 | 139 | for (int idx = VALUE_INDENT - strlen(varname); idx > 0; idx--) 140 | sprintf(dbgout, " "); 141 | 142 | sprintf(dbgout,"= 0x%6x\n", var); 143 | return; 144 | } 145 | 146 | 147 | void CCDBG_DUMP_UINT_func(const char* varname, const unsigned int var) 148 | { 149 | print_indent(); 150 | sprintf(dbgout, " %s", varname); 151 | 152 | for (int idx = VALUE_INDENT - strlen(varname); idx > 0; idx--) 153 | sprintf(dbgout, " "); 154 | 155 | sprintf(dbgout,"= %u\n", var); 156 | return; 157 | } 158 | 159 | 160 | void CCDBG_DUMP_INT_func(const char* varname, const unsigned int var) 161 | { 162 | print_indent(); 163 | sprintf(dbgout, " %s", varname); 164 | 165 | for (int idx = VALUE_INDENT - strlen(varname); idx > 0; idx--) 166 | sprintf(dbgout, " "); 167 | 168 | sprintf(dbgout,"= %d\n", var); 169 | return; 170 | } 171 | 172 | 173 | void CCDBG_DUMP_UINT24_T_BIN_func(const char* varname, const uint24_t var) 174 | { 175 | char b_char; 176 | 177 | print_indent(); 178 | sprintf(dbgout, " %s", varname); 179 | 180 | for (int i = VALUE_INDENT - strlen(varname); i > 0; i--) 181 | sprintf(dbgout, " "); 182 | 183 | sprintf(dbgout, "= "); 184 | 185 | for (int byte = 24; byte >= 0; byte--) 186 | { 187 | b_char = ((var & (1 << byte)) ? '1' : '0'); 188 | sprintf(dbgout, "%c", b_char); 189 | 190 | if (!(byte % 4) && byte < 24) 191 | sprintf(dbgout, " "); 192 | } 193 | 194 | sprintf(dbgout,"\n"); 195 | return; 196 | } 197 | 198 | #endif 199 | -------------------------------------------------------------------------------- /src/ccdbg/ccdbg.h: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: ccdbg.h 3 | // Purpose: ccdbg provides macros for pretty-printing variable values. 4 | // Version: 0.2.4 5 | 6 | 7 | /* 8 | BSD 3-Clause License 9 | 10 | Copyright (c) 2024, Caleb "Captain Calc" Arant 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 16 | 1. Redistributions of source code must retain the above copyright notice, this 17 | list of conditions and the following disclaimer. 18 | 19 | 2. Redistributions in binary form must reproduce the above copyright notice, 20 | this list of conditions and the following disclaimer in the documentation 21 | and/or other materials provided with the distribution. 22 | 23 | 3. Neither the name of the copyright holder nor the names of its 24 | contributors may be used to endorse or promote products derived from 25 | this software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 31 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 35 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | */ 38 | 39 | 40 | // NOTE ON SPRINTF() 41 | // 42 | // As of version 0.2.4, ccdbg can use the built-in sprintf() that the TI-OS has. 43 | // If you add `HAS_PRINTF = NO` to your program's Makefile, you can remove about 44 | // 8000 bytes from the debug binary. 45 | 46 | 47 | // CHANGE LOG 48 | // 49 | // Version Description 50 | // 51 | // 0.1.0 Added CCDBG_DUMP_BIN() 52 | // 53 | // 0.1.1 Added USE_CCDBG. This flag removes the necessity to put 54 | // #if NDEBUG \ #endif commands around debug statements. This was 55 | // necessary in version 0.1.0 if the programmer wanted to run 56 | // make without debug and leave the debugging statements in the 57 | // program code. 58 | // 59 | // 0.2.0 Converted several macros into functions to reduce overall 60 | // program size when building with debug. Removed 61 | // CCDBG_PRINT_SECTION_HEADER. Renamed CCDBG_PRINT_MSG to 62 | // CCDBG_PUTS. 63 | // 64 | // 0.2.1 Removed "#define dbg_sprintf sprintf". This allows programmers 65 | // to use debug.h and ccdbg.h simultaneously without redefinition 66 | // warnings. 67 | // 68 | // 0.2.2 Changed BLOCK_INDENT from 4 to 2. 69 | // 70 | // 0.2.3 Changed buggy CCDBG_DUMP_BIN to CCDBG_DUMP_UINT24_T_BIN. 71 | // 72 | // 0.2.4 Moved the code for all of the remaining macros into functions 73 | // to reduce program size when running `make debug`. Renamed 74 | // CCDBG_OPEN_CHECKPOINT() and CCDBG_CLOSE_CHECKPOINT() to 75 | // CCDBG_BEGINBLOCK() and CCDBG_ENDBLOCK(), respectively. Patched 76 | // buggy CCDBG_DUMP_STR(). 77 | 78 | 79 | #ifndef CCDBG_H 80 | #define CCDBG_H 81 | 82 | #ifdef __cplusplus 83 | extern "C" { 84 | #endif 85 | 86 | 87 | #ifndef NDEBUG 88 | #define USE_CCDBG 1 89 | #endif 90 | 91 | 92 | #if USE_CCDBG 93 | 94 | #define dbgout ((char*)0xFB0000) 95 | #define dbgerr ((char*)0xFC0000) 96 | 97 | #define BLOCK_INDENT 2 98 | #define VALUE_INDENT 50 99 | extern unsigned int g_ccdbg_chkpt_indent; 100 | 101 | // These functions are not designed to be called directly. Access them 102 | // through their corresponding macros. 103 | void print_indent(); 104 | void CCDBG_DUMP_STR_func(const char* varname, const char* var); 105 | void CCDBG_DUMP_PTR_func(const char* varname, const unsigned int var); 106 | void CCDBG_DUMP_UINT_func(const char* varname, const unsigned int var); 107 | void CCDBG_DUMP_INT_func(const char* varname, const unsigned int var); 108 | 109 | // LIBRARY FUNCTIONS 110 | // =========================================================================== 111 | 112 | void CCDBG_BEGINBLOCK(const char* name); 113 | 114 | void CCDBG_ENDBLOCK(); 115 | 116 | void CCDBG_PUTS(const char* s); 117 | 118 | #define CCDBG_DUMP_PTR(varname) \ 119 | do { CCDBG_DUMP_PTR_func(#varname, (unsigned int)varname); } while (0) 120 | 121 | #define CCDBG_DUMP_UINT(varname) \ 122 | do { CCDBG_DUMP_UINT_func(#varname, varname); } while (0) 123 | 124 | #define CCDBG_DUMP_INT(varname) \ 125 | do { CCDBG_DUMP_INT_func(#varname, varname); } while (0) 126 | 127 | #define CCDBG_DUMP_STR(varname) \ 128 | do { CCDBG_DUMP_STR_func(#varname, varname); } while (0) 129 | 130 | #define CCDBG_DUMP_UINT24_T_BIN(varname) \ 131 | do { CCDBG_DUMP_UINT24_T_BIN_func(#varname, varname); } while (0) 132 | 133 | // =========================================================================== 134 | 135 | #else 136 | 137 | #define CCDBG_BEGINBLOCK(...) ((void)0) 138 | #define CCDBG_ENDBLOCK(...) ((void)0) 139 | #define CCDBG_PUTS(...) ((void)0) 140 | #define CCDBG_DUMP_PTR(...) ((void)0) 141 | #define CCDBG_DUMP_INT(...) ((void)0) 142 | #define CCDBG_DUMP_UINT(...) ((void)0) 143 | #define CCDBG_DUMP_STR(...) ((void)0) 144 | #define CCDBG_DUMP_UINT24_T_BIN(...) ((void)0) 145 | 146 | #endif 147 | 148 | #if __cplusplus 149 | } 150 | #endif 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /src/cutil.c: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: cutil.c 3 | // Purpose: Contains definitions of the functions declared in cutil.h. 4 | 5 | 6 | /* 7 | BSD 3-Clause License 8 | 9 | Copyright (c) 2024, Caleb "Captain Calc" Arant 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | 1. Redistributions of source code must retain the above copyright notice, this 16 | list of conditions and the following disclaimer. 17 | 18 | 2. Redistributions in binary form must reproduce the above copyright notice, 19 | this list of conditions and the following disclaimer in the documentation 20 | and/or other materials provided with the distribution. 21 | 22 | 3. Neither the name of the copyright holder nor the names of its 23 | contributors may be used to endorse or promote products derived from 24 | this software without specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 30 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 34 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | 39 | #include 40 | #include 41 | #include 42 | 43 | #include "cutil.h" 44 | #include "defines.h" 45 | 46 | 47 | // ============================================================================= 48 | // PUBLIC FUNCTION DEFINITIONS 49 | // ============================================================================= 50 | 51 | 52 | void cutil_UintToHex(char* const buffer, uint24_t number) 53 | { 54 | const char* const CHARS = "0123456789abcdef"; 55 | 56 | for (int8_t idx = 5; idx >= 0; idx--) 57 | { 58 | buffer[idx] = CHARS[number % 16]; 59 | number /= 16; 60 | } 61 | 62 | return; 63 | } 64 | 65 | 66 | uint24_t cutil_HexToUint(const char* const buffer) 67 | { 68 | const char *hex_chars = { "0123456789abcdef" }; 69 | uint8_t length = strlen(buffer); 70 | uint24_t place = 1; 71 | uint24_t integer = 0; 72 | 73 | while (length > 0) 74 | { 75 | length--; 76 | 77 | for (uint8_t idx = 0; idx < 16; idx++) 78 | { 79 | if (*(buffer + length) == hex_chars[idx]) 80 | { 81 | integer += place * idx; 82 | }; 83 | }; 84 | 85 | place *= 16; 86 | }; 87 | 88 | return integer; 89 | } 90 | 91 | 92 | uint24_t cutil_Log10(uint24_t value) 93 | { 94 | uint24_t log = 1; 95 | 96 | while (value) { value /= 10; if (value) log++; } 97 | 98 | return log; 99 | } 100 | 101 | 102 | bool cutil_IsVarHidden(const char* const name) 103 | { 104 | if (name[0] <= 0x20) 105 | return true; 106 | 107 | return false; 108 | } 109 | -------------------------------------------------------------------------------- /src/cutil.h: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: cutil.h 3 | // Purpose: Declares common C routines. 4 | 5 | 6 | /* 7 | BSD 3-Clause License 8 | 9 | Copyright (c) 2024, Caleb "Captain Calc" Arant 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | 1. Redistributions of source code must retain the above copyright notice, this 16 | list of conditions and the following disclaimer. 17 | 18 | 2. Redistributions in binary form must reproduce the above copyright notice, 19 | this list of conditions and the following disclaimer in the documentation 20 | and/or other materials provided with the distribution. 21 | 22 | 3. Neither the name of the copyright holder nor the names of its 23 | contributors may be used to endorse or promote products derived from 24 | this software without specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 30 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 34 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | 39 | #ifndef CUTIL_H 40 | #define CUTIL_H 41 | 42 | 43 | #include 44 | 45 | void cutil_UintToHex(char* const buffer, uint24_t number); 46 | 47 | uint24_t cutil_HexToUint(const char* const buffer); 48 | 49 | uint24_t cutil_Log10(uint24_t value); 50 | 51 | bool cutil_IsVarHidden(const char* const name); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /src/defines.c: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: defines.c 3 | // Purpose: Defines some of the declarations in defines.h 4 | 5 | 6 | /* 7 | BSD 3-Clause License 8 | 9 | Copyright (c) 2024, Caleb "Captain Calc" Arant 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | 1. Redistributions of source code must retain the above copyright notice, this 16 | list of conditions and the following disclaimer. 17 | 18 | 2. Redistributions in binary form must reproduce the above copyright notice, 19 | this list of conditions and the following disclaimer in the documentation 20 | and/or other materials provided with the distribution. 21 | 22 | 3. Neither the name of the copyright holder nor the names of its 23 | contributors may be used to endorse or promote products derived from 24 | this software without specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 30 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 34 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | 39 | #include "defines.h" 40 | 41 | #define BLACK (0x00) 42 | #define BLUE (0x3d) 43 | #define DK_GRAY (0x6b) 44 | #define LT_GRAY (0xb5) 45 | #define WHITE (0xff) 46 | 47 | 48 | const char* G_UPPERCASE_LETTERS_KEYMAP[7] = { 49 | "\0\0\0\0\0\0\0\0", "\0XSNIDA\0", "\0YTOJEB\0", "\0ZUPKFC\0", 50 | "\0\0VQLG\0\0", "\0\0WRMH\0\0", "\0\0\0\0" 51 | }; 52 | 53 | const char* G_LOWERCASE_LETTERS_KEYMAP[7] = { 54 | "\0\0\0\0\0\0\0\0", "\0xsnida\0", "\0ytojeb\0", "\0zupkfc\0", 55 | "\0\0vqlg\0\0", "\0\0wrmh\0\0", "\0\0\0\0" 56 | }; 57 | 58 | const char* G_DIGITS_KEYMAP[7] = { 59 | "\0\0\0\0\0\0\0\0", "\0\0\0\0\0\0\0", "\x30\x31\x34\x37\0\0\0\0", 60 | "\0\x32\x35\x38\0\0\0\0", "\0\x33\x36\x39\0\0\0\0", "\0\0\0\0\0\0\0\0", 61 | "\0\0\0\0" 62 | }; 63 | 64 | const char* G_HEX_NIBBLES_KEYMAP[7] = { 65 | "\0\0\0\0\0\0\0\0", "\0\0\0\0\0\x0D\x0A\0", "\x00\x01\x04\x07\0\x0E\x0B\0", 66 | "\0\x02\x05\x08\0\x0F\x0C\0", "\0\x03\x06\x09\0\0\0\0", "\0\0\0\0\0\0\0\0", 67 | "\0\0\0\0" 68 | }; 69 | 70 | const char* G_HEX_ASCII_KEYMAP[7] = { 71 | "\0\0\0\0\0\0\0\0", "\0\0\0\0\0da\0", "\x30\x31\x34\x37\0eb\0", 72 | "\0\x32\x35\x38\0fc\0", "\0\x33\x36\x39\0\0\0\0", "\0\0\0\0\0\0\0\0", 73 | "\0\0\0\0" 74 | }; 75 | 76 | 77 | s_color g_color = { 78 | .bar = DK_GRAY, 79 | .bar_text = WHITE, 80 | .bar_text_dark = LT_GRAY, 81 | .background = WHITE, 82 | .editor_side_panel = LT_GRAY, 83 | .editor_cursor = BLUE, 84 | .editor_text_normal = BLACK, 85 | .editor_text_selected = WHITE, 86 | .list_cursor = BLACK, 87 | .list_text_normal = BLACK, 88 | .list_text_selected = WHITE 89 | }; 90 | -------------------------------------------------------------------------------- /src/defines.h: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: defines.h 3 | // Purpose: Declares commonly used defines, data structures, and macros. 4 | 5 | 6 | /* 7 | BSD 3-Clause License 8 | 9 | Copyright (c) 2024, Caleb "Captain Calc" Arant 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | 1. Redistributions of source code must retain the above copyright notice, this 16 | list of conditions and the following disclaimer. 17 | 18 | 2. Redistributions in binary form must reproduce the above copyright notice, 19 | this list of conditions and the following disclaimer in the documentation 20 | and/or other materials provided with the distribution. 21 | 22 | 3. Neither the name of the copyright holder nor the names of its 23 | contributors may be used to endorse or promote products derived from 24 | this software without specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 30 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 34 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | 39 | #ifndef DEFINES_H 40 | #define DEFINES_H 41 | 42 | 43 | #include 44 | #include 45 | 46 | 47 | #define STRING_PREPEND(head, tail) head tail 48 | 49 | // These are not defined in the toolchain. 50 | #define OS_TYPE_PICT (0x07) 51 | #define OS_TYPE_GDB (0x08) 52 | #define OS_TYPE_GROUP (0x17) 53 | 54 | // The TI-OS token for theta is 0x5b. HexaEdit uses 0x7f to represent theta, so 55 | // the program can print '[' (0x5b). 56 | #define G_HEXAEDIT_THETA (0x7f) 57 | 58 | #define G_EDIT_BUFFER_APPVAR_NAME ("HXAEDITb") 59 | #define G_RECENTS_APPVAR_NAME ("HXAEDITr") 60 | #define G_RECENTS_APPVAR_SIZE (255) 61 | 62 | #define G_FONT_HEIGHT (7) 63 | #define G_ROWS_ONSCREEN (18) 64 | #define G_COLS_ONSCREEN (8) 65 | #define G_NUM_BYTES_ONSCREEN (G_ROWS_ONSCREEN * G_COLS_ONSCREEN) 66 | #define G_EDITOR_NAME_MAX_LEN (20) 67 | #define G_MAX_SELECTION_SIZE (255) 68 | 69 | #define G_ROM_BASE_ADDRESS ((uint8_t*)0x000000) 70 | #define G_ROM_SIZE (0x400000) 71 | #define G_RAM_BASE_ADDRESS ((uint8_t*)0xd00000) 72 | #define G_RAM_SIZE (0x065000) 73 | #define G_PORTS_BASE_ADDRESS ((uint8_t*)0xe00000) 74 | #define G_PORTS_SIZE (0x200000) 75 | 76 | #define min(x, y) ((x > y ? y : x)) 77 | 78 | extern const char* G_UPPERCASE_LETTERS_KEYMAP[7]; 79 | extern const char* G_LOWERCASE_LETTERS_KEYMAP[7]; 80 | extern const char* G_DIGITS_KEYMAP[7]; 81 | extern const char* G_HEX_NIBBLES_KEYMAP[7]; 82 | extern const char* G_HEX_ASCII_KEYMAP[7]; 83 | 84 | 85 | // can have three values: 86 | // 'r': readonly 87 | // 'w': read/write 88 | // 'i': read/write/resize (for variables only) 89 | // can have two values: 90 | // 'a': addresses 91 | // 'o': offsets 92 | // can have four values: 93 | // 'A': uppercase letters 94 | // 'a': lowercase letters 95 | // '0': numbers 96 | // 'x': hexadecimal characters 97 | typedef struct 98 | { 99 | char name[G_EDITOR_NAME_MAX_LEN]; 100 | uint8_t name_length; 101 | char access_type; 102 | bool is_tios_var; 103 | uint8_t tios_var_type; 104 | bool undo_buffer_active; 105 | uint24_t num_changes; 106 | 107 | uint8_t* base_address; 108 | uint24_t data_size; 109 | uint24_t buffer_size; 110 | 111 | uint24_t window_offset; 112 | 113 | char location_col_mode; 114 | char writing_mode; 115 | 116 | uint24_t near_size; 117 | uint24_t far_size; 118 | uint8_t selection_size; 119 | bool selection_active; 120 | bool high_nibble; 121 | } s_editor; 122 | 123 | 124 | typedef struct 125 | { 126 | uint8_t bar; 127 | uint8_t bar_text; 128 | uint8_t bar_text_dark; 129 | uint8_t background; 130 | uint8_t editor_side_panel; 131 | uint8_t editor_cursor; 132 | uint8_t editor_text_normal; 133 | uint8_t editor_text_selected; 134 | uint8_t list_cursor; 135 | uint8_t list_text_normal; 136 | uint8_t list_text_selected; 137 | } s_color; 138 | 139 | extern s_color g_color; 140 | 141 | 142 | #endif 143 | -------------------------------------------------------------------------------- /src/editor.c: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: editor.c 3 | // Purpose: Defines the functions declared in editor.h as well as several static 4 | // supporting functions. 5 | 6 | 7 | /* 8 | BSD 3-Clause License 9 | 10 | Copyright (c) 2024, Caleb "Captain Calc" Arant 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 16 | 1. Redistributions of source code must retain the above copyright notice, this 17 | list of conditions and the following disclaimer. 18 | 19 | 2. Redistributions in binary form must reproduce the above copyright notice, 20 | this list of conditions and the following disclaimer in the documentation 21 | and/or other materials provided with the distribution. 22 | 23 | 3. Neither the name of the copyright holder nor the names of its 24 | contributors may be used to endorse or promote products derived from 25 | this software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 31 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 35 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | */ 38 | 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include "ccdbg/ccdbg.h" 48 | #include "cutil.h" 49 | #include "defines.h" 50 | #include "editor.h" 51 | #include "gui.h" 52 | #include "hevat.h" 53 | #include "keypad.h" 54 | #include "tools.h" 55 | 56 | 57 | // ============================================================================= 58 | // STATIC FUNCTION DECLARATIONS 59 | // ============================================================================= 60 | 61 | 62 | // Description: Handles the editor's main loop. 63 | static void run_editor(s_editor* const editor); 64 | 65 | 66 | static void goto_prompt(s_editor* const editor); 67 | 68 | 69 | static void insert_bytes_prompt(s_editor* const editor); 70 | 71 | 72 | static void find_viewer( 73 | s_editor* const editor, 74 | const uint24_t matches[], 75 | const uint8_t num_matches, 76 | const uint8_t phrase_length 77 | ); 78 | 79 | 80 | static void find_prompt(s_editor* const editor); 81 | 82 | 83 | static bool save_changes_prompt(s_editor* const editor); 84 | 85 | 86 | static void toggle_cursor_selection( 87 | s_editor* const editor, bool selection_active 88 | ); 89 | 90 | 91 | // ============================================================================= 92 | // PUBLIC FUNCTION DEFINITIONS 93 | // ============================================================================= 94 | 95 | 96 | bool editor_OpenVarEditor( 97 | s_editor* const editor, void* const vatptr, const uint24_t offset 98 | ) 99 | { 100 | CCDBG_BEGINBLOCK("editor_OpenVarEditor"); 101 | 102 | s_calc_var var; 103 | uint24_t var_data_size; 104 | bool retval = true; 105 | uint8_t* var_data; 106 | 107 | var.vatptr = vatptr; 108 | hevat_GetVarInfoByVAT(&var); 109 | memset(editor->name, '\0', G_EDITOR_NAME_MAX_LEN); 110 | strncpy(editor->name, var.name, var.name_length); 111 | editor->name_length = var.name_length; 112 | editor->is_tios_var = true; 113 | editor->tios_var_type = var.type; 114 | editor->undo_buffer_active = true; 115 | editor->num_changes = 0; 116 | editor->base_address = tool_EditBufferPtr(&editor->buffer_size); 117 | 118 | if (var.named) 119 | { 120 | editor->access_type = 'i'; 121 | var_data = var.data + 2; 122 | var_data_size = var.size - 2; 123 | } 124 | else if (var.archived) 125 | { 126 | editor->access_type = 'r'; 127 | var_data = var.data; 128 | var_data_size = var.size; 129 | } 130 | else 131 | { 132 | editor->access_type = 'w'; 133 | var_data = var.data; 134 | var_data_size = var.size; 135 | } 136 | 137 | editor->selection_size = 1; 138 | editor->selection_active = false; 139 | editor->high_nibble = true; 140 | 141 | if (tool_BufferVarData(editor, var_data, var_data_size, offset)) 142 | { 143 | tool_InitUndoStack(); 144 | run_editor(editor); 145 | } 146 | else 147 | { 148 | gui_ErrorWindow( 149 | "You do not have enough$free RAM to edit this$variable. Archive or" \ 150 | "delete$variables to free more RAM.$Make sure the EDB is$greater than" \ 151 | "the variable's$size." 152 | ); 153 | 154 | retval = false; 155 | } 156 | 157 | CCDBG_ENDBLOCK(); 158 | 159 | return retval; 160 | } 161 | 162 | 163 | void editor_OpenMemEditor( 164 | s_editor* const editor, 165 | const char* const name, 166 | uint8_t* const base_address, 167 | const uint24_t size, 168 | const uint24_t offset 169 | ) 170 | { 171 | CCDBG_BEGINBLOCK("editor_OpenMemEditor"); 172 | CCDBG_DUMP_UINT(strlen(name)); 173 | 174 | memset(editor->name, '\0', G_EDITOR_NAME_MAX_LEN); 175 | strncpy(editor->name, name, strlen(name)); 176 | editor->name_length = strlen(name); 177 | editor->is_tios_var = false; 178 | editor->tios_var_type = 0; 179 | editor->undo_buffer_active = true; 180 | editor->num_changes = 0; 181 | editor->base_address = base_address; 182 | editor->data_size = size; 183 | editor->buffer_size = size; 184 | 185 | if ((uint24_t)base_address < (uint24_t)G_ROM_BASE_ADDRESS + G_ROM_SIZE) 186 | editor->access_type = 'r'; 187 | else 188 | editor->access_type = 'w'; 189 | 190 | editor->near_size = offset + 1; 191 | editor->far_size = size - offset - 1; 192 | editor->selection_size = 1; 193 | editor->selection_active = false; 194 | editor->high_nibble = true; 195 | 196 | tool_InitUndoStack(); 197 | run_editor(editor); 198 | 199 | CCDBG_ENDBLOCK(); 200 | 201 | return; 202 | } 203 | 204 | 205 | // ============================================================================= 206 | // STATIC FUNCTION DEFINITIONS 207 | // ============================================================================= 208 | 209 | 210 | static void run_editor(s_editor* const editor) 211 | { 212 | CCDBG_BEGINBLOCK("run_editor"); 213 | 214 | const uint8_t KEYPRESS_DELAY_THRESHOLD = 7; 215 | bool quit = false; 216 | bool redraw_location_col = true; // Draw the column for initialization. 217 | bool blit = true; 218 | bool accel_cursor = false; 219 | uint8_t writing_value = 0; 220 | 221 | if (editor->selection_size > 1) 222 | editor->selection_active = true; 223 | 224 | tool_UpdateWindowOffset(editor); 225 | 226 | while (!quit) 227 | { 228 | gfx_SetColor(g_color.bar); 229 | gfx_VertLine_NoClip(60, 20, 200); 230 | gfx_VertLine_NoClip(61, 20, 200); 231 | gfx_VertLine_NoClip(230, 20, 200); 232 | gfx_VertLine_NoClip(231, 20, 200); 233 | 234 | // gui_DrawTitleBar() must be called every iteration because the battery 235 | // status updates on a timer. 236 | gui_DrawTitleBar(editor); 237 | gui_DrawToolBar(editor); 238 | gui_PrintData(editor); 239 | 240 | if (redraw_location_col) 241 | { 242 | gui_DrawLocationColumn(editor); 243 | redraw_location_col = false; 244 | blit = true; 245 | } 246 | 247 | if (blit) 248 | { 249 | gfx_BlitBuffer(); 250 | blit = false; 251 | } 252 | else 253 | gfx_SwapDraw(); 254 | 255 | // Slow down the cursor for small variables. 256 | if (editor->data_size < G_NUM_BYTES_ONSCREEN / 2) 257 | delay(30); 258 | 259 | keypad_IdleKeypadBlock(); 260 | 261 | if ( 262 | keypad_SinglePressExclusive(kb_KeyYequ) 263 | && tool_IsAvailable(editor, &tool_FindPhrase) 264 | ) 265 | { 266 | find_prompt(editor); 267 | redraw_location_col = true; 268 | } 269 | 270 | if ( 271 | keypad_SinglePressExclusive(kb_KeyWindow) 272 | && tool_IsAvailable(editor, &tool_InsertBytes) 273 | ) 274 | { 275 | insert_bytes_prompt(editor); 276 | redraw_location_col = true; 277 | } 278 | 279 | if (keypad_SinglePressExclusive(kb_KeyZoom)) 280 | { 281 | if (tool_IsAvailable(editor, &tool_Goto)) 282 | { 283 | goto_prompt(editor); 284 | } 285 | else if (tool_IsAvailable(editor, &tool_CopyBytes)) 286 | { 287 | tool_CopyBytes(editor); 288 | } 289 | } 290 | 291 | if (keypad_SinglePressExclusive(kb_KeyTrace)) 292 | { 293 | if (tool_IsAvailable(editor, &tool_UndoLastAction)) 294 | { 295 | tool_UndoLastAction(editor); 296 | } 297 | else if (tool_IsAvailable(editor, &tool_CutBytes)) 298 | { 299 | tool_AddUndo_DeleteOrCutBytes(editor); 300 | tool_CutBytes(editor); 301 | } 302 | 303 | redraw_location_col = true; 304 | } 305 | 306 | if (keypad_SinglePressExclusive(kb_KeyGraph)) 307 | { 308 | if (tool_IsAvailable(editor, &tool_SwitchWritingMode)) 309 | { 310 | tool_SwitchWritingMode(editor); 311 | } 312 | else if (tool_IsAvailable(editor, &tool_PasteBytes)) 313 | { 314 | tool_AddUndo_PasteBytes(editor); 315 | tool_PasteBytes(editor); 316 | redraw_location_col = true; 317 | } 318 | } 319 | 320 | if ( 321 | ( 322 | keypad_SinglePressExclusive(kb_Key2nd) 323 | || keypad_SinglePressExclusive(kb_KeyEnter) 324 | ) 325 | && editor->near_size 326 | ) 327 | { 328 | toggle_cursor_selection(editor, !editor->selection_active); 329 | } 330 | 331 | if ( 332 | keypad_SinglePressExclusive(kb_KeyMode) 333 | && !editor->is_tios_var 334 | ) 335 | { 336 | if (editor->location_col_mode == 'a') 337 | editor->location_col_mode = 'o'; 338 | else 339 | editor->location_col_mode = 'a'; 340 | 341 | redraw_location_col = true; 342 | } 343 | 344 | if ( 345 | kb_IsDown(kb_KeyDel) 346 | && tool_IsAvailable(editor, &tool_DeleteBytes) 347 | ) 348 | { 349 | tool_AddUndo_DeleteOrCutBytes(editor); 350 | tool_DeleteBytes(editor); 351 | redraw_location_col = true; 352 | } 353 | 354 | if (keypad_SinglePressExclusive(kb_KeyClear)) 355 | { 356 | if (editor->selection_active) 357 | toggle_cursor_selection(editor, false); 358 | else if (editor->num_changes) 359 | quit = save_changes_prompt(editor); 360 | else 361 | quit = true; 362 | } 363 | 364 | if (kb_IsDown(kb_KeyAlpha)) 365 | accel_cursor = true; 366 | else 367 | accel_cursor = false; 368 | 369 | if (keypad_KeyPressedOrHeld(kb_KeyLeft, KEYPRESS_DELAY_THRESHOLD)) 370 | tool_MoveCursor(editor, 0, 1); 371 | 372 | if (keypad_KeyPressedOrHeld(kb_KeyRight, KEYPRESS_DELAY_THRESHOLD)) 373 | tool_MoveCursor(editor, 1, 1); 374 | 375 | if (keypad_KeyPressedOrHeld(kb_KeyUp, KEYPRESS_DELAY_THRESHOLD)) 376 | { 377 | tool_MoveCursor( 378 | editor, 0, (accel_cursor ? G_NUM_BYTES_ONSCREEN : G_COLS_ONSCREEN) 379 | ); 380 | } 381 | 382 | if (keypad_KeyPressedOrHeld(kb_KeyDown, KEYPRESS_DELAY_THRESHOLD)) 383 | { 384 | tool_MoveCursor( 385 | editor, 1, (accel_cursor ? G_NUM_BYTES_ONSCREEN : G_COLS_ONSCREEN) 386 | ); 387 | } 388 | 389 | if (editor->writing_mode == 'x') 390 | { 391 | if ( 392 | keypad_ExclusiveNibble(&writing_value) 393 | && tool_IsAvailable(editor, &tool_WriteNibble) 394 | ) 395 | { 396 | tool_AddUndo_WriteNibble(editor); 397 | tool_WriteNibble(editor, writing_value); 398 | 399 | if (!editor->high_nibble) 400 | tool_MoveCursor(editor, 1, 1); 401 | else 402 | editor->high_nibble = false; 403 | } 404 | } 405 | else 406 | { 407 | if ( 408 | keypad_ExclusiveASCII(&writing_value, editor->writing_mode) 409 | && tool_IsAvailable(editor, &tool_WriteByte) 410 | ) 411 | { 412 | tool_AddUndo_WriteByte(editor); 413 | tool_WriteByte(editor, writing_value); 414 | tool_MoveCursor(editor, 1, 1); 415 | } 416 | } 417 | 418 | redraw_location_col |= tool_UpdateWindowOffset(editor); 419 | } 420 | 421 | CCDBG_ENDBLOCK(); 422 | return; 423 | } 424 | 425 | 426 | static void goto_prompt(s_editor* const editor) 427 | { 428 | const char** keymap = NULL; 429 | char keymap_indicator = 'x'; 430 | char buffer[8] = { '\0' }; 431 | uint8_t buffer_size; 432 | uint24_t offset; 433 | uint24_t address; 434 | 435 | if (editor->location_col_mode == 'o') 436 | { 437 | keymap = G_DIGITS_KEYMAP; 438 | keymap_indicator = '0'; 439 | buffer_size = 7; 440 | } 441 | else 442 | { 443 | keymap = G_HEX_ASCII_KEYMAP; 444 | buffer_size = 6; 445 | } 446 | 447 | while (true) 448 | { 449 | kb_Scan(); 450 | gui_DrawInputPrompt("Goto:", 102); 451 | gui_DrawKeymapIndicator(keymap_indicator, 135, 223); 452 | gui_SetTextColor(g_color.background, g_color.list_text_normal); 453 | gfx_BlitRectangle(1, 0, LCD_HEIGHT - 20, LCD_WIDTH, 20); 454 | gui_Input(buffer, buffer_size, 44, 224, 99, keymap); 455 | 456 | if (keypad_SinglePressExclusive(kb_KeyClear)) 457 | return; 458 | 459 | if ( 460 | keypad_SinglePressExclusive(kb_Key2nd) 461 | || keypad_SinglePressExclusive(kb_KeyEnter) 462 | ) 463 | { 464 | break; 465 | } 466 | } 467 | 468 | CCDBG_PUTS(buffer); 469 | 470 | if (editor->location_col_mode == 'o') 471 | offset = atoi(buffer); 472 | else 473 | { 474 | address = cutil_HexToUint(buffer); 475 | 476 | if (address < (uint24_t)editor->base_address) 477 | offset = 0; 478 | else 479 | offset = address - (uint24_t)editor->base_address; 480 | } 481 | 482 | CCDBG_DUMP_UINT(offset); 483 | 484 | tool_Goto(editor, offset); 485 | return; 486 | } 487 | 488 | 489 | static void insert_bytes_prompt(s_editor* const editor) 490 | { 491 | char buffer[7] = { '\0' }; 492 | 493 | while (true) 494 | { 495 | kb_Scan(); 496 | gui_DrawInputPrompt("Insert:", 102); 497 | gui_DrawKeymapIndicator('0', 151, 223); 498 | gui_SetTextColor(g_color.background, g_color.list_text_normal); 499 | gfx_BlitRectangle(1, 0, LCD_HEIGHT - 20, LCD_WIDTH, 20); 500 | gui_Input(buffer, 6, 60, 224, 99, G_DIGITS_KEYMAP); 501 | 502 | if (keypad_SinglePressExclusive(kb_KeyClear)) 503 | return; 504 | 505 | if ( 506 | keypad_SinglePressExclusive(kb_Key2nd) 507 | || keypad_SinglePressExclusive(kb_KeyEnter) 508 | ) 509 | { 510 | break; 511 | } 512 | } 513 | 514 | tool_AddUndo_InsertBytes(editor, atoi(buffer)); 515 | tool_InsertBytes(editor, atoi(buffer)); 516 | return; 517 | } 518 | 519 | 520 | static void ascii_to_nibble(char* ascii_buffer, char* nibble_buffer) 521 | { 522 | assert(strlen(ascii_buffer) % 2 == 0); 523 | 524 | uint8_t idx = 0; 525 | uint8_t length = strlen(ascii_buffer); 526 | 527 | while (idx < length) 528 | { 529 | nibble_buffer[idx / 2] = ( 530 | ascii_buffer[idx] <= '9' 531 | ? ascii_buffer[idx] - '0' 532 | : ascii_buffer[idx] - 'a' + 10 533 | ) << 4; 534 | idx++; 535 | nibble_buffer[idx / 2] |= ( 536 | ascii_buffer[idx] <= '9' 537 | ? ascii_buffer[idx] - '0' 538 | : ascii_buffer[idx] - 'a' + 10 539 | ); 540 | idx++; 541 | } 542 | 543 | return; 544 | } 545 | 546 | 547 | static void find_viewer( 548 | s_editor* const editor, 549 | const uint24_t matches[], 550 | const uint8_t num_matches, 551 | const uint8_t phrase_length 552 | ) 553 | { 554 | CCDBG_BEGINBLOCK("find_viewer"); 555 | 556 | const uint8_t KEYPRESS_DELAY_THRESHOLD = 8; 557 | uint8_t prev_idx = 0; 558 | uint8_t idx = 0; 559 | 560 | editor->selection_size = phrase_length; 561 | 562 | while (true) 563 | { 564 | 565 | CCDBG_DUMP_UINT(idx); 566 | CCDBG_DUMP_UINT(matches[idx]); 567 | 568 | // This section massages the window offset using selective goto actions to 569 | // make the entire selected phrase appear onscreen. 570 | // ================== 571 | editor->selection_active = false; 572 | tool_Goto(editor, matches[idx]); 573 | 574 | if (prev_idx >= idx) 575 | tool_UpdateWindowOffset(editor); 576 | 577 | tool_Goto(editor, matches[idx] + editor->selection_size - 1); 578 | 579 | if (prev_idx <= idx) 580 | tool_UpdateWindowOffset(editor); 581 | 582 | editor->selection_active = true; 583 | // ================== 584 | 585 | gui_DrawLocationColumn(editor); 586 | gui_PrintData(editor); 587 | gui_DrawFindPhraseToolbar(idx, num_matches); 588 | gfx_BlitBuffer(); 589 | 590 | keypad_IdleKeypadBlock(); 591 | 592 | if ( 593 | keypad_SinglePressExclusive(kb_Key2nd) 594 | || keypad_SinglePressExclusive(kb_KeyClear) 595 | ) 596 | { 597 | break; 598 | } 599 | 600 | prev_idx = idx; 601 | 602 | if (keypad_KeyPressedOrHeld(kb_KeyUp, KEYPRESS_DELAY_THRESHOLD)) 603 | idx = (idx ? idx - 1 : num_matches - 1); 604 | else if (keypad_KeyPressedOrHeld(kb_KeyDown, KEYPRESS_DELAY_THRESHOLD)) 605 | idx = (idx + 1) % num_matches; 606 | } 607 | 608 | editor->selection_active = false; 609 | editor->selection_size = 1; 610 | 611 | CCDBG_ENDBLOCK(); 612 | 613 | return; 614 | } 615 | 616 | 617 | static void find_prompt(s_editor* const editor) 618 | { 619 | const char** keymaps[] = { 620 | G_HEX_ASCII_KEYMAP, G_UPPERCASE_LETTERS_KEYMAP, 621 | G_LOWERCASE_LETTERS_KEYMAP, G_DIGITS_KEYMAP 622 | }; 623 | const char keymap_indicators[] = { 'x', 'A', 'a', '0' }; 624 | char buffer[17] = { '\0' }; 625 | char phrase[8] = { '\0' }; 626 | uint24_t matches[255]; 627 | uint8_t num_matches = 0; 628 | uint8_t phrase_length; 629 | uint8_t keymap_idx = 0; 630 | uint8_t buffer_size = 16; 631 | bool find_phrase = false; 632 | 633 | while (true) 634 | { 635 | kb_Scan(); 636 | gui_DrawInputPrompt("Find:", 152); 637 | gui_DrawKeymapIndicator(keymap_indicators[keymap_idx], 182, 223); 638 | gui_SetTextColor(g_color.background, g_color.list_text_normal); 639 | gfx_BlitRectangle(1, 0, LCD_HEIGHT - 20, LCD_WIDTH, 20); 640 | gui_Input(buffer, buffer_size, 42, 224, 149, keymaps[keymap_idx]); 641 | 642 | if (keypad_SinglePressExclusive(kb_KeyClear) && !strlen(buffer)) 643 | break; 644 | 645 | if (keypad_SinglePressExclusive(kb_KeyAlpha)) 646 | { 647 | if (!strlen(buffer)) 648 | keymap_idx = (keymap_idx + 1) % 4; 649 | else if (keymaps[keymap_idx] != G_HEX_ASCII_KEYMAP) 650 | keymap_idx = ((keymap_idx + 1) % 4) + (keymap_idx == 3 ? 1 : 0); 651 | 652 | if (keymaps[keymap_idx] == G_HEX_ASCII_KEYMAP) 653 | buffer_size = 16; 654 | else 655 | buffer_size = 8; 656 | } 657 | 658 | if ( 659 | keypad_SinglePressExclusive(kb_Key2nd) 660 | || keypad_SinglePressExclusive(kb_KeyEnter) 661 | ) 662 | { 663 | phrase_length = strlen(buffer); 664 | 665 | if (keymaps[keymap_idx] == G_HEX_ASCII_KEYMAP) 666 | { 667 | if (phrase_length > 3 && phrase_length % 2 == 0) 668 | { 669 | ascii_to_nibble(buffer, phrase); 670 | phrase_length /= 2; 671 | find_phrase = true; 672 | } 673 | else 674 | gui_DrawFindPromptMessage("4 or more chars"); 675 | } 676 | else 677 | { 678 | if (phrase_length > 1) 679 | { 680 | strncpy(phrase, buffer, buffer_size); 681 | find_phrase = true; 682 | } 683 | else 684 | gui_DrawFindPromptMessage("2 or more chars"); 685 | } 686 | 687 | if (find_phrase) 688 | { 689 | gui_DrawFindPromptMessage("Searching..."); 690 | 691 | tool_FindPhrase( 692 | editor, (const uint8_t*)phrase, phrase_length, matches, &num_matches 693 | ); 694 | 695 | if (num_matches) 696 | find_viewer(editor, matches, num_matches, phrase_length); 697 | else 698 | { 699 | gui_DrawFindPromptMessage("0 matches"); 700 | 701 | while (true) 702 | { 703 | keypad_IdleKeypadBlock(); 704 | 705 | if (keypad_SinglePressExclusive(kb_KeyClear)) 706 | break; 707 | } 708 | } 709 | 710 | break; 711 | } 712 | } 713 | } 714 | 715 | return; 716 | } 717 | 718 | 719 | // Post: Exit editor -> true 720 | // Do not exit editor -> false 721 | static bool save_changes_prompt(s_editor* const editor) 722 | { 723 | bool retval = false; 724 | bool quit = false; 725 | int8_t save_var_retval; 726 | 727 | gui_DrawSavePrompt(); 728 | gfx_BlitRectangle(1, 0, 220, LCD_WIDTH, 20); 729 | 730 | while (!quit) 731 | { 732 | keypad_IdleKeypadBlock(); 733 | 734 | if (keypad_SinglePressExclusive(kb_KeyZoom)) 735 | quit = true; 736 | 737 | if (keypad_SinglePressExclusive(kb_KeyTrace)) 738 | { 739 | if (!editor->is_tios_var) 740 | { 741 | while (editor->num_changes) 742 | tool_UndoLastAction(editor); 743 | } 744 | 745 | retval = true; 746 | quit = true; 747 | } 748 | 749 | if (keypad_SinglePressExclusive(kb_KeyGraph)) 750 | { 751 | if (editor->is_tios_var) 752 | save_var_retval = tool_SaveModifiedVar(editor); 753 | else 754 | save_var_retval = 1; 755 | 756 | if (save_var_retval == 0) 757 | { 758 | gui_ErrorWindow("Unable to save changes."); 759 | } 760 | else if (save_var_retval == -1) 761 | { 762 | gui_MessageWindowBlocking( 763 | "Fatal Error", "Program will close.$Changes may not be$saved." 764 | ); 765 | tool_FatalErrorExit(); 766 | } 767 | 768 | retval = true; 769 | quit = true; 770 | } 771 | } 772 | 773 | return retval; 774 | } 775 | 776 | 777 | static void toggle_cursor_selection( 778 | s_editor* const editor, bool selection_active 779 | ) 780 | { 781 | editor->selection_active = selection_active; 782 | 783 | if (!selection_active) 784 | editor->selection_size = 1; 785 | 786 | return; 787 | } 788 | -------------------------------------------------------------------------------- /src/editor.h: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: editor.h 3 | // Purpose: Declares the functions that spawn HexaEdit's GUI editors. 4 | 5 | /* 6 | BSD 3-Clause License 7 | 8 | Copyright (c) 2024, Caleb "Captain Calc" Arant 9 | All rights reserved. 10 | 11 | Redistribution and use in source and binary forms, with or without 12 | modification, are permitted provided that the following conditions are met: 13 | 14 | 1. Redistributions of source code must retain the above copyright notice, this 15 | list of conditions and the following disclaimer. 16 | 17 | 2. Redistributions in binary form must reproduce the above copyright notice, 18 | this list of conditions and the following disclaimer in the documentation 19 | and/or other materials provided with the distribution. 20 | 21 | 3. Neither the name of the copyright holder nor the names of its 22 | contributors may be used to endorse or promote products derived from 23 | this software without specific prior written permission. 24 | 25 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 28 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 29 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 31 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 33 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 34 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35 | */ 36 | 37 | 38 | #ifndef EDITOR_H 39 | #define EDITOR_H 40 | 41 | 42 | #include "defines.h" 43 | 44 | 45 | bool editor_OpenVarEditor( 46 | s_editor* const editor, void* const vatptr, const uint24_t offset 47 | ); 48 | 49 | 50 | void editor_OpenMemEditor( 51 | s_editor* const editor, 52 | const char* const name, 53 | uint8_t* const base_address, 54 | const uint24_t size, 55 | const uint24_t offset 56 | ); 57 | 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /src/gui.c: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: gui.h 3 | // Purpose: Defines the functions declared in gui.h. 4 | 5 | 6 | /* 7 | BSD 3-Clause License 8 | 9 | Copyright (c) 2024, Caleb "Captain Calc" Arant 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | 1. Redistributions of source code must retain the above copyright notice, this 16 | list of conditions and the following disclaimer. 17 | 18 | 2. Redistributions in binary form must reproduce the above copyright notice, 19 | this list of conditions and the following disclaimer in the documentation 20 | and/or other materials provided with the distribution. 21 | 22 | 3. Neither the name of the copyright holder nor the names of its 23 | contributors may be used to endorse or promote products derived from 24 | this software without specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 30 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 34 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | #include "ccdbg/ccdbg.h" 53 | #include "asmutil.h" 54 | #include "cutil.h" 55 | #include "gui.h" 56 | #include "hevat.h" 57 | #include "keypad.h" 58 | #include "tools.h" 59 | 60 | 61 | // Some defines for how characters are spaced in the editor GUI. 62 | #define HEX_COL_WIDTH (20) 63 | #define ASCII_COL_WIDTH (10) 64 | #define ROW_HEIGHT (11) 65 | 66 | #define LIST_ITEM_PXL_HEIGHT (G_FONT_HEIGHT + 3) 67 | 68 | 69 | // ============================================================================= 70 | // STATIC FUNCTION DECLARATIONS 71 | // ============================================================================= 72 | 73 | 74 | static void print_ascii(uint8_t value, uint24_t xpos, uint8_t ypos); 75 | 76 | 77 | static void print_hex(uint8_t value, uint24_t xpos, uint8_t ypos); 78 | 79 | 80 | // Pre: Text colors set. 81 | static void draw_battery_status(void); 82 | 83 | 84 | // Description: Returns the number of bytes onscreen at any given moment. 85 | static uint8_t get_num_bytes_onscreen(const s_editor* const editor); 86 | 87 | 88 | static void print_text_wrap(const char* const text); 89 | 90 | 91 | static void draw_list_background(const list* const list, uint8_t color); 92 | 93 | 94 | static void draw_list( 95 | const list* const list, const list_color_palette* const color_palette 96 | ); 97 | 98 | 99 | // ============================================================================= 100 | // PUBLIC FUNCTION DEFINITIONS 101 | // ============================================================================= 102 | 103 | 104 | void gui_SetTextColor(uint8_t bg_color, uint8_t fg_color) 105 | { 106 | gfx_SetTextBGColor(bg_color); 107 | gfx_SetTextFGColor(fg_color); 108 | gfx_SetTextTransparentColor(bg_color); 109 | return; 110 | } 111 | 112 | 113 | void gui_PrintText(const char* const text) 114 | { 115 | // Ensure we are within the character index limit imposed by 116 | // gfx_SetCharData() when using the default font. 117 | assert(G_HEXAEDIT_THETA <= 127); 118 | 119 | static const uint8_t LETTER_o_CHARACTER_DATA[8] = { 120 | 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00 121 | }; 122 | static const uint8_t THETA_CHARACTER_DATA[8] = { 123 | 0x7c, 0xc6, 0xfe, 0xfe, 0xc6, 0xc6, 0x7c, 0x00 124 | }; 125 | 126 | const char* character = text; 127 | 128 | gfx_SetCharData(G_HEXAEDIT_THETA, THETA_CHARACTER_DATA); 129 | 130 | while (*character != '\0') 131 | { 132 | gfx_PrintChar(*character); 133 | character++; 134 | }; 135 | 136 | gfx_SetCharData(G_HEXAEDIT_THETA, LETTER_o_CHARACTER_DATA); 137 | 138 | return; 139 | } 140 | 141 | 142 | void gui_MessageWindowBlocking(const char* const title, const char* const msg) 143 | { 144 | const uint8_t WIDTH = 200; 145 | const uint8_t HEIGHT = 100; 146 | const uint24_t XPOS = (LCD_WIDTH - WIDTH) / 2; 147 | const uint8_t YPOS = (LCD_HEIGHT - HEIGHT) / 2; 148 | 149 | gfx_SetColor(g_color.background); 150 | gfx_FillRectangle_NoClip(XPOS - 2, YPOS - 2, WIDTH + 4, HEIGHT + 4); 151 | gfx_SetColor(g_color.bar); 152 | gfx_FillRectangle_NoClip(XPOS, YPOS, WIDTH, HEIGHT); 153 | gfx_SetColor(g_color.editor_side_panel); 154 | gfx_FillRectangle_NoClip(XPOS + 2, YPOS + 16, WIDTH - 4, HEIGHT - 18); 155 | 156 | gfx_SetTextXY(XPOS + 4, YPOS + 18); 157 | gui_SetTextColor(g_color.editor_side_panel, g_color.editor_text_normal); 158 | print_text_wrap(msg); 159 | 160 | gfx_SetColor(g_color.bar); 161 | gfx_FillRectangle_NoClip(XPOS + WIDTH - 57, YPOS + HEIGHT - 14, 55, 12); 162 | gui_SetTextColor(g_color.bar, g_color.bar_text); 163 | gfx_PrintStringXY(title, XPOS + 3, YPOS + 4); 164 | gfx_PrintStringXY("[clear]", XPOS + WIDTH - 52, YPOS + HEIGHT - 11); 165 | 166 | gfx_BlitRectangle(1, XPOS - 2, YPOS - 2, WIDTH + 4, HEIGHT + 4); 167 | 168 | do { 169 | keypad_IdleKeypadBlock(); 170 | } while (!keypad_SinglePressExclusive(kb_KeyClear)); 171 | 172 | return; 173 | } 174 | 175 | void gui_ErrorWindow(const char* const msg) 176 | { 177 | gui_MessageWindowBlocking("Error", msg); 178 | return; 179 | } 180 | 181 | 182 | void gui_DrawActiveList(const list* const list) 183 | { 184 | list_color_palette color_palette = { 185 | .background = g_color.background, 186 | .cursor = g_color.list_cursor, 187 | .cursor_text = g_color.list_text_selected, 188 | .normal_text = g_color.list_text_normal 189 | }; 190 | 191 | draw_list(list, &color_palette); 192 | return; 193 | } 194 | 195 | 196 | void gui_DrawDormantList(const list* const list) 197 | { 198 | list_color_palette color_palette = { 199 | .background = g_color.editor_side_panel, 200 | .cursor = g_color.bar, 201 | .cursor_text = g_color.list_text_selected, 202 | .normal_text = g_color.list_text_normal 203 | }; 204 | 205 | draw_list(list, &color_palette); 206 | return; 207 | } 208 | 209 | 210 | void gui_EraseHEVATEntryInfo(void) 211 | { 212 | gfx_SetColor(g_color.background); 213 | gfx_FillRectangle_NoClip(214, 20, 106, 152); 214 | return; 215 | } 216 | 217 | 218 | void gui_DrawHEVATEntryInfo(void* vatptr) 219 | { 220 | CCDBG_BEGINBLOCK("gui_DrawHEVATEntryInfo"); 221 | CCDBG_DUMP_PTR(vatptr); 222 | 223 | const uint24_t XPOS = 216; 224 | const uint8_t START_YPOS = 22; 225 | const uint8_t DIVIDER_PXL_HEIGHT = LIST_ITEM_PXL_HEIGHT + 1; 226 | 227 | s_calc_var var; 228 | char ptr[7] = { '\0' }; 229 | uint24_t size; 230 | 231 | for (uint8_t idx = 0; idx < 4; idx++) 232 | { 233 | gfx_SetColor(g_color.editor_side_panel); 234 | gfx_FillRectangle_NoClip( 235 | XPOS - 2, START_YPOS - 2 + (idx * 2 * DIVIDER_PXL_HEIGHT), 236 | 106, 237 | DIVIDER_PXL_HEIGHT 238 | ); 239 | } 240 | 241 | var.vatptr = vatptr; 242 | hevat_GetVarInfoByVAT(&var); 243 | 244 | gui_SetTextColor(g_color.background, g_color.list_text_normal); 245 | gfx_SetTextXY(XPOS, START_YPOS); 246 | gfx_PrintString("OS Type: "); 247 | gfx_PrintUInt(var.type, cutil_Log10(var.type)); 248 | 249 | gfx_SetTextXY(XPOS, START_YPOS + 11); 250 | gfx_PrintString("VAT: 0x"); 251 | cutil_UintToHex(ptr, (uint24_t)vatptr); 252 | gfx_PrintString(ptr); 253 | 254 | gfx_SetTextXY(XPOS, START_YPOS + 22); 255 | gfx_PrintString("Data: 0x"); 256 | cutil_UintToHex(ptr, (uint24_t)var.data); 257 | gfx_PrintString(ptr); 258 | 259 | size = var.size; 260 | 261 | // Do not include size bytes at the start of programs, protected programs, 262 | // appvars, and groups. 263 | if (var.named) 264 | size -= 2; 265 | 266 | gfx_SetTextXY(XPOS, START_YPOS + 33); 267 | gfx_PrintString("Size: "); 268 | gfx_PrintUInt(size, cutil_Log10(size)); 269 | 270 | gfx_SetTextXY(XPOS, START_YPOS + 44); 271 | gfx_PrintString("Location: "); 272 | gfx_PrintString((var.archived ? "ROM" : "RAM")); 273 | 274 | gfx_SetTextXY(XPOS, START_YPOS + 55); 275 | gfx_PrintString("Locked: "); 276 | gfx_PrintString((var.type == OS_TYPE_PROT_PRGM) ? "Yes" : "No"); 277 | 278 | gfx_SetTextXY(XPOS, START_YPOS + 66); 279 | gfx_PrintString("Hidden: "); 280 | gfx_PrintString((cutil_IsVarHidden(var.name) ? "Yes" : "No")); 281 | 282 | CCDBG_ENDBLOCK(); 283 | return; 284 | } 285 | 286 | 287 | void gui_DrawMemoryAmounts(const s_editor* const editor) 288 | { 289 | void* free = NULL; 290 | uint24_t free_ram = os_MemChk(&free); 291 | 292 | gui_SetTextColor(g_color.background, g_color.list_text_normal); 293 | gfx_SetTextXY(216, 189); 294 | gfx_PrintString("EDB: "); 295 | gfx_PrintUInt(editor->buffer_size, cutil_Log10(editor->buffer_size)); 296 | 297 | gfx_SetTextXY(216, 200); 298 | gfx_PrintString("RAM: "); 299 | gfx_PrintUInt(free_ram, cutil_Log10(free_ram)); 300 | 301 | os_ArcChk(); 302 | gfx_SetTextXY(216, 211); 303 | gfx_PrintString("ROM: "); 304 | gfx_PrintUInt(os_TempFreeArc, cutil_Log10(os_TempFreeArc)); 305 | 306 | return; 307 | } 308 | 309 | 310 | void gui_DrawMainMenuTopBar(uint24_t num_list_items) 311 | { 312 | gfx_SetColor(g_color.bar); 313 | gfx_FillRectangle_NoClip(0, 0, LCD_WIDTH, 20); 314 | 315 | gui_SetTextColor(g_color.bar, g_color.list_text_normal); 316 | gfx_PrintStringXY(STRING_PREPEND("HexaEdit ", PROGRAM_VERSION), 4, 5); 317 | gfx_SetTextFGColor(g_color.bar_text); 318 | gfx_PrintStringXY(STRING_PREPEND("HexaEdit ", PROGRAM_VERSION), 5, 6); 319 | 320 | gfx_SetTextXY(130, 6); 321 | gfx_SetTextFGColor(g_color.bar_text); 322 | gfx_PrintUInt(num_list_items, cutil_Log10(num_list_items)); 323 | gfx_PrintString(" items"); 324 | 325 | draw_battery_status(); 326 | return; 327 | } 328 | 329 | 330 | void gui_DrawMainMenuListDividers(void) 331 | { 332 | gfx_SetColor(g_color.bar); 333 | gfx_VertLine_NoClip(105, 20, 200); 334 | gfx_VertLine_NoClip(106, 20, 200); 335 | gfx_VertLine_NoClip(212, 20, 200); 336 | gfx_VertLine_NoClip(213, 20, 200); 337 | return; 338 | } 339 | 340 | 341 | void gui_DrawMainMenuBottomBar(void) 342 | { 343 | gfx_SetColor(g_color.bar); 344 | gfx_FillRectangle_NoClip(0, 220, LCD_WIDTH, 20); 345 | gui_SetTextColor(g_color.bar, g_color.bar_text); 346 | 347 | gfx_PrintStringXY("ROM", 5, 226); 348 | gfx_PrintStringXY("RAM", 68, 226); 349 | gfx_PrintStringXY("Ports", 138, 226); 350 | gfx_PrintStringXY("About", 274, 226); 351 | return; 352 | } 353 | 354 | 355 | void gui_DrawLocationColumn(const s_editor* const editor) 356 | { 357 | char address[7] = { '\0' }; 358 | uint24_t offset; 359 | uint8_t num_bytes_onscreen = get_num_bytes_onscreen(editor); 360 | uint8_t num_rows_onscreen = (num_bytes_onscreen / G_COLS_ONSCREEN) 361 | + (num_bytes_onscreen % G_COLS_ONSCREEN ? 1 : 0); 362 | 363 | gfx_SetColor(g_color.editor_side_panel); 364 | gfx_FillRectangle_NoClip(0, 20, 60, 200); 365 | gui_SetTextColor(g_color.editor_side_panel, g_color.editor_text_normal); 366 | 367 | for (uint8_t row = 0; row < num_rows_onscreen; row++) 368 | { 369 | gfx_SetTextXY(3, 22 + (row * ROW_HEIGHT)); 370 | 371 | offset = editor->window_offset + (row * G_COLS_ONSCREEN); 372 | 373 | if (editor->location_col_mode == 'a') 374 | { 375 | cutil_UintToHex(address,(uint24_t)editor->base_address + offset); 376 | gfx_PrintString(address); 377 | } 378 | else 379 | gfx_PrintUInt(offset, 7); 380 | } 381 | 382 | return; 383 | } 384 | 385 | 386 | void gui_PrintData(const s_editor* const editor) 387 | { 388 | const uint8_t START_HEX_XPOS = 67; 389 | const uint8_t START_YPOS = 22; 390 | const uint8_t START_ASCII_XPOS = 237; 391 | 392 | uint24_t hex_xpos = START_HEX_XPOS; 393 | uint8_t ypos = START_YPOS; 394 | uint24_t ascii_xpos = START_ASCII_XPOS; 395 | uint8_t* window_address = editor->base_address + editor->window_offset; 396 | uint8_t* address = window_address; 397 | uint24_t address_offset; 398 | 399 | // Take the minimum of the number of bytes that can fit onscreen and the 400 | // number of bytes in both segments of the edit buffer, starting from the 401 | // window offset. 402 | uint8_t count = get_num_bytes_onscreen(editor); 403 | 404 | gfx_SetColor(g_color.background); 405 | gfx_FillRectangle_NoClip(START_HEX_XPOS - 5, START_YPOS - 2, 168, 200); 406 | gfx_SetColor(g_color.editor_side_panel); 407 | gfx_FillRectangle_NoClip(START_ASCII_XPOS - 5, START_YPOS - 2, 88, 200); 408 | 409 | for (uint8_t idx = 0; idx < count; idx++) 410 | { 411 | address_offset = address - editor->base_address; 412 | 413 | if (address_offset == editor->near_size) 414 | address = editor->base_address + editor->buffer_size - editor->far_size; 415 | 416 | gui_SetTextColor(g_color.background, g_color.editor_text_normal); 417 | 418 | if ( 419 | address_offset >= (editor->near_size - editor->selection_size) 420 | && address_offset < editor->near_size 421 | ) 422 | { 423 | gfx_SetColor(g_color.editor_cursor); 424 | gfx_FillRectangle_NoClip( 425 | hex_xpos - 1, ypos - 1, HEX_COL_WIDTH, ROW_HEIGHT 426 | ); 427 | gfx_FillRectangle_NoClip( 428 | ascii_xpos - 1, ypos - 1, ASCII_COL_WIDTH, ROW_HEIGHT 429 | ); 430 | gui_SetTextColor(g_color.editor_cursor, g_color.editor_text_selected); 431 | } 432 | 433 | if (editor->window_offset + idx + 1 == editor->near_size) 434 | { 435 | gfx_SetColor(g_color.editor_text_normal); 436 | gfx_HorizLine_NoClip( 437 | hex_xpos - 1 + (9 * !editor->high_nibble), ypos + G_FONT_HEIGHT + 1, 9 438 | ); 439 | } 440 | 441 | gfx_SetColor(g_color.editor_text_normal); 442 | print_hex(*address, hex_xpos, ypos); 443 | print_ascii(*address, ascii_xpos, ypos); 444 | 445 | hex_xpos += HEX_COL_WIDTH; 446 | ascii_xpos += ASCII_COL_WIDTH; 447 | 448 | if (idx && ((idx % G_COLS_ONSCREEN) == (G_COLS_ONSCREEN - 1))) 449 | { 450 | hex_xpos = START_HEX_XPOS; 451 | ascii_xpos = START_ASCII_XPOS; 452 | ypos += ROW_HEIGHT; 453 | } 454 | 455 | address++; 456 | } 457 | 458 | return; 459 | } 460 | 461 | 462 | void gui_DrawTitleBar(const s_editor* const editor) 463 | { 464 | char name[G_EDITOR_NAME_MAX_LEN] = { '\0' }; 465 | uint8_t cutcopy_buffer_size = tool_GetCutCopyBufferSize(); 466 | 467 | gfx_SetColor(g_color.bar); 468 | gfx_FillRectangle_NoClip(0, 0, LCD_WIDTH, 20); 469 | gui_SetTextColor(g_color.bar, g_color.bar_text); 470 | 471 | gfx_SetTextXY(5, 6); 472 | 473 | if (editor->num_changes) 474 | gfx_PrintString("* "); 475 | 476 | if (editor->is_tios_var) 477 | { 478 | hevat_VarNameToASCII( 479 | name, 480 | (const uint8_t*)editor->name, 481 | asmutil_IsNamedVar(editor->tios_var_type) 482 | ); 483 | } 484 | else 485 | strncpy(name, editor->name, editor->name_length); 486 | 487 | gui_PrintText(name); 488 | 489 | gfx_SetTextXY(90, 6); 490 | gfx_PrintUInt(editor->data_size, cutil_Log10(editor->data_size)); 491 | gfx_PrintString(" B"); 492 | 493 | gfx_SetTextXY(184, 6); 494 | gfx_PrintUInt(editor->selection_size, 3); 495 | gfx_PrintString(" ("); 496 | gfx_PrintUInt(cutcopy_buffer_size, 3); 497 | gfx_PrintChar(')'); 498 | 499 | gfx_SetColor(g_color.bar_text); 500 | gfx_FillRectangle_NoClip( 501 | 169, 4, gfx_GetCharWidth(editor->writing_mode) + 1, G_FONT_HEIGHT + 4 502 | ); 503 | gfx_SetTextXY(170, 6); 504 | gui_SetTextColor(g_color.bar_text, g_color.bar); 505 | gfx_PrintChar(editor->writing_mode); 506 | 507 | draw_battery_status(); 508 | return; 509 | } 510 | 511 | 512 | void gui_DrawToolBar(const s_editor* const editor) 513 | { 514 | typedef struct 515 | { 516 | char* name; 517 | uint24_t xpos; 518 | void* func; 519 | } s_toolbar_tool; 520 | 521 | const uint8_t NUM_SELECTION_INACTIVE_TOOLS = 5; 522 | const s_toolbar_tool SELECTION_INACTIVE_TOOLS[] = { 523 | { .name = "Find", .xpos = 5, .func = tool_FindPhrase }, 524 | { .name = "Insert", .xpos = 62, .func = tool_InsertBytes }, 525 | { .name = "Goto", .xpos = 138, .func = tool_Goto }, 526 | { .name = "Undo", .xpos = 224, .func = tool_UndoLastAction }, 527 | { .name = "wMODE", .xpos = 277, .func = tool_SwitchWritingMode }, 528 | }; 529 | 530 | const uint8_t NUM_SELECTION_ACTIVE_TOOLS = 3; 531 | const s_toolbar_tool SELECTION_ACTIVE_TOOLS[] = { 532 | { .name = "Copy", .xpos = 138, .func = tool_CopyBytes }, 533 | { .name = "Cut", .xpos = 224, .func = tool_CutBytes }, 534 | { .name = "Paste", .xpos = 277, .func = tool_PasteBytes }, 535 | }; 536 | 537 | const s_toolbar_tool* tools = SELECTION_INACTIVE_TOOLS; 538 | uint8_t num_tools = NUM_SELECTION_INACTIVE_TOOLS; 539 | uint24_t decimal; 540 | 541 | gfx_SetColor(g_color.bar); 542 | gfx_FillRectangle_NoClip(0, 220, LCD_WIDTH, 20); 543 | gui_SetTextColor(g_color.bar, g_color.bar_text_dark); 544 | 545 | if (editor->selection_active) 546 | { 547 | tools = SELECTION_ACTIVE_TOOLS; 548 | num_tools = NUM_SELECTION_ACTIVE_TOOLS; 549 | 550 | if (editor->near_size && editor->selection_size <= sizeof(uint24_t)) 551 | { 552 | gfx_SetTextFGColor(g_color.bar_text); 553 | gfx_PrintStringXY("Decimal: ", 5, 226); 554 | decimal = 0; 555 | 556 | for (uint8_t idx = 0; idx < editor->selection_size; idx++) 557 | { 558 | decimal += ( 559 | *( 560 | editor->base_address + editor->near_size 561 | - editor->selection_size + idx 562 | ) << (8 * idx) 563 | ); 564 | } 565 | 566 | gfx_PrintUInt(decimal, cutil_Log10(decimal)); 567 | } 568 | } 569 | 570 | for (uint8_t idx = 0; idx < num_tools; idx++) 571 | { 572 | gfx_SetTextFGColor(g_color.bar_text_dark); 573 | 574 | if (tool_IsAvailable(editor, tools[idx].func)) 575 | gfx_SetTextFGColor(g_color.bar_text); 576 | 577 | gfx_PrintStringXY(tools[idx].name, tools[idx].xpos, 226); 578 | } 579 | 580 | return; 581 | } 582 | 583 | 584 | void gui_DrawFindPromptMessage(const char* const message) 585 | { 586 | uint24_t width = gfx_GetStringWidth(message); 587 | 588 | gfx_SetColor(g_color.bar); 589 | gfx_FillRectangle_NoClip(220, 226, LCD_WIDTH - 220, 10); 590 | 591 | gui_SetTextColor(g_color.bar, g_color.bar_text); 592 | gfx_PrintStringXY(message, 315 - width, 226); 593 | gfx_BlitRectangle(1, 0, 220, LCD_WIDTH, 20); 594 | return; 595 | } 596 | 597 | 598 | void gui_DrawFindPhraseToolbar( 599 | const uint8_t match_idx, const uint8_t num_matches 600 | ) 601 | { 602 | uint24_t actual_match_idx = match_idx + (num_matches ? 1 : 0); 603 | 604 | gfx_SetColor(g_color.bar); 605 | gfx_FillRectangle_NoClip(0, 220, LCD_WIDTH, 20); 606 | gui_SetTextColor(g_color.bar, g_color.bar_text); 607 | 608 | gfx_SetTextXY(5, 226); 609 | gfx_PrintUInt(actual_match_idx, cutil_Log10(actual_match_idx)); 610 | gfx_PrintString(" / "); 611 | gfx_PrintUInt(num_matches, cutil_Log10(num_matches)); 612 | return; 613 | } 614 | 615 | 616 | void gui_DrawSavePrompt(void) 617 | { 618 | gfx_SetColor(g_color.bar); 619 | gfx_FillRectangle_NoClip(0, 220, LCD_WIDTH, 20); 620 | gui_SetTextColor(g_color.bar, g_color.bar_text); 621 | 622 | gfx_PrintStringXY("Save changes?", 5, 226); 623 | gfx_PrintStringXY("Cancel", 132, 226); 624 | gfx_PrintStringXY("No", 226, 226); 625 | gfx_PrintStringXY("Yes", 285, 226); 626 | return; 627 | } 628 | 629 | 630 | void gui_DrawInputPrompt( 631 | const char* const prompt, const uint24_t input_field_width 632 | ) 633 | { 634 | uint24_t x = gfx_GetStringWidth(prompt) + 10; 635 | 636 | gfx_SetColor(g_color.bar); 637 | gfx_FillRectangle_NoClip(0, LCD_HEIGHT - 20, LCD_WIDTH, 20); 638 | 639 | gui_SetTextColor(g_color.bar, g_color.bar_text); 640 | gfx_PrintStringXY(prompt, 5, 226); 641 | 642 | gfx_SetColor(g_color.list_text_normal); 643 | gfx_FillRectangle_NoClip(x, 223, input_field_width, G_FONT_HEIGHT + 6); 644 | 645 | gfx_SetColor(g_color.background); 646 | gfx_FillRectangle_NoClip( 647 | x + 1, 224, input_field_width - 2, G_FONT_HEIGHT + 4 648 | ); 649 | 650 | return; 651 | } 652 | 653 | 654 | void gui_DrawKeymapIndicator( 655 | const char indicator, const uint24_t x_pos, const uint8_t y_pos 656 | ) 657 | { 658 | gfx_SetColor(g_color.list_cursor); 659 | gfx_FillRectangle_NoClip( 660 | x_pos, y_pos, gfx_GetCharWidth(indicator) + 3, G_FONT_HEIGHT + 6 661 | ); 662 | 663 | gui_SetTextColor(g_color.list_cursor, g_color.list_text_selected); 664 | gfx_SetTextXY(x_pos + 2, y_pos + 3); 665 | gfx_PrintChar(indicator); 666 | return; 667 | } 668 | 669 | 670 | void gui_Input( 671 | char* const buffer, 672 | const uint8_t buffer_size, 673 | const uint24_t x_pos, 674 | const uint8_t y_pos, 675 | const uint24_t width, 676 | const char* const keymap[7] 677 | ) 678 | { 679 | uint8_t value; 680 | uint8_t offset = strlen(buffer); 681 | 682 | gfx_SetTextXY(x_pos + 2, y_pos + 2); 683 | gui_PrintText(buffer); 684 | gfx_FillRectangle_NoClip( 685 | x_pos + gfx_GetStringWidth(buffer) + 2, y_pos + 1, 2, G_FONT_HEIGHT + 2 686 | ); 687 | gfx_BlitRectangle(1, x_pos, y_pos, width, G_FONT_HEIGHT + 4); 688 | gfx_SetColor(g_color.list_cursor); 689 | 690 | keypad_IdleKeypadBlock(); 691 | 692 | // The [del] is not a single-press-exclusive because the user should be able 693 | // to hold the [del] key to remove multiple characters from the buffer. 694 | if (kb_IsDown(kb_KeyDel) && offset) 695 | buffer[--offset] = '\0'; 696 | 697 | if (strlen(buffer) && keypad_SinglePressExclusive(kb_KeyClear)) 698 | memset(buffer, '\0', buffer_size); 699 | 700 | if (!keypad_ExclusiveKeymap(keymap, &value) && offset < buffer_size) 701 | buffer[offset++] = value; 702 | 703 | delay(150); 704 | 705 | return; 706 | } 707 | 708 | 709 | // ============================================================================= 710 | // STATIC FUNCTION DEFINITIONS 711 | // ============================================================================= 712 | 713 | 714 | static void print_ascii(uint8_t value, uint24_t xpos, uint8_t ypos) 715 | { 716 | gfx_SetTextXY(xpos, ypos); 717 | 718 | if (value < 32 || value > 127) 719 | gfx_Rectangle_NoClip(xpos, ypos + 1, 6, 6); 720 | else 721 | gfx_PrintChar(value); 722 | 723 | return; 724 | } 725 | 726 | 727 | static void print_hex(uint8_t value, uint24_t xpos, uint8_t ypos) 728 | { 729 | const char HEX_CHARS[] = "0123456789abcdef"; 730 | 731 | char hex[3] = { '\0' }; 732 | 733 | hex[0] = HEX_CHARS[value / 16]; 734 | hex[1] = HEX_CHARS[value % 16]; 735 | gfx_PrintStringXY(hex, xpos, ypos); 736 | return; 737 | } 738 | 739 | static void draw_battery_status(void) 740 | { 741 | const double FIVE_MIN_IN_SEC = 300; 742 | 743 | static uint8_t charging = 0; 744 | static uint8_t battery_status = 0; 745 | static double prev_clock = 0; 746 | uint8_t percentage; 747 | double curr_clock = clock(); 748 | 749 | if ( 750 | !prev_clock 751 | || ((curr_clock - prev_clock) / CLOCKS_PER_SEC) > FIVE_MIN_IN_SEC) 752 | { 753 | prev_clock = curr_clock; 754 | battery_status = boot_GetBatteryStatus(); 755 | charging = boot_BatteryCharging(); 756 | } 757 | 758 | percentage = battery_status * 25; 759 | 760 | gfx_SetTextXY( 761 | 290 - gfx_GetCharWidth('%') 762 | - (cutil_Log10(percentage) * gfx_GetCharWidth('0')), 763 | 6 764 | ); 765 | gui_SetTextColor(g_color.bar, g_color.bar_text); 766 | gfx_PrintUInt(percentage, cutil_Log10(percentage)); 767 | gfx_PrintChar('%'); 768 | 769 | gfx_SetColor(g_color.bar_text); 770 | gfx_Rectangle(294, 6, 2, 7); 771 | gfx_Rectangle_NoClip(296, 4, 19, 11); 772 | 773 | if (charging) 774 | { 775 | for ( 776 | uint8_t idx = 0; 777 | idx < (battery_status == 4 ? 4 : battery_status + 1); 778 | idx++ 779 | ) 780 | { 781 | gfx_FillRectangle_NoClip( 782 | 310 - (idx * 4), 6 + (idx * 2), 3, 7 - (idx * 2) 783 | ); 784 | } 785 | } 786 | else 787 | { 788 | for (uint8_t idx = 0; idx < battery_status; idx++) 789 | { 790 | gfx_FillRectangle_NoClip(310 - (idx * 4), 6, 3, 7); 791 | } 792 | } 793 | 794 | return; 795 | } 796 | 797 | 798 | static uint8_t get_num_bytes_onscreen(const s_editor* const editor) 799 | { 800 | uint8_t count = min( 801 | editor->data_size - editor->window_offset, 802 | G_NUM_BYTES_ONSCREEN 803 | ); 804 | 805 | return count; 806 | } 807 | 808 | 809 | static void print_text_wrap(const char* const text) 810 | { 811 | const char* c = text; 812 | uint24_t orig_xpos = gfx_GetTextX(); 813 | 814 | while (*c != '\0') 815 | { 816 | if (*c == '$') 817 | gfx_SetTextXY(orig_xpos, gfx_GetTextY() + 9); 818 | else 819 | gfx_PrintChar(*c); 820 | 821 | c++; 822 | } 823 | 824 | return; 825 | } 826 | 827 | 828 | static void draw_list_background(const list* const list, uint8_t color) 829 | { 830 | uint8_t xpos = list->xpos - 2; 831 | uint24_t ypos = list->ypos - 2; 832 | uint24_t width = LIST_WIDTH_IN_PIXELS + 4; 833 | uint24_t height = 200; 834 | 835 | gfx_SetColor(color); 836 | gfx_FillRectangle_NoClip(xpos, ypos, width, height); 837 | return; 838 | } 839 | 840 | 841 | static void draw_list( 842 | const list* const list, const list_color_palette* const color_palette 843 | ) 844 | { 845 | CCDBG_BEGINBLOCK("draw_list"); 846 | 847 | char print_name[20] = { '\0' }; 848 | uint8_t ypos = list->ypos; 849 | uint24_t last_visible_item_index = list->window_offset + min( 850 | list->total_item_count, list->visible_item_count 851 | ); 852 | 853 | draw_list_background(list, color_palette->background); 854 | 855 | CCDBG_PUTS("After draw_list_background"); 856 | 857 | for (uint8_t idx = list->window_offset; idx < last_visible_item_index; idx++) 858 | { 859 | if (idx == list_GetCursorIndex(list)) 860 | { 861 | 862 | CCDBG_PUTS("Highlighting item"); 863 | 864 | gfx_SetColor(color_palette->cursor); 865 | gfx_FillRectangle_NoClip( 866 | list->xpos, ypos, LIST_WIDTH_IN_PIXELS, LIST_ITEM_HEIGHT_IN_PIXELS 867 | ); 868 | gui_SetTextColor(color_palette->cursor, color_palette->cursor_text); 869 | } 870 | else 871 | { 872 | 873 | CCDBG_PUTS("Not highlighting item"); 874 | 875 | gui_SetTextColor(color_palette->background, color_palette->normal_text); 876 | } 877 | 878 | gfx_SetTextXY(list->xpos + 1, ypos + 1); 879 | list->get_item_name(print_name, idx); 880 | gui_PrintText(print_name); 881 | ypos += LIST_ITEM_HEIGHT_IN_PIXELS; 882 | } 883 | 884 | CCDBG_ENDBLOCK(); 885 | 886 | return; 887 | } 888 | -------------------------------------------------------------------------------- /src/gui.h: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: gui.h 3 | // Purpose: Declares all of the graphical routines used by HexaEdit. 4 | 5 | 6 | /* 7 | BSD 3-Clause License 8 | 9 | Copyright (c) 2024, Caleb "Captain Calc" Arant 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | 1. Redistributions of source code must retain the above copyright notice, this 16 | list of conditions and the following disclaimer. 17 | 18 | 2. Redistributions in binary form must reproduce the above copyright notice, 19 | this list of conditions and the following disclaimer in the documentation 20 | and/or other materials provided with the distribution. 21 | 22 | 3. Neither the name of the copyright holder nor the names of its 23 | contributors may be used to endorse or promote products derived from 24 | this software without specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 30 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 34 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | 39 | #ifndef GUI_H 40 | #define GUI_H 41 | 42 | 43 | #include "defines.h" 44 | #include "list.h" 45 | 46 | 47 | // TODO: Rename 48 | void gui_SetTextColor(uint8_t bg_color, uint8_t fg_color); 49 | 50 | void gui_PrintText(const char* const text); 51 | 52 | void gui_MessageWindowBlocking(const char* const title, const char* const msg); 53 | 54 | void gui_ErrorWindow(const char* const msg); 55 | 56 | void gui_DrawActiveList(const list* const list); 57 | 58 | void gui_DrawDormantList(const list* const list); 59 | 60 | void gui_EraseHEVATEntryInfo(void); 61 | 62 | void gui_DrawHEVATEntryInfo(void* vatptr); 63 | 64 | void gui_DrawMemoryAmounts(const s_editor* const editor); 65 | 66 | void gui_DrawMainMenuTopBar(uint24_t num_list_items); 67 | 68 | void gui_DrawMainMenuListDividers(void); 69 | 70 | void gui_DrawMainMenuBottomBar(void); 71 | 72 | void gui_DrawLocationColumn(const s_editor* const editor); 73 | 74 | void gui_PrintData(const s_editor* const editor); 75 | 76 | void gui_DrawTitleBar(const s_editor* const editor); 77 | 78 | void gui_DrawToolBar(const s_editor* const editor); 79 | 80 | void gui_DrawFindPromptMessage(const char* const message); 81 | 82 | void gui_DrawFindPhraseToolbar( 83 | const uint8_t match_idx, const uint8_t num_matches 84 | ); 85 | 86 | void gui_DrawSavePrompt(void); 87 | 88 | void gui_DrawInputPrompt( 89 | const char* const prompt, const uint24_t input_field_width 90 | ); 91 | 92 | void gui_DrawKeymapIndicator( 93 | const char indicator, const uint24_t x_pos, const uint8_t y_pos 94 | ); 95 | 96 | // excludes the null terminator. If you give a of 8, 97 | // the actual number of bytes in the buffer should be 9. 98 | void gui_Input( 99 | char* const buffer, 100 | const uint8_t buffer_size, 101 | const uint24_t x_pos, 102 | const uint8_t y_pos, 103 | const uint24_t width, 104 | const char* const keymap[7] 105 | ); 106 | 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /src/hevat.c: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: hevat.c 3 | // Purpose: Defines the functions declared in hevat.h and any supporting static 4 | // functions. 5 | 6 | 7 | /* 8 | BSD 3-Clause License 9 | 10 | Copyright (c) 2024, Caleb "Captain Calc" Arant 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 16 | 1. Redistributions of source code must retain the above copyright notice, this 17 | list of conditions and the following disclaimer. 18 | 19 | 2. Redistributions in binary form must reproduce the above copyright notice, 20 | this list of conditions and the following disclaimer in the documentation 21 | and/or other materials provided with the distribution. 22 | 23 | 3. Neither the name of the copyright holder nor the names of its 24 | contributors may be used to endorse or promote products derived from 25 | this software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 31 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 35 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | */ 38 | 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include "ccdbg/ccdbg.h" 48 | #include "asmutil.h" 49 | #include "defines.h" 50 | #include "hevat.h" 51 | 52 | 53 | #define MAX_NUM_RECENTS (15) 54 | #define MAX_NUM_HEVAT_ENTRIES (1015) 55 | 56 | 57 | const char* HEVAT__GROUP_NAMES[HEVAT__NUM_GROUPS] = { 58 | "Recents...", "Appvar", "Prot Prgm", "Program", "Real", "Real List", 59 | "Matrix", "Equation", "String", "Picture", "GDB", "Complex", "Cplx List", 60 | "Group", "Other" 61 | }; 62 | 63 | 64 | // Do NOT use these variables outside this file. 65 | static void* g_hevat[MAX_NUM_HEVAT_ENTRIES] = { NULL }; 66 | static uint24_t g_num_vatptrs = 0; 67 | 68 | // Holds the number of entries for a given group index. 69 | static uint24_t g_num_entries[HEVAT__NUM_GROUPS] = { 0 }; 70 | 71 | 72 | // ============================================================================= 73 | // STATIC FUNCTION DECLARATIONS 74 | // ============================================================================= 75 | 76 | 77 | // Description: Converts a TI-OS variable type into an HEVAT_GROUP_INDEX. 78 | // Pre: must be valid. 79 | // Post: The HEVAT_GROUP_INDEX will be returned. 80 | static uint8_t hevat_group_index(const uint24_t os_var_type); 81 | 82 | 83 | static bool load_recents_entries(void); 84 | 85 | 86 | // Description: Counts the number of VAT pointers present on the calculator 87 | // and tallies the number of them that point to each TI-OS 88 | // variable type. 89 | // Pre: None 90 | // Post: and set. 91 | static void count_vatptrs(void); 92 | 93 | 94 | // Description: Determines where the given group starts in the HEVAT. 95 | // Pre: count_vatptrs() should have been called. 96 | // Post: Returns the offset in the HEVAT where the given group starts. 97 | static uint24_t hevat_offset(const uint8_t hevat_group_idx); 98 | 99 | 100 | // Description: Loads all of the TI-OS VAT pointers into the HEVAT. 101 | // Pre: count_vatptrs() should have been called. 102 | // Post: HEVAT contains VAT pointers sorted by variable type. 103 | static void load_vatptr_entries(void); 104 | 105 | 106 | // Description: Performs an alphabetical string comparision between the names 107 | // of the variables at each of the given TI-OS VAT pointers. 108 | // Pre: Both VAT pointers should be valid. 109 | // Post: If the name of the variable at (N1) occurs before 110 | // the namve of the variable at (N2) in alphabetical 111 | // order, -1 returned. 112 | // If N1 is equal to N2, 0 returned. 113 | // If N1 occurs after N2 in alphabetical order, 1 returned. 114 | static int8_t entry_name_cmp(void* vatptr_one, void* vatptr_two); 115 | 116 | 117 | // Description: Sorts the VAT pointers in the HEVAT alphabetically. Uses 118 | // insertion sort. 119 | static void sort_hevat(void); 120 | 121 | 122 | static void get_variable_name( 123 | char* const buffer, uint8_t hevat_group_idx, uint24_t index 124 | ); 125 | 126 | 127 | static char hex_char(uint8_t nibble) 128 | { 129 | nibble &= 0x0F; 130 | return (nibble < 10 ? '0' + nibble : 'A' + nibble - 10); 131 | } 132 | 133 | 134 | static void hex_byte(char** dest, uint8_t byte) 135 | { 136 | *(*dest)++ = hex_char(byte >> 4); 137 | *(*dest)++ = hex_char(byte >> 0); 138 | return; 139 | } 140 | 141 | 142 | // ============================================================================= 143 | // PUBLIC FUNCTION DEFINITIONS 144 | // ============================================================================= 145 | 146 | 147 | bool hevat_Load(void) 148 | { 149 | CCDBG_BEGINBLOCK("hevat_Load"); 150 | CCDBG_DUMP_PTR(g_hevat); 151 | 152 | memset(g_hevat, '\0', sizeof g_hevat); 153 | g_num_vatptrs = 0; 154 | 155 | for (uint8_t idx = 0; idx < HEVAT__NUM_GROUPS; idx++) 156 | g_num_entries[idx] = 0; 157 | 158 | if (!load_recents_entries()) 159 | { 160 | CCDBG_PUTS("Could not load recent entries"); 161 | CCDBG_ENDBLOCK(); 162 | 163 | return false; 164 | } 165 | 166 | count_vatptrs(); 167 | load_vatptr_entries(); 168 | sort_hevat(); 169 | 170 | CCDBG_ENDBLOCK(); 171 | 172 | return true; 173 | } 174 | 175 | 176 | bool hevat_SaveRecents(void) 177 | { 178 | CCDBG_BEGINBLOCK("tool_SaveRecents"); 179 | 180 | s_calc_var var; 181 | uint8_t handle; 182 | 183 | if (!(handle = ti_Open(G_RECENTS_APPVAR_NAME, "r+"))) 184 | { 185 | CCDBG_PUTS("Cannot open recents appvar"); 186 | CCDBG_ENDBLOCK(); 187 | 188 | return false; 189 | } 190 | 191 | CCDBG_PUTS("Opened recents appvar"); 192 | 193 | memset(ti_GetDataPtr(handle), '\0', ti_GetSize(handle)); 194 | 195 | for (uint8_t idx = 0; idx < g_num_entries[HEVAT__RECENTS]; idx++) 196 | { 197 | var.vatptr = g_hevat[idx]; 198 | hevat_GetVarInfoByVAT(&var); 199 | 200 | assert( 201 | ti_Tell(handle) + sizeof var.type + sizeof var.name_length + var.name_length 202 | < ti_GetSize(handle) 203 | ); 204 | CCDBG_PUTS(var.name); 205 | CCDBG_DUMP_UINT(var.type); 206 | CCDBG_DUMP_UINT(var.name_length); 207 | 208 | if (ti_Write(&var.type, sizeof var.type, 1, handle) != 1) 209 | { 210 | CCDBG_PUTS("Cannot write type"); 211 | CCDBG_ENDBLOCK(); 212 | 213 | return false; 214 | } 215 | 216 | if (ti_Write(&var.name_length, sizeof var.name_length, 1, handle) != 1) 217 | { 218 | CCDBG_PUTS("Cannot write name length"); 219 | CCDBG_ENDBLOCK(); 220 | 221 | return false; 222 | } 223 | 224 | if (ti_Write(var.name, var.name_length, 1, handle) != 1) 225 | { 226 | CCDBG_PUTS("Cannot write name"); 227 | CCDBG_ENDBLOCK(); 228 | 229 | return false; 230 | } 231 | } 232 | 233 | ti_Close(handle); 234 | 235 | CCDBG_ENDBLOCK(); 236 | 237 | return true; 238 | } 239 | 240 | 241 | void* hevat_Ptr(const uint8_t hevat_group_idx, const uint24_t offset) 242 | { 243 | assert(g_num_entries[hevat_group_idx] > offset); 244 | 245 | return g_hevat[hevat_offset(hevat_group_idx) + offset]; 246 | } 247 | 248 | 249 | void hevat_Name( 250 | char* name, 251 | uint24_t* name_length, 252 | const uint8_t hevat_group_idx, 253 | const uint24_t offset 254 | ) 255 | { 256 | void* data = NULL; 257 | uint24_t type = 0; 258 | 259 | os_NextSymEntry( 260 | hevat_Ptr(hevat_group_idx, offset), &type, name_length, name, &data 261 | ); 262 | 263 | return; 264 | } 265 | 266 | 267 | uint24_t hevat_NumEntries(const uint8_t hevat_group_idx) 268 | { 269 | return g_num_entries[hevat_group_idx]; 270 | } 271 | 272 | 273 | void hevat_AddRecent(void* vatptr) 274 | { 275 | uint8_t idx = 0; 276 | 277 | while (g_hevat[idx] && g_hevat[idx] != vatptr && idx < MAX_NUM_RECENTS) 278 | idx++; 279 | 280 | if (idx == MAX_NUM_RECENTS) 281 | idx--; 282 | else if (g_hevat[idx] != vatptr) 283 | g_num_entries[HEVAT__RECENTS]++; 284 | 285 | while (idx) 286 | { 287 | g_hevat[idx] = g_hevat[idx - 1]; 288 | idx--; 289 | } 290 | 291 | g_hevat[0] = vatptr; 292 | return; 293 | } 294 | 295 | 296 | // Based on the CEmu core/vat.c code by the CE-Programming team. 297 | bool hevat_GetVarInfoByVAT(s_calc_var* const var) 298 | { 299 | const uint8_t* userMem = (const uint8_t*)0xD1A881; 300 | const uint8_t* OPBase = *(const uint8_t**)0xD02590; 301 | const uint8_t* pTemp = *(const uint8_t**)0xD0259A; 302 | const uint8_t* progPtr = *(const uint8_t**)0xD0259D; 303 | const uint8_t* symTable = (const uint8_t*)0xD3FFFF; 304 | 305 | uint8_t* orig_vatptr = var->vatptr; 306 | uint24_t data = 0; 307 | uint8_t idx; 308 | 309 | assert(var->vatptr); 310 | 311 | if (var->vatptr < userMem || var->vatptr <= OPBase || var->vatptr > symTable) 312 | return false; 313 | 314 | memset(var, 0x00, sizeof *var); 315 | var->vatptr = orig_vatptr; 316 | 317 | var->type_one = *var->vatptr--; 318 | var->type_two = *var->vatptr--; 319 | var->version = *var->vatptr--; 320 | data = *var->vatptr--; 321 | data |= *var->vatptr << 8; var->vatptr--; 322 | data |= *var->vatptr << 16; var->vatptr--; 323 | var->data = (uint8_t*)data; 324 | 325 | if ((var->named = (var->vatptr > pTemp) && (var->vatptr <= progPtr))) 326 | { 327 | var->name_length = *var->vatptr; 328 | var->vatptr--; 329 | 330 | if (!var->name_length || var->name_length > 8) 331 | return false; 332 | } 333 | else 334 | var->name_length = 3; 335 | 336 | var->archived = ( 337 | ((uint24_t)var->data > 0x0C0000) && ((uint24_t)var->data < 0x400000) 338 | ); 339 | 340 | if (var->archived) 341 | { 342 | // Skip past the duplicate header. 343 | var->data += 9 + var->named + var->name_length; 344 | } 345 | else if (var->data < userMem || var->data > symTable) 346 | return false; 347 | 348 | var->type = (calc_var_type_t)(var->type_one & 0x3F); 349 | 350 | switch(var->type) 351 | { 352 | case CALC_VAR_TYPE_REAL: 353 | case CALC_VAR_TYPE_REAL_FRAC: 354 | case CALC_VAR_TYPE_REAL_RADICAL: 355 | case CALC_VAR_TYPE_REAL_PI: 356 | case CALC_VAR_TYPE_REAL_PI_FRAC: 357 | var->size = 9; 358 | break; 359 | 360 | case CALC_VAR_TYPE_REAL_LIST: 361 | var->size = 2 + (*(uint16_t*)var->data) * 9; 362 | break; 363 | 364 | case CALC_VAR_TYPE_MATRIX: 365 | var->size = 2 + (*(uint8_t*)var->data) * (*(uint8_t*)(var->data + 1)) * 9; 366 | break; 367 | 368 | case CALC_VAR_TYPE_CPLX: 369 | case CALC_VAR_TYPE_CPLX_FRAC: 370 | case CALC_VAR_TYPE_CPLX_RADICAL: 371 | case CALC_VAR_TYPE_CPLX_PI: 372 | case CALC_VAR_TYPE_CPLX_PI_FRAC: 373 | var->size = 18; 374 | break; 375 | 376 | case CALC_VAR_TYPE_CPLX_LIST: 377 | var->size = 2 + (*(uint16_t*)var->data) * 18; 378 | break; 379 | 380 | default: 381 | var->size = 2 + (*(uint16_t*)var->data); 382 | break; 383 | } 384 | 385 | for (idx = 0; idx != var->name_length; idx++) 386 | var->name[idx] = *var->vatptr--; 387 | 388 | memset(&var->name[idx], 0x00, sizeof var->name - idx); 389 | var->vatptr = orig_vatptr; 390 | return true; 391 | } 392 | 393 | 394 | // Based on the CEmu core/vat.c code by the CE-Programming team. 395 | void hevat_VarNameToASCII(char buffer[20], const uint8_t name[8], bool named) 396 | { 397 | char* dest = buffer; 398 | uint8_t idx = 0; 399 | 400 | // If the variable is a user-defined list, put the 'L' in and increment the 401 | // index so the for-loop can parse the list's ASCII name. 402 | if (name[0] == 0x5D) 403 | { 404 | *dest++ = 'L'; 405 | idx++; 406 | } 407 | 408 | for ( 409 | ; 410 | idx < 8 && ( 411 | (name[idx] >= 'A' && name[idx] <= 'Z' + 1) 412 | || (idx && name[idx] >= 'a' && name[idx] <= 'z') 413 | || (idx && name[idx] >= '0' && name[idx] <= '9') 414 | ); 415 | idx++ 416 | ) 417 | { 418 | // 'Z' + 1 is the TI-OS token for theta. 419 | if (name[idx] == 'Z' + 1) 420 | *dest++ = G_HEXAEDIT_THETA; 421 | else 422 | *dest++ = name[idx]; 423 | } 424 | 425 | // In English: If the variable is a TI-OS list or is a non-ASCII name, do.... 426 | if (!(idx - (name[0] == 0x5D))) 427 | { 428 | switch(name[0]) 429 | { 430 | case '!': 431 | case '#': 432 | case '.': 433 | case '@': 434 | *dest++ = name[0]; 435 | break; 436 | 437 | case '$': 438 | *dest++ = name[0]; 439 | hex_byte(&dest, name[2]); 440 | hex_byte(&dest, name[1]); 441 | break; 442 | 443 | case 0x3C: 444 | *dest++ = 'I'; 445 | *dest++ = 'm'; 446 | *dest++ = 'a'; 447 | *dest++ = 'g'; 448 | *dest++ = 'e'; 449 | *dest++ = '0' + (name[1] + 1) % 10; 450 | break; 451 | 452 | case 0x5C: 453 | *dest++ = '['; 454 | *dest++ = 'A' + name[1]; 455 | *dest++ = ']'; 456 | break; 457 | 458 | // We already have the 'L' in place. 459 | case 0x5D: 460 | *dest++ = '1' + name[1]; 461 | break; 462 | 463 | case 0x5E: 464 | if (name[1] < 0x20) 465 | { 466 | *dest++ = 'Y'; 467 | *dest++ = '0' + (name[1] % 0x10); 468 | } 469 | else if (name[1] < 0x40) 470 | { 471 | if (name[1] % 2 == 0) 472 | *dest++ = 'X'; 473 | else 474 | *dest++ = 'Y'; 475 | 476 | *dest++ = '0' + ((name[1] % 0x20) / 2); 477 | *dest++ = 'T'; 478 | } 479 | else if (name[1] < 0x80) 480 | { 481 | *dest++ = 'r'; 482 | *dest++ = '0' + (name[1] % 0x40); 483 | } 484 | else 485 | { 486 | *dest++ = 'u' + (name[1] & 3); 487 | } 488 | break; 489 | 490 | case 0x60: 491 | *dest++ = 'P'; 492 | *dest++ = 'i'; 493 | *dest++ = 'c'; 494 | *dest++ = '0' + (name[1] + 1) % 10; 495 | break; 496 | 497 | case 0x61: 498 | *dest++ = 'G'; 499 | *dest++ = 'D'; 500 | *dest++ = 'B'; 501 | *dest++ = '0' + (name[1] + 1) % 10; 502 | break; 503 | 504 | case 0x62: 505 | if (name[1] == 0x21) 506 | *dest++ = 'n'; 507 | 508 | break; 509 | 510 | case 0xAA: 511 | *dest++ = 'S'; 512 | *dest++ = 't'; 513 | *dest++ = 'r'; 514 | *dest++ = '0' + (name[1] + 1) % 10; 515 | break; 516 | 517 | case 0x72: 518 | if (!named) { 519 | *dest++ = 'A'; 520 | *dest++ = 'n'; 521 | *dest++ = 's'; 522 | break; 523 | } 524 | 525 | default: 526 | idx = 0; 527 | 528 | // If a variable name is hidden, recover the mangled first byte of its 529 | // name. 530 | if (name[0] < 0x20) 531 | { 532 | *dest++ = name[0] | 0x40; 533 | idx++; 534 | } 535 | 536 | for ( 537 | ; 538 | idx < 8 && ( 539 | (name[idx] >= 'A' && name[idx] <= 'Z' + 1) 540 | || (name[idx] >= 'a' && name[idx] <= 'z') 541 | || (name[idx] >= '0' && name[idx] <= '9') 542 | ); 543 | idx++ 544 | ) 545 | { 546 | if (name[idx] == 'Z' + 1) 547 | *dest++ = G_HEXAEDIT_THETA; 548 | else 549 | *dest++ = name[idx]; 550 | } 551 | 552 | if (!idx) 553 | { 554 | for (; idx < 8 && name[idx]; idx++) 555 | hex_byte(&dest, name[idx]); 556 | } 557 | 558 | break; 559 | } 560 | } 561 | 562 | *dest = '\0'; 563 | return; 564 | } 565 | 566 | 567 | bool hevat_GetVarInfoByNameAndType( 568 | s_calc_var* const var, 569 | const char name[8], 570 | const uint8_t name_length, 571 | const uint8_t var_type 572 | ) 573 | { 574 | void* last_entry = os_GetSymTablePtr(); 575 | void* entry; 576 | uint24_t vat_type = 0; 577 | uint24_t vat_name_length = 0; 578 | char vat_name[9]; 579 | void* data = NULL; 580 | 581 | while (last_entry != NULL) 582 | { 583 | entry = os_NextSymEntry( 584 | last_entry, &vat_type, &vat_name_length, vat_name, &data 585 | ); 586 | var->vatptr = last_entry; 587 | hevat_GetVarInfoByVAT(var); 588 | 589 | if ( 590 | var->type == var_type 591 | && var->name_length == name_length 592 | && !memcmp(var->name, name, min(var->name_length, name_length)) 593 | ) 594 | { 595 | return true; 596 | } 597 | 598 | last_entry = entry; 599 | }; 600 | 601 | return false; 602 | } 603 | 604 | 605 | void hevat_GetHEVATGroupNames(char buffer[20], uint24_t index) 606 | { 607 | assert(index < HEVAT__NUM_GROUPS); 608 | 609 | const char* group_name = HEVAT__GROUP_NAMES[index]; 610 | 611 | memcpy(buffer, group_name, strlen(group_name)); 612 | buffer[strlen(group_name)] = '\0'; 613 | return; 614 | } 615 | 616 | 617 | void hevat_GetRecentsVariableName(char buffer[20], uint24_t index) 618 | { 619 | get_variable_name(buffer, HEVAT__RECENTS, index); 620 | return; 621 | } 622 | 623 | void hevat_GetAppvarVariableName(char buffer[20], uint24_t index) 624 | { 625 | get_variable_name(buffer, HEVAT__APPVAR, index); 626 | return; 627 | } 628 | 629 | void hevat_GetProtProgramVariableName(char buffer[20], uint24_t index) 630 | { 631 | get_variable_name(buffer, HEVAT__PROT_PROGRAM, index); 632 | return; 633 | } 634 | 635 | void hevat_GetProgramVariableName(char buffer[20], uint24_t index) 636 | { 637 | get_variable_name(buffer, HEVAT__PROGRAM, index); 638 | return; 639 | } 640 | 641 | void hevat_GetRealVariableName(char buffer[20], uint24_t index) 642 | { 643 | get_variable_name(buffer, HEVAT__REAL, index); 644 | return; 645 | } 646 | 647 | void hevat_GetListVariableName(char buffer[20], uint24_t index) 648 | { 649 | get_variable_name(buffer, HEVAT__LIST, index); 650 | return; 651 | } 652 | 653 | void hevat_GetMatrixVariableName(char buffer[20], uint24_t index) 654 | { 655 | get_variable_name(buffer, HEVAT__MATRIX, index); 656 | return; 657 | } 658 | 659 | void hevat_GetEquationVariableName(char buffer[20], uint24_t index) 660 | { 661 | get_variable_name(buffer, HEVAT__EQUATION, index); 662 | return; 663 | } 664 | 665 | void hevat_GetStringVariableName(char buffer[20], uint24_t index) 666 | { 667 | get_variable_name(buffer, HEVAT__STRING, index); 668 | return; 669 | } 670 | 671 | void hevat_GetPictureVariableName(char buffer[20], uint24_t index) 672 | { 673 | get_variable_name(buffer, HEVAT__PICTURE, index); 674 | return; 675 | } 676 | 677 | void hevat_GetGDBVariableName(char buffer[20], uint24_t index) 678 | { 679 | get_variable_name(buffer, HEVAT__GDB, index); 680 | return; 681 | } 682 | 683 | void hevat_GetComplexVariableName(char buffer[20], uint24_t index) 684 | { 685 | get_variable_name(buffer, HEVAT__COMPLEX, index); 686 | return; 687 | } 688 | 689 | void hevat_GetComplexListVariableName(char buffer[20], uint24_t index) 690 | { 691 | get_variable_name(buffer, HEVAT__COMPLEX_LIST, index); 692 | return; 693 | } 694 | 695 | void hevat_GetGroupVariableName(char buffer[20], uint24_t index) 696 | { 697 | get_variable_name(buffer, HEVAT__GROUP, index); 698 | return; 699 | } 700 | 701 | void hevat_GetOtherVariableName(char buffer[20], uint24_t index) 702 | { 703 | get_variable_name(buffer, HEVAT__OTHER, index); 704 | return; 705 | } 706 | 707 | 708 | // ============================================================================= 709 | // STATIC FUNCTION DEFINITIONS 710 | // ============================================================================= 711 | 712 | 713 | static uint8_t hevat_group_index(const uint24_t os_var_type) 714 | { 715 | const uint24_t OS_TO_HEVAT_LUT[26] = { 716 | OS_TYPE_REAL, HEVAT__REAL, 717 | OS_TYPE_REAL_LIST, HEVAT__LIST, 718 | OS_TYPE_MATRIX, HEVAT__MATRIX, 719 | OS_TYPE_EQU, HEVAT__EQUATION, 720 | OS_TYPE_STR, HEVAT__STRING, 721 | OS_TYPE_PRGM, HEVAT__PROGRAM, 722 | OS_TYPE_PROT_PRGM, HEVAT__PROT_PROGRAM, 723 | OS_TYPE_PICT, HEVAT__PICTURE, 724 | OS_TYPE_GDB, HEVAT__GDB, 725 | OS_TYPE_CPLX, HEVAT__COMPLEX, 726 | OS_TYPE_CPLX_LIST, HEVAT__COMPLEX_LIST, 727 | OS_TYPE_APPVAR, HEVAT__APPVAR, 728 | OS_TYPE_GROUP, HEVAT__GROUP 729 | }; 730 | 731 | for (uint8_t idx = 0; idx < 26; idx += 2) 732 | { 733 | if (os_var_type == OS_TO_HEVAT_LUT[idx]) 734 | return OS_TO_HEVAT_LUT[idx + 1]; 735 | } 736 | 737 | return HEVAT__OTHER; 738 | } 739 | 740 | 741 | static bool load_recents_entries(void) 742 | { 743 | CCDBG_BEGINBLOCK("load_recents_entries"); 744 | 745 | s_calc_var var; 746 | char name[8]; 747 | uint8_t type; 748 | uint8_t name_length; 749 | uint8_t handle; 750 | uint8_t idx = 0; 751 | 752 | if (!(handle = ti_Open(G_RECENTS_APPVAR_NAME, "r"))) 753 | { 754 | CCDBG_PUTS("Could not open recents appvar"); 755 | CCDBG_ENDBLOCK(); 756 | 757 | return false; 758 | } 759 | 760 | while ((ti_Read(&type, sizeof type, 1, handle)) == 1) 761 | { 762 | if ((ti_Read(&name_length, sizeof name_length, 1, handle)) != 1) 763 | { 764 | CCDBG_PUTS("Could not read name length"); 765 | CCDBG_ENDBLOCK(); 766 | 767 | return false; 768 | } 769 | 770 | if (name_length == 0) 771 | break; 772 | 773 | if ((ti_Read(name, name_length, 1, handle)) != 1) 774 | { 775 | CCDBG_PUTS("Could not read name"); 776 | CCDBG_ENDBLOCK(); 777 | 778 | return false; 779 | } 780 | 781 | if (hevat_GetVarInfoByNameAndType(&var, name, name_length, type)) 782 | g_hevat[idx++] = var.vatptr; 783 | } 784 | 785 | g_num_entries[HEVAT__RECENTS] = idx; 786 | ti_Close(handle); 787 | 788 | CCDBG_ENDBLOCK(); 789 | 790 | return true; 791 | } 792 | 793 | 794 | static void count_vatptrs() 795 | { 796 | CCDBG_BEGINBLOCK("count_vatptrs()"); 797 | 798 | void* entry = os_GetSymTablePtr(); 799 | uint24_t os_var_type = 0; 800 | uint24_t name_length = 0; 801 | char name[9]; 802 | void* data = NULL; 803 | 804 | while (entry != NULL) 805 | { 806 | entry = os_NextSymEntry(entry, &os_var_type, &name_length, name, &data); 807 | g_num_entries[hevat_group_index(os_var_type)]++; 808 | g_num_vatptrs++; 809 | }; 810 | 811 | // Decrement the number of VAT pointers and the number of appvar HEVAT entries 812 | // by one because we are not counting HexaEdit's edit buffer appvar. 813 | g_num_vatptrs--; 814 | g_num_entries[HEVAT__APPVAR]--; 815 | 816 | CCDBG_ENDBLOCK(); 817 | 818 | return; 819 | } 820 | 821 | 822 | static uint24_t hevat_offset(const uint8_t hevat_group_idx) 823 | { 824 | uint24_t offset = 0; 825 | 826 | for (uint8_t idx = 0; idx < hevat_group_idx; idx++) 827 | { 828 | if (!idx) 829 | offset = MAX_NUM_RECENTS; 830 | else 831 | offset += g_num_entries[idx]; 832 | } 833 | 834 | return offset; 835 | } 836 | 837 | 838 | static void load_vatptr_entries() 839 | { 840 | CCDBG_BEGINBLOCK("load_vatptr_entries"); 841 | 842 | void* entry = os_GetSymTablePtr(); 843 | void* last_entry; 844 | uint24_t os_var_type = 0; 845 | uint24_t name_length = 0; 846 | char name[9]; 847 | void* data = NULL; 848 | 849 | uint24_t curr_num_entries[MAX_NUM_HEVAT_ENTRIES] = { 0 }; 850 | uint8_t hevat_group_idx; 851 | uint24_t offset; 852 | uint24_t num_loaded = 0; 853 | 854 | while (entry != NULL && num_loaded < MAX_NUM_HEVAT_ENTRIES) 855 | { 856 | last_entry = entry; 857 | entry = os_NextSymEntry(entry, &os_var_type, &name_length, name, &data); 858 | 859 | // Do not load the VAT entry for HexaEdit's edit buffer appvar. 860 | if ( 861 | os_var_type == OS_TYPE_APPVAR 862 | && !strncmp(G_EDIT_BUFFER_APPVAR_NAME, name, min(8, name_length)) 863 | ) 864 | { 865 | continue; 866 | } 867 | 868 | hevat_group_idx = hevat_group_index(os_var_type); 869 | offset = hevat_offset(hevat_group_idx); 870 | 871 | g_hevat[offset + curr_num_entries[hevat_group_idx]] = last_entry; 872 | 873 | curr_num_entries[hevat_group_idx]++; 874 | num_loaded++; 875 | } 876 | 877 | CCDBG_ENDBLOCK(); 878 | return; 879 | } 880 | 881 | 882 | static int8_t entry_name_cmp(void* vatptr_one, void* vatptr_two) 883 | { 884 | assert(vatptr_one != NULL); 885 | assert(vatptr_two != NULL); 886 | 887 | uint24_t type_one = 0; 888 | uint24_t type_two = 0; 889 | uint24_t name_one_len = 0; 890 | uint24_t name_two_len = 0; 891 | char src_name_one[9] = { '\0' }; 892 | char src_name_two[9] = { '\0' }; 893 | char name_one[20] = { '\0' }; 894 | char name_two[20] = { '\0' }; 895 | void* data = NULL; 896 | bool named = false; 897 | 898 | os_NextSymEntry(vatptr_one, &type_one, &name_one_len, src_name_one, &data); 899 | os_NextSymEntry(vatptr_two, &type_two, &name_two_len, src_name_two, &data); 900 | 901 | assert(type_one == type_two); 902 | 903 | named = asmutil_IsNamedVar(type_one); 904 | 905 | hevat_VarNameToASCII(name_one, (const uint8_t*)src_name_one, named); 906 | hevat_VarNameToASCII(name_two, (const uint8_t*)src_name_two, named); 907 | 908 | for (uint8_t idx = 0; idx < name_one_len; idx++) 909 | { 910 | if (name_one[idx] >= 'a') 911 | name_one[idx] = name_one[idx] - 'a' + 'A'; 912 | } 913 | 914 | for (uint8_t idx = 0; idx < name_two_len; idx++) 915 | { 916 | if (name_two[idx] >= 'a') 917 | name_two[idx] = name_two[idx] - 'a' + 'A'; 918 | } 919 | 920 | return strncmp(name_one, name_two, min(name_one_len, name_two_len)); 921 | } 922 | 923 | 924 | static void sort_hevat() 925 | { 926 | CCDBG_BEGINBLOCK("sort_hevat()"); 927 | 928 | for ( 929 | uint8_t group_idx = HEVAT__APPVAR; 930 | group_idx < HEVAT__NUM_GROUPS; 931 | group_idx++ 932 | ) 933 | { 934 | int24_t offset = (int24_t)hevat_offset(group_idx); 935 | uint24_t num_entries = g_num_entries[group_idx]; 936 | 937 | for (uint24_t idx_one = 1; idx_one < num_entries; idx_one++) 938 | { 939 | void* key = g_hevat[offset + idx_one]; 940 | 941 | int24_t idx_two = idx_one - 1; 942 | 943 | while ( 944 | (idx_two >= 0) 945 | && (entry_name_cmp(g_hevat[offset + idx_two], key) > 0) 946 | ) 947 | { 948 | g_hevat[offset + idx_two + 1] = g_hevat[offset + idx_two]; 949 | idx_two--; 950 | } 951 | 952 | g_hevat[offset + idx_two + 1] = key; 953 | } 954 | } 955 | 956 | CCDBG_ENDBLOCK(); 957 | 958 | return; 959 | } 960 | 961 | 962 | static void get_variable_name( 963 | char* const buffer, uint8_t hevat_group_idx, uint24_t index 964 | ) 965 | { 966 | CCDBG_BEGINBLOCK("get_variable_name"); 967 | 968 | s_calc_var var; 969 | bool var_found = false; 970 | 971 | var.vatptr = hevat_Ptr(hevat_group_idx, index); 972 | var_found = hevat_GetVarInfoByVAT(&var); 973 | 974 | // Since the HEVAT is built from the TI-OS VAT, should always be 975 | // true. If it is not, the HEVAT has been corrupted. 976 | if (var_found) 977 | hevat_VarNameToASCII(buffer, (const uint8_t*)var.name, var.named); 978 | else 979 | assert(false); 980 | 981 | CCDBG_ENDBLOCK(); 982 | 983 | return; 984 | } 985 | -------------------------------------------------------------------------------- /src/hevat.h: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: hevat.h 3 | // Purpose: Provides the HexaEdit VAT system (HEVAT) used to track all TI-OS 4 | // variables present on the calculator as well as those that have 5 | // been recently edited by HexaEdit. It is an interface to the TI-OS 6 | // VAT with a few extra features. 7 | 8 | 9 | /* 10 | BSD 3-Clause License 11 | 12 | Copyright (c) 2024, Caleb "Captain Calc" Arant 13 | All rights reserved. 14 | 15 | Redistribution and use in source and binary forms, with or without 16 | modification, are permitted provided that the following conditions are met: 17 | 18 | 1. Redistributions of source code must retain the above copyright notice, this 19 | list of conditions and the following disclaimer. 20 | 21 | 2. Redistributions in binary form must reproduce the above copyright notice, 22 | this list of conditions and the following disclaimer in the documentation 23 | and/or other materials provided with the distribution. 24 | 25 | 3. Neither the name of the copyright holder nor the names of its 26 | contributors may be used to endorse or promote products derived from 27 | this software without specific prior written permission. 28 | 29 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 30 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 32 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 33 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 35 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 36 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 37 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | */ 40 | 41 | 42 | #ifndef HEVAT_H 43 | #define HEVAT_H 44 | 45 | 46 | #include 47 | 48 | 49 | // Based on the CEmu core/vat.c code by the CE-Programming team. 50 | typedef enum calc_var_type : uint8_t 51 | { 52 | CALC_VAR_TYPE_REAL = 0, 53 | CALC_VAR_TYPE_REAL_LIST, 54 | CALC_VAR_TYPE_MATRIX, 55 | CALC_VAR_TYPE_EQU, 56 | CALC_VAR_TYPE_STRING, 57 | CALC_VAR_TYPE_PROG, 58 | CALC_VAR_TYPE_PROT_PROG, 59 | CALC_VAR_TYPE_PICTURE, 60 | CALC_VAR_TYPE_GDB, 61 | CALC_VAR_TYPE_UNKNOWN, 62 | CALC_VAR_TYPE_UNKNOWN_EQU, 63 | CALC_VAR_TYPE_NEW_EQU, 64 | CALC_VAR_TYPE_CPLX, 65 | CALC_VAR_TYPE_CPLX_LIST, 66 | CALC_VAR_TYPE_UNDEF, 67 | CALC_VAR_TYPE_WINDOW, 68 | CALC_VAR_TYPE_RCL_WINDOW, 69 | CALC_VAR_TYPE_TABLE_RANGE, 70 | CALC_VAR_TYPE_LCD, 71 | CALC_VAR_TYPE_BACKUP, 72 | CALC_VAR_TYPE_APP, 73 | CALC_VAR_TYPE_APP_VAR, 74 | CALC_VAR_TYPE_TEMP_PROG, 75 | CALC_VAR_TYPE_GROUP, 76 | CALC_VAR_TYPE_REAL_FRAC, 77 | CALC_VAR_TYPE_UNKNOWN1, 78 | CALC_VAR_TYPE_IMAGE, 79 | CALC_VAR_TYPE_CPLX_FRAC, 80 | CALC_VAR_TYPE_REAL_RADICAL, 81 | CALC_VAR_TYPE_CPLX_RADICAL, 82 | CALC_VAR_TYPE_CPLX_PI, 83 | CALC_VAR_TYPE_CPLX_PI_FRAC, 84 | CALC_VAR_TYPE_REAL_PI, 85 | CALC_VAR_TYPE_REAL_PI_FRAC, 86 | CALC_VAR_TYPE_UNKNOWN2, 87 | CALC_VAR_TYPE_OPERATING_SYSTEM, 88 | CALC_VAR_TYPE_FLASH_APP, 89 | CALC_VAR_TYPE_CERTIFICATE, 90 | CALC_VAR_TYPE_UNKNOWN3, 91 | CALC_VAR_TYPE_CERTIFICATE_MEMORY, 92 | CALC_VAR_TYPE_UNKNOWN4, 93 | CALC_VAR_TYPE_CLOCK, 94 | CALC_VAR_TYPE_UNKNOWN5, 95 | CALC_VAR_TYPE_UNKNOWN6, 96 | CALC_VAR_TYPE_UNKNOWN7, 97 | CALC_VAR_TYPE_UNKNOWN8, 98 | CALC_VAR_TYPE_UNKNOWN9, 99 | CALC_VAR_TYPE_UNKNOWN10, 100 | CALC_VAR_TYPE_UNKNOWN11, 101 | CALC_VAR_TYPE_UNKNOWN12, 102 | CALC_VAR_TYPE_UNKNOWN13, 103 | CALC_VAR_TYPE_UNKNOWN14, 104 | CALC_VAR_TYPE_UNKNOWN15, 105 | CALC_VAR_TYPE_UNKNOWN16, 106 | CALC_VAR_TYPE_UNKNOWN17, 107 | CALC_VAR_TYPE_UNKNOWN18, 108 | CALC_VAR_TYPE_UNKNOWN19, 109 | CALC_VAR_TYPE_UNKNOWN20, 110 | CALC_VAR_TYPE_UNKNOWN21, 111 | CALC_VAR_TYPE_UNKNOWN22, 112 | CALC_VAR_TYPE_UNKNOWN23, 113 | CALC_VAR_TYPE_UNKNOWN24, 114 | CALC_VAR_TYPE_FLASH_LICENSE, 115 | CALC_VAR_TYPE_UNKNOWN25 116 | } calc_var_type_t; 117 | 118 | 119 | // Based on the CEmu core/vat.c code by the CE-Programming team. 120 | typedef struct 121 | { 122 | uint8_t* vatptr; 123 | uint8_t* data; 124 | uint8_t type_one, type_two; 125 | uint8_t version; 126 | uint8_t name_length; 127 | char name[9]; 128 | calc_var_type_t type; 129 | uint16_t size; 130 | bool archived; 131 | bool named; 132 | } s_calc_var; 133 | 134 | 135 | // This gives the position of each group of entries in the HEVAT. 136 | enum HEVAT_GROUP_INDEX : uint8_t 137 | { 138 | HEVAT__RECENTS = 0, 139 | HEVAT__APPVAR, 140 | HEVAT__PROT_PROGRAM, 141 | HEVAT__PROGRAM, 142 | HEVAT__REAL, 143 | HEVAT__LIST, 144 | HEVAT__MATRIX, 145 | HEVAT__EQUATION, 146 | HEVAT__STRING, 147 | HEVAT__PICTURE, 148 | HEVAT__GDB, 149 | HEVAT__COMPLEX, 150 | HEVAT__COMPLEX_LIST, 151 | HEVAT__GROUP, 152 | HEVAT__OTHER, 153 | HEVAT__NUM_GROUPS 154 | }; 155 | 156 | 157 | extern const char* HEVAT__GROUP_NAMES[HEVAT__NUM_GROUPS]; 158 | 159 | 160 | bool hevat_Load(void); 161 | 162 | 163 | bool hevat_SaveRecents(void); 164 | 165 | 166 | // Description: Returns the pointer in the HEVAT for the given group index and 167 | // offset. 168 | // Pre: HEVAT should be loaded. 169 | // Post: Returns pointer in the HEVAT at the offset within the group. 170 | void* hevat_Ptr(const uint8_t hevat_group_idx, const uint24_t offset); 171 | 172 | 173 | void hevat_Name( 174 | char* name, 175 | uint24_t* name_length, 176 | const uint8_t hevat_group_idx, 177 | const uint24_t offset 178 | ); 179 | 180 | 181 | uint24_t hevat_NumEntries(const uint8_t hevat_group_idx); 182 | 183 | 184 | void hevat_AddRecent(void* vatptr); 185 | 186 | 187 | // Pre: vatptr> should be set and valid. 188 | bool hevat_GetVarInfoByVAT(s_calc_var* const var); 189 | 190 | 191 | void hevat_VarNameToASCII(char buffer[20], const uint8_t name[8], bool named); 192 | 193 | 194 | bool hevat_GetVarInfoByNameAndType( 195 | s_calc_var* const var, 196 | const char name[8], 197 | const uint8_t name_length, 198 | const uint8_t var_type 199 | ); 200 | 201 | void hevat_GetHEVATGroupNames(char buffer[20], uint24_t index); 202 | 203 | void hevat_GetRecentsVariableName(char buffer[20], uint24_t index); 204 | 205 | void hevat_GetAppvarVariableName(char buffer[20], uint24_t index); 206 | 207 | void hevat_GetProtProgramVariableName(char buffer[20], uint24_t index); 208 | 209 | void hevat_GetProgramVariableName(char buffer[20], uint24_t index); 210 | 211 | void hevat_GetRealVariableName(char buffer[20], uint24_t index); 212 | 213 | void hevat_GetListVariableName(char buffer[20], uint24_t index); 214 | 215 | void hevat_GetMatrixVariableName(char buffer[20], uint24_t index); 216 | 217 | void hevat_GetEquationVariableName(char buffer[20], uint24_t index); 218 | 219 | void hevat_GetStringVariableName(char buffer[20], uint24_t index); 220 | 221 | void hevat_GetPictureVariableName(char buffer[20], uint24_t index); 222 | 223 | void hevat_GetGDBVariableName(char buffer[20], uint24_t index); 224 | 225 | void hevat_GetComplexVariableName(char buffer[20], uint24_t index); 226 | 227 | void hevat_GetComplexListVariableName(char buffer[20], uint24_t index); 228 | 229 | void hevat_GetGroupVariableName(char buffer[20], uint24_t index); 230 | 231 | void hevat_GetOtherVariableName(char buffer[20], uint24_t index); 232 | 233 | 234 | #endif 235 | -------------------------------------------------------------------------------- /src/keypad.c: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: keypad.c 3 | // Purpose: Defines the functions declared in keypad.h. 4 | 5 | 6 | /* 7 | BSD 3-Clause License 8 | 9 | Copyright (c) 2024, Caleb "Captain Calc" Arant 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | 1. Redistributions of source code must retain the above copyright notice, this 16 | list of conditions and the following disclaimer. 17 | 18 | 2. Redistributions in binary form must reproduce the above copyright notice, 19 | this list of conditions and the following disclaimer in the documentation 20 | and/or other materials provided with the distribution. 21 | 22 | 3. Neither the name of the copyright holder nor the names of its 23 | contributors may be used to endorse or promote products derived from 24 | this software without specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 30 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 34 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | 39 | #include 40 | #include 41 | 42 | #include "ccdbg/ccdbg.h" 43 | #include "defines.h" 44 | #include "keypad.h" 45 | 46 | 47 | // File global. Do NOT use this variable outside of this file. 48 | // 7 key groups * 8 possible keys per group = 56. Some of the bytes in this 49 | // array are never used because they do not have keys associated with them. 50 | uint8_t key_counters[56] = { 0 }; 51 | 52 | 53 | // https://www.eevblog.com/forum/beginners/from-bit-position-to-array-index/ 54 | #define only_one_bit_set(byte) \ 55 | ( (byte & (byte - 1) || !byte) ? 0 : 1 ) 56 | 57 | 58 | // ============================================================================= 59 | // PUBLIC FUNCTION DEFINITIONS 60 | // ============================================================================= 61 | 62 | 63 | // https://www.eevblog.com/forum/beginners/from-bit-position-to-array-index/ 64 | static uint8_t bit_to_idx(uint8_t byte) 65 | { 66 | uint8_t result = 0; 67 | if (byte & 0b11110000) result |= 4; 68 | if (byte & 0b11001100) result |= 2; 69 | if (byte & 0b10101010) result |= 1; 70 | return result; 71 | } 72 | 73 | 74 | // Post: If a pressed key is found with a corresponding keymap value, 75 | // set and 0 returned. 76 | // If more than one key is pressed, 1 returned. 77 | // If no keys with corresponding keymap values were found, 2 returned. 78 | uint8_t keypad_ExclusiveKeymap( 79 | const char* const keymap[8], uint8_t* const value 80 | ) 81 | { 82 | bool key_pressed = false; 83 | bool value_found = false; 84 | 85 | for (uint8_t idx = 1; idx < 8; idx++) 86 | { 87 | if (kb_Data[idx]) 88 | { 89 | if (key_pressed) 90 | return 1; 91 | 92 | key_pressed = true; 93 | 94 | if (only_one_bit_set(kb_Data[idx])) 95 | { 96 | *value = (keymap[idx - 1][bit_to_idx(kb_Data[idx])]); 97 | value_found = true; 98 | } 99 | } 100 | } 101 | 102 | if (value_found) 103 | return 0; 104 | 105 | return 2; 106 | } 107 | 108 | 109 | // Description: Retrieves an uppercase, lowercase, or numerical symbol based on 110 | // the given mode and the state of the keypad. 111 | // Pre: should be one of ['A', 'a', '0']. 112 | // 'A' = uppercase letters 113 | // 'a' = lowercase letters 114 | // '0' = digits 115 | // Post: If valid and keypad state, ASCII set and true 116 | // returned. 117 | // Otherwise, false returned. 118 | bool keypad_ExclusiveASCII(uint8_t* const value, const char mode) 119 | { 120 | const char** keymap = G_UPPERCASE_LETTERS_KEYMAP; 121 | 122 | if (mode == 'a') 123 | keymap = G_LOWERCASE_LETTERS_KEYMAP; 124 | else if (mode == '0') 125 | keymap = G_DIGITS_KEYMAP; 126 | 127 | if (!keypad_ExclusiveKeymap(keymap, value) && *value != 0x00) 128 | return true; 129 | 130 | return false; 131 | } 132 | 133 | 134 | bool keypad_ExclusiveNibble(uint8_t* const value) 135 | { 136 | if (!keypad_ExclusiveKeymap(G_HEX_NIBBLES_KEYMAP, value)) 137 | { 138 | if (*value == 0x00 && !kb_IsDown(kb_Key0)) 139 | return false; 140 | 141 | return true; 142 | } 143 | 144 | return false; 145 | } 146 | 147 | 148 | bool keypad_SinglePressExclusive(kb_lkey_t key) 149 | { 150 | bool block_until_idle_keypad = false; 151 | bool key_pressed = false; 152 | 153 | // If the key is not pressed, terminate early so that the function does not 154 | // update the keypad data registers. 155 | if (!kb_IsDown(key)) 156 | return key_pressed; 157 | 158 | key_pressed = true; 159 | 160 | while (true) 161 | { 162 | kb_Scan(); 163 | 164 | if (!kb_IsDown(key)) 165 | break; 166 | 167 | for (uint8_t idx = 1; idx < 8; idx++) 168 | { 169 | if (idx == (key >> 8)) 170 | { 171 | if (kb_Data[idx] != (uint8_t)key) 172 | block_until_idle_keypad = true; 173 | } 174 | else if (kb_Data[idx]) 175 | { 176 | block_until_idle_keypad = true; 177 | } 178 | } 179 | 180 | if (block_until_idle_keypad) 181 | { 182 | while (kb_AnyKey()) 183 | kb_Scan(); 184 | 185 | key_pressed = false; 186 | } 187 | } 188 | 189 | return key_pressed; 190 | } 191 | 192 | 193 | bool keypad_KeyPressedOrHeld(kb_lkey_t key, uint8_t threshold) 194 | { 195 | // kb_lkey_t is an uint16_t. 196 | // Casting to an uint8_t discards the upper byte, which is desired. 197 | uint8_t index = (8 * ((key >> 8) - 1)) + bit_to_idx((uint8_t)key); 198 | 199 | assert(index < sizeof key_counters); 200 | 201 | if (kb_IsDown(key)) 202 | { 203 | if (key_counters[index] < 255) 204 | key_counters[index]++; 205 | } 206 | else 207 | { 208 | key_counters[index] = 0; 209 | } 210 | 211 | if (key_counters[index] == 1 || key_counters[index] >= threshold) 212 | return true; 213 | 214 | return false; 215 | } 216 | 217 | 218 | void keypad_IdleKeypadBlock(void) 219 | { 220 | bool reset_key_counters = false; 221 | 222 | while (true) 223 | { 224 | kb_Scan(); 225 | 226 | if (kb_AnyKey()) 227 | break; 228 | 229 | if (!reset_key_counters) 230 | { 231 | memset(key_counters, '\0', sizeof key_counters); 232 | reset_key_counters = true; 233 | } 234 | } 235 | 236 | return; 237 | } 238 | -------------------------------------------------------------------------------- /src/keypad.h: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: keypad.h 3 | // Purpose: Provides functions for scanning the keypad and acknowledging 4 | // keypresses. 5 | 6 | 7 | /* 8 | BSD 3-Clause License 9 | 10 | Copyright (c) 2024, Caleb "Captain Calc" Arant 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 16 | 1. Redistributions of source code must retain the above copyright notice, this 17 | list of conditions and the following disclaimer. 18 | 19 | 2. Redistributions in binary form must reproduce the above copyright notice, 20 | this list of conditions and the following disclaimer in the documentation 21 | and/or other materials provided with the distribution. 22 | 23 | 3. Neither the name of the copyright holder nor the names of its 24 | contributors may be used to endorse or promote products derived from 25 | this software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 31 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 35 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | */ 38 | 39 | 40 | #ifndef KEYMAP_H 41 | #define KEYMAP_H 42 | 43 | 44 | #include 45 | 46 | 47 | uint8_t keypad_ExclusiveKeymap( 48 | const char* const keymap[8], uint8_t* const value 49 | ); 50 | bool keypad_ExclusiveASCII(uint8_t* const value, const char mode); 51 | bool keypad_ExclusiveNibble(uint8_t* const value); 52 | 53 | 54 | // Description: Checks if a key is pressed and if so, blocks until it is 55 | // released. If any other key is pressed during the block, the 56 | // function will block until all keys are released and not register 57 | // any keypress. 58 | // Pre: must be a valid long keycode. 59 | // Post: Returns true when is released if no other key was pressed 60 | // during the time was pressed. 61 | // Returns false if was not pressed or if any other key was 62 | // pressed while was pressed. 63 | bool keypad_SinglePressExclusive(kb_lkey_t key); 64 | 65 | 66 | // Description: Determines if a key is pressed or held. The 67 | // parameter adjusts the delay between the first press and the held 68 | // state. 69 | // Pre: must be a valid long keycode. 70 | // Post: Returns true when key is first pressed or if the key has been 71 | // held for number of calls to the function. 72 | // Returns false if key is not pressed or if the function has been 73 | // called between 1 and times while the key is held. 74 | bool keypad_KeyPressedOrHeld(kb_lkey_t key, uint8_t threshold); 75 | 76 | 77 | // Description: Loops until a key is pressed. 78 | // Pre: None 79 | // Post: If a key has not been pressed for one cycle, it resets the 80 | // counter for each key used by keypad_KeyPressedOrHeld(). 81 | void keypad_IdleKeypadBlock(void); 82 | 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /src/list.c: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: list.c 3 | // Purpose: Defines the functions declared in list.h. 4 | 5 | 6 | /* 7 | BSD 3-Clause License 8 | 9 | Copyright (c) 2024, Caleb "Captain Calc" Arant 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | 1. Redistributions of source code must retain the above copyright notice, this 16 | list of conditions and the following disclaimer. 17 | 18 | 2. Redistributions in binary form must reproduce the above copyright notice, 19 | this list of conditions and the following disclaimer in the documentation 20 | and/or other materials provided with the distribution. 21 | 22 | 3. Neither the name of the copyright holder nor the names of its 23 | contributors may be used to endorse or promote products derived from 24 | this software without specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 30 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 34 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "ccdbg/ccdbg.h" 44 | #include "defines.h" 45 | #include "hevat.h" 46 | #include "list.h" 47 | 48 | 49 | void list_Initialize(list* const list) 50 | { 51 | list->visible_item_count = VISIBLE_ITEM_COUNT; 52 | list_MoveCursorIndexToStart(list); 53 | return; 54 | } 55 | 56 | 57 | void list_SetRoutineToGetItemNames( 58 | list* const list, void (*routine)(char*, uint24_t) 59 | ) 60 | { 61 | assert(routine != NULL); 62 | 63 | list->get_item_name = routine; 64 | return; 65 | } 66 | 67 | 68 | void list_SetPosition( 69 | list* const list, const uint24_t xpos, const uint8_t ypos 70 | ) 71 | { 72 | assert(xpos < LCD_WIDTH); 73 | assert(ypos < LCD_HEIGHT); 74 | 75 | list->xpos = xpos; 76 | list->ypos = ypos; 77 | return; 78 | } 79 | 80 | 81 | void list_SetTotalItemCount(list* const list, const uint24_t count) 82 | { 83 | list->total_item_count = count; 84 | return; 85 | } 86 | 87 | 88 | uint24_t list_GetTotalItemCount(list* const list) 89 | { 90 | return list->total_item_count; 91 | } 92 | 93 | 94 | uint24_t list_GetCursorIndex(const list* const list) 95 | { 96 | assert(list->window_offset + list->cursor_offset < list->total_item_count); 97 | 98 | return list->window_offset + list->cursor_offset; 99 | } 100 | 101 | 102 | void list_MoveCursorIndexToStart(list* const list) 103 | { 104 | list->window_offset = 0; 105 | list->cursor_offset = 0; 106 | return; 107 | } 108 | 109 | 110 | void list_IncrementCursorIndex(list* const list) 111 | { 112 | uint24_t last_visible_item_offset = min( 113 | list->total_item_count, list->visible_item_count 114 | ); 115 | 116 | if ((list->cursor_offset + 1) < last_visible_item_offset) 117 | { 118 | list->cursor_offset++; 119 | } 120 | else if (list_GetCursorIndex(list) + 1 < list->total_item_count) 121 | { 122 | list->window_offset++; 123 | } 124 | 125 | return; 126 | } 127 | 128 | 129 | void list_DecrementCursorIndex(list* const list) 130 | { 131 | if (list->cursor_offset) 132 | { 133 | list->cursor_offset--; 134 | } 135 | else if (list->window_offset) 136 | { 137 | list->window_offset--; 138 | } 139 | 140 | return; 141 | } 142 | 143 | 144 | void list_JumpToItemWhoseNameStartsWithLetter( 145 | list* const list, const uint8_t letter 146 | ) 147 | { 148 | CCDBG_BEGINBLOCK("list_JumpToItemWhoseNameStartsWithLetter"); 149 | CCDBG_DUMP_UINT(letter); 150 | 151 | char print_name[20] = { '\0' }; 152 | uint24_t left = 0; 153 | uint24_t right = list->total_item_count; 154 | uint24_t middle; 155 | bool less_than; 156 | 157 | while (left < right) 158 | { 159 | middle = (left + right) / 2; 160 | 161 | CCDBG_DUMP_UINT(middle); 162 | 163 | list->get_item_name(print_name, middle); 164 | 165 | if (print_name[0] >= 'a') 166 | less_than = ((print_name[0] - 'a' + 'A') < letter); 167 | else 168 | less_than = (print_name[0] < letter); 169 | 170 | if (less_than) 171 | left = middle + 1; 172 | else 173 | right = middle; 174 | } 175 | 176 | CCDBG_DUMP_UINT(left); 177 | 178 | if (left == list->total_item_count) 179 | left--; 180 | 181 | while (list_GetCursorIndex(list) < left) 182 | list_IncrementCursorIndex(list); 183 | 184 | while (list_GetCursorIndex(list) > left) 185 | list_DecrementCursorIndex(list); 186 | 187 | CCDBG_ENDBLOCK(); 188 | 189 | return; 190 | } 191 | -------------------------------------------------------------------------------- /src/list.h: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: list.h 3 | // Purpose: Declares the API for manipulating the main menu list objects. 4 | 5 | 6 | /* 7 | BSD 3-Clause License 8 | 9 | Copyright (c) 2024, Caleb "Captain Calc" Arant 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | 1. Redistributions of source code must retain the above copyright notice, this 16 | list of conditions and the following disclaimer. 17 | 18 | 2. Redistributions in binary form must reproduce the above copyright notice, 19 | this list of conditions and the following disclaimer in the documentation 20 | and/or other materials provided with the distribution. 21 | 22 | 3. Neither the name of the copyright holder nor the names of its 23 | contributors may be used to endorse or promote products derived from 24 | this software without specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 30 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 34 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | #ifndef LIST_H 39 | #define LIST_H 40 | 41 | 42 | #include 43 | 44 | 45 | typedef struct 46 | { 47 | void (*get_item_name)(char[20], uint24_t); 48 | uint24_t total_item_count; 49 | uint8_t visible_item_count; 50 | uint24_t xpos; 51 | uint8_t ypos; 52 | uint24_t window_offset; 53 | uint24_t cursor_offset; 54 | } list; 55 | 56 | #define VISIBLE_ITEM_COUNT (19) 57 | #define LIST_WIDTH_IN_PIXELS (101) 58 | #define LIST_ITEM_HEIGHT_IN_PIXELS (G_FONT_HEIGHT + 3) 59 | 60 | typedef struct 61 | { 62 | uint8_t background; 63 | uint8_t cursor; 64 | uint8_t cursor_text; 65 | uint8_t normal_text; 66 | } list_color_palette; 67 | 68 | 69 | void list_Initialize(list* const list); 70 | 71 | void list_SetRoutineToGetItemNames( 72 | list* const list, void (*routine)(char*, uint24_t) 73 | ); 74 | 75 | void list_SetPosition( 76 | list* const list, const uint24_t xpos, const uint8_t ypos 77 | ); 78 | 79 | void list_SetTotalItemCount(list* const list, const uint24_t count); 80 | 81 | uint24_t list_GetTotalItemCount(list* const list); 82 | 83 | uint24_t list_GetCursorIndex(const list* const list); 84 | 85 | void list_MoveCursorIndexToStart(list* const list); 86 | 87 | void list_IncrementCursorIndex(list* const list); 88 | 89 | void list_DecrementCursorIndex(list* const list); 90 | 91 | void list_JumpToItemWhoseNameStartsWithLetter( 92 | list* const list, const uint8_t letter 93 | ); 94 | 95 | 96 | #endif 97 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: main.c 3 | // Purpose: Initializes global data structures, sets up program files, and 4 | // determines whether to spawn a Headless Start editor or start the 5 | // main menu. 6 | 7 | /* 8 | BSD 3-Clause License 9 | 10 | Copyright (c) 2024, Caleb "Captain Calc" Arant 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 16 | 1. Redistributions of source code must retain the above copyright notice, this 17 | list of conditions and the following disclaimer. 18 | 19 | 2. Redistributions in binary form must reproduce the above copyright notice, 20 | this list of conditions and the following disclaimer in the documentation 21 | and/or other materials provided with the distribution. 22 | 23 | 3. Neither the name of the copyright holder nor the names of its 24 | contributors may be used to endorse or promote products derived from 25 | this software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 31 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 35 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | */ 38 | 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include "ccdbg/ccdbg.h" 46 | #include "defines.h" 47 | #include "gui.h" 48 | #include "main_gui.h" 49 | #include "main_hl.h" 50 | #include "tools.h" 51 | 52 | 53 | // ============================================================================= 54 | // STATIC FUNCTION DECLARATIONS 55 | // ============================================================================= 56 | 57 | 58 | // Description: Starts the calculator's 8-bit graphics. 59 | // Pre: Calculator must be in TI-OS graphics mode. 60 | // Post: 8-bit graphics set up. 61 | static void open_gfx(void); 62 | 63 | 64 | // Description: Ends the 8-bit graphics mode and returns to the TI-OS graphics 65 | // mode. 66 | // Pre: Calculator must be in 8-bit graphics mode. 67 | // Post: Calculator in TI-OS graphics mode. 68 | static void close_gfx(void); 69 | 70 | 71 | // ============================================================================= 72 | // MAIN FUNCTION 73 | // ============================================================================= 74 | 75 | 76 | int main(void) 77 | { 78 | CCDBG_BEGINBLOCK("main"); 79 | 80 | int retval = 0; 81 | bool headless_start = false; 82 | 83 | s_editor editor = { 84 | .name = { '\0' }, 85 | .name_length = 0, 86 | .access_type = '\0', 87 | .is_tios_var = false, 88 | .tios_var_type = 0, 89 | .undo_buffer_active = false, 90 | .num_changes = 0, 91 | .base_address = NULL, 92 | .data_size = 0, 93 | .buffer_size = 0, 94 | .window_offset = 0, 95 | .location_col_mode = 'o', 96 | .writing_mode = 'x', 97 | .near_size = 0, 98 | .far_size = 0, 99 | .selection_size = 1, 100 | .selection_active = false, 101 | .high_nibble = true 102 | }; 103 | 104 | // mainhl_SetMemEditor(); 105 | // mainhl_SetVarEditor(); 106 | headless_start = mainhl_CheckAns(); 107 | 108 | CCDBG_PUTS("Checked Ans."); 109 | 110 | if (!tool_CreateRecentsAppvar()) 111 | { 112 | open_gfx(); 113 | gui_ErrorWindow("Cannot create Recents$appvar."); 114 | close_gfx(); 115 | 116 | CCDBG_ENDBLOCK(); 117 | 118 | return 1; 119 | } 120 | 121 | CCDBG_PUTS("Created Recents appvar."); 122 | 123 | if (!tool_CreateEditBuffer(&editor)) 124 | { 125 | open_gfx(); 126 | gui_ErrorWindow("Cannot create edit$buffer."); 127 | close_gfx(); 128 | 129 | CCDBG_ENDBLOCK(); 130 | 131 | return 1; 132 | } 133 | 134 | CCDBG_PUTS("Created edit buffer."); 135 | 136 | open_gfx(); 137 | 138 | if (headless_start) 139 | retval = mainhl_RunEditor(&editor); 140 | else 141 | retval = maingui_Main(&editor); 142 | 143 | close_gfx(); 144 | tool_DeleteEditBuffer(); 145 | 146 | CCDBG_ENDBLOCK(); 147 | 148 | return retval; 149 | } 150 | 151 | 152 | // ============================================================================= 153 | // STATIC FUNCTION DEFINITIONS 154 | // ============================================================================= 155 | 156 | 157 | static void open_gfx(void) 158 | { 159 | gfx_Begin(); 160 | gfx_SetDrawBuffer(); 161 | kb_SetMode(MODE_3_CONTINUOUS); 162 | return; 163 | } 164 | 165 | 166 | static void close_gfx(void) 167 | { 168 | gfx_End(); 169 | return; 170 | } 171 | -------------------------------------------------------------------------------- /src/main_gui.c: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: main_gui.c 3 | // Purpose: Defines the functions declared in main_gui.h and any supporting 4 | // static functions. 5 | 6 | 7 | /* 8 | BSD 3-Clause License 9 | 10 | Copyright (c) 2024, Caleb "Captain Calc" Arant 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 16 | 1. Redistributions of source code must retain the above copyright notice, this 17 | list of conditions and the following disclaimer. 18 | 19 | 2. Redistributions in binary form must reproduce the above copyright notice, 20 | this list of conditions and the following disclaimer in the documentation 21 | and/or other materials provided with the distribution. 22 | 23 | 3. Neither the name of the copyright holder nor the names of its 24 | contributors may be used to endorse or promote products derived from 25 | this software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 31 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 35 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | */ 38 | 39 | 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | #include "ccdbg/ccdbg.h" 46 | #include "defines.h" 47 | #include "editor.h" 48 | #include "gui.h" 49 | #include "hevat.h" 50 | #include "keypad.h" 51 | #include "list.h" 52 | #include "main_gui.h" 53 | #include "tools.h" 54 | 55 | 56 | // ============================================================================= 57 | // STATIC FUNCTION DECLARATIONS 58 | // ============================================================================= 59 | 60 | 61 | static void set_routine_to_get_item_names_for_variables_list( 62 | list* const list, const uint8_t hevat_group_idx 63 | ); 64 | 65 | 66 | // ============================================================================= 67 | // PUBLIC FUNCTION DEFINITIONS 68 | // ============================================================================= 69 | 70 | 71 | int maingui_Main(s_editor* const editor) 72 | { 73 | CCDBG_BEGINBLOCK("maingui_Main"); 74 | 75 | const uint8_t KEYPRESS_DELAY_THRESHOLD = 8; 76 | 77 | list hevat_groups_list; 78 | list variables_list; 79 | void* vatptr; 80 | list* active_list = &hevat_groups_list; 81 | bool quit = false; 82 | bool redraw_all = true; 83 | bool open_variable = false; 84 | uint8_t hevat_group_idx = HEVAT__RECENTS; 85 | uint8_t letter; 86 | 87 | if (!hevat_Load()) 88 | return 1; 89 | 90 | list_Initialize(&hevat_groups_list); 91 | list_SetPosition(&hevat_groups_list, 2, 22); 92 | list_SetTotalItemCount(&hevat_groups_list, HEVAT__NUM_GROUPS); 93 | list_SetRoutineToGetItemNames( 94 | &hevat_groups_list, &hevat_GetHEVATGroupNames 95 | ); 96 | 97 | list_Initialize(&variables_list); 98 | list_SetPosition(&variables_list, 109, 22); 99 | 100 | CCDBG_PUTS("After initialization"); 101 | 102 | while (!quit) 103 | { 104 | if (open_variable) 105 | { 106 | vatptr = hevat_Ptr( 107 | hevat_group_idx, list_GetCursorIndex(&variables_list) 108 | ); 109 | 110 | if (editor_OpenVarEditor(editor, vatptr, 0)) 111 | hevat_AddRecent(vatptr); 112 | 113 | redraw_all = true; 114 | open_variable = false; 115 | } 116 | 117 | if (redraw_all) 118 | { 119 | gfx_FillScreen(g_color.background); 120 | gui_DrawMainMenuListDividers(); 121 | gui_DrawMemoryAmounts(editor); 122 | gui_DrawMainMenuBottomBar(); 123 | } 124 | 125 | gui_DrawMainMenuTopBar(list_GetTotalItemCount(active_list)); 126 | 127 | CCDBG_PUTS("Before HEVAT group wrangling."); 128 | 129 | if (list_GetCursorIndex(&hevat_groups_list) != hevat_group_idx) 130 | list_MoveCursorIndexToStart(&variables_list); 131 | 132 | hevat_group_idx = list_GetCursorIndex(&hevat_groups_list); 133 | list_SetTotalItemCount(&variables_list, hevat_NumEntries(hevat_group_idx)); 134 | set_routine_to_get_item_names_for_variables_list( 135 | &variables_list, hevat_group_idx 136 | ); 137 | 138 | if (active_list == &hevat_groups_list) 139 | { 140 | gui_DrawActiveList(&hevat_groups_list); 141 | gui_DrawDormantList(&variables_list); 142 | 143 | // Slow down the cursor movement speed. 144 | delay(30); 145 | } 146 | else 147 | { 148 | gui_DrawDormantList(&hevat_groups_list); 149 | gui_DrawActiveList(&variables_list); 150 | 151 | gui_EraseHEVATEntryInfo(); 152 | gui_DrawHEVATEntryInfo( 153 | hevat_Ptr(hevat_group_idx, list_GetCursorIndex(&variables_list)) 154 | ); 155 | } 156 | 157 | if (redraw_all) 158 | { 159 | gfx_BlitBuffer(); 160 | redraw_all = false; 161 | } 162 | else 163 | gfx_SwapDraw(); 164 | 165 | keypad_IdleKeypadBlock(); 166 | 167 | if (keypad_SinglePressExclusive(kb_KeyYequ)) 168 | { 169 | editor_OpenMemEditor(editor, "ROM", G_ROM_BASE_ADDRESS, G_ROM_SIZE, 0); 170 | redraw_all = true; 171 | } 172 | 173 | if (keypad_SinglePressExclusive(kb_KeyWindow)) 174 | { 175 | editor_OpenMemEditor(editor, "RAM", G_RAM_BASE_ADDRESS, G_RAM_SIZE, 0); 176 | redraw_all = true; 177 | } 178 | 179 | if (keypad_SinglePressExclusive(kb_KeyZoom)) 180 | { 181 | editor_OpenMemEditor( 182 | editor, "Ports", G_PORTS_BASE_ADDRESS, G_PORTS_SIZE, 0 183 | ); 184 | redraw_all = true; 185 | } 186 | 187 | if (keypad_SinglePressExclusive(kb_KeyGraph)) 188 | { 189 | gui_MessageWindowBlocking( 190 | "About", 191 | "Author:$ Caleb \"Captain Calc\" Arant$$This program can damage" \ 192 | "$your calculator if used$incautiously.$$Read the README." 193 | ); 194 | redraw_all = true; 195 | } 196 | 197 | if (keypad_SinglePressExclusive(kb_KeyClear)) 198 | quit = true; 199 | 200 | if (keypad_KeyPressedOrHeld(kb_KeyUp, KEYPRESS_DELAY_THRESHOLD)) 201 | list_DecrementCursorIndex(active_list); 202 | 203 | if (keypad_KeyPressedOrHeld(kb_KeyDown, KEYPRESS_DELAY_THRESHOLD)) 204 | list_IncrementCursorIndex(active_list); 205 | 206 | if (active_list == &hevat_groups_list) 207 | { 208 | if ( 209 | keypad_SinglePressExclusive(kb_KeyRight) 210 | && list_GetTotalItemCount(&variables_list) > 0) 211 | { 212 | active_list = &variables_list; 213 | } 214 | } 215 | else 216 | { 217 | if ( 218 | keypad_SinglePressExclusive(kb_Key2nd) 219 | || keypad_SinglePressExclusive(kb_KeyEnter) 220 | || keypad_SinglePressExclusive(kb_KeyRight) 221 | ) 222 | { 223 | open_variable = true; 224 | } 225 | 226 | if (keypad_SinglePressExclusive(kb_KeyLeft)) 227 | { 228 | active_list = &hevat_groups_list; 229 | redraw_all = true; 230 | } 231 | 232 | if ( 233 | hevat_group_idx != HEVAT__RECENTS 234 | && keypad_ExclusiveASCII(&letter, 'A') 235 | ) 236 | { 237 | list_JumpToItemWhoseNameStartsWithLetter(&variables_list, letter); 238 | } 239 | } 240 | } 241 | 242 | if (!hevat_SaveRecents()) 243 | { 244 | gui_MessageWindowBlocking( 245 | "Warning", "Cannot save variables to$Recents appvar." 246 | ); 247 | } 248 | 249 | CCDBG_ENDBLOCK(); 250 | return 0; 251 | } 252 | 253 | 254 | // ============================================================================= 255 | // STATIC FUNCTION DEFINITIONS 256 | // ============================================================================= 257 | 258 | 259 | static void set_routine_to_get_item_names_for_variables_list( 260 | list* const list, const uint8_t hevat_group_idx 261 | ) 262 | { 263 | assert(hevat_group_idx < HEVAT__NUM_GROUPS); 264 | 265 | void (*routine_list[HEVAT__NUM_GROUPS])(char*, uint24_t) = { 266 | &hevat_GetRecentsVariableName, 267 | &hevat_GetAppvarVariableName, 268 | &hevat_GetProtProgramVariableName, 269 | &hevat_GetProgramVariableName, 270 | &hevat_GetRealVariableName, 271 | &hevat_GetListVariableName, 272 | &hevat_GetMatrixVariableName, 273 | &hevat_GetEquationVariableName, 274 | &hevat_GetStringVariableName, 275 | &hevat_GetPictureVariableName, 276 | &hevat_GetGDBVariableName, 277 | &hevat_GetComplexVariableName, 278 | &hevat_GetComplexListVariableName, 279 | &hevat_GetGroupVariableName, 280 | &hevat_GetOtherVariableName 281 | }; 282 | 283 | list_SetRoutineToGetItemNames(list, routine_list[hevat_group_idx]); 284 | return; 285 | } 286 | -------------------------------------------------------------------------------- /src/main_gui.h: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: main_gui.h 3 | // Purpose: Provides the API for starting HexaEdit's main menu. 4 | 5 | 6 | /* 7 | BSD 3-Clause License 8 | 9 | Copyright (c) 2024, Caleb "Captain Calc" Arant 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | 1. Redistributions of source code must retain the above copyright notice, this 16 | list of conditions and the following disclaimer. 17 | 18 | 2. Redistributions in binary form must reproduce the above copyright notice, 19 | this list of conditions and the following disclaimer in the documentation 20 | and/or other materials provided with the distribution. 21 | 22 | 3. Neither the name of the copyright holder nor the names of its 23 | contributors may be used to endorse or promote products derived from 24 | this software without specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 30 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 34 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | 39 | #ifndef MAIN_GUI_H 40 | #define MAIN_GUI_H 41 | 42 | 43 | int maingui_Main(s_editor* const editor); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/main_hl.c: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: main_hl.h 3 | // Purpose: Defines the functions declared in main_hl.h. 4 | 5 | 6 | /* 7 | BSD 3-Clause License 8 | 9 | Copyright (c) 2024, Caleb "Captain Calc" Arant 10 | All rights reserved. 11 | 12 | Redistribution and use in source and binary forms, with or without 13 | modification, are permitted provided that the following conditions are met: 14 | 15 | 1. Redistributions of source code must retain the above copyright notice, this 16 | list of conditions and the following disclaimer. 17 | 18 | 2. Redistributions in binary form must reproduce the above copyright notice, 19 | this list of conditions and the following disclaimer in the documentation 20 | and/or other materials provided with the distribution. 21 | 22 | 3. Neither the name of the copyright holder nor the names of its 23 | contributors may be used to endorse or promote products derived from 24 | this software without specific prior written permission. 25 | 26 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 27 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 29 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 30 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 33 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 34 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | */ 37 | 38 | 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | 47 | #include "ccdbg/ccdbg.h" 48 | #include "editor.h" 49 | #include "gui.h" 50 | #include "main_hl.h" 51 | 52 | 53 | enum HEADER_FLAGS : uint8_t 54 | { 55 | COLORSCHEME_PRESENT = 1 << 0, 56 | MEMORY_EDITOR = 1 << 1, 57 | VARIABLE_EDITOR = 1 << 2, 58 | }; 59 | 60 | enum MEMORY_EDITOR_FLAGS : uint8_t 61 | { 62 | RAM_EDITOR = 0, 63 | PORTS_EDITOR, 64 | ROM_VIEWER 65 | }; 66 | 67 | typedef struct 68 | { 69 | char header[8]; 70 | uint8_t flags; 71 | } s_header; 72 | 73 | typedef struct 74 | { 75 | uint8_t flag; 76 | uint24_t cursor_offset; 77 | } s_mem_editor; 78 | 79 | typedef struct 80 | { 81 | char name[8]; 82 | uint8_t name_length; 83 | uint8_t type; 84 | uint24_t cursor_offset; 85 | } s_var_editor; 86 | 87 | 88 | // File globals. Do NOT use these outside of this file. 89 | const char* ANS_CONFIG_HEADER = "HexaEdit"; 90 | uint8_t g_ans_config[40] = { '\0' }; 91 | 92 | 93 | // ============================================================================= 94 | // STATIC FUNCTION DECLARATIONS 95 | // ============================================================================= 96 | 97 | 98 | static void write_header(const uint8_t flags, const uint8_t handle) 99 | { 100 | ti_Write("HexaEdit", 8, 1, handle); 101 | ti_Write(&flags, 1, 1, handle); 102 | return; 103 | } 104 | 105 | 106 | static void write_mem_editor( 107 | const s_mem_editor* const mem_editor, const uint8_t handle 108 | ) 109 | { 110 | ti_Write(mem_editor, sizeof(s_mem_editor), 1, handle); 111 | return; 112 | } 113 | 114 | 115 | static void write_var_editor( 116 | const s_var_editor* const var_editor, const uint8_t handle 117 | ) 118 | { 119 | ti_Write(var_editor, sizeof(s_var_editor), 1, handle); 120 | return; 121 | } 122 | 123 | 124 | static void write_colorscheme( 125 | const s_color* const colorscheme, const uint8_t handle 126 | ) 127 | { 128 | ti_Write(colorscheme, sizeof(s_color), 1, handle); 129 | return; 130 | } 131 | 132 | 133 | static uint8_t read_flags(void) 134 | { 135 | s_header* header = (s_header*)g_ans_config; 136 | 137 | return header->flags; 138 | } 139 | 140 | 141 | static s_mem_editor* read_mem_editor(void) 142 | { 143 | return (s_mem_editor*)(g_ans_config + sizeof(s_header)); 144 | } 145 | 146 | 147 | static s_var_editor* read_var_editor(void) 148 | { 149 | return (s_var_editor*)(g_ans_config + sizeof(s_header)); 150 | } 151 | 152 | 153 | static s_color* read_colorscheme(void) 154 | { 155 | uint8_t flags = read_flags(); 156 | 157 | if (flags & MEMORY_EDITOR) 158 | { 159 | return (s_color*)(g_ans_config + sizeof(s_header) + sizeof(s_mem_editor)); 160 | } 161 | else if (flags & VARIABLE_EDITOR) 162 | { 163 | return (s_color*)(g_ans_config + sizeof(s_header) + sizeof(s_var_editor)); 164 | } 165 | 166 | return NULL; 167 | } 168 | 169 | 170 | // ============================================================================= 171 | // PUBLIC FUNCTION DECLARATIONS 172 | // ============================================================================= 173 | 174 | void mainhl_SetMemEditor(void) 175 | { 176 | uint8_t handle; 177 | s_mem_editor mem_editor = { 178 | .flag = RAM_EDITOR, 179 | .cursor_offset = 0 180 | }; 181 | s_color colorscheme = { 182 | .bar = 0, 183 | .bar_text = 127, 184 | .bar_text_dark = 130, 185 | .background = 200, 186 | .editor_side_panel = 130, 187 | .editor_cursor = 0x3d, 188 | .editor_text_normal = 0, 189 | .editor_text_selected = 127 190 | }; 191 | 192 | if ((handle = ti_OpenVar(OS_VAR_ANS, "w", OS_TYPE_STR))) 193 | { 194 | write_header(MEMORY_EDITOR | COLORSCHEME_PRESENT, handle); 195 | write_mem_editor(&mem_editor, handle); 196 | write_colorscheme(&colorscheme, handle); 197 | ti_Close(handle); 198 | } 199 | 200 | return; 201 | } 202 | 203 | 204 | void mainhl_SetVarEditor(void) 205 | { 206 | uint8_t handle; 207 | s_var_editor var_editor = { 208 | .name = OS_VAR_L1, 209 | .name_length = 3, 210 | .type = OS_TYPE_REAL_LIST, 211 | .cursor_offset = 0 212 | }; 213 | s_color colorscheme = { 214 | .bar = 0, 215 | .bar_text = 127, 216 | .bar_text_dark = 130, 217 | .background = 200, 218 | .editor_side_panel = 130, 219 | .editor_cursor = 0x3d, 220 | .editor_text_normal = 0, 221 | .editor_text_selected = 127 222 | }; 223 | 224 | if ((handle = ti_OpenVar(OS_VAR_ANS, "w", OS_TYPE_STR))) 225 | { 226 | write_header(VARIABLE_EDITOR | COLORSCHEME_PRESENT, handle); 227 | write_var_editor(&var_editor, handle); 228 | write_colorscheme(&colorscheme, handle); 229 | ti_Close(handle); 230 | } 231 | } 232 | 233 | 234 | bool mainhl_CheckAns(void) 235 | { 236 | CCDBG_BEGINBLOCK("mainhl_CheckAns"); 237 | 238 | bool retval = false; 239 | uint8_t handle; 240 | 241 | if ((handle = ti_OpenVar(OS_VAR_ANS, "r", OS_TYPE_STR))) 242 | { 243 | 244 | if ( 245 | !memcmp( 246 | ti_GetDataPtr(handle), ANS_CONFIG_HEADER, strlen(ANS_CONFIG_HEADER) 247 | ) 248 | ) 249 | { 250 | // We load the contents of Ans into an array that is global to this file. 251 | // This allows us to open Ans only once, reducing the number of file 252 | // operations that could potentially fail. 253 | ti_Read(g_ans_config, ti_GetSize(handle), 1, handle); 254 | retval = true; 255 | } 256 | 257 | ti_Close(handle); 258 | } 259 | 260 | CCDBG_DUMP_PTR(g_ans_config); 261 | CCDBG_DUMP_UINT(retval); 262 | CCDBG_ENDBLOCK(); 263 | 264 | return retval; 265 | } 266 | 267 | 268 | int mainhl_RunEditor(s_editor* const editor) 269 | { 270 | CCDBG_BEGINBLOCK("mainhl_RunEditor"); 271 | 272 | const char* const NAME_ARRAY[] = { "RAM", "Ports", "ROM" }; 273 | s_mem_editor* mem_editor; 274 | s_var_editor* var_editor; 275 | s_calc_var var; 276 | const char* name = NULL; 277 | uint8_t* base_address = NULL; 278 | uint24_t size = 0; 279 | uint8_t flags = read_flags(); 280 | bool var_opened = false; 281 | int retval = 0; 282 | 283 | CCDBG_DUMP_UINT(flags); 284 | 285 | if (flags & COLORSCHEME_PRESENT) 286 | memcpy(&g_color, read_colorscheme(), sizeof(s_color)); 287 | 288 | if (flags & MEMORY_EDITOR) 289 | { 290 | mem_editor = read_mem_editor(); 291 | 292 | switch (mem_editor->flag) 293 | { 294 | case RAM_EDITOR: 295 | name = NAME_ARRAY[0]; 296 | base_address = G_RAM_BASE_ADDRESS; 297 | size = G_RAM_SIZE; 298 | 299 | CCDBG_PUTS("Is RAM editor."); 300 | 301 | break; 302 | 303 | case PORTS_EDITOR: 304 | name = NAME_ARRAY[1]; 305 | base_address = G_PORTS_BASE_ADDRESS; 306 | size = G_PORTS_SIZE; 307 | 308 | CCDBG_PUTS("Is Ports Editor."); 309 | 310 | break; 311 | 312 | case ROM_VIEWER: 313 | name = NAME_ARRAY[2]; 314 | base_address = G_ROM_BASE_ADDRESS; 315 | size = G_ROM_SIZE; 316 | 317 | CCDBG_PUTS("Is ROM viewer."); 318 | 319 | break; 320 | 321 | default: 322 | assert(false); 323 | } 324 | 325 | if (mem_editor->cursor_offset < size) 326 | { 327 | editor_OpenMemEditor( 328 | editor, name, base_address, size, mem_editor->cursor_offset 329 | ); 330 | } 331 | } 332 | else if (flags & VARIABLE_EDITOR) 333 | { 334 | var_editor = read_var_editor(); 335 | 336 | var_opened = hevat_GetVarInfoByNameAndType( 337 | &var, 338 | var_editor->name, 339 | var_editor->name_length, 340 | var_editor->type 341 | ); 342 | 343 | CCDBG_PUTS("Is variable editor."); 344 | CCDBG_DUMP_UINT(var_opened); 345 | 346 | if (var_opened) 347 | editor_OpenVarEditor(editor, var.vatptr, var_editor->cursor_offset); 348 | else 349 | { 350 | gui_ErrorWindow("Variable could not$be opened."); 351 | retval = 1; 352 | } 353 | } 354 | 355 | ti_DeleteVar(OS_VAR_ANS, OS_TYPE_STR); 356 | CCDBG_ENDBLOCK(); 357 | 358 | return retval; 359 | } 360 | -------------------------------------------------------------------------------- /src/main_hl.h: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: main_hl.h 3 | // Purpose: Declares the API for HexaEdit's Headless Start, a way to spawn a GUI 4 | // editor without going through the main menu. 5 | 6 | 7 | /* 8 | BSD 3-Clause License 9 | 10 | Copyright (c) 2024, Caleb "Captain Calc" Arant 11 | All rights reserved. 12 | 13 | Redistribution and use in source and binary forms, with or without 14 | modification, are permitted provided that the following conditions are met: 15 | 16 | 1. Redistributions of source code must retain the above copyright notice, this 17 | list of conditions and the following disclaimer. 18 | 19 | 2. Redistributions in binary form must reproduce the above copyright notice, 20 | this list of conditions and the following disclaimer in the documentation 21 | and/or other materials provided with the distribution. 22 | 23 | 3. Neither the name of the copyright holder nor the names of its 24 | contributors may be used to endorse or promote products derived from 25 | this software without specific prior written permission. 26 | 27 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 28 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 30 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 31 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 33 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 34 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 35 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 36 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 | */ 38 | 39 | 40 | #ifndef MAIN_HL_H 41 | #define MAIN_HL_H 42 | 43 | 44 | #include "defines.h" 45 | 46 | // HEADER 47 | // +----------------+-----------------+ 48 | // | Description | Size (in bytes) | 49 | // +----------------+-----------------+ 50 | // | Header | 8 | 51 | // | Flags | 1 | 52 | // +----------------+-----------------+ 53 | // Total | 9 | 54 | // +-----------------+ 55 | // 56 | 57 | // After writing the HEADER, you should either write the MEMORY EDITOR block or 58 | // the VARIABLE EDITOR block, but never both. 59 | 60 | // MEMORY EDITOR 61 | // 62 | // +----------------+-----------------+ 63 | // | Description | Size (in bytes) | 64 | // +----------------+-----------------+ 65 | // | Flag | 1 | 66 | // | Cursor offset | 3 | 67 | // +----------------+-----------------+ 68 | // Total | 4 | 69 | // +-----------------+ 70 | // 71 | 72 | // VARIABLE EDITOR 73 | // 74 | // +----------------+-----------------+ 75 | // | Description | Size (in bytes) | 76 | // +----------------+-----------------+ 77 | // | Name | 8 | 78 | // | Name length | 1 | 79 | // | Variable type | 1 | 80 | // | Cursor offset | 3 | 81 | // +----------------+-----------------+ 82 | // Total | 13 | 83 | // +-----------------+ 84 | // 85 | 86 | void mainhl_SetMemEditor(void); 87 | 88 | void mainhl_SetVarEditor(void); 89 | 90 | bool mainhl_CheckAns(void); 91 | 92 | int mainhl_RunEditor(s_editor* const editor); 93 | 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /src/tools.h: -------------------------------------------------------------------------------- 1 | // Name: Captain Calc 2 | // File: tools.h 3 | // Purpose: Declares several standalone functions, tools, that modify the 4 | // the editor's state or buffer. These are the core functionality of 5 | // HexaEdit. 6 | 7 | 8 | /* 9 | BSD 3-Clause License 10 | 11 | Copyright (c) 2024, Caleb "Captain Calc" Arant 12 | All rights reserved. 13 | 14 | Redistribution and use in source and binary forms, with or without 15 | modification, are permitted provided that the following conditions are met: 16 | 17 | 1. Redistributions of source code must retain the above copyright notice, this 18 | list of conditions and the following disclaimer. 19 | 20 | 2. Redistributions in binary form must reproduce the above copyright notice, 21 | this list of conditions and the following disclaimer in the documentation 22 | and/or other materials provided with the distribution. 23 | 24 | 3. Neither the name of the copyright holder nor the names of its 25 | contributors may be used to endorse or promote products derived from 26 | this software without specific prior written permission. 27 | 28 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 29 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 31 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 32 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 34 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 35 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 36 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 | */ 39 | 40 | 41 | #ifndef TOOLS_H 42 | #define TOOLS_H 43 | 44 | 45 | #include "defines.h" 46 | 47 | 48 | void tool_FatalErrorExit(void); 49 | 50 | 51 | uint8_t tool_GetCutCopyBufferSize(); 52 | 53 | 54 | void tool_InitUndoStack(void); 55 | 56 | 57 | bool tool_CreateRecentsAppvar(void); 58 | 59 | 60 | bool tool_CreateEditBuffer(s_editor* const editor); 61 | 62 | 63 | // Post: If successful, pointer returned and set to buffer size. 64 | // Otherwise, NULL returned and is undefined. 65 | void* tool_EditBufferPtr(uint24_t* size); 66 | 67 | 68 | bool tool_CheckFreeRAM(const uint24_t amt); 69 | 70 | 71 | // Description: Success -> 1 72 | // Variable not saved, but program can continue -> 0 73 | // Fatal program error -> -1 74 | int8_t tool_SaveModifiedVar(s_editor* const editor); 75 | 76 | 77 | // Pre: base_address> and buffer_size> 78 | // Post: data_size>, near_size>, and far_size> set. 79 | bool tool_BufferVarData( 80 | s_editor* const editor, 81 | void* data, 82 | const uint24_t size, 83 | const uint24_t offset 84 | ); 85 | 86 | 87 | void tool_LoadEditBufferIntoVar( 88 | s_editor* const editor, uint8_t* const var_data 89 | ); 90 | 91 | 92 | // Description: Deletes the edit buffer appvar. 93 | // Pre: Edit buffer appvar must exist. 94 | // Post: Edit buffer appvar deleted. 95 | void tool_DeleteEditBuffer(void); 96 | 97 | 98 | // Description: Determines based on the editor's state if a tool can be used. 99 | // Pre: Pointer to tool must be valid. 100 | // Post: If tool can be used, true returned. 101 | // If tool cannot be used, false returned. 102 | bool tool_IsAvailable(const s_editor* const editor, void* const tool_func_ptr); 103 | 104 | 105 | // Description: == 0 decreases the size of the near buffer. 106 | // == 1 increases the size of the near buffer. 107 | void tool_MoveCursor( 108 | s_editor* const editor, const uint8_t direction, const uint24_t amt 109 | ); 110 | 111 | 112 | bool tool_UpdateWindowOffset(s_editor* const editor); 113 | 114 | 115 | void tool_WriteNibble(s_editor* const editor, uint8_t nibble); 116 | 117 | 118 | void tool_WriteByte(s_editor* const editor, uint8_t byte); 119 | 120 | 121 | // Description: Moves the editing cursor to the given offset. If the offset 122 | // exceeds the data size, the offset defaults to the maximum valid 123 | // offset. 124 | void tool_Goto(s_editor* const editor, uint24_t offset); 125 | 126 | 127 | void tool_InsertBytes(s_editor* const editor, const uint24_t num); 128 | 129 | 130 | void tool_DeleteBytes(s_editor* const editor); 131 | 132 | 133 | void tool_CopyBytes(const s_editor* const editor); 134 | 135 | 136 | void tool_CutBytes(s_editor* const editor); 137 | 138 | 139 | void tool_PasteBytes(s_editor* const editor); 140 | 141 | 142 | void tool_FindPhrase( 143 | s_editor* const editor, 144 | const uint8_t phrase[], 145 | const uint8_t length, 146 | uint24_t matches[], 147 | uint8_t* num_matches 148 | ); 149 | 150 | 151 | void tool_SwitchWritingMode(s_editor* const editor); 152 | 153 | 154 | void tool_UndoLastAction(s_editor* const editor); 155 | 156 | 157 | void tool_AddUndo_WriteNibble(s_editor* const editor); 158 | 159 | 160 | void tool_AddUndo_WriteByte(s_editor* const editor); 161 | 162 | 163 | void tool_AddUndo_InsertBytes(s_editor* const editor, const uint8_t num_bytes); 164 | 165 | 166 | void tool_AddUndo_DeleteOrCutBytes(s_editor* const editor); 167 | 168 | 169 | void tool_AddUndo_PasteBytes(s_editor* const editor); 170 | 171 | 172 | #endif 173 | --------------------------------------------------------------------------------