hyx.c (6503B)
1/* 2 * 3 * Copyright (c) 2016-2024 Lorenz Panny 4 * 5 * This is hyx version 2024.02.29. 6 * Check for newer versions at https://yx7.cc/code. 7 * Please report bugs to lorenz@yx7.cc. 8 * 9 * Contributors: 10 * 2018, anonymous Faster search algorithm. 11 * 2020, Leah Neukirchen Suspend on ^Z. File information on ^G. 12 * 2022, Jeffrey H. Johnson Makefile tweaks for MacOS. 13 * 2022, Mario Haustein Makefile tweaks for Gentoo. 14 * 2023, Josef Schönberger Use alternate screen. Home/End keys. 15 * 16 * This program is released under the MIT license; see license.txt. 17 * 18 */ 19 20#include "common.h" 21#include "blob.h" 22#include "view.h" 23#include "input.h" 24#include "ansi.h" 25 26#include <stdlib.h> 27#include <stdio.h> 28#include <string.h> 29#include <signal.h> 30#include <setjmp.h> 31 32 33struct blob blob; 34struct view view; 35struct input input; 36 37bool quit; 38 39jmp_buf jmp_mainloop; 40 41 42void die(char const *s) 43{ 44 view_text(&view, true); 45 fprintf(stderr, "%s\n", s); 46 exit(EXIT_FAILURE); 47} 48 49void pdie(char const *s) 50{ 51 view_text(&view, true); 52 perror(s); 53 exit(EXIT_FAILURE); 54} 55 56static void sighdlr(int num) 57{ 58 switch (num) { 59 case SIGWINCH: 60 view.winch = true; 61 break; 62 case SIGTSTP: 63 view.tstp = true; 64 break; 65 case SIGCONT: 66 view.cont = true; 67 break; 68 case SIGALRM: 69 /* This is used in parsing escape sequences, 70 * but we don't need to do anything here. */ 71 break; 72 case SIGINT: 73 /* ignore */ 74 break; 75 default: 76 die("unrecognized signal"); 77 } 78} 79 80__attribute__((noreturn)) void version() 81{ 82 printf("This is hyx version 2024.02.29.\n"); 83 exit(EXIT_SUCCESS); 84} 85 86__attribute__((noreturn)) void help(int st) 87{ 88 bool tty = isatty(fileno(stdout)); 89 90 printf("\n"); 91 printf(" %shyx: a minimalistic hex editor%s\n", 92 tty ? color_green : "", tty ? color_normal : ""); 93 printf(" ------------------------------\n\n"); 94 95 printf(" %sinvocation:%s hyx [filename]\n", 96 tty ? color_yellow : "", tty ? color_normal : ""); 97 98 printf(" %sinvocation:%s [command] | hyx\n\n", 99 tty ? color_yellow : "", tty ? color_normal : ""); 100 101 printf(" %skeys:%s\n\n", 102 tty ? color_yellow : "", tty ? color_normal : ""); 103 printf("q quit\n"); 104 printf("\n"); 105 printf("h, j, k, l move cursor\n"); 106 printf("(hex digits) edit bytes (in hex mode)\n"); 107 printf("(printable) edit bytes (in ascii mode)\n"); 108 printf("i switch between replace and insert modes\n"); 109 printf("tab switch between hex and ascii input\n"); 110 printf("\n"); 111 printf("u undo\n"); 112 printf("ctrl+r redo\n"); 113 printf("\n"); 114 printf("v start a selection\n"); 115 printf("escape abort a selection\n"); 116 printf("x delete current byte or selection\n"); 117 printf("s substitute current byte or selection\n"); 118 printf("y copy current byte or selection to clipboard\n"); 119 printf("p paste\n"); 120 printf("P paste and move cursor\n"); 121 printf("\n"); 122 printf("], [ increase/decrease number of columns\n"); 123 printf("\n"); 124 printf("ctrl+u, ctrl+d scroll up/down one page\n"); 125 printf("g, G jump to start/end of screen or file\n"); 126 printf("^, $ jump to start/end of current line\n"); 127 printf("\n"); 128 printf(": enter command (see below)\n"); 129 printf("\n"); 130 printf("/x (hex string) search for hexadecimal bytes\n"); 131 printf("/s (characters) search for unicode string (utf8)\n"); 132 printf("/w (characters) search for unicode string (ucs2)\n"); 133 printf("n, N jump to next/previous match\n"); 134 printf("\n"); 135 printf("ctrl+a, ctrl+x increment/decrement current byte\n"); 136 printf("\n"); 137 printf("ctrl+g show file name and current position\n"); 138 printf("ctrl+z suspend editor; use \"fg\" to continue\n"); 139 printf("\n"); 140 141 printf(" %scommands:%s\n\n", 142 tty ? color_yellow : "", tty ? color_normal : ""); 143 printf("$offset jump to offset (supports hex/dec/oct)\n"); 144 printf("q quit\n"); 145 printf("w [$filename] save\n"); 146 printf("wq [$filename] save and quit\n"); 147 printf("color y/n toggle colors\n"); 148 149 printf("\n"); 150 151 exit(st); 152} 153 154int main(int argc, char **argv) 155{ 156 struct sigaction sigact; 157 158 char *filename = NULL; 159 160 for (size_t i = 1; i < (size_t) argc; ++i) { 161 if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) 162 help(0); 163 else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) 164 version(); 165 else if (!filename) 166 filename = argv[i]; 167 else 168 help(EXIT_FAILURE); 169 } 170 171 blob_init(&blob); 172 if (!isatty(fileno(stdin))) { 173 if (filename) help(EXIT_FAILURE); 174 blob_load_stream(&blob, stdin); 175 if (!freopen("/dev/tty", "r", stdin)) 176 pdie("could not reopen controlling TTY"); 177 } 178 else { 179 blob_load(&blob, filename); 180 } 181 182 view_init(&view, &blob, &input); 183 input_init(&input, &view); 184 185 /* set up signal handler */ 186 memset(&sigact, 0, sizeof(sigact)); 187 sigact.sa_handler = sighdlr; 188 sigaction(SIGWINCH, &sigact, NULL); 189 sigaction(SIGTSTP, &sigact, NULL); 190 sigaction(SIGCONT, &sigact, NULL); 191 sigaction(SIGALRM, &sigact, NULL); 192 sigaction(SIGINT, &sigact, NULL); 193 194 view_recompute(&view, true); 195 view_visual(&view); 196 197 do { 198 /* This is used to redraw immediately when the window size changes. */ 199 setjmp(jmp_mainloop); 200 201 if (view.winch) { 202 view_recompute(&view, true); 203 view.winch = false; 204 } 205 if (view.tstp) { 206 view_text(&view, true); 207 view.tstp = false; 208 raise(SIGSTOP); 209 /* should continue with view.cont == true */ 210 } 211 if (view.cont) { 212 view_recompute(&view, true); 213 view_dirty_from(&view, 0); 214 view_visual(&view); 215 view.cont = false; 216 } 217 assert(input.cur >= view.start && input.cur < view.start + view.rows * view.cols); 218 view_update(&view); 219 220 input_get(&input, &quit); 221 222 } while (!quit); 223 224 view_text(&view, true); 225 226 input_free(&input); 227 view_free(&view); 228 blob_free(&blob); 229} 230