_A BRIEF MACRO PACKAGE FOR EDITING BINARY FILES_ by James Rodriguez [LISTING ONE] /ª _iniô _hex_ediô _bin_oî _bin_ofæ _bin_mouså write_buffeò */ #define HEX #define SHOW_DELAY 50 #define UP -11 #define DOWN 11 #define LEFT -1 #define RIGHT 1 #define PGUP -21 #define PGDN 21 #define TOP 30 #define BOTTOM -31 #define HOME -40 #define END -41 extern _package_buf, delete_curr_buffer; int __hex_files, __bin_keyboard, __hex_window, __asc_window, __unix_files; _init () { __hex_files = create_buffer ("HEXFILES", NULL, 1); //Binary file database __unix_files = create_buffer ("UNIXFILE", NULL, 1); //Unix file database register_macro (6, "_bin_edit"); keyboard_push (); // Create a new keyboard set_mouse_action("_bin_mouse"); // Define the mouse handler add_hex_keys(); // Add key assignments __bin_keyboard = inq_keyboard (); // Store the keyboard identifier keyboard_pop (1); // Reset the stack } // _hex_edit: associates a system buffer with a hex buffer and modifies // the package information for .HEX files. Called by _bin_edit. void _hex_edit (string file_name, int in_memory) { int __hex_buffer, __asc_buffer, tmp_buf, current_buffer; string buffer_name, file_ext, buffer_id, file_path; global __hex_buffer, __asc_buffer; if (get_parm (0, file_name)) { get_parm (1, in_memory); // Check any flag passed if (index (file_name, ".")) { file_ext = substr (file_name, 1 + rindex (file_name, ".")); file_name = substr (file_name, 1, rindex (file_name, ".") - 1); } else file_ext = ""; buffer_name = substr (file_name, rindex (file_name, "\\") + 1); current_buffer = inq_buffer (); if (inq_called () == "_bin_edit") delete_buffer (current_buffer); // Error check for bad buffer name tmp_buf = create_buffer (buffer_name + ".hex", file_name + ".hex", 0); if (tmp_buf) { set_buffer (__hex_files); top_of_buffer (); if (search_fwd (file_name + ",", 0, 0)) edit_file (file_name + ".hex"); // It's already in a buffer else { delete_buffer (tmp_buf); sprintf (file_path, "bbe BH %s.%s %s.hex %s.asc>&nul", file_name, file_ext, file_name, file_name); // Do the hex files already exist? if (!exist (file_name + ".hex") && !exist (file_name + ".asc")) { message ("Generating hex file"); dos (file_path); // spawn standalone program to convert file } else message ("Editing existing files."); __hex_buffer = create_buffer (buffer_name + ".hex", file_name + ".hex", 0); __asc_buffer = create_buffer (buffer_name + ("." + file_ext), file_name + ".asc", 1); // Save info in the database for later. sprintf (buffer_id, "oldb=%10d,newb=%10d,file=%s,ext=%s", __hex_buffer, __asc_buffer, file_name, file_ext); set_buffer (__hex_files); beginning_of_line (); insert (buffer_id + "\n"); set_buffer (__hex_buffer); top_of_buffer (); drop_anchor (); move_rel (0, 1); // Access the package buffer and configure for the hex extension. if (first_time ()) { if (!_package_buf) load_macro ("language"); set_buffer (_package_buf); top_of_buffer (); while (search_fwd ("<.hex", 1, 0)) delete_line (); // Add the correct lines in packages to make this work. insert (".hex_equivalents\n"); insert (".hex_new;\n"); insert (".hex_existing;\n"); insert (".hex_first;\n"); insert (".hex_on;_on,_bin_on\n"); // Enabled _bin_on insert (".hex;=hex,,=hex\n"); top_of_buffer (); } set_buffer (__hex_buffer); if (! in_memory) call_registered_macro (1); } } } } // _bin_on: edits the hex and ascii files in side by side windows by creating // and moving an edge. Insures correct local keyboard by setting it explicitly. // Looks in hex_files buffer for filename and extract buffer ids. Associate // buffers with windows and return. string _bin_on () { int i; string buf_to_find, exten; inq_names (buf_to_find, exten); buf_to_find = substr (buf_to_find, 1, (rindex (buf_to_find, exten) - strlen (exten)) + 1); i = inq_buffer(); set_buffer (__hex_files); // Edit the system buffer to find buffer id's. top_of_buffer (); if (search_fwd (buf_to_find + ",", 0, 0)) // Find the line with filename. { keyboard_flush(); // Remove any pending keystrokes use_local_keyboard (0); // Detach the local keyboard keyboard_push (__bin_keyboard); // Activate the hex keyboard set_mouse_action("_bin_mouse"); // Attach the mouse event handler beginning_of_line (); buf_to_find = trim (read ()); // Parse out the buffer ids buf_to_find = ltrim (substr (buf_to_find, index (buf_to_find, "oldb=") + 5, 10)); __hex_buffer = atoi (buf_to_find, 1); beginning_of_line (); buf_to_find = read (); buf_to_find = ltrim (substr (buf_to_find, index (buf_to_find, "newb=") + 5, 10)); __asc_buffer = atoi (buf_to_find, 1); set_buffer (__hex_buffer); // Unregister the registered macro so a recursive situation does not // arise from the window manipulations. unregister_macro (1, "_call_on_packages"); create_edge (3); __hex_window = inq_window (); move_edge (1, 12); change_window (1); __asc_window = inq_window (); attach_buffer (__asc_buffer); // Attach the system buffer to a window if (!inq_marked ()) drop_anchor (2); else refresh (); refresh (); change_window (3); register_macro (1, "_call_on_packages"); // Enable the language macro. returns "_bin_off"; // Return the off event for the language package. } else { set_buffer(i); // This is an error check to allow editing returns ""; // of files with .hex extensions which are not } // under the binary package control. } // _bin_off -- deletes the created window and resets the keyboard. void _bin_off () { keyboard_flush(); keyboard_pop (); keyboard_push (); add_hex_keys(); __bin_keyboard = inq_keyboard (); delete_edge (1); // Delete the window keyboard_pop (1); set_mouse_action("_mouse_action"); // Reset the mouse handler } #define BUTTON_1_CLICK 10 #define BUTTON_2_CLICK 11 #define BUTTON_1_DBLCLK 13 #define BUTTON_2_DBLCLK 14 #define VERTICAL_SCROLL 17 #define CLOSE_WINDOW 19 #define SET_WINDOW 20 #define STATUS_AREA 21 #define SCROLLBAR__LINEUP 0 #define SCROLLBAR__LINEDOWN 1 #define SCROLLBAR__PAGEUP 2 #define SCROLLBAR__PAGEDOWN 3 #define SCROLLBAR__TOP 6 #define SCROLLBAR__BOTTOM 7 #define TITLE_BAR 1 void _bin_mouse(int action, int modifier, int line, int col) { if (inq_window() == __asc_window) col = col*2; // Modify the column parameter if clicked in ascii window switch (action) { case STATUS_AREA: // Go to offset on status area click execute_macro(inq_assignment("")); case SET_WINDOW: // A different window was selected { if (col!=TITLE_BAR && line == __asc_window) // Disregard mouse action { // on the border. unregister_macro (1, "_call_on_packages"); set_window (__asc_window); } } case BUTTON_2_CLICK: case BUTTON_2_DBLCLK: case BUTTON_1_CLICK: case BUTTON_1_DBLCLK: { int lines,cols; if (col % 2) // Modify column parameter to event byte value col++; if (col > 50) // If past formatted string length go to the end of col = 50; // the string. unregister_macro (1, "_call_on_packages"); set_window (__hex_window); inq_position(lines, cols); raise_anchor (); move_rel(0,-1); save_position(); if (move_abs(line,col)) { // If beyond the end of buffer ignore the action if (! inq_position(lines,cols) && lines==line && cols == col) { restore_position(0); move_rel(0,-1); set_window (__asc_window); raise_anchor (); move_abs(line,col / 2); drop_anchor (2); refresh (); set_window (__hex_window); } else restore_position(); } else restore_position(); drop_anchor (); move_rel (0, 1); register_macro (1, "_call_on_packages"); refresh (); switch (action) { case BUTTON_2_DBLCLK: // Opens a line (feature not shown) { execute_macro(inq_assignment("")); } case BUTTON_1_DBLCLK: // Double click modifies current byte. { string sread, character; int hex_val; raise_anchor (); move_rel (0, -1); sread = "Enter new value for "; if (read (1) != "\n") sread += read (2); sread += ": "; if (get_parm (NULL, character, sread, 2)) { hex_val = _bin_atoh (character); sprintf (character, "%02x", hex_val); // Convert int to hex unregister_macro (1, "_call_on_packages"); set_window (__asc_window); switch (hex_val) // Make sure the value is displayable. { case 13: case 9: case 0: sread = "."; default: sprintf (sread, "%c", hex_val); } /* Insert the value in the hex and ascii buffers ** rehighlight both windows and return. */ insert ("%s", sread); raise_anchor (); delete_char (); move_rel (0, -1); drop_anchor (2); refresh (); set_window (__hex_window); insert ("%s", upper (character)); delete_char (2); move_rel (0, -2); } drop_anchor (); move_rel (0, 1); refresh (); register_macro (1, "_call_on_packages"); refresh (); } } } case VERTICAL_SCROLL: // Vertical scroll bar events. { switch (line) { case SCROLLBAR__LINEUP: // Click on up arrow execute_macro(inq_assignment("")); case SCROLLBAR__LINEDOWN: // Click on down arrow execute_macro(inq_assignment("")); case SCROLLBAR__PAGEUP: // Click above thumb button execute_macro(inq_assignment("")); case SCROLLBAR__PAGEDOWN: // Click below thumb button execute_macro(inq_assignment("")); case SCROLLBAR__TOP: // Double click on up arrow execute_macro(inq_assignment("")); case SCROLLBAR__BOTTOM: // Double click on down arrow execute_macro(inq_assignment("")); } } } } // write_buffer: A replacement for write_buffer. Checks file extension, cleans // up system buffers. Note: conversion back to binary is not done if buffer // has not been modified. replacement int write_buffer () { int buf_to_edit, buf_to_delete, file_is_controlled, file_was_modified; string file_name, ext, response, response2, old_buffer, write_command; inq_names (file_name, ext); /* if write_buffer was not called from the keyboard and the extension ** isn't .hex or .unx call write_buffer. */ if ("" == inq_called () && (ext == "hex" || ext == "unx")) if (get_parm (0, response, "Convert file? ", 1, "Y")) if (get_parm (1, response2, "Delete buffer? ", 1, "Y")) { int file_is_hex; file_is_hex = 0; buf_to_edit = inq_buffer (); // Store the current buffer id raise_anchor (); // Remove the highlight if (inq_modified ()) // Only write and convert if changed { returns write_buffer (); // Preserve the return value file_was_modified = 1; } else file_was_modified = 0; // if not changed don't reconvert // Remove the extension. if (index (file_name, ".")) file_name = substr (file_name, 1, rindex (file_name, ".") - 1); // Make the system buffer database current if (ext == "hex") { set_buffer (__hex_files); file_is_hex = 1; } else set_buffer (__unix_files); // Not used in this example top_of_buffer (); // Try to find filename record and extract original extension. if (search_fwd (file_name + ",ext=", 0, 0)) { beginning_of_line (); ext = trim (read ()); file_is_controlled=1; // Find the ascii buffer associated with the hex buffer if (file_is_hex) { int temp_buffer=inq_buffer(); ext = ltrim (substr (ext, index (ext, "newb=") + 5)); old_buffer = substr (ext, 1, 10); // Retrieve the buffer id buf_to_delete = atoi (old_buffer, 1); set_buffer(buf_to_delete); raise_anchor(); write_buffer(); drop_anchor(2); set_buffer(temp_buffer); if (upper (response2) == "Y") delete_buffer (buf_to_delete); } ext = trim (substr (ext, rindex (ext, "=") + 1)); beginning_of_line (); if (upper (response2) == "Y") delete_line (); // Delete the record } // Reset the current buffer set_buffer (buf_to_edit); if (file_is_hex) sprintf (write_command, "bbe HB %s.hex %s.%s>&nul", file_name, file_name, ext); else sprintf (write_command, "bbe DU %s.unx %s.%s>&nul", file_name, file_name, ext); if (file_was_modified && upper (response) == "Y" && file_is_controlled) { message ("%s", write_command); dos (write_command); // Call DOS to execute the conversion message ("Conversion complete"); } // Delete the current buffer and the converted file(s). if (upper (response2) == "Y") { if (1 != delete_curr_buffer()) { file_is_controlled=-1; delete_buffer(buf_to_edit); } if (file_is_hex) { sprintf (response, "%s.hex", file_name); del (response); sprintf (response, "%s.asc", file_name); } else sprintf (response, "%s.unx", file_name); del (response); if (file_is_controlled == -1) // No other buffers exit("y"); } else if (file_is_hex && file_is_controlled) { move_rel (0, -1); drop_anchor (); move_rel (0, 1); } } else ; else ; else // Call the primitive return write_buffer (); } [LISTING TWO] /* _bin_add _bin_atoh add_hex_keys _bin_edit _bin_delete */ // _bin_move -- this macro handles synchronized positioning. void _bin_move (int direction) { int col, line; get_parm(0,direction); raise_anchor (); unregister_macro (1, "_call_on_packages"); // Remove the language control set_window (__asc_window); raise_anchor (); inq_position (line, col); switch (direction) { case LEFT: case RIGHT: { if ((col == 25 && direction == RIGHT) || (col==1 && direction==LEFT)) { // Scrolling is needed move_rel (direction,0); col = (direction == LEFT ? 25 : 1); move_abs (0,col); } else move_rel (0,direction); } case UP: case DOWN: move_rel (direction % 10,0); case PGUP: case PGDN: { inq_window_size(line); // Get the number of lines in the window move_rel ((direction % 20) * line,0); } case HOME: move_abs(0,1); // Beginning of line case END: move_abs(0,25); // End of line case TOP: move_abs(1,1); // Top of buffer case BOTTOM: { end_of_buffer(); move_abs(0,25); // End of buffer } } while (inq_position (line,col)) // We might be in virtual space if move_rel (-1, 0); // so move up until we're not. drop_anchor (2); refresh (); set_window (__hex_window); move_abs(line,col * 2); // Reposition in the hex buffer move_rel (0, -1); // Highlight the current byte. drop_anchor (); move_rel (0, 1); refresh (); register_macro (1, "_call_on_packages"); } // _bin_add: overwrites the byte in hex window. It is assigned to all of valid // hex editing keys and uses push_back to get the original key. void _bin_add (string key_read) { string character, sread; int hex_val, temp_hex; // Get the parameter which is key pressed and push it back on keyboard // buffer so that it displays in prompt as if it were typed there. get_parm (0, key_read); push_back (key_to_int (key_read)); raise_anchor (); // Read the text from the buffer to display the old value at the prompt. move_rel (0, -1); sread = "Enter new value for "; if (read (1) != "\n") sread += read (2); sread += ": "; if (get_parm (1, character, sread, 2)) { // Limit the prompt response to two characters hex_val = _bin_atoh(character); sprintf (character, "%02x", hex_val); // Convert the int to hex. unregister_macro (1, "_call_on_packages"); // Don't disturb the windows. set_window (__asc_window); switch (hex_val) // Make sure the value typed is displayable { case 13: case 9: case 0: sread = "."; default: sprintf (sread, "%c", hex_val); } raise_anchor (); delete_char (); // Remove the old character and insert the new. insert ("%s", sread); move_rel(0,-1); drop_anchor (2); refresh (); set_window (__hex_window); delete_char (2); // Remove the old byte and insert the new. insert ("%s", upper (character)); } drop_anchor (); move_rel (0, 1); refresh (); register_macro (1, "_call_on_packages"); // Reenable the language macro refresh (); execute_macro(inq_assignment("")); // Move to the next byte. } // _bin_delete: converts the current byte to XX which will be ignored when // reconverted. Parameter is for deleting a full line. void _bin_delete (~int line) { get_parm(0,line); unregister_macro (1, "_call_on_packages"); set_window (__asc_window); raise_anchor (); if (line) { save_position(); move_abs(0,1); drop_anchor(3); translate("?",".",1,1,1,1); // Change any character to a "." raise_anchor (); restore_position(); } else { delete_char (); insert ("."); move_rel (0, -1); } drop_anchor (2); refresh (); set_window (__hex_window); raise_anchor (); if (line) { save_position(); move_abs(0,1); drop_anchor(3); translate("?","X",1,1,1,1); // Change any character to "X" raise_anchor (); restore_position(); move_rel (0, -1); } else { move_rel (0, 1); insert ("XX"); move_rel (0, -4); delete_char (2); } drop_anchor (); move_rel (0, 1); register_macro (1, "_call_on_packages"); refresh (); } // _bin_atoh -- accepts a "hex" string and returns an integer. int _bin_atoh (string to_convert) { string str_rev; int converted, loop_count, t_int; get_parm (0, to_convert); // Read a character from the end of the string and multiply // it by the loop count which is multiplied by 16 on each iteration. while (strlen (trim (to_convert))) { str_rev = substr (to_convert, strlen (to_convert), 1); t_int = index("123456789ABCDEF",upper(str_rev)); loop_count *= 16; if (0 == loop_count) loop_count = 1; converted += t_int * loop_count; to_convert = substr (to_convert, 1, strlen (to_convert) - 1); } return converted; } // add_hex_keys -- adds hex editing keys to the keyboard. add_hex_keys() { string macro_name, key_name; int loop; for (loop=48; loop<58; loop++) // Assign the numeric keys { // to the keyboard sprintf (key_name, "<%c>",loop); sprintf (macro_name, "_bin_add \"%c\"",loop); assign_to_key (key_name, macro_name); } for (loop=65;loop<71;loop++) // Assign the a-f Hex keys { // to the keyboard sprintf (key_name, "<%c>",loop); sprintf (macro_name, "_bin_add \"%c\"",loop); assign_to_key (key_name, macro_name); assign_to_key (lower(key_name), macro_name); } assign_to_key ("", "edit_next_buffer"); assign_to_key ("", "edit_file"); assign_to_key ("", "write_buffer"); assign_to_key ("", "exit"); sprintf (macro_name, "_bin_move %d", UP); assign_to_key ("", macro_name); sprintf (macro_name, "_bin_move %d", DOWN); assign_to_key ("", macro_name); assign_to_key ("", macro_name); sprintf (macro_name, "_bin_move %d", LEFT); assign_to_key ("", macro_name); sprintf (macro_name, "_bin_move %d", RIGHT); assign_to_key ("", macro_name); sprintf (macro_name, "_bin_move %d", PGUP); assign_to_key ("", macro_name); sprintf (macro_name, "_bin_move %d", PGDN); assign_to_key ("", macro_name); sprintf (macro_name, "_bin_move %d", TOP); assign_to_key ("", macro_name); sprintf (macro_name, "_bin_move %d", BOTTOM); assign_to_key ("", macro_name); sprintf (macro_name, "_bin_move %d", HOME); assign_to_key ("", macro_name); sprintf (macro_name, "_bin_move %d", END); assign_to_key ("", macro_name); } // _bin_edit -- registered macro for trapping Null files message. void _bin_edit () { if (inq_message () == "Null characters in file fixed.") { string okay; string file; inq_names (file); // See if the conversion is requested. if (get_parm (0, okay, "Okay to create HEX file to edit? ", 1, "Y")) if (upper (okay) == "Y") _hex_edit (file, 0); // Call _hex_edit to do conversion else // Other wise let the user frustrate themselves. message ("You asked for it."); } } on_packages"); // Don't disturb the windows. set_window (__asc_window);