Changeset 2725 in MondoRescue for branches/2.2.9/mindi-busybox/editors/vi.c
- Timestamp:
- Feb 25, 2011, 9:26:54 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/2.2.9/mindi-busybox/editors/vi.c
r1765 r2725 4 4 * Copyright (C) 2000, 2001 Sterling Huxley <sterling@europa.com> 5 5 * 6 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.6 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 7 */ 8 8 … … 24 24 #include "libbb.h" 25 25 26 /* the CRASHME code is unmaintained, and doesn't currently build */ 26 27 #define ENABLE_FEATURE_VI_CRASHME 0 27 28 29 28 30 #if ENABLE_LOCALE_SUPPORT 29 #define Isprint(c) isprint((c)) 31 32 #if ENABLE_FEATURE_VI_8BIT 33 //FIXME: this does not work properly for Unicode anyway 34 # define Isprint(c) (isprint)(c) 30 35 #else 36 # define Isprint(c) isprint_asciionly(c) 37 #endif 38 39 #else 40 31 41 /* 0x9b is Meta-ESC */ 42 #if ENABLE_FEATURE_VI_8BIT 32 43 #define Isprint(c) ((unsigned char)(c) >= ' ' && (c) != 0x7f && (unsigned char)(c) != 0x9b) 33 #endif 44 #else 45 #define Isprint(c) ((unsigned char)(c) >= ' ' && (unsigned char)(c) < 0x7f) 46 #endif 47 48 #endif 49 34 50 35 51 enum { 36 MAX_LINELEN = CONFIG_FEATURE_VI_MAX_LEN, 52 MAX_TABSTOP = 32, // sanity limit 53 // User input len. Need not be extra big. 54 // Lines in file being edited *can* be bigger than this. 55 MAX_INPUT_LEN = 128, 56 // Sanity limits. We have only one buffer of this size. 37 57 MAX_SCR_COLS = CONFIG_FEATURE_VI_MAX_LEN, 58 MAX_SCR_ROWS = CONFIG_FEATURE_VI_MAX_LEN, 38 59 }; 39 40 // Misc. non-Ascii keys that report an escape sequence41 #define VI_K_UP (char)128 // cursor key Up42 #define VI_K_DOWN (char)129 // cursor key Down43 #define VI_K_RIGHT (char)130 // Cursor Key Right44 #define VI_K_LEFT (char)131 // cursor key Left45 #define VI_K_HOME (char)132 // Cursor Key Home46 #define VI_K_END (char)133 // Cursor Key End47 #define VI_K_INSERT (char)134 // Cursor Key Insert48 #define VI_K_PAGEUP (char)135 // Cursor Key Page Up49 #define VI_K_PAGEDOWN (char)136 // Cursor Key Page Down50 #define VI_K_FUN1 (char)137 // Function Key F151 #define VI_K_FUN2 (char)138 // Function Key F252 #define VI_K_FUN3 (char)139 // Function Key F353 #define VI_K_FUN4 (char)140 // Function Key F454 #define VI_K_FUN5 (char)141 // Function Key F555 #define VI_K_FUN6 (char)142 // Function Key F656 #define VI_K_FUN7 (char)143 // Function Key F757 #define VI_K_FUN8 (char)144 // Function Key F858 #define VI_K_FUN9 (char)145 // Function Key F959 #define VI_K_FUN10 (char)146 // Function Key F1060 #define VI_K_FUN11 (char)147 // Function Key F1161 #define VI_K_FUN12 (char)148 // Function Key F1262 60 63 61 /* vt102 typical ESC sequence */ 64 62 /* terminal standout start/normal ESC sequence */ 65 static const char SOs[] ALIGN1 = "\033[7m"; 66 static const char SOn[] ALIGN1 = "\033[0m"; 63 #define SOs "\033[7m" 64 #define SOn "\033[0m" 67 65 /* terminal bell sequence */ 68 static const char bell[] ALIGN1 = "\007"; 66 #define bell "\007" 69 67 /* Clear-end-of-line and Clear-end-of-screen ESC sequence */ 70 static const char Ceol[] ALIGN1 = "\033[0K"; 71 static const char Ceos[] ALIGN1 = "\033[0J"; 68 #define Ceol "\033[K" 69 #define Ceos "\033[J" 72 70 /* Cursor motion arbitrary destination ESC sequence */ 73 static const char CMrc[] ALIGN1 = "\033[%d;%dH"; 71 #define CMrc "\033[%u;%uH" 74 72 /* Cursor motion up and down ESC sequence */ 75 static const char CMup[] ALIGN1 = "\033[A"; 76 static const char CMdown[] ALIGN1 = "\n"; 77 73 #define CMup "\033[A" 74 #define CMdown "\n" 75 76 #if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK 77 // cmds modifying text[] 78 // vda: removed "aAiIs" as they switch us into insert mode 79 // and remembering input for replay after them makes no sense 80 static const char modifying_cmds[] = "cCdDJoOpPrRxX<>~"; 81 #endif 78 82 79 83 enum { … … 92 96 }; 93 97 98 94 99 /* vi.c expects chars to be unsigned. */ 95 100 /* busybox build system provides that, but it's better */ 96 101 /* to audit and fix the source */ 97 102 98 static smallint vi_setops; 103 struct globals { 104 /* many references - keep near the top of globals */ 105 char *text, *end; // pointers to the user data in memory 106 char *dot; // where all the action takes place 107 int text_size; // size of the allocated buffer 108 109 /* the rest */ 110 smallint vi_setops; 99 111 #define VI_AUTOINDENT 1 100 112 #define VI_SHOWMATCH 2 … … 107 119 #define err_method (vi_setops & VI_ERR_METHOD) 108 120 109 110 static smallint editing; // >0 while we are editing a file111 // [code audit says "can be 0 or 1 only"]112 static smallint cmd_mode; // 0=command 1=insert 2=replace113 static smallint file_modified; // buffer contents changed114 static smallint last_file_modified = -1;115 static int fn_start; // index of first cmd line file name116 static int save_argc; // how many file names on cmd line117 static int cmdcnt; // repetition count118 static int rows, columns; // the terminal screen is this size119 static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset120 static char *status_buffer; // mesages to the user121 #define STATUS_BUFFER_LEN 200122 static int have_status_msg; // is default edit status needed?123 // [don't make smallint!]124 static int last_status_cksum; // hash of current status line125 static char *current_filename; // current file name126 //static char *text, *end; // pointers to the user data in memory127 static char *screen; // pointer to the virtual screen buffer128 static int screensize; // and its size129 static char *screenbegin; // index into text[], of top line on the screen130 //static char *dot; // where all the action takes place131 static int tabstop;132 static char erase_char; // the users erase character133 static char last_input_char; // last char read from user134 static char last_forward_char; // last char searched for with 'f'135 136 121 #if ENABLE_FEATURE_VI_READONLY 137 //static smallint vi_readonly, readonly; 138 static smallint readonly_mode = 0; 122 smallint readonly_mode; 139 123 #define SET_READONLY_FILE(flags) ((flags) |= 0x01) 140 124 #define SET_READONLY_MODE(flags) ((flags) |= 0x02) 141 125 #define UNSET_READONLY_FILE(flags) ((flags) &= 0xfe) 142 126 #else 143 #define readonly_mode 0 144 #define SET_READONLY_FILE(flags) 145 #define SET_READONLY_MODE(flags) 146 #define UNSET_READONLY_FILE(flags) 147 #endif 127 #define SET_READONLY_FILE(flags) ((void)0) 128 #define SET_READONLY_MODE(flags) ((void)0) 129 #define UNSET_READONLY_FILE(flags) ((void)0) 130 #endif 131 132 smallint editing; // >0 while we are editing a file 133 // [code audit says "can be 0, 1 or 2 only"] 134 smallint cmd_mode; // 0=command 1=insert 2=replace 135 int file_modified; // buffer contents changed (counter, not flag!) 136 int last_file_modified; // = -1; 137 int fn_start; // index of first cmd line file name 138 int save_argc; // how many file names on cmd line 139 int cmdcnt; // repetition count 140 unsigned rows, columns; // the terminal screen is this size 141 #if ENABLE_FEATURE_VI_ASK_TERMINAL 142 int get_rowcol_error; 143 #endif 144 int crow, ccol; // cursor is on Crow x Ccol 145 int offset; // chars scrolled off the screen to the left 146 int have_status_msg; // is default edit status needed? 147 // [don't make smallint!] 148 int last_status_cksum; // hash of current status line 149 char *current_filename; 150 char *screenbegin; // index into text[], of top line on the screen 151 char *screen; // pointer to the virtual screen buffer 152 int screensize; // and its size 153 int tabstop; 154 int last_forward_char; // last char searched for with 'f' (int because of Unicode) 155 char erase_char; // the users erase character 156 char last_input_char; // last char read from user 148 157 149 158 #if ENABLE_FEATURE_VI_DOT_CMD 150 static smallint adding2q;// are we currently adding user input to q151 static char *last_modifying_cmd; // last modifying cmd for "." 152 static char *ioq, *ioq_start;// pointer to string for get_one_char to "read"159 smallint adding2q; // are we currently adding user input to q 160 int lmc_len; // length of last_modifying_cmd 161 char *ioq, *ioq_start; // pointer to string for get_one_char to "read" 153 162 #endif 154 163 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 155 static int last_row;// where the cursor was last moved to164 int last_row; // where the cursor was last moved to 156 165 #endif 157 166 #if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME 158 static int my_pid; 159 #endif 160 #if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK 161 static char *modifying_cmds; // cmds that modify text[] 167 int my_pid; 162 168 #endif 163 169 #if ENABLE_FEATURE_VI_SEARCH 164 static char *last_search_pattern; // last pattern from a '/' or '?' search 165 #endif 166 167 /* Moving biggest data to malloced space... */ 168 struct globals { 169 /* many references - keep near the top of globals */ 170 char *text, *end; // pointers to the user data in memory 171 int text_size; // size of the allocated buffer 172 char *dot; // where all the action takes place 170 char *last_search_pattern; // last pattern from a '/' or '?' search 171 #endif 172 173 /* former statics */ 173 174 #if ENABLE_FEATURE_VI_YANKMARK 175 char *edit_file__cur_line; 176 #endif 177 int refresh__old_offset; 178 int format_edit_status__tot; 179 180 /* a few references only */ 181 #if ENABLE_FEATURE_VI_YANKMARK 182 int YDreg, Ureg; // default delete register and orig line for "U" 174 183 char *reg[28]; // named register a-z, "D", and "U" 0-25,26,27 175 int YDreg, Ureg; // default delete register and orig line for "U"176 184 char *mark[28]; // user marks points somewhere in text[]- a-z and previous context '' 177 185 char *context_start, *context_end; 178 186 #endif 179 /* a few references only */180 187 #if ENABLE_FEATURE_VI_USE_SIGNALS 181 jmp_buf restart;// catch_sig()182 #endif 183 struct termios term_orig, term_vi; 188 sigjmp_buf restart; // catch_sig() 189 #endif 190 struct termios term_orig, term_vi; // remember what the cooked mode was 184 191 #if ENABLE_FEATURE_VI_COLON 185 192 char *initial_cmds[3]; // currently 2 entries, NULL terminated 186 193 #endif 194 // Should be just enough to hold a key sequence, 195 // but CRASHME mode uses it as generated command buffer too 196 #if ENABLE_FEATURE_VI_CRASHME 197 char readbuffer[128]; 198 #else 199 char readbuffer[KEYCODE_BUFFER_SIZE]; 200 #endif 201 #define STATUS_BUFFER_LEN 200 202 char status_buffer[STATUS_BUFFER_LEN]; // messages to the user 203 #if ENABLE_FEATURE_VI_DOT_CMD 204 char last_modifying_cmd[MAX_INPUT_LEN]; // last modifying cmd for "." 205 #endif 206 char get_input_line__buf[MAX_INPUT_LEN]; /* former static */ 207 208 char scr_out_buf[MAX_SCR_COLS + MAX_TABSTOP * 2]; 187 209 }; 188 210 #define G (*ptr_to_globals) … … 192 214 #define dot (G.dot ) 193 215 #define reg (G.reg ) 216 217 #define vi_setops (G.vi_setops ) 218 #define editing (G.editing ) 219 #define cmd_mode (G.cmd_mode ) 220 #define file_modified (G.file_modified ) 221 #define last_file_modified (G.last_file_modified ) 222 #define fn_start (G.fn_start ) 223 #define save_argc (G.save_argc ) 224 #define cmdcnt (G.cmdcnt ) 225 #define rows (G.rows ) 226 #define columns (G.columns ) 227 #define crow (G.crow ) 228 #define ccol (G.ccol ) 229 #define offset (G.offset ) 230 #define status_buffer (G.status_buffer ) 231 #define have_status_msg (G.have_status_msg ) 232 #define last_status_cksum (G.last_status_cksum ) 233 #define current_filename (G.current_filename ) 234 #define screen (G.screen ) 235 #define screensize (G.screensize ) 236 #define screenbegin (G.screenbegin ) 237 #define tabstop (G.tabstop ) 238 #define last_forward_char (G.last_forward_char ) 239 #define erase_char (G.erase_char ) 240 #define last_input_char (G.last_input_char ) 241 #if ENABLE_FEATURE_VI_READONLY 242 #define readonly_mode (G.readonly_mode ) 243 #else 244 #define readonly_mode 0 245 #endif 246 #define adding2q (G.adding2q ) 247 #define lmc_len (G.lmc_len ) 248 #define ioq (G.ioq ) 249 #define ioq_start (G.ioq_start ) 250 #define last_row (G.last_row ) 251 #define my_pid (G.my_pid ) 252 #define last_search_pattern (G.last_search_pattern) 253 254 #define edit_file__cur_line (G.edit_file__cur_line) 255 #define refresh__old_offset (G.refresh__old_offset) 256 #define format_edit_status__tot (G.format_edit_status__tot) 257 194 258 #define YDreg (G.YDreg ) 195 259 #define Ureg (G.Ureg ) … … 201 265 #define term_vi (G.term_vi ) 202 266 #define initial_cmds (G.initial_cmds ) 267 #define readbuffer (G.readbuffer ) 268 #define scr_out_buf (G.scr_out_buf ) 269 #define last_modifying_cmd (G.last_modifying_cmd ) 270 #define get_input_line__buf (G.get_input_line__buf) 271 272 #define INIT_G() do { \ 273 SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ 274 last_file_modified = -1; \ 275 /* "" but has space for 2 chars: */ \ 276 IF_FEATURE_VI_SEARCH(last_search_pattern = xzalloc(2);) \ 277 } while (0) 278 203 279 204 280 static int init_text_buffer(char *); // init from file or create new 205 281 static void edit_file(char *); // edit one file 206 static void do_cmd( char); // execute a command282 static void do_cmd(int); // execute a command 207 283 static int next_tabstop(int); 208 284 static void sync_cursor(char *, int *, int *); // synchronize the screen cursor to dot … … 227 303 static char *new_screen(int, int); // malloc virtual screen memory 228 304 static char *char_insert(char *, char); // insert the char c at 'p' 229 static char *stupid_insert(char *, char); // stupidly insert the char c at 'p' 230 static char find_range(char **, char **, char); // return pointers for an object 305 // might reallocate text[]! use p += stupid_insert(p, ...), 306 // and be careful to not use pointers into potentially freed text[]! 307 static uintptr_t stupid_insert(char *, char); // stupidly insert the char c at 'p' 308 static int find_range(char **, char **, char); // return pointers for an object 231 309 static int st_test(char *, int, int, char *); // helper for skip_thing() 232 310 static char *skip_thing(char *, int, int, int); // skip some object 233 311 static char *find_pair(char *, char); // find matching pair () [] {} 234 312 static char *text_hole_delete(char *, char *); // at "p", delete a 'size' byte hole 235 static char *text_hole_make(char *, int); // at "p", make a 'size' byte hole 313 // might reallocate text[]! use p += text_hole_make(p, ...), 314 // and be careful to not use pointers into potentially freed text[]! 315 static uintptr_t text_hole_make(char *, int); // at "p", make a 'size' byte hole 236 316 static char *yank_delete(char *, char *, int, int); // yank text[] into register then delete 237 317 static void show_help(void); // display some help info 238 318 static void rawmode(void); // set "raw" mode on tty 239 319 static void cookmode(void); // return to "cooked" mode on tty 240 static int mysleep(int); // sleep for 'h' 1/100 seconds 241 static char readit(void); // read (maybe cursor) key from stdin 242 static char get_one_char(void); // read 1 char from stdin 320 // sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready) 321 static int mysleep(int); 322 static int readit(void); // read (maybe cursor) key from stdin 323 static int get_one_char(void); // read 1 char from stdin 243 324 static int file_size(const char *); // what is the byte size of "fn" 244 #if ENABLE_FEATURE_VI_READONLY 325 #if !ENABLE_FEATURE_VI_READONLY 326 #define file_insert(fn, p, update_ro_status) file_insert(fn, p) 327 #endif 328 // file_insert might reallocate text[]! 245 329 static int file_insert(const char *, char *, int); 246 #else247 static int file_insert(const char *, char *);248 #endif249 330 static int file_write(char *, char *, char *); 331 #if !ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 332 #define place_cursor(a, b, optimize) place_cursor(a, b) 333 #endif 250 334 static void place_cursor(int, int, int); 251 335 static void screen_erase(void); 252 336 static void clear_to_eol(void); 253 337 static void clear_to_eos(void); 338 static void go_bottom_and_clear_to_eol(void); 254 339 static void standout_start(void); // send "start reverse video" sequence 255 340 static void standout_end(void); // send "end reverse video" sequence 256 341 static void flash(int); // flash the terminal screen 257 342 static void show_status_line(void); // put a message on the bottom line 258 static void psb(const char *, ...); // Print Status Buf259 static void psbs(const char *, ...); // Print Status Buf in standout mode260 static void n i(const char *); // display messages343 static void status_line(const char *, ...); // print to status buf 344 static void status_line_bold(const char *, ...); 345 static void not_implemented(const char *); // display "Not implemented" message 261 346 static int format_edit_status(void); // format file status on status line 262 347 static void redraw(int); // force a full screen refresh 263 static void format_line(char*, char*, int);348 static char* format_line(char* /*, int*/); 264 349 static void refresh(int); // update the terminal from screen[] 265 350 … … 292 377 #endif 293 378 #if ENABLE_FEATURE_VI_YANKMARK || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) || ENABLE_FEATURE_VI_CRASHME 294 static char *string_insert(char *, char *); // insert the string at 'p' 379 // might reallocate text[]! use p += string_insert(p, ...), 380 // and be careful to not use pointers into potentially freed text[]! 381 static uintptr_t string_insert(char *, const char *); // insert the string at 'p' 295 382 #endif 296 383 #if ENABLE_FEATURE_VI_YANKMARK … … 311 398 } 312 399 313 int vi_main(int argc, char **argv) ;400 int vi_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 314 401 int vi_main(int argc, char **argv) 315 402 { 316 403 int c; 317 RESERVE_CONFIG_BUFFER(STATUS_BUFFER, STATUS_BUFFER_LEN); 404 405 INIT_G(); 318 406 319 407 #if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME 320 408 my_pid = getpid(); 321 409 #endif 322 323 PTR_TO_GLOBALS = xzalloc(sizeof(G));324 325 410 #if ENABLE_FEATURE_VI_CRASHME 326 411 srand((long) my_pid); 327 412 #endif 328 329 status_buffer = STATUS_BUFFER;330 last_status_cksum = 0;331 text = NULL;332 333 413 #ifdef NO_SUCH_APPLET_YET 334 414 /* If we aren't "vi", we are "view" */ … … 338 418 #endif 339 419 340 vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE | VI_ERR_METHOD; 341 #if ENABLE_FEATURE_VI_YANKMARK 342 memset(reg, 0, sizeof(reg)); // init the yank regs 343 #endif 344 #if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK 345 modifying_cmds = (char *) "aAcCdDiIJoOpPrRsxX<>~"; // cmds modifying text[] 346 #endif 347 420 vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE; 348 421 // 1- process $HOME/.exrc file (not inplemented yet) 349 422 // 2- process EXINIT variable from environment … … 353 426 char *p = getenv("EXINIT"); 354 427 if (p && *p) 355 initial_cmds[0] = xstr dup(p);356 } 357 #endif 358 while ((c = getopt(argc, argv, "hCR " USE_FEATURE_VI_COLON("c:"))) != -1) {428 initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN); 429 } 430 #endif 431 while ((c = getopt(argc, argv, "hCRH" IF_FEATURE_VI_COLON("c:"))) != -1) { 359 432 switch (c) { 360 433 #if ENABLE_FEATURE_VI_CRASHME … … 368 441 break; 369 442 #endif 370 //case 'r': // recover flag- ignore- we don't use tmp file371 //case 'x': // encryption flag- ignore372 //case 'c': // execute command first373 443 #if ENABLE_FEATURE_VI_COLON 374 444 case 'c': // cmd line vi command 375 445 if (*optarg) 376 initial_cmds[initial_cmds[0] != 0] = xstr dup(optarg);446 initial_cmds[initial_cmds[0] != 0] = xstrndup(optarg, MAX_INPUT_LEN); 377 447 break; 378 //case 'h': // help -- just use default 379 #endif 448 #endif 449 case 'H': 450 show_help(); 451 /* fall through */ 380 452 default: 381 show_help();453 bb_show_usage(); 382 454 return 1; 383 455 } … … 390 462 391 463 //----- This is the main file handling loop -------------- 392 if (optind >= argc) { 393 edit_file(0); 394 } else { 395 for (; optind < argc; optind++) { 396 edit_file(argv[optind]); 397 } 464 while (1) { 465 edit_file(argv[optind]); /* param might be NULL */ 466 if (++optind >= argc) 467 break; 398 468 } 399 469 //----------------------------------------------------------- … … 411 481 /* allocate/reallocate text buffer */ 412 482 free(text); 413 text_size = size * 2; 414 if (text_size < 10240) 415 text_size = 10240; // have a minimum size for new files 483 text_size = size + 10240; 416 484 screenbegin = dot = end = text = xzalloc(text_size); 417 485 … … 425 493 rc = 0; 426 494 } else { 427 rc = file_insert(fn, text 428 USE_FEATURE_VI_READONLY(, 1)); 495 rc = file_insert(fn, text, 1); 429 496 } 430 497 file_modified = 0; … … 437 504 } 438 505 439 static void edit_file(char * fn) 440 { 441 char c; 506 #if ENABLE_FEATURE_VI_WIN_RESIZE 507 static int query_screen_dimensions(void) 508 { 509 int err = get_terminal_width_height(STDIN_FILENO, &columns, &rows); 510 if (rows > MAX_SCR_ROWS) 511 rows = MAX_SCR_ROWS; 512 if (columns > MAX_SCR_COLS) 513 columns = MAX_SCR_COLS; 514 return err; 515 } 516 #else 517 # define query_screen_dimensions() (0) 518 #endif 519 520 static void edit_file(char *fn) 521 { 522 #if ENABLE_FEATURE_VI_YANKMARK 523 #define cur_line edit_file__cur_line 524 #endif 525 int c; 442 526 int size; 443 444 527 #if ENABLE_FEATURE_VI_USE_SIGNALS 445 528 int sig; 446 529 #endif 447 #if ENABLE_FEATURE_VI_YANKMARK 448 static char *cur_line; 449 #endif 450 451 editing = 1; // 0= exit, 1= one file, 2= multiple files 530 531 editing = 1; // 0 = exit, 1 = one file, 2 = multiple files 452 532 rawmode(); 453 533 rows = 24; 454 534 columns = 80; 455 535 size = 0; 456 if (ENABLE_FEATURE_VI_WIN_RESIZE) 457 get_terminal_width_height(0, &columns, &rows); 536 IF_FEATURE_VI_ASK_TERMINAL(G.get_rowcol_error =) query_screen_dimensions(); 537 #if ENABLE_FEATURE_VI_ASK_TERMINAL 538 if (G.get_rowcol_error /* TODO? && no input on stdin */) { 539 uint64_t k; 540 write1("\033[999;999H" "\033[6n"); 541 fflush_all(); 542 k = read_key(STDIN_FILENO, readbuffer, /*timeout_ms:*/ 100); 543 if ((int32_t)k == KEYCODE_CURSOR_POS) { 544 uint32_t rc = (k >> 32); 545 columns = (rc & 0x7fff); 546 if (columns > MAX_SCR_COLS) 547 columns = MAX_SCR_COLS; 548 rows = ((rc >> 16) & 0x7fff); 549 if (rows > MAX_SCR_ROWS) 550 rows = MAX_SCR_ROWS; 551 } 552 } 553 #endif 458 554 new_screen(rows, columns); // get memory for virtual screen 459 555 init_text_buffer(fn); … … 470 566 471 567 #if ENABLE_FEATURE_VI_USE_SIGNALS 472 catch_sig(0);568 signal(SIGINT, catch_sig); 473 569 signal(SIGWINCH, winch_sig); 474 570 signal(SIGTSTP, suspend_sig); 475 sig = s etjmp(restart);571 sig = sigsetjmp(restart, 1); 476 572 if (sig != 0) { 477 573 screenbegin = dot = text; … … 485 581 c = '\0'; 486 582 #if ENABLE_FEATURE_VI_DOT_CMD 487 free(last_modifying_cmd);488 583 free(ioq_start); 489 ioq = ioq_start = last_modifying_cmd = NULL; 584 ioq = ioq_start = NULL; 585 lmc_len = 0; 490 586 adding2q = 0; 491 587 #endif 492 redraw(FALSE); // dont force every col re-draw493 588 494 589 #if ENABLE_FEATURE_VI_COLON … … 497 592 int n = 0; 498 593 499 while ((p = initial_cmds[n]) ) {594 while ((p = initial_cmds[n]) != NULL) { 500 595 do { 501 596 q = p; 502 p = strchr(q, '\n');597 p = strchr(q, '\n'); 503 598 if (p) 504 599 while (*p == '\n') … … 513 608 } 514 609 #endif 610 redraw(FALSE); // dont force every col re-draw 515 611 //------This is the main Vi cmd handling loop ----------------------- 516 612 while (editing > 0) { … … 521 617 } else { 522 618 crashme = 0; 523 dot = string_insert(text, "\n\n##### Ran out of text to work on. #####\n\n"); // insert the string 619 string_insert(text, "\n\n##### Ran out of text to work on. #####\n\n"); // insert the string 620 dot = text; 524 621 refresh(FALSE); 525 622 } … … 537 634 // These are commands that change text[]. 538 635 // Remember the input for the "." command 539 if (!adding2q && ioq_start == 0 636 if (!adding2q && ioq_start == NULL 637 && cmd_mode == 0 // command mode 638 && c > '\0' // exclude NUL and non-ASCII chars 639 && c < 0x7f // (Unicode and such) 540 640 && strchr(modifying_cmds, c) 541 641 ) { … … 544 644 #endif 545 645 do_cmd(c); // execute the user command 546 // 646 547 647 // poll to see if there is input already waiting. if we are 548 648 // not able to display output fast enough to keep up, skip 549 649 // the display update until we catch up with input. 550 if ( mysleep(0) == 0) {551 // no input pending - so update output650 if (!readbuffer[0] && mysleep(0) == 0) { 651 // no input pending - so update output 552 652 refresh(FALSE); 553 653 show_status_line(); … … 560 660 //------------------------------------------------------------------- 561 661 562 place_cursor(rows, 0, FALSE); // go to bottom of screen 563 clear_to_eol(); // Erase to end of line 662 go_bottom_and_clear_to_eol(); 564 663 cookmode(); 664 #undef cur_line 565 665 } 566 666 567 667 //----- The Colon commands ------------------------------------- 568 668 #if ENABLE_FEATURE_VI_COLON 569 static char *get_one_address(char * 669 static char *get_one_address(char *p, int *addr) // get colon addr, if present 570 670 { 571 671 int st; 572 672 char *q; 573 574 #if ENABLE_FEATURE_VI_YANKMARK 575 char c; 576 #endif 577 #if ENABLE_FEATURE_VI_SEARCH 578 char *pat, buf[MAX_LINELEN]; 579 #endif 673 IF_FEATURE_VI_YANKMARK(char c;) 674 IF_FEATURE_VI_SEARCH(char *pat;) 580 675 581 676 *addr = -1; // assume no addr … … 584 679 q = begin_line(dot); 585 680 *addr = count_lines(text, q); 681 } 586 682 #if ENABLE_FEATURE_VI_YANKMARK 587 }else if (*p == '\'') { // is this a mark addr683 else if (*p == '\'') { // is this a mark addr 588 684 p++; 589 685 c = tolower(*p); … … 594 690 q = mark[(unsigned char) c]; 595 691 if (q != NULL) { // is mark valid 596 *addr = count_lines(text, q); // count lines692 *addr = count_lines(text, q); 597 693 } 598 694 } 695 } 599 696 #endif 600 697 #if ENABLE_FEATURE_VI_SEARCH 601 } else if (*p == '/') { // a search pattern 602 q = buf; 603 for (p++; *p; p++) { 604 if (*p == '/') 605 break; 606 *q++ = *p; 607 *q = '\0'; 608 } 609 pat = xstrdup(buf); // save copy of pattern 698 else if (*p == '/') { // a search pattern 699 q = strchrnul(++p, '/'); 700 pat = xstrndup(p, q - p); // save copy of pattern 701 p = q; 610 702 if (*p == '/') 611 703 p++; … … 615 707 } 616 708 free(pat); 617 #endif 618 } else if (*p == '$') { // the last line in file 709 } 710 #endif 711 else if (*p == '$') { // the last line in file 619 712 p++; 620 713 q = begin_line(end - 1); … … 623 716 sscanf(p, "%d%n", addr, &st); 624 717 p += st; 625 } else { // I don't reconise this626 // unrecogni sed address- assume -1718 } else { 719 // unrecognized address - assume -1 627 720 *addr = -1; 628 721 } … … 665 758 int l = strlen(opname) - 1; /* opname have + ' ' */ 666 759 760 // maybe strncmp? we had tons of erroneous strncasecmp's... 667 761 if (strncasecmp(a, opname, l) == 0 668 762 || strncasecmp(a, short_opname, 2) == 0 … … 676 770 #endif 677 771 678 static void colon(char * buf) 772 // buf must be no longer than MAX_INPUT_LEN! 773 static void colon(char *buf) 679 774 { 680 775 char c, *orig_buf, *buf1, *q, *r; 681 char *fn, cmd[MAX_ LINELEN], args[MAX_LINELEN];776 char *fn, cmd[MAX_INPUT_LEN], args[MAX_INPUT_LEN]; 682 777 int i, l, li, ch, b, e; 683 int useforce = FALSE, forced = FALSE;778 int useforce, forced = FALSE; 684 779 685 780 // :3154 // if (-e line 3154) goto it else stay put … … 699 794 700 795 if (!buf[0]) 701 goto vc1;796 goto ret; 702 797 if (*buf == ':') 703 798 buf++; // move past the ':' … … 708 803 r = end - 1; 709 804 li = count_lines(text, end - 1); 710 fn = current_filename; // default to current file 711 memset(cmd, '\0', MAX_LINELEN); // clear cmd[] 712 memset(args, '\0', MAX_LINELEN); // clear args[] 805 fn = current_filename; 713 806 714 807 // look for optional address(es) :. :1 :1,9 :'q,'a :% … … 725 818 *buf1++ = *buf++; 726 819 } 820 *buf1 = '\0'; 727 821 // get any ARGuments 728 822 while (isblank(*buf)) 729 823 buf++; 730 824 strcpy(args, buf); 825 useforce = FALSE; 731 826 buf1 = last_char_is(cmd, '!'); 732 827 if (buf1) { … … 759 854 } 760 855 #if ENABLE_FEATURE_ALLOW_EXEC 761 else if ( strncmp(cmd, "!", 1) == 0) { // run a cmd856 else if (cmd[0] == '!') { // run a cmd 762 857 int retcode; 763 858 // :!ls run the <cmd> 764 alarm(0); // wait for input- no alarms 765 place_cursor(rows - 1, 0, FALSE); // go to Status line 766 clear_to_eol(); // clear the line 859 go_bottom_and_clear_to_eol(); 767 860 cookmode(); 768 861 retcode = system(orig_buf + 1); // run the cmd … … 771 864 rawmode(); 772 865 Hit_Return(); // let user see results 773 alarm(3); // done waiting for input 774 } 775 #endif 776 else if (strncmp(cmd, "=", i) == 0) { // where is the address 866 } 867 #endif 868 else if (cmd[0] == '=' && !cmd[1]) { // where is the address 777 869 if (b < 0) { // no addr given- use defaults 778 870 b = e = count_lines(text, dot); 779 871 } 780 psb("%d", b);781 } else if (strnc asecmp(cmd, "delete", i) == 0) { // delete lines872 status_line("%d", b); 873 } else if (strncmp(cmd, "delete", i) == 0) { // delete lines 782 874 if (b < 0) { // no addr given- use defaults 783 875 q = begin_line(dot); // assume .,. for the range … … 786 878 dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines 787 879 dot_skip_over_ws(); 788 } else if (strnc asecmp(cmd, "edit", i) == 0) { // Edit a file880 } else if (strncmp(cmd, "edit", i) == 0) { // Edit a file 789 881 // don't edit, if the current file has been modified 790 if (file_modified && ! 791 psbs("No write since last change (:edit! overrides)");792 goto vc1;882 if (file_modified && !useforce) { 883 status_line_bold("No write since last change (:edit! overrides)"); 884 goto ret; 793 885 } 794 886 if (args[0]) { … … 800 892 } else { 801 893 // no user file name, no current name- punt 802 psbs("No current filename");803 goto vc1;894 status_line_bold("No current filename"); 895 goto ret; 804 896 } 805 897 806 898 if (init_text_buffer(fn) < 0) 807 goto vc1;899 goto ret; 808 900 809 901 #if ENABLE_FEATURE_VI_YANKMARK … … 819 911 // how many lines in text[]? 820 912 li = count_lines(text, end - 1); 821 psb("\"%s\"%s"822 USE_FEATURE_VI_READONLY("%s")913 status_line("\"%s\"%s" 914 IF_FEATURE_VI_READONLY("%s") 823 915 " %dL, %dC", current_filename, 824 916 (file_size(fn) < 0 ? " [New file]" : ""), 825 USE_FEATURE_VI_READONLY(917 IF_FEATURE_VI_READONLY( 826 918 ((readonly_mode) ? " [Readonly]" : ""), 827 919 ) 828 920 li, ch); 829 } else if (strnc asecmp(cmd, "file", i) == 0) { // what File is this921 } else if (strncmp(cmd, "file", i) == 0) { // what File is this 830 922 if (b != -1 || e != -1) { 831 ni("No address allowed on this command");832 goto vc1;923 status_line_bold("No address allowed on this command"); 924 goto ret; 833 925 } 834 926 if (args[0]) { … … 840 932 last_status_cksum = 0; // force status update 841 933 } 842 } else if (strnc asecmp(cmd, "features", i) == 0) { // what features are available934 } else if (strncmp(cmd, "features", i) == 0) { // what features are available 843 935 // print out values of all features 844 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen 845 clear_to_eol(); // clear the line 936 go_bottom_and_clear_to_eol(); 846 937 cookmode(); 847 938 show_help(); 848 939 rawmode(); 849 940 Hit_Return(); 850 } else if (strnc asecmp(cmd, "list", i) == 0) { // literal print line941 } else if (strncmp(cmd, "list", i) == 0) { // literal print line 851 942 if (b < 0) { // no addr given- use defaults 852 943 q = begin_line(dot); // assume .,. for the range 853 944 r = end_line(dot); 854 945 } 855 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen 856 clear_to_eol(); // clear the line 946 go_bottom_and_clear_to_eol(); 857 947 puts("\r"); 858 948 for (; q <= r; q++) { … … 864 954 c = '.'; 865 955 standout_start(); 866 956 } 867 957 if (c == '\n') { 868 958 write1("$\r"); 869 959 } else if (c < ' ' || c == 127) { 870 putchar('^');960 bb_putchar('^'); 871 961 if (c == 127) 872 962 c = '?'; … … 874 964 c += '@'; 875 965 } 876 putchar(c);966 bb_putchar(c); 877 967 if (c_is_no_print) 878 968 standout_end(); 879 969 } 880 #if ENABLE_FEATURE_VI_SET881 vc2:882 #endif883 970 Hit_Return(); 884 } else if (strnc asecmp(cmd, "quit", i) == 0 // Quit885 || strnc asecmp(cmd, "next", i) == 0 // edit next file971 } else if (strncmp(cmd, "quit", i) == 0 // quit 972 || strncmp(cmd, "next", i) == 0 // edit next file 886 973 ) { 974 int n; 887 975 if (useforce) { 888 976 // force end of argv list … … 891 979 } 892 980 editing = 0; 893 goto vc1;981 goto ret; 894 982 } 895 983 // don't exit if the file been modified 896 984 if (file_modified) { 897 psbs("No write since last change (:%s! overrides)",985 status_line_bold("No write since last change (:%s! overrides)", 898 986 (*cmd == 'q' ? "quit" : "next")); 899 goto vc1;987 goto ret; 900 988 } 901 989 // are there other file to edit 902 if (*cmd == 'q' && optind < save_argc - 1) { 903 psbs("%d more file to edit", (save_argc - optind - 1)); 904 goto vc1; 905 } 906 if (*cmd == 'n' && optind >= save_argc - 1) { 907 psbs("No more files to edit"); 908 goto vc1; 990 n = save_argc - optind - 1; 991 if (*cmd == 'q' && n > 0) { 992 status_line_bold("%d more file(s) to edit", n); 993 goto ret; 994 } 995 if (*cmd == 'n' && n <= 0) { 996 status_line_bold("No more files to edit"); 997 goto ret; 909 998 } 910 999 editing = 0; 911 } else if (strnc asecmp(cmd, "read", i) == 0) { // read file into text[]1000 } else if (strncmp(cmd, "read", i) == 0) { // read file into text[] 912 1001 fn = args; 913 1002 if (!fn[0]) { 914 psbs("No filename given");915 goto vc1;1003 status_line_bold("No filename given"); 1004 goto ret; 916 1005 } 917 1006 if (b < 0) { // no addr given- use defaults … … 921 1010 if (b != 0) 922 1011 q = next_line(q); 923 ch = file_insert(fn, q USE_FEATURE_VI_READONLY(, 0)); 1012 { // dance around potentially-reallocated text[] 1013 uintptr_t ofs = q - text; 1014 ch = file_insert(fn, q, 0); 1015 q = text + ofs; 1016 } 924 1017 if (ch < 0) 925 goto vc1; // nothing was inserted1018 goto ret; // nothing was inserted 926 1019 // how many lines in text[]? 927 1020 li = count_lines(q, q + ch - 1); 928 psb("\"%s\""929 USE_FEATURE_VI_READONLY("%s")1021 status_line("\"%s\"" 1022 IF_FEATURE_VI_READONLY("%s") 930 1023 " %dL, %dC", fn, 931 USE_FEATURE_VI_READONLY((readonly_mode ? " [Readonly]" : ""),)1024 IF_FEATURE_VI_READONLY((readonly_mode ? " [Readonly]" : ""),) 932 1025 li, ch); 933 1026 if (ch > 0) { … … 935 1028 if (q <= dot) 936 1029 dot += ch; 937 file_modified++;938 } 939 } else if (strnc asecmp(cmd, "rewind", i) == 0) { // rewind cmd line args940 if (file_modified && ! 941 psbs("No write since last change (:rewind! overrides)");1030 /*file_modified++; - done by file_insert */ 1031 } 1032 } else if (strncmp(cmd, "rewind", i) == 0) { // rewind cmd line args 1033 if (file_modified && !useforce) { 1034 status_line_bold("No write since last change (:rewind! overrides)"); 942 1035 } else { 943 1036 // reset the filenames to edit … … 946 1039 } 947 1040 #if ENABLE_FEATURE_VI_SET 948 } else if (strnc asecmp(cmd, "set", i) == 0) { // set or clear features1041 } else if (strncmp(cmd, "set", i) == 0) { // set or clear features 949 1042 #if ENABLE_FEATURE_VI_SETOPTS 950 1043 char *argp; … … 954 1047 if (!args[0] || strcasecmp(args, "all") == 0) { 955 1048 // print out values of all options 956 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen957 clear_to_eol(); // clear the line958 printf("----------------------------------------\r\n");959 1049 #if ENABLE_FEATURE_VI_SETOPTS 960 if (!autoindent) 961 printf("no"); 962 printf("autoindent "); 963 if (!err_method) 964 printf("no"); 965 printf("flash "); 966 if (!ignorecase) 967 printf("no"); 968 printf("ignorecase "); 969 if (!showmatch) 970 printf("no"); 971 printf("showmatch "); 972 printf("tabstop=%d ", tabstop); 973 #endif 974 printf("\r\n"); 975 goto vc2; 1050 status_line_bold( 1051 "%sautoindent " 1052 "%sflash " 1053 "%signorecase " 1054 "%sshowmatch " 1055 "tabstop=%u", 1056 autoindent ? "" : "no", 1057 err_method ? "" : "no", 1058 ignorecase ? "" : "no", 1059 showmatch ? "" : "no", 1060 tabstop 1061 ); 1062 #endif 1063 goto ret; 976 1064 } 977 1065 #if ENABLE_FEATURE_VI_SETOPTS 978 1066 argp = args; 979 1067 while (*argp) { 980 if (strnc asecmp(argp, "no", 2) == 0)1068 if (strncmp(argp, "no", 2) == 0) 981 1069 i = 2; // ":set noautoindent" 982 1070 setops(argp, "autoindent ", i, "ai", VI_AUTOINDENT); 983 setops(argp, "flash " , i, "fl", VI_ERR_METHOD);1071 setops(argp, "flash " , i, "fl", VI_ERR_METHOD); 984 1072 setops(argp, "ignorecase ", i, "ic", VI_IGNORECASE); 985 setops(argp, "showmatch " , i, "ic", VI_SHOWMATCH);986 /* tabstopXXXX */987 if (strncasecmp(argp + i, "tabstop=%d ", 7) == 0) {988 sscanf( strchr(argp + i, '='), "tabstop=%d" + 7, &ch);989 if ( ch > 0 && ch < columns - 1)990 tabstop = ch;1073 setops(argp, "showmatch " , i, "sm", VI_SHOWMATCH ); 1074 if (strncmp(argp + i, "tabstop=", 8) == 0) { 1075 int t = 0; 1076 sscanf(argp + i+8, "%u", &t); 1077 if (t > 0 && t <= MAX_TABSTOP) 1078 tabstop = t; 991 1079 } 992 while (*argp && *argp != ' ') 993 argp++; // skip to arg delimiter (i.e. blank) 994 while (*argp && *argp == ' ') 995 argp++; // skip all delimiting blanks 1080 argp = skip_non_whitespace(argp); 1081 argp = skip_whitespace(argp); 996 1082 } 997 1083 #endif /* FEATURE_VI_SETOPTS */ 998 1084 #endif /* FEATURE_VI_SET */ 999 1085 #if ENABLE_FEATURE_VI_SEARCH 1000 } else if ( strncasecmp(cmd, "s", 1) == 0) { // substitute a pattern with a replacement pattern1086 } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern 1001 1087 char *ls, *F, *R; 1002 1088 int gflag; … … 1009 1095 F = orig_buf + 2; // start of "find" 1010 1096 R = strchr(F, c); // middle delimiter 1011 if (!R) goto colon_s_fail; 1097 if (!R) 1098 goto colon_s_fail; 1012 1099 *R++ = '\0'; // terminate "find" 1013 1100 buf1 = strchr(R, c); 1014 if (!buf1) goto colon_s_fail; 1101 if (!buf1) 1102 goto colon_s_fail; 1015 1103 *buf1++ = '\0'; // terminate "replace" 1016 1104 if (*buf1 == 'g') { // :s/foo/bar/g … … 1030 1118 buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" 1031 1119 if (buf1) { 1120 uintptr_t bias; 1032 1121 // we found the "find" pattern - delete it 1033 1122 text_hole_delete(buf1, buf1 + strlen(F) - 1); 1034 1123 // inset the "replace" patern 1035 string_insert(buf1, R); // insert the string 1124 bias = string_insert(buf1, R); // insert the string 1125 buf1 += bias; 1126 ls += bias; 1127 /*q += bias; - recalculated anyway */ 1036 1128 // check for "global" :s/foo/bar/g 1037 1129 if (gflag == 1) { … … 1045 1137 } 1046 1138 #endif /* FEATURE_VI_SEARCH */ 1047 } else if (strnc asecmp(cmd, "version", i) == 0) { // show software version1048 psb("%s",BB_VER " " BB_BT);1049 } else if (strnc asecmp(cmd, "write", i) == 0 // write text to file1050 || strnc asecmp(cmd, "wq", i) == 01051 || strnc asecmp(cmd, "wn", i) == 01052 || strncasecmp(cmd, "x", i) == 01139 } else if (strncmp(cmd, "version", i) == 0) { // show software version 1140 status_line(BB_VER " " BB_BT); 1141 } else if (strncmp(cmd, "write", i) == 0 // write text to file 1142 || strncmp(cmd, "wq", i) == 0 1143 || strncmp(cmd, "wn", i) == 0 1144 || (cmd[0] == 'x' && !cmd[1]) 1053 1145 ) { 1054 1146 // is there a file name to write to? … … 1058 1150 #if ENABLE_FEATURE_VI_READONLY 1059 1151 if (readonly_mode && !useforce) { 1060 psbs("\"%s\" File is read only", fn);1061 goto vc3;1152 status_line_bold("\"%s\" File is read only", fn); 1153 goto ret; 1062 1154 } 1063 1155 #endif … … 1081 1173 if (l < 0) { 1082 1174 if (l == -1) 1083 psbs("\"%s\" %s", fn, strerror(errno));1175 status_line_bold("\"%s\" %s", fn, strerror(errno)); 1084 1176 } else { 1085 psb("\"%s\" %dL, %dC", fn, li, l);1177 status_line("\"%s\" %dL, %dC", fn, li, l); 1086 1178 if (q == text && r == end - 1 && l == ch) { 1087 1179 file_modified = 0; 1088 1180 last_file_modified = -1; 1089 1181 } 1090 if ((cmd[0] == 'x' || cmd[1] == 'q' || cmd[1] == 'n' || 1091 cmd[0] == 'X' || cmd[1] == 'Q' || cmd[1] == 'N') 1092 && l == ch) { 1182 if ((cmd[0] == 'x' || cmd[1] == 'q' || cmd[1] == 'n' 1183 || cmd[0] == 'X' || cmd[1] == 'Q' || cmd[1] == 'N' 1184 ) 1185 && l == ch 1186 ) { 1093 1187 editing = 0; 1094 1188 } 1095 1189 } 1096 #if ENABLE_FEATURE_VI_READONLY1097 vc3:;1098 #endif1099 1190 #if ENABLE_FEATURE_VI_YANKMARK 1100 } else if (strnc asecmp(cmd, "yank", i) == 0) { // yank lines1191 } else if (strncmp(cmd, "yank", i) == 0) { // yank lines 1101 1192 if (b < 0) { // no addr given- use defaults 1102 1193 q = begin_line(dot); // assume .,. for the range … … 1105 1196 text_yank(q, r, YDreg); 1106 1197 li = count_lines(q, r); 1107 psb("Yank %d lines (%d chars) into [%c]",1198 status_line("Yank %d lines (%d chars) into [%c]", 1108 1199 li, strlen(reg[YDreg]), what_reg()); 1109 1200 #endif 1110 1201 } else { 1111 1202 // cmd unknown 1112 n i(cmd);1113 } 1114 vc1:1203 not_implemented(cmd); 1204 } 1205 ret: 1115 1206 dot = bound_dot(dot); // make sure "dot" is valid 1116 1207 return; 1117 1208 #if ENABLE_FEATURE_VI_SEARCH 1118 1209 colon_s_fail: 1119 psb(":s expression missing delimiters");1210 status_line(":s expression missing delimiters"); 1120 1211 #endif 1121 1212 } … … 1125 1216 static void Hit_Return(void) 1126 1217 { 1127 charc;1128 1129 standout_start(); // start reverse video1218 int c; 1219 1220 standout_start(); 1130 1221 write1("[Hit return to continue]"); 1131 standout_end(); // end reverse video1132 while ((c = get_one_char()) != '\n' && c != '\r') /*do nothing */1133 ;1222 standout_end(); 1223 while ((c = get_one_char()) != '\n' && c != '\r') 1224 continue; 1134 1225 redraw(TRUE); // force redraw all 1135 1226 } … … 1141 1232 1142 1233 //----- Synchronize the cursor to Dot -------------------------- 1143 static void sync_cursor(char *d, int *row, int *col)1234 static NOINLINE void sync_cursor(char *d, int *row, int *col) 1144 1235 { 1145 1236 char *beg_cur; // begin and end of "d" line 1146 char *end_scr; // begin and end of screen1147 1237 char *tp; 1148 1238 int cnt, ro, co; … … 1150 1240 beg_cur = begin_line(d); // first char of cur line 1151 1241 1152 end_scr = end_screen(); // last char of screen1153 1154 1242 if (beg_cur < screenbegin) { 1155 // "d" is before 1243 // "d" is before top line on screen 1156 1244 // how many lines do we have to move 1157 1245 cnt = count_lines(beg_cur, screenbegin); … … 1164 1252 } 1165 1253 } 1166 } else if (beg_cur > end_scr) { 1167 // "d" is after bottom line on screen 1168 // how many lines do we have to move 1169 cnt = count_lines(end_scr, beg_cur); 1170 if (cnt > (rows - 1) / 2) 1171 goto sc1; // too many lines 1172 for (ro = 0; ro < cnt - 1; ro++) { 1173 // move screen begin the same amount 1174 screenbegin = next_line(screenbegin); 1175 // now, move the end of screen 1176 end_scr = next_line(end_scr); 1177 end_scr = end_line(end_scr); 1254 } else { 1255 char *end_scr; // begin and end of screen 1256 end_scr = end_screen(); // last char of screen 1257 if (beg_cur > end_scr) { 1258 // "d" is after bottom line on screen 1259 // how many lines do we have to move 1260 cnt = count_lines(end_scr, beg_cur); 1261 if (cnt > (rows - 1) / 2) 1262 goto sc1; // too many lines 1263 for (ro = 0; ro < cnt - 1; ro++) { 1264 // move screen begin the same amount 1265 screenbegin = next_line(screenbegin); 1266 // now, move the end of screen 1267 end_scr = next_line(end_scr); 1268 end_scr = end_line(end_scr); 1269 } 1178 1270 } 1179 1271 } … … 1188 1280 // find out what col "d" is on 1189 1281 co = 0; 1190 do {// drive "co" to correct column1191 if (*tp == '\n' || *tp == '\0')1282 while (tp < d) { // drive "co" to correct column 1283 if (*tp == '\n') //vda || *tp == '\0') 1192 1284 break; 1193 1285 if (*tp == '\t') { 1194 if (d == tp && cmd_mode) { /* handle tabs like real vi */ 1286 // handle tabs like real vi 1287 if (d == tp && cmd_mode) { 1195 1288 break; 1196 } else {1197 co = next_tabstop(co);1198 1289 } 1199 } else if (*tp < ' ' || *tp == 127) { 1200 co++; // display as ^X, use 2 columns 1201 } 1202 } while (tp++ < d && ++co); 1290 co = next_tabstop(co); 1291 } else if ((unsigned char)*tp < ' ' || *tp == 0x7f) { 1292 co++; // display as ^X, use 2 columns 1293 } 1294 co++; 1295 tp++; 1296 } 1203 1297 1204 1298 // "co" is the column where "dot" is. … … 1233 1327 1234 1328 //----- Text Movement Routines --------------------------------- 1235 static char *begin_line(char * p) // return pointer to first char cur line 1236 { 1237 while (p > text && p[-1] != '\n') 1238 p--; // go to cur line B-o-l 1329 static char *begin_line(char *p) // return pointer to first char cur line 1330 { 1331 if (p > text) { 1332 p = memrchr(text, '\n', p - text); 1333 if (!p) 1334 return text; 1335 return p + 1; 1336 } 1239 1337 return p; 1240 1338 } 1241 1339 1242 static char *end_line(char * p) // return pointer to NL of cur line line 1243 { 1244 while (p < end - 1 && *p != '\n') 1245 p++; // go to cur line E-o-l 1340 static char *end_line(char *p) // return pointer to NL of cur line 1341 { 1342 if (p < end - 1) { 1343 p = memchr(p, '\n', end - p - 1); 1344 if (!p) 1345 return end - 1; 1346 } 1246 1347 return p; 1247 1348 } 1248 1349 1249 static inline char *dollar_line(char * p) // return pointer to just before NL line 1250 { 1251 while (p < end - 1 && *p != '\n') 1252 p++; // go to cur line E-o-l 1350 static char *dollar_line(char *p) // return pointer to just before NL line 1351 { 1352 p = end_line(p); 1253 1353 // Try to stay off of the Newline 1254 1354 if (*p == '\n' && (p - begin_line(p)) > 0) … … 1257 1357 } 1258 1358 1259 static char *prev_line(char * 1359 static char *prev_line(char *p) // return pointer first char prev line 1260 1360 { 1261 1361 p = begin_line(p); // goto begining of cur line 1262 if (p [-1] == '\n' && p > text)1362 if (p > text && p[-1] == '\n') 1263 1363 p--; // step to prev line 1264 1364 p = begin_line(p); // goto begining of prev line … … 1266 1366 } 1267 1367 1268 static char *next_line(char * 1368 static char *next_line(char *p) // return pointer first char next line 1269 1369 { 1270 1370 p = end_line(p); 1271 if ( *p == '\n' && p < end - 1)1371 if (p < end - 1 && *p == '\n') 1272 1372 p++; // step to next line 1273 1373 return p; … … 1288 1388 } 1289 1389 1290 static int count_lines(char * start, char * stop) // count line from start to stop 1390 // count line from start to stop 1391 static int count_lines(char *start, char *stop) 1291 1392 { 1292 1393 char *q; 1293 1394 int cnt; 1294 1395 1295 if (stop < start) { 1396 if (stop < start) { // start and stop are backwards- reverse them 1296 1397 q = start; 1297 1398 start = stop; … … 1299 1400 } 1300 1401 cnt = 0; 1301 stop = end_line(stop); // get to end of this line 1302 for (q = start; q <= stop && q <= end - 1; q++) { 1303 if (*q == '\n') 1402 stop = end_line(stop); 1403 while (start <= stop && start <= end - 1) { 1404 start = end_line(start); 1405 if (*start == '\n') 1304 1406 cnt++; 1407 start++; 1305 1408 } 1306 1409 return cnt; … … 1340 1443 } 1341 1444 1342 static char *move_to_col(char * 1445 static char *move_to_col(char *p, int l) 1343 1446 { 1344 1447 int co; … … 1346 1449 p = begin_line(p); 1347 1450 co = 0; 1348 do{1349 if (*p == '\n' || *p == '\0')1451 while (co < l && p < end) { 1452 if (*p == '\n') //vda || *p == '\0') 1350 1453 break; 1351 1454 if (*p == '\t') { 1352 1455 co = next_tabstop(co); 1353 1456 } else if (*p < ' ' || *p == 127) { 1354 co++; // display as ^X, use 2 columns 1355 } 1356 } while (++co <= l && p++ < end); 1457 co++; // display as ^X, use 2 columns 1458 } 1459 co++; 1460 p++; 1461 } 1357 1462 return p; 1358 1463 } … … 1375 1480 if (dir < 0) { 1376 1481 // scroll Backwards 1377 // ctrl-Y 1482 // ctrl-Y scroll up one line 1378 1483 screenbegin = prev_line(screenbegin); 1379 1484 } else { 1380 1485 // scroll Forwards 1381 // ctrl-E 1486 // ctrl-E scroll down one line 1382 1487 screenbegin = next_line(screenbegin); 1383 1488 } … … 1404 1509 } 1405 1510 1406 static char *bound_dot(char * 1511 static char *bound_dot(char *p) // make sure text[0] <= P < "end" 1407 1512 { 1408 1513 if (p >= end && end > text) { … … 1447 1552 1448 1553 #if ENABLE_FEATURE_VI_SEARCH 1449 static int mycmp(const char * s1, const char * s2, int len) 1450 { 1451 int i; 1452 1453 i = strncmp(s1, s2, len); 1554 static int mycmp(const char *s1, const char *s2, int len) 1555 { 1454 1556 if (ENABLE_FEATURE_VI_SETOPTS && ignorecase) { 1455 i =strncasecmp(s1, s2, len);1456 } 1457 return i;1557 return strncasecmp(s1, s2, len); 1558 } 1559 return strncmp(s1, s2, len); 1458 1560 } 1459 1561 1460 1562 // search for pattern starting at p 1461 static char *char_search(char * p, const char *pat, int dir, int range)1563 static char *char_search(char *p, const char *pat, int dir, int range) 1462 1564 { 1463 1565 #ifndef REGEX_SEARCH … … 1517 1619 if (q != 0) { 1518 1620 // The pattern was not compiled 1519 psbs("bad search pattern: \"%s\": %s", pat, q);1621 status_line_bold("bad search pattern: \"%s\": %s", pat, q); 1520 1622 i = 0; // return p if pattern not compiled 1521 1623 goto cs1; … … 1552 1654 #endif /* FEATURE_VI_SEARCH */ 1553 1655 1554 static char *char_insert(char * 1656 static char *char_insert(char *p, char c) // insert the char c at 'p' 1555 1657 { 1556 1658 if (c == 22) { // Is this an ctrl-V? 1557 p = stupid_insert(p, '^'); // use ^ to indicate literal next 1558 p--; // backup onto ^ 1659 p += stupid_insert(p, '^'); // use ^ to indicate literal next 1559 1660 refresh(FALSE); // show the ^ 1560 1661 c = get_one_char(); 1561 1662 *p = c; 1562 1663 p++; 1563 file_modified++; // has the file been modified1664 file_modified++; 1564 1665 } else if (c == 27) { // Is this an ESC? 1565 1666 cmd_mode = 0; … … 1583 1684 c = '\n'; // translate \r to \n 1584 1685 sp = p; // remember addr of insert 1585 p =stupid_insert(p, c); // insert the char1686 p += 1 + stupid_insert(p, c); // insert the char 1586 1687 #if ENABLE_FEATURE_VI_SETOPTS 1587 1688 if (showmatch && strchr(")]}", *sp) != NULL) { … … 1590 1691 if (autoindent && c == '\n') { // auto indent the new line 1591 1692 char *q; 1592 1593 q = prev_line(p); // use prev line as templet 1594 for (; isblank(*q); q++) { 1595 p = stupid_insert(p, *q); // insert the char 1693 size_t len; 1694 q = prev_line(p); // use prev line as template 1695 len = strspn(q, " \t"); // space or tab 1696 if (len) { 1697 uintptr_t bias; 1698 bias = text_hole_make(p, len); 1699 p += bias; 1700 q += bias; 1701 memcpy(p, q, len); 1702 p += len; 1596 1703 } 1597 1704 } … … 1601 1708 } 1602 1709 1603 static char *stupid_insert(char * p, char c) // stupidly insert the char c at 'p' 1604 { 1605 p = text_hole_make(p, 1); 1606 if (p != 0) { 1607 *p = c; 1608 file_modified++; // has the file been modified 1609 p++; 1610 } 1611 return p; 1612 } 1613 1614 static char find_range(char ** start, char ** stop, char c) 1615 { 1616 char *save_dot, *p, *q; 1617 int cnt; 1710 // might reallocate text[]! use p += stupid_insert(p, ...), 1711 // and be careful to not use pointers into potentially freed text[]! 1712 static uintptr_t stupid_insert(char *p, char c) // stupidly insert the char c at 'p' 1713 { 1714 uintptr_t bias; 1715 bias = text_hole_make(p, 1); 1716 p += bias; 1717 *p = c; 1718 //file_modified++; - done by text_hole_make() 1719 return bias; 1720 } 1721 1722 static int find_range(char **start, char **stop, char c) 1723 { 1724 char *save_dot, *p, *q, *t; 1725 int cnt, multiline = 0; 1618 1726 1619 1727 save_dot = dot; … … 1627 1735 } 1628 1736 q = end_line(q); 1629 } else if (strchr("^%$0bBeEft ", c)) {1737 } else if (strchr("^%$0bBeEfth\b\177", c)) { 1630 1738 // These cmds operate on char positions 1631 1739 do_cmd(c); // execute movement cmd … … 1656 1764 q = dot; 1657 1765 } else { 1658 c = 27; // error- return an ESC char 1659 //break; 1660 } 1766 // nothing -- this causes any other values of c to 1767 // represent the one-character range under the 1768 // cursor. this is correct for ' ' and 'l', but 1769 // perhaps no others. 1770 // 1771 } 1772 if (q < p) { 1773 t = q; 1774 q = p; 1775 p = t; 1776 } 1777 1778 // backward char movements don't include start position 1779 if (q > p && strchr("^0bBh\b\177", c)) q--; 1780 1781 multiline = 0; 1782 for (t = p; t <= q; t++) { 1783 if (*t == '\n') { 1784 multiline = 1; 1785 break; 1786 } 1787 } 1788 1661 1789 *start = p; 1662 1790 *stop = q; 1663 if (q < p) {1664 *start = q;1665 *stop = p;1666 }1667 1791 dot = save_dot; 1668 return c;1669 } 1670 1671 static int st_test(char * p, int type, int dir, char *tested)1792 return multiline; 1793 } 1794 1795 static int st_test(char *p, int type, int dir, char *tested) 1672 1796 { 1673 1797 char c, c0, ci; … … 1681 1805 if (type == S_BEFORE_WS) { 1682 1806 c = ci; 1683 test = ( (!isspace(c)) || c == '\n');1807 test = (!isspace(c) || c == '\n'); 1684 1808 } 1685 1809 if (type == S_TO_WS) { 1686 1810 c = c0; 1687 test = ( (!isspace(c)) || c == '\n');1811 test = (!isspace(c) || c == '\n'); 1688 1812 } 1689 1813 if (type == S_OVER_WS) { 1690 1814 c = c0; 1691 test = ((isspace(c)));1815 test = isspace(c); 1692 1816 } 1693 1817 if (type == S_END_PUNCT) { 1694 1818 c = ci; 1695 test = ((ispunct(c)));1819 test = ispunct(c); 1696 1820 } 1697 1821 if (type == S_END_ALNUM) { 1698 1822 c = ci; 1699 test = ( (isalnum(c)) || c == '_');1823 test = (isalnum(c) || c == '_'); 1700 1824 } 1701 1825 *tested = c; … … 1703 1827 } 1704 1828 1705 static char *skip_thing(char * 1829 static char *skip_thing(char *p, int linecnt, int dir, int type) 1706 1830 { 1707 1831 char c; … … 1721 1845 1722 1846 // find matching char of pair () [] {} 1723 static char *find_pair(char * p,char c)1847 static char *find_pair(char *p, const char c) 1724 1848 { 1725 1849 char match, *q; … … 1730 1854 dir = 1; // assume forward 1731 1855 switch (c) { 1732 case '(': 1733 match = ')'; 1734 break; 1735 case '[': 1736 match = ']'; 1737 break; 1738 case '{': 1739 match = '}'; 1740 break; 1741 case ')': 1742 match = '('; 1743 dir = -1; 1744 break; 1745 case ']': 1746 match = '['; 1747 dir = -1; 1748 break; 1749 case '}': 1750 match = '{'; 1751 dir = -1; 1752 break; 1856 case '(': match = ')'; break; 1857 case '[': match = ']'; break; 1858 case '{': match = '}'; break; 1859 case ')': match = '('; dir = -1; break; 1860 case ']': match = '['; dir = -1; break; 1861 case '}': match = '{'; dir = -1; break; 1753 1862 } 1754 1863 for (q = p + dir; text <= q && q < end; q += dir) { … … 1768 1877 #if ENABLE_FEATURE_VI_SETOPTS 1769 1878 // show the matching char of a pair, () [] {} 1770 static void showmatching(char * 1879 static void showmatching(char *p) 1771 1880 { 1772 1881 char *q, *save_dot; … … 1788 1897 #endif /* FEATURE_VI_SETOPTS */ 1789 1898 1790 // open a hole in text[] 1791 static char *text_hole_make(char * p, int size) // at "p", make a 'size' byte hole 1792 { 1793 char *src, *dest; 1794 int cnt; 1899 // open a hole in text[] 1900 // might reallocate text[]! use p += text_hole_make(p, ...), 1901 // and be careful to not use pointers into potentially freed text[]! 1902 static uintptr_t text_hole_make(char *p, int size) // at "p", make a 'size' byte hole 1903 { 1904 uintptr_t bias = 0; 1795 1905 1796 1906 if (size <= 0) 1797 goto thm0; 1798 src = p; 1799 dest = p + size; 1800 cnt = end - src; // the rest of buffer 1801 if ( ((end + size) >= (text + text_size)) // TODO: realloc here 1802 || memmove(dest, src, cnt) != dest) { 1803 psbs("can't create room for new characters"); 1804 p = NULL; 1805 goto thm0; 1806 } 1907 return bias; 1908 end += size; // adjust the new END 1909 if (end >= (text + text_size)) { 1910 char *new_text; 1911 text_size += end - (text + text_size) + 10240; 1912 new_text = xrealloc(text, text_size); 1913 bias = (new_text - text); 1914 screenbegin += bias; 1915 dot += bias; 1916 end += bias; 1917 p += bias; 1918 text = new_text; 1919 } 1920 memmove(p + size, p, end - size - p); 1807 1921 memset(p, ' ', size); // clear new hole 1808 end += size; // adjust the new END 1809 file_modified++; // has the file been modified 1810 thm0: 1811 return p; 1922 file_modified++; 1923 return bias; 1812 1924 } 1813 1925 1814 1926 // close a hole in text[] 1815 static char *text_hole_delete(char * p, char * q) // delete "p" thru"q", inclusive1927 static char *text_hole_delete(char *p, char *q) // delete "p" through "q", inclusive 1816 1928 { 1817 1929 char *src, *dest; … … 1834 1946 if (src >= end) 1835 1947 goto thd_atend; // just delete the end of the buffer 1836 if (memmove(dest, src, cnt) != dest) { 1837 psbs("can't delete the character"); 1838 } 1948 memmove(dest, src, cnt); 1839 1949 thd_atend: 1840 1950 end = end - hole_size; // adjust the new END … … 1843 1953 if (end <= text) 1844 1954 dest = end = text; // keep pointers valid 1845 file_modified++; // has the file been modified1955 file_modified++; 1846 1956 thd0: 1847 1957 return dest; … … 1851 1961 // if dist <= 0, do not include, or go past, a NewLine 1852 1962 // 1853 static char *yank_delete(char * start, char *stop, int dist, int yf)1963 static char *yank_delete(char *start, char *stop, int dist, int yf) 1854 1964 { 1855 1965 char *p; … … 1895 2005 #endif 1896 2006 #if ENABLE_FEATURE_VI_YANKMARK 1897 "\n\tLine marking with 1898 "\n\tNamed buffers with 2007 "\n\tLine marking with 'x" 2008 "\n\tNamed buffers with \"x" 1899 2009 #endif 1900 2010 #if ENABLE_FEATURE_VI_READONLY … … 1918 2028 } 1919 2029 1920 static inline void print_literal(char * buf, const char * s) // copy s to buf, convert unprintable1921 {1922 unsigned char c;1923 char b[2];1924 1925 b[1] = '\0';1926 buf[0] = '\0';1927 if (!s[0])1928 s = "(NULL)";1929 for (; *s; s++) {1930 int c_is_no_print;1931 1932 c = *s;1933 c_is_no_print = (c & 0x80) && !Isprint(c);1934 if (c_is_no_print) {1935 strcat(buf, SOn);1936 c = '.';1937 }1938 if (c < ' ' || c == 127) {1939 strcat(buf, "^");1940 if (c == 127)1941 c = '?';1942 else1943 c += '@';1944 }1945 b[0] = c;1946 strcat(buf, b);1947 if (c_is_no_print)1948 strcat(buf, SOs);1949 if (*s == '\n')1950 strcat(buf, "$");1951 }1952 }1953 1954 2030 #if ENABLE_FEATURE_VI_DOT_CMD 1955 2031 static void start_new_cmd_q(char c) 1956 2032 { 1957 // release old cmd1958 free(last_modifying_cmd);1959 2033 // get buffer for new cmd 1960 last_modifying_cmd = xzalloc(MAX_LINELEN);1961 2034 // if there is a current cmd count put it in the buffer first 1962 if (cmdcnt > 0) 1963 sprintf(last_modifying_cmd, "%d%c", cmdcnt, c);1964 else// just save char c onto queue2035 if (cmdcnt > 0) { 2036 lmc_len = sprintf(last_modifying_cmd, "%d%c", cmdcnt, c); 2037 } else { // just save char c onto queue 1965 2038 last_modifying_cmd[0] = c; 2039 lmc_len = 1; 2040 } 1966 2041 adding2q = 1; 1967 2042 } … … 1979 2054 || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) \ 1980 2055 || ENABLE_FEATURE_VI_CRASHME 1981 static char *string_insert(char * p, char * s) // insert the string at 'p' 1982 { 1983 int cnt, i; 2056 // might reallocate text[]! use p += string_insert(p, ...), 2057 // and be careful to not use pointers into potentially freed text[]! 2058 static uintptr_t string_insert(char *p, const char *s) // insert the string at 'p' 2059 { 2060 uintptr_t bias; 2061 int i; 1984 2062 1985 2063 i = strlen(s); 1986 if (text_hole_make(p, i)) { 1987 strncpy(p, s, i); 2064 bias = text_hole_make(p, i); 2065 p += bias; 2066 memcpy(p, s, i); 2067 #if ENABLE_FEATURE_VI_YANKMARK 2068 { 2069 int cnt; 1988 2070 for (cnt = 0; *s != '\0'; s++) { 1989 2071 if (*s == '\n') 1990 2072 cnt++; 1991 2073 } 2074 status_line("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); 2075 } 2076 #endif 2077 return bias; 2078 } 2079 #endif 2080 1992 2081 #if ENABLE_FEATURE_VI_YANKMARK 1993 psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); 1994 #endif 1995 } 1996 return p; 1997 } 1998 #endif 1999 2000 #if ENABLE_FEATURE_VI_YANKMARK 2001 static char *text_yank(char * p, char * q, int dest) // copy text into a register 2002 { 2003 char *t; 2004 int cnt; 2005 2006 if (q < p) { // they are backwards- reverse them 2007 t = q; 2008 q = p; 2009 p = t; 2010 } 2011 cnt = q - p + 1; 2012 t = reg[dest]; 2013 free(t); // if already a yank register, free it 2014 t = xmalloc(cnt + 1); // get a new register 2015 memset(t, '\0', cnt + 1); // clear new text[] 2016 strncpy(t, p, cnt); // copy text[] into bufer 2017 reg[dest] = t; 2082 static char *text_yank(char *p, char *q, int dest) // copy text into a register 2083 { 2084 int cnt = q - p; 2085 if (cnt < 0) { // they are backwards- reverse them 2086 p = q; 2087 cnt = -cnt; 2088 } 2089 free(reg[dest]); // if already a yank register, free it 2090 reg[dest] = xstrndup(p, cnt + 1); 2018 2091 return p; 2019 2092 } … … 2050 2123 } 2051 2124 2052 static inline char *swap_context(char *p) // goto new context for '' command make this the current context2125 static char *swap_context(char *p) // goto new context for '' command make this the current context 2053 2126 { 2054 2127 char *tmp; … … 2080 2153 term_vi.c_cc[VTIME] = 0; 2081 2154 erase_char = term_vi.c_cc[VERASE]; 2082 tcsetattr (0, TCSANOW,&term_vi);2155 tcsetattr_stdin_TCSANOW(&term_vi); 2083 2156 } 2084 2157 2085 2158 static void cookmode(void) 2086 2159 { 2087 fflush(stdout); 2088 tcsetattr(0, TCSANOW, &term_orig); 2089 } 2090 2160 fflush_all(); 2161 tcsetattr_stdin_TCSANOW(&term_orig); 2162 } 2163 2164 #if ENABLE_FEATURE_VI_USE_SIGNALS 2091 2165 //----- Come here when we get a window resize signal --------- 2092 #if ENABLE_FEATURE_VI_USE_SIGNALS 2093 static void winch_sig(int sig ATTRIBUTE_UNUSED) 2094 { 2166 static void winch_sig(int sig UNUSED_PARAM) 2167 { 2168 int save_errno = errno; 2169 // FIXME: do it in main loop!!! 2095 2170 signal(SIGWINCH, winch_sig); 2096 if (ENABLE_FEATURE_VI_WIN_RESIZE) 2097 get_terminal_width_height(0, &columns, &rows); 2171 query_screen_dimensions(); 2098 2172 new_screen(rows, columns); // get memory for virtual screen 2099 2173 redraw(TRUE); // re-draw the screen 2174 errno = save_errno; 2100 2175 } 2101 2176 2102 2177 //----- Come here when we get a continue signal ------------------- 2103 static void cont_sig(int sig ATTRIBUTE_UNUSED) 2104 { 2105 rawmode(); // terminal to "raw" 2106 last_status_cksum = 0; // force status update 2107 redraw(TRUE); // re-draw the screen 2178 static void cont_sig(int sig UNUSED_PARAM) 2179 { 2180 int save_errno = errno; 2181 rawmode(); // terminal to "raw" 2182 last_status_cksum = 0; // force status update 2183 redraw(TRUE); // re-draw the screen 2108 2184 2109 2185 signal(SIGTSTP, suspend_sig); 2110 2186 signal(SIGCONT, SIG_DFL); 2111 kill(my_pid, SIGCONT); 2187 //kill(my_pid, SIGCONT); // huh? why? we are already "continued"... 2188 errno = save_errno; 2112 2189 } 2113 2190 2114 2191 //----- Come here when we get a Suspend signal ------------------- 2115 static void suspend_sig(int sig ATTRIBUTE_UNUSED)2116 { 2117 place_cursor(rows - 1, 0, FALSE); // go to bottom of screen2118 clear_to_eol(); // Erase to end of line2119 cookmode(); 2192 static void suspend_sig(int sig UNUSED_PARAM) 2193 { 2194 int save_errno = errno; 2195 go_bottom_and_clear_to_eol(); 2196 cookmode(); // terminal to "cooked" 2120 2197 2121 2198 signal(SIGCONT, cont_sig); 2122 2199 signal(SIGTSTP, SIG_DFL); 2123 2200 kill(my_pid, SIGTSTP); 2201 errno = save_errno; 2124 2202 } 2125 2203 … … 2128 2206 { 2129 2207 signal(SIGINT, catch_sig); 2130 if (sig) 2131 longjmp(restart, sig); 2208 siglongjmp(restart, sig); 2132 2209 } 2133 2210 #endif /* FEATURE_VI_USE_SIGNALS */ 2134 2211 2135 static int mysleep(int hund) // sleep for 'h' 1/100 seconds 2136 { 2137 fd_set rfds; 2138 struct timeval tv; 2139 2140 // Don't hang- Wait 5/100 seconds- 1 Sec= 1000000 2141 fflush(stdout); 2142 FD_ZERO(&rfds); 2143 FD_SET(0, &rfds); 2144 tv.tv_sec = 0; 2145 tv.tv_usec = hund * 10000; 2146 select(1, &rfds, NULL, NULL, &tv); 2147 return FD_ISSET(0, &rfds); 2148 } 2149 2150 #define readbuffer bb_common_bufsiz1 2151 2152 static int readed_for_parse; 2212 static int mysleep(int hund) // sleep for 'hund' 1/100 seconds or stdin ready 2213 { 2214 struct pollfd pfd[1]; 2215 2216 pfd[0].fd = STDIN_FILENO; 2217 pfd[0].events = POLLIN; 2218 return safe_poll(pfd, 1, hund*10) > 0; 2219 } 2153 2220 2154 2221 //----- IO Routines -------------------------------------------- 2155 static char readit(void) // read (maybe cursor) key from stdin 2156 { 2157 char c; 2158 int n; 2159 struct esc_cmds { 2160 const char *seq; 2161 char val; 2162 }; 2163 2164 static const struct esc_cmds esccmds[] = { 2165 {"OA", VI_K_UP}, // cursor key Up 2166 {"OB", VI_K_DOWN}, // cursor key Down 2167 {"OC", VI_K_RIGHT}, // Cursor Key Right 2168 {"OD", VI_K_LEFT}, // cursor key Left 2169 {"OH", VI_K_HOME}, // Cursor Key Home 2170 {"OF", VI_K_END}, // Cursor Key End 2171 {"[A", VI_K_UP}, // cursor key Up 2172 {"[B", VI_K_DOWN}, // cursor key Down 2173 {"[C", VI_K_RIGHT}, // Cursor Key Right 2174 {"[D", VI_K_LEFT}, // cursor key Left 2175 {"[H", VI_K_HOME}, // Cursor Key Home 2176 {"[F", VI_K_END}, // Cursor Key End 2177 {"[1~", VI_K_HOME}, // Cursor Key Home 2178 {"[2~", VI_K_INSERT}, // Cursor Key Insert 2179 {"[4~", VI_K_END}, // Cursor Key End 2180 {"[5~", VI_K_PAGEUP}, // Cursor Key Page Up 2181 {"[6~", VI_K_PAGEDOWN},// Cursor Key Page Down 2182 {"OP", VI_K_FUN1}, // Function Key F1 2183 {"OQ", VI_K_FUN2}, // Function Key F2 2184 {"OR", VI_K_FUN3}, // Function Key F3 2185 {"OS", VI_K_FUN4}, // Function Key F4 2186 {"[15~", VI_K_FUN5}, // Function Key F5 2187 {"[17~", VI_K_FUN6}, // Function Key F6 2188 {"[18~", VI_K_FUN7}, // Function Key F7 2189 {"[19~", VI_K_FUN8}, // Function Key F8 2190 {"[20~", VI_K_FUN9}, // Function Key F9 2191 {"[21~", VI_K_FUN10}, // Function Key F10 2192 {"[23~", VI_K_FUN11}, // Function Key F11 2193 {"[24~", VI_K_FUN12}, // Function Key F12 2194 {"[11~", VI_K_FUN1}, // Function Key F1 2195 {"[12~", VI_K_FUN2}, // Function Key F2 2196 {"[13~", VI_K_FUN3}, // Function Key F3 2197 {"[14~", VI_K_FUN4}, // Function Key F4 2198 }; 2199 enum { ESCCMDS_COUNT = ARRAY_SIZE(esccmds) }; 2200 2201 alarm(0); // turn alarm OFF while we wait for input 2202 fflush(stdout); 2203 n = readed_for_parse; 2204 // get input from User- are there already input chars in Q? 2205 if (n <= 0) { 2206 ri0: 2207 // the Q is empty, wait for a typed char 2208 n = read(0, readbuffer, MAX_LINELEN - 1); 2209 if (n < 0) { 2210 if (errno == EINTR) 2211 goto ri0; // interrupted sys call 2212 if (errno == EBADF || errno == EFAULT || errno == EINVAL 2213 || errno == EIO) 2214 editing = 0; 2215 errno = 0; 2216 } 2217 if (n <= 0) 2218 return 0; // error 2219 if (readbuffer[0] == 27) { 2220 fd_set rfds; 2221 struct timeval tv; 2222 2223 // This is an ESC char. Is this Esc sequence? 2224 // Could be bare Esc key. See if there are any 2225 // more chars to read after the ESC. This would 2226 // be a Function or Cursor Key sequence. 2227 FD_ZERO(&rfds); 2228 FD_SET(0, &rfds); 2229 tv.tv_sec = 0; 2230 tv.tv_usec = 50000; // Wait 5/100 seconds- 1 Sec=1000000 2231 2232 // keep reading while there are input chars and room in buffer 2233 while (select(1, &rfds, NULL, NULL, &tv) > 0 && n <= (MAX_LINELEN - 5)) { 2234 // read the rest of the ESC string 2235 int r = read(0, (void *) (readbuffer + n), MAX_LINELEN - n); 2236 if (r > 0) { 2237 n += r; 2238 } 2239 } 2240 } 2241 readed_for_parse = n; 2242 } 2243 c = readbuffer[0]; 2244 if (c == 27 && n > 1) { 2245 // Maybe cursor or function key? 2246 const struct esc_cmds *eindex; 2247 2248 for (eindex = esccmds; eindex < &esccmds[ESCCMDS_COUNT]; eindex++) { 2249 int cnt = strlen(eindex->seq); 2250 2251 if (n <= cnt) 2252 continue; 2253 if (strncmp(eindex->seq, readbuffer + 1, cnt)) 2254 continue; 2255 // is a Cursor key- put derived value back into Q 2256 c = eindex->val; 2257 // for squeeze out the ESC sequence 2258 n = cnt + 1; 2259 break; 2260 } 2261 if (eindex == &esccmds[ESCCMDS_COUNT]) { 2262 /* defined ESC sequence not found, set only one ESC */ 2263 n = 1; 2264 } 2265 } else { 2266 n = 1; 2267 } 2268 // remove key sequence from Q 2269 readed_for_parse -= n; 2270 memmove(readbuffer, readbuffer + n, MAX_LINELEN - n); 2271 alarm(3); // we are done waiting for input, turn alarm ON 2222 static int readit(void) // read (maybe cursor) key from stdin 2223 { 2224 int c; 2225 2226 fflush_all(); 2227 c = read_key(STDIN_FILENO, readbuffer, /*timeout off:*/ -2); 2228 if (c == -1) { // EOF/error 2229 go_bottom_and_clear_to_eol(); 2230 cookmode(); // terminal to "cooked" 2231 bb_error_msg_and_die("can't read user input"); 2232 } 2272 2233 return c; 2273 2234 } 2274 2235 2275 2236 //----- IO Routines -------------------------------------------- 2276 static charget_one_char(void)2277 { 2278 static charc;2237 static int get_one_char(void) 2238 { 2239 int c; 2279 2240 2280 2241 #if ENABLE_FEATURE_VI_DOT_CMD 2281 // ! adding2q && ioq == 0 read()2282 // ! adding2q && ioq != 0 *ioq2283 // adding2q *last_modifying_cmd= read()2284 2242 if (!adding2q) { 2285 2243 // we are not adding to the q. … … 2290 2248 } else { 2291 2249 // there is a queue to get chars from first 2292 c = *ioq++; 2250 // careful with correct sign expansion! 2251 c = (unsigned char)*ioq++; 2293 2252 if (c == '\0') { 2294 2253 // the end of the q, read from STDIN … … 2301 2260 // adding STDIN chars to q 2302 2261 c = readit(); // get the users input 2303 if (last_modifying_cmd != 0) { 2304 int len = strlen(last_modifying_cmd); 2305 if (len >= MAX_LINELEN - 1) { 2306 psbs("last_modifying_cmd overrun"); 2307 } else { 2308 // add new char to q 2309 last_modifying_cmd[len] = c; 2310 } 2262 if (lmc_len >= MAX_INPUT_LEN - 1) { 2263 status_line_bold("last_modifying_cmd overrun"); 2264 } else { 2265 // add new char to q 2266 last_modifying_cmd[lmc_len++] = c; 2311 2267 } 2312 2268 } … … 2314 2270 c = readit(); // get the users input 2315 2271 #endif /* FEATURE_VI_DOT_CMD */ 2316 return c; // return the char, where ever it came from 2317 } 2318 2319 static char *get_input_line(const char * prompt) // get input line- use "status line" 2320 { 2321 static char *obufp; 2322 2323 char buf[MAX_LINELEN]; 2324 char c; 2272 return c; 2273 } 2274 2275 // Get input line (uses "status line" area) 2276 static char *get_input_line(const char *prompt) 2277 { 2278 // char [MAX_INPUT_LEN] 2279 #define buf get_input_line__buf 2280 2281 int c; 2325 2282 int i; 2326 2283 2327 2284 strcpy(buf, prompt); 2328 2285 last_status_cksum = 0; // force status update 2329 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen 2330 clear_to_eol(); // clear the line 2286 go_bottom_and_clear_to_eol(); 2331 2287 write1(prompt); // write out the :, /, or ? prompt 2332 2288 2333 2289 i = strlen(buf); 2334 while (i < MAX_ LINELEN) {2335 c = get_one_char(); // read user input2290 while (i < MAX_INPUT_LEN) { 2291 c = get_one_char(); 2336 2292 if (c == '\n' || c == '\r' || c == 27) 2337 break; // is this end of input2293 break; // this is end of input 2338 2294 if (c == erase_char || c == 8 || c == 127) { 2339 2295 // user wants to erase prev char 2340 i--; // backup to prev char 2341 buf[i] = '\0'; // erase the char 2342 buf[i + 1] = '\0'; // null terminate buffer 2343 write1("\b \b"); // erase char on screen 2344 if (i <= 0) { // user backs up before b-o-l, exit 2296 buf[--i] = '\0'; 2297 write1("\b \b"); // erase char on screen 2298 if (i <= 0) // user backs up before b-o-l, exit 2345 2299 break; 2346 } 2347 } else { 2348 buf[i] = c; // save char in buffer 2349 buf[i + 1] = '\0'; // make sure buffer is null terminated 2350 putchar(c); // echo the char back to user 2351 i++; 2300 } else if (c > 0 && c < 256) { // exclude Unicode 2301 // (TODO: need to handle Unicode) 2302 buf[i] = c; 2303 buf[++i] = '\0'; 2304 bb_putchar(c); 2352 2305 } 2353 2306 } 2354 2307 refresh(FALSE); 2355 free(obufp); 2356 obufp = xstrdup(buf); 2357 return obufp; 2308 return buf; 2309 #undef buf 2358 2310 } 2359 2311 … … 2364 2316 2365 2317 cnt = -1; 2366 if (fn && fn[0] &&stat(fn, &st_buf) == 0) // see if file exists2318 if (fn && stat(fn, &st_buf) == 0) // see if file exists 2367 2319 cnt = (int) st_buf.st_size; 2368 2320 return cnt; 2369 2321 } 2370 2322 2371 static int file_insert(const char * fn, char *p 2372 USE_FEATURE_VI_READONLY(, int update_ro_status))2323 // might reallocate text[]! 2324 static int file_insert(const char *fn, char *p, int update_ro_status) 2373 2325 { 2374 2326 int cnt = -1; … … 2378 2330 /* Validate file */ 2379 2331 if (stat(fn, &statbuf) < 0) { 2380 psbs("\"%s\" %s", fn, strerror(errno));2332 status_line_bold("\"%s\" %s", fn, strerror(errno)); 2381 2333 goto fi0; 2382 2334 } 2383 if ( (statbuf.st_mode & S_IFREG) == 0) {2335 if (!S_ISREG(statbuf.st_mode)) { 2384 2336 // This is not a regular file 2385 psbs("\"%s\" Not a regular file", fn);2337 status_line_bold("\"%s\" Not a regular file", fn); 2386 2338 goto fi0; 2387 2339 } 2388 /* // this check is done by open()2389 if ((statbuf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) {2390 // dont have any read permissions2391 psbs("\"%s\" Not readable", fn);2392 goto fi0;2393 }2394 */2395 2340 if (p < text || p > end) { 2396 psbs("Trying to insert file outside of memory");2341 status_line_bold("Trying to insert file outside of memory"); 2397 2342 goto fi0; 2398 2343 } … … 2401 2346 fd = open(fn, O_RDONLY); 2402 2347 if (fd < 0) { 2403 psbs("\"%s\" %s", fn, strerror(errno));2348 status_line_bold("\"%s\" %s", fn, strerror(errno)); 2404 2349 goto fi0; 2405 2350 } 2406 2351 size = statbuf.st_size; 2407 p = text_hole_make(p, size); 2408 if (p == NULL) 2409 goto fi0; 2410 cnt = read(fd, p, size); 2352 p += text_hole_make(p, size); 2353 cnt = safe_read(fd, p, size); 2411 2354 if (cnt < 0) { 2412 psbs("\"%s\" %s", fn, strerror(errno));2355 status_line_bold("\"%s\" %s", fn, strerror(errno)); 2413 2356 p = text_hole_delete(p, p + size - 1); // un-do buffer insert 2414 2357 } else if (cnt < size) { 2415 2358 // There was a partial read, shrink unused space text[] 2416 2359 p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert 2417 psbs("cannot read all of file \"%s\"", fn);2360 status_line_bold("can't read all of file \"%s\"", fn); 2418 2361 } 2419 2362 if (cnt >= size) … … 2435 2378 } 2436 2379 2437 2438 static int file_write(char * fn, char * first, char * last) 2380 static int file_write(char *fn, char *first, char *last) 2439 2381 { 2440 2382 int fd, cnt, charcnt; 2441 2383 2442 2384 if (fn == 0) { 2443 psbs("No current filename");2385 status_line_bold("No current filename"); 2444 2386 return -2; 2445 2387 } 2446 charcnt = 0; 2447 // FIXIT- use the correct umask() 2448 fd = open(fn, (O_WRONLY | O_CREAT | O_TRUNC), 0664); 2388 /* By popular request we do not open file with O_TRUNC, 2389 * but instead ftruncate() it _after_ successful write. 2390 * Might reduce amount of data lost on power fail etc. 2391 */ 2392 fd = open(fn, (O_WRONLY | O_CREAT), 0666); 2449 2393 if (fd < 0) 2450 2394 return -1; 2451 2395 cnt = last - first + 1; 2452 charcnt = write(fd, first, cnt); 2396 charcnt = full_write(fd, first, cnt); 2397 ftruncate(fd, charcnt); 2453 2398 if (charcnt == cnt) { 2454 2399 // good write 2455 //file_modified = FALSE; // the file has not been modified2400 //file_modified = FALSE; 2456 2401 } else { 2457 2402 charcnt = 0; … … 2470 2415 // . ... . 2471 2416 // 22,0 ... 22,79 2472 // 23,0 ... 23,79 status line 2473 // 2417 // 23,0 ... 23,79 <- status line 2474 2418 2475 2419 //----- Move the cursor to row x col (count from 0, not 1) ------- 2476 static void place_cursor(int row, int col, int opti) 2477 { 2478 char cm1[MAX_LINELEN]; 2420 static void place_cursor(int row, int col, int optimize) 2421 { 2422 char cm1[sizeof(CMrc) + sizeof(int)*3 * 2]; 2423 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2424 enum { 2425 SZ_UP = sizeof(CMup), 2426 SZ_DN = sizeof(CMdown), 2427 SEQ_SIZE = SZ_UP > SZ_DN ? SZ_UP : SZ_DN, 2428 }; 2429 char cm2[SEQ_SIZE * 5 + 32]; // bigger than worst case size 2430 #endif 2479 2431 char *cm; 2480 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR2481 char cm2[MAX_LINELEN];2482 char *screenp;2483 // char cm3[MAX_LINELEN];2484 int Rrow = last_row;2485 #endif2486 2487 memset(cm1, '\0', MAX_LINELEN); // clear the buffer2488 2432 2489 2433 if (row < 0) row = 0; … … 2495 2439 sprintf(cm1, CMrc, row + 1, col + 1); 2496 2440 cm = cm1; 2497 if (!opti)2498 goto pc0;2499 2441 2500 2442 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2501 //----- find the minimum # of chars to move cursor ------------- 2502 //----- 2. Try moving with discreet chars (Newline, [back]space, ...) 2503 memset(cm2, '\0', MAX_LINELEN); // clear the buffer 2504 2505 // move to the correct row 2506 while (row < Rrow) { 2507 // the cursor has to move up 2508 strcat(cm2, CMup); 2509 Rrow--; 2510 } 2511 while (row > Rrow) { 2512 // the cursor has to move down 2513 strcat(cm2, CMdown); 2514 Rrow++; 2515 } 2516 2517 // now move to the correct column 2518 strcat(cm2, "\r"); // start at col 0 2519 // just send out orignal source char to get to correct place 2520 screenp = &screen[row * columns]; // start of screen line 2521 strncat(cm2, screenp, col); 2522 2523 //----- 3. Try some other way of moving cursor 2524 //--------------------------------------------- 2525 2526 // pick the shortest cursor motion to send out 2527 cm = cm1; 2528 if (strlen(cm2) < strlen(cm)) { 2529 cm = cm2; 2530 } /* else if (strlen(cm3) < strlen(cm)) { 2531 cm= cm3; 2532 } */ 2443 if (optimize && col < 16) { 2444 char *screenp; 2445 int Rrow = last_row; 2446 int diff = Rrow - row; 2447 2448 if (diff < -5 || diff > 5) 2449 goto skip; 2450 2451 //----- find the minimum # of chars to move cursor ------------- 2452 //----- 2. Try moving with discreet chars (Newline, [back]space, ...) 2453 cm2[0] = '\0'; 2454 2455 // move to the correct row 2456 while (row < Rrow) { 2457 // the cursor has to move up 2458 strcat(cm2, CMup); 2459 Rrow--; 2460 } 2461 while (row > Rrow) { 2462 // the cursor has to move down 2463 strcat(cm2, CMdown); 2464 Rrow++; 2465 } 2466 2467 // now move to the correct column 2468 strcat(cm2, "\r"); // start at col 0 2469 // just send out orignal source char to get to correct place 2470 screenp = &screen[row * columns]; // start of screen line 2471 strncat(cm2, screenp, col); 2472 2473 // pick the shortest cursor motion to send out 2474 if (strlen(cm2) < strlen(cm)) { 2475 cm = cm2; 2476 } 2477 skip: ; 2478 } 2479 last_row = row; 2533 2480 #endif /* FEATURE_VI_OPTIMIZE_CURSOR */ 2534 pc0: 2535 write1(cm); // move the cursor 2481 write1(cm); 2536 2482 } 2537 2483 … … 2540 2486 { 2541 2487 write1(Ceol); // Erase from cursor to end of line 2488 } 2489 2490 static void go_bottom_and_clear_to_eol(void) 2491 { 2492 place_cursor(rows - 1, 0, FALSE); // go to bottom of screen 2493 clear_to_eol(); // erase to end of line 2542 2494 } 2543 2495 … … 2612 2564 } 2613 2565 if (have_status_msg || ((cnt > 0 && last_status_cksum != cksum))) { 2614 last_status_cksum = cksum; // remember if we have seen this line2615 place_cursor(rows - 1, 0, FALSE); // put cursor on status line2566 last_status_cksum = cksum; // remember if we have seen this line 2567 go_bottom_and_clear_to_eol(); 2616 2568 write1(status_buffer); 2617 clear_to_eol();2618 2569 if (have_status_msg) { 2619 2570 if (((int)strlen(status_buffer) - (have_status_msg - 1)) > … … 2626 2577 place_cursor(crow, ccol, FALSE); // put cursor back in correct place 2627 2578 } 2628 fflush (stdout);2579 fflush_all(); 2629 2580 } 2630 2581 2631 2582 //----- format the status buffer, the bottom line of screen ------ 2632 2583 // format status buffer, with STANDOUT mode 2633 static void psbs(const char *format, ...)2584 static void status_line_bold(const char *format, ...) 2634 2585 { 2635 2586 va_list args; … … 2637 2588 va_start(args, format); 2638 2589 strcpy(status_buffer, SOs); // Terminal standout mode on 2639 vsprintf(status_buffer + s trlen(status_buffer), format, args);2590 vsprintf(status_buffer + sizeof(SOs)-1, format, args); 2640 2591 strcat(status_buffer, SOn); // Terminal standout mode off 2641 2592 va_end(args); … … 2645 2596 2646 2597 // format status buffer 2647 static void psb(const char *format, ...)2598 static void status_line(const char *format, ...) 2648 2599 { 2649 2600 va_list args; … … 2656 2607 } 2657 2608 2658 static void ni(const char * s) // display messages 2659 { 2660 char buf[MAX_LINELEN]; 2609 // copy s to buf, convert unprintable 2610 static void print_literal(char *buf, const char *s) 2611 { 2612 char *d; 2613 unsigned char c; 2614 2615 buf[0] = '\0'; 2616 if (!s[0]) 2617 s = "(NULL)"; 2618 2619 d = buf; 2620 for (; *s; s++) { 2621 int c_is_no_print; 2622 2623 c = *s; 2624 c_is_no_print = (c & 0x80) && !Isprint(c); 2625 if (c_is_no_print) { 2626 strcpy(d, SOn); 2627 d += sizeof(SOn)-1; 2628 c = '.'; 2629 } 2630 if (c < ' ' || c == 0x7f) { 2631 *d++ = '^'; 2632 c |= '@'; /* 0x40 */ 2633 if (c == 0x7f) 2634 c = '?'; 2635 } 2636 *d++ = c; 2637 *d = '\0'; 2638 if (c_is_no_print) { 2639 strcpy(d, SOs); 2640 d += sizeof(SOs)-1; 2641 } 2642 if (*s == '\n') { 2643 *d++ = '$'; 2644 *d = '\0'; 2645 } 2646 if (d - buf > MAX_INPUT_LEN - 10) // paranoia 2647 break; 2648 } 2649 } 2650 2651 static void not_implemented(const char *s) 2652 { 2653 char buf[MAX_INPUT_LEN]; 2661 2654 2662 2655 print_literal(buf, s); 2663 psbs("\'%s\' is not implemented", buf);2664 } 2665 2666 static int format_edit_status(void)// show file status on status line2667 { 2668 static int tot; 2656 status_line_bold("\'%s\' is not implemented", buf); 2657 } 2658 2659 // show file status on status line 2660 static int format_edit_status(void) 2661 { 2669 2662 static const char cmd_mode_indicator[] ALIGN1 = "-IR-"; 2663 2664 #define tot format_edit_status__tot 2665 2670 2666 int cur, percent, ret, trunc_at; 2671 2667 … … 2718 2714 2719 2715 return trunc_at; /* had to truncate */ 2716 #undef tot 2720 2717 } 2721 2718 … … 2724 2721 { 2725 2722 place_cursor(0, 0, FALSE); // put cursor in correct place 2726 clear_to_eos(); // tel terminal to erase display2723 clear_to_eos(); // tell terminal to erase display 2727 2724 screen_erase(); // erase the internal screen buffer 2728 2725 last_status_cksum = 0; // force status update … … 2732 2729 2733 2730 //----- Format a text[] line into a buffer --------------------- 2734 static void format_line(char *dest, char *src, int li) 2735 { 2731 static char* format_line(char *src /*, int li*/) 2732 { 2733 unsigned char c; 2736 2734 int co; 2737 char c; 2738 2739 for (co = 0; co < MAX_SCR_COLS; co++) { 2740 c = ' '; // assume blank 2741 if (li > 0 && co == 0) { 2742 c = '~'; // not first line, assume Tilde 2743 } 2744 // are there chars in text[] and have we gone past the end 2745 if (text < end && src < end) { 2735 int ofs = offset; 2736 char *dest = scr_out_buf; // [MAX_SCR_COLS + MAX_TABSTOP * 2] 2737 2738 c = '~'; // char in col 0 in non-existent lines is '~' 2739 co = 0; 2740 while (co < columns + tabstop) { 2741 // have we gone past the end? 2742 if (src < end) { 2746 2743 c = *src++; 2747 } 2748 if (c == '\n') 2749 break; 2750 if ((c & 0x80) && !Isprint(c)) { 2751 c = '.'; 2752 } 2753 if ((unsigned char)(c) < ' ' || c == 0x7f) { 2754 if (c == '\t') { 2755 c = ' '; 2756 // co % 8 != 7 2757 for (; (co % tabstop) != (tabstop - 1); co++) { 2758 dest[co] = c; 2744 if (c == '\n') 2745 break; 2746 if ((c & 0x80) && !Isprint(c)) { 2747 c = '.'; 2748 } 2749 if (c < ' ' || c == 0x7f) { 2750 if (c == '\t') { 2751 c = ' '; 2752 // co % 8 != 7 2753 while ((co % tabstop) != (tabstop - 1)) { 2754 dest[co++] = c; 2755 } 2756 } else { 2757 dest[co++] = '^'; 2758 if (c == 0x7f) 2759 c = '?'; 2760 else 2761 c += '@'; // Ctrl-X -> 'X' 2759 2762 } 2760 } else {2761 dest[co++] = '^';2762 if (c == 0x7f)2763 c = '?';2764 else2765 c += '@'; // make it visible2766 2763 } 2767 2764 } 2768 // the co++ is done here so that the column will 2769 // not be overwritten when we blank-out the rest of line 2770 dest[co] = c; 2765 dest[co++] = c; 2766 // discard scrolled-off-to-the-left portion, 2767 // in tabstop-sized pieces 2768 if (ofs >= tabstop && co >= tabstop) { 2769 memmove(dest, dest + tabstop, co); 2770 co -= tabstop; 2771 ofs -= tabstop; 2772 } 2771 2773 if (src >= end) 2772 2774 break; 2773 2775 } 2776 // check "short line, gigantic offset" case 2777 if (co < ofs) 2778 ofs = co; 2779 // discard last scrolled off part 2780 co -= ofs; 2781 dest += ofs; 2782 // fill the rest with spaces 2783 if (co < columns) 2784 memset(&dest[co], ' ', columns - co); 2785 return dest; 2774 2786 } 2775 2787 … … 2781 2793 static void refresh(int full_screen) 2782 2794 { 2783 static int old_offset; 2795 #define old_offset refresh__old_offset 2784 2796 2785 2797 int li, changed; 2786 char buf[MAX_SCR_COLS];2787 2798 char *tp, *sp; // pointer into text[] and screen[] 2788 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2789 i nt last_li = -2; // last line that changed- for optimizing cursor movement2790 #endif 2791 2792 if (ENABLE_FEATURE_VI_WIN_RESIZE)2793 get_terminal_width_height(0, &columns, &rows);2799 2800 if (ENABLE_FEATURE_VI_WIN_RESIZE IF_FEATURE_VI_ASK_TERMINAL(&& !G.get_rowcol_error) ) { 2801 unsigned c = columns, r = rows; 2802 query_screen_dimensions(); 2803 full_screen |= (c - columns) | (r - rows); 2804 } 2794 2805 sync_cursor(dot, &crow, &ccol); // where cursor will be (on "dot") 2795 2806 tp = screenbegin; // index into text[] of top line … … 2798 2809 for (li = 0; li < rows - 1; li++) { 2799 2810 int cs, ce; // column start & end 2800 memset(buf, ' ', MAX_SCR_COLS); // blank-out the buffer 2801 buf[MAX_SCR_COLS-1] = 0; // NULL terminate the buffer 2802 // format current text line into buf 2803 format_line(buf, tp, li); 2811 char *out_buf; 2812 // format current text line 2813 out_buf = format_line(tp /*, li*/); 2804 2814 2805 2815 // skip to the end of the current text[] line 2806 while (tp < end && *tp++ != '\n') /*no-op*/; 2807 2808 // see if there are any changes between vitual screen and buf 2816 if (tp < end) { 2817 char *t = memchr(tp, '\n', end - tp); 2818 if (!t) t = end - 1; 2819 tp = t + 1; 2820 } 2821 2822 // see if there are any changes between vitual screen and out_buf 2809 2823 changed = FALSE; // assume no change 2810 cs = 0;2811 ce = columns-1;2824 cs = 0; 2825 ce = columns - 1; 2812 2826 sp = &screen[li * columns]; // start of screen line 2813 2827 if (full_screen) { … … 2818 2832 // look forward for first difference between buf and screen 2819 2833 for (; cs <= ce; cs++) { 2820 if ( buf[cs + offset] != sp[cs]) {2834 if (out_buf[cs] != sp[cs]) { 2821 2835 changed = TRUE; // mark for redraw 2822 2836 break; … … 2824 2838 } 2825 2839 2826 // look backward for last difference between buf and screen2827 for ( 2828 if ( buf[ce + offset] != sp[ce]) {2840 // look backward for last difference between out_buf and screen 2841 for (; ce >= cs; ce--) { 2842 if (out_buf[ce] != sp[ce]) { 2829 2843 changed = TRUE; // mark for redraw 2830 2844 break; … … 2840 2854 2841 2855 // make a sanity check of columns indexes 2842 if (cs < 0) cs = 0;2843 if (ce > columns -1) ce= columns-1;2844 if (cs > ce) { cs= 0; ce= columns-1;}2845 // is there a change between vitual screen and buf2856 if (cs < 0) cs = 0; 2857 if (ce > columns - 1) ce = columns - 1; 2858 if (cs > ce) { cs = 0; ce = columns - 1; } 2859 // is there a change between vitual screen and out_buf 2846 2860 if (changed) { 2847 // 2848 mem move(sp+cs, buf+(cs+offset), ce-cs+1);2861 // copy changed part of buffer to virtual screen 2862 memcpy(sp+cs, out_buf+cs, ce-cs+1); 2849 2863 2850 2864 // move cursor to column of first change 2851 if (offset != old_offset) { 2852 // opti_cur_move is still too stupid 2853 // to handle offsets correctly 2854 place_cursor(li, cs, FALSE); 2855 } else { 2856 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2857 // if this just the next line 2858 // try to optimize cursor movement 2859 // otherwise, use standard ESC sequence 2860 place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE); 2861 last_li= li; 2862 #else 2863 place_cursor(li, cs, FALSE); // use standard ESC sequence 2864 #endif /* FEATURE_VI_OPTIMIZE_CURSOR */ 2865 } 2865 //if (offset != old_offset) { 2866 // // place_cursor is still too stupid 2867 // // to handle offsets correctly 2868 // place_cursor(li, cs, FALSE); 2869 //} else { 2870 place_cursor(li, cs, TRUE); 2871 //} 2866 2872 2867 2873 // write line out to terminal 2868 { 2869 int nic = ce - cs + 1; 2870 char *out = sp + cs; 2871 2872 while (nic-- > 0) { 2873 putchar(*out); 2874 out++; 2875 } 2876 } 2877 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2878 last_row = li; 2879 #endif 2880 } 2881 } 2882 2883 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2884 place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE); 2885 last_row = crow; 2886 #else 2887 place_cursor(crow, ccol, FALSE); 2888 #endif 2889 2890 if (offset != old_offset) 2891 old_offset = offset; 2874 fwrite(&sp[cs], ce - cs + 1, 1, stdout); 2875 } 2876 } 2877 2878 place_cursor(crow, ccol, TRUE); 2879 2880 old_offset = offset; 2881 #undef old_offset 2892 2882 } 2893 2883 … … 2914 2904 2915 2905 //----- Execute a Vi Command ----------------------------------- 2916 static void do_cmd(char c) 2917 { 2918 const char *msg; 2919 char c1, *p, *q, buf[9], *save_dot; 2920 int cnt, i, j, dir, yf; 2921 2922 c1 = c; // quiet the compiler 2923 cnt = yf = dir = 0; // quiet the compiler 2924 msg = p = q = save_dot = buf; // quiet the compiler 2925 memset(buf, '\0', 9); // clear buf 2906 static void do_cmd(int c) 2907 { 2908 const char *msg = msg; // for compiler 2909 char *p, *q, *save_dot; 2910 char buf[12]; 2911 int dir; 2912 int cnt, i, j; 2913 int c1; 2914 2915 // c1 = c; // quiet the compiler 2916 // cnt = yf = 0; // quiet the compiler 2917 // msg = p = q = save_dot = buf; // quiet the compiler 2918 memset(buf, '\0', 12); 2926 2919 2927 2920 show_status_line(); … … 2929 2922 /* if this is a cursor key, skip these checks */ 2930 2923 switch (c) { 2931 case VI_K_UP: 2932 case VI_K_DOWN: 2933 case VI_K_LEFT: 2934 case VI_K_RIGHT: 2935 case VI_K_HOME: 2936 case VI_K_END: 2937 case VI_K_PAGEUP: 2938 case VI_K_PAGEDOWN: 2924 case KEYCODE_UP: 2925 case KEYCODE_DOWN: 2926 case KEYCODE_LEFT: 2927 case KEYCODE_RIGHT: 2928 case KEYCODE_HOME: 2929 case KEYCODE_END: 2930 case KEYCODE_PAGEUP: 2931 case KEYCODE_PAGEDOWN: 2932 case KEYCODE_DELETE: 2939 2933 goto key_cmd_mode; 2940 2934 } … … 2942 2936 if (cmd_mode == 2) { 2943 2937 // flip-flop Insert/Replace mode 2944 if (c == VI_K_INSERT)2938 if (c == KEYCODE_INSERT) 2945 2939 goto dc_i; 2946 2940 // we are 'R'eplacing the current *dot with new char … … 2959 2953 if (cmd_mode == 1) { 2960 2954 // hitting "Insert" twice means "R" replace mode 2961 if (c == VI_K_INSERT) goto dc5;2955 if (c == KEYCODE_INSERT) goto dc5; 2962 2956 // insert the char c at "dot" 2963 2957 if (1 <= c || Isprint(c)) { … … 2995 2989 //case ')': // )- 2996 2990 //case '*': // *- 2997 //case ',': // ,-2998 2991 //case '=': // =- 2999 2992 //case '@': // @- … … 3009 3002 //case '_': // _- 3010 3003 //case '`': // `- 3011 //case 'g': // g-3012 3004 //case 'u': // u- FIXME- there is no undo 3013 3005 //case 'v': // v- 3014 default: // unrecogni sed command3006 default: // unrecognized command 3015 3007 buf[0] = c; 3016 3008 buf[1] = '\0'; 3017 if (c < ' ') { 3018 buf[0] = '^'; 3019 buf[1] = c + '@'; 3020 buf[2] = '\0'; 3021 } 3022 ni(buf); 3009 not_implemented(buf); 3023 3010 end_cmd_q(); // stop adding to q 3024 3011 case 0x00: // nul- ignore 3025 3012 break; 3026 3013 case 2: // ctrl-B scroll up full screen 3027 case VI_K_PAGEUP: // Cursor Key Page Up3014 case KEYCODE_PAGEUP: // Cursor Key Page Up 3028 3015 dot_scroll(rows - 2, -1); 3029 3016 break; 3030 #if ENABLE_FEATURE_VI_USE_SIGNALS3031 case 0x03: // ctrl-C interrupt3032 longjmp(restart, 1);3033 break;3034 case 26: // ctrl-Z suspend3035 suspend_sig(SIGTSTP);3036 break;3037 #endif3038 3017 case 4: // ctrl-D scroll down half screen 3039 3018 dot_scroll((rows - 2) / 2, 1); … … 3043 3022 break; 3044 3023 case 6: // ctrl-F scroll down full screen 3045 case VI_K_PAGEDOWN: // Cursor Key Page Down3024 case KEYCODE_PAGEDOWN: // Cursor Key Page Down 3046 3025 dot_scroll(rows - 2, 1); 3047 3026 break; … … 3050 3029 break; 3051 3030 case 'h': // h- move left 3052 case VI_K_LEFT: // cursor key Left3031 case KEYCODE_LEFT: // cursor key Left 3053 3032 case 8: // ctrl-H- move left (This may be ERASE char) 3054 3033 case 0x7f: // DEL- move left (This may be ERASE char) 3055 if ( cmdcnt-- > 1) {3034 if (--cmdcnt > 0) { 3056 3035 do_cmd(c); 3057 } // repeat cnt3036 } 3058 3037 dot_left(); 3059 3038 break; 3060 3039 case 10: // Newline ^J 3061 3040 case 'j': // j- goto next line, same col 3062 case VI_K_DOWN: // cursor key Down3063 if ( cmdcnt-- > 1) {3041 case KEYCODE_DOWN: // cursor key Down 3042 if (--cmdcnt > 0) { 3064 3043 do_cmd(c); 3065 } // repeat cnt3044 } 3066 3045 dot_next(); // go to next B-o-l 3067 3046 dot = move_to_col(dot, ccol + offset); // try stay in same col … … 3078 3057 case 13: // Carriage Return ^M 3079 3058 case '+': // +- goto next line 3080 if ( cmdcnt-- > 1) {3059 if (--cmdcnt > 0) { 3081 3060 do_cmd(c); 3082 } // repeat cnt3061 } 3083 3062 dot_next(); 3084 3063 dot_skip_over_ws(); … … 3099 3078 case ' ': // move right 3100 3079 case 'l': // move right 3101 case VI_K_RIGHT: // Cursor Key Right3102 if ( cmdcnt-- > 1) {3080 case KEYCODE_RIGHT: // Cursor Key Right 3081 if (--cmdcnt > 0) { 3103 3082 do_cmd(c); 3104 } // repeat cnt3083 } 3105 3084 dot_right(); 3106 3085 break; 3107 3086 #if ENABLE_FEATURE_VI_YANKMARK 3108 3087 case '"': // "- name a register to use for Delete/Yank 3109 c1 = get_one_char(); 3110 c1 = tolower(c1); 3111 if (islower(c1)) { 3112 YDreg = c1 - 'a'; 3088 c1 = (get_one_char() | 0x20) - 'a'; // | 0x20 is tolower() 3089 if ((unsigned)c1 <= 25) { // a-z? 3090 YDreg = c1; 3113 3091 } else { 3114 3092 indicate_error(c); … … 3116 3094 break; 3117 3095 case '\'': // '- goto a specific mark 3118 c1 = get_one_char(); 3119 c1 = tolower(c1); 3120 if (islower(c1)) { 3121 c1 = c1 - 'a'; 3096 c1 = (get_one_char() | 0x20) - 'a'; 3097 if ((unsigned)c1 <= 25) { // a-z? 3122 3098 // get the b-o-l 3123 q = mark[ (unsigned char)c1];3099 q = mark[c1]; 3124 3100 if (text <= q && q < end) { 3125 3101 dot = q; … … 3140 3116 // correct location! It could be off by many lines! 3141 3117 // Well..., at least its quick and dirty. 3142 c1 = get_one_char(); 3143 c1 = tolower(c1); 3144 if (islower(c1)) { 3145 c1 = c1 - 'a'; 3118 c1 = (get_one_char() | 0x20) - 'a'; 3119 if ((unsigned)c1 <= 25) { // a-z? 3146 3120 // remember the line 3147 mark[ (int)c1] = dot;3121 mark[c1] = dot; 3148 3122 } else { 3149 3123 indicate_error(c); … … 3153 3127 case 'p': // p- put register after 3154 3128 p = reg[YDreg]; 3155 if (p == 0) {3156 psbs("Nothing in register %c", what_reg());3129 if (p == NULL) { 3130 status_line_bold("Nothing in register %c", what_reg()); 3157 3131 break; 3158 3132 } … … 3174 3148 dot_right(); // move to right, can move to NL 3175 3149 } 3176 dot =string_insert(dot, p); // insert the string3150 string_insert(dot, p); // insert the string 3177 3151 end_cmd_q(); // stop adding to q 3178 3152 break; … … 3182 3156 q = end_line(dot); 3183 3157 p = text_hole_delete(p, q); // delete cur line 3184 p = string_insert(p, reg[Ureg]); // insert orig line3158 p += string_insert(p, reg[Ureg]); // insert orig line 3185 3159 dot = p; 3186 3160 dot_skip_over_ws(); … … 3189 3163 #endif /* FEATURE_VI_YANKMARK */ 3190 3164 case '$': // $- goto end of line 3191 case VI_K_END: // Cursor Key End 3192 if (cmdcnt-- > 1) { 3165 case KEYCODE_END: // Cursor Key End 3166 if (--cmdcnt > 0) { 3167 dot_next(); 3193 3168 do_cmd(c); 3194 } // repeat cnt3169 } 3195 3170 dot = end_line(dot); 3196 3171 break; … … 3216 3191 // dont separate these two commands. 'f' depends on ';' 3217 3192 // 3218 //**** fall thr uto ... ';'3193 //**** fall through to ... ';' 3219 3194 case ';': // ;- look at rest of line for last forward char 3220 if ( cmdcnt-- > 1) {3195 if (--cmdcnt > 0) { 3221 3196 do_cmd(';'); 3222 } // repeat cnt3197 } 3223 3198 if (last_forward_char == 0) 3224 3199 break; … … 3230 3205 dot = q; 3231 3206 break; 3207 case ',': // repeat latest 'f' in opposite direction 3208 if (--cmdcnt > 0) { 3209 do_cmd(','); 3210 } 3211 if (last_forward_char == 0) 3212 break; 3213 q = dot - 1; 3214 while (q >= text && *q != '\n' && *q != last_forward_char) { 3215 q--; 3216 } 3217 if (q >= text && *q == last_forward_char) 3218 dot = q; 3219 break; 3220 3232 3221 case '-': // -- goto prev line 3233 if ( cmdcnt-- > 1) {3222 if (--cmdcnt > 0) { 3234 3223 do_cmd(c); 3235 } // repeat cnt3224 } 3236 3225 dot_prev(); 3237 3226 dot_skip_over_ws(); … … 3241 3230 // Stuff the last_modifying_cmd back into stdin 3242 3231 // and let it be re-executed. 3243 if (last_modifying_cmd != 0) { 3232 if (lmc_len > 0) { 3233 last_modifying_cmd[lmc_len] = 0; 3244 3234 ioq = ioq_start = xstrdup(last_modifying_cmd); 3245 3235 } … … 3252 3242 buf[1] = '\0'; 3253 3243 q = get_input_line(buf); // get input line- use "status line" 3254 if (q[0] && !q[1]) 3244 if (q[0] && !q[1]) { 3245 if (last_search_pattern[0]) 3246 last_search_pattern[0] = c; 3255 3247 goto dc3; // if no pat re-use old pat 3248 } 3256 3249 if (q[0]) { // strlen(q) > 1: new pat- save it and find 3257 3250 // there is a new pat … … 3263 3256 break; 3264 3257 case 'N': // N- backward search for last pattern 3265 if ( cmdcnt-- > 1) {3258 if (--cmdcnt > 0) { 3266 3259 do_cmd(c); 3267 } // repeat cnt3260 } 3268 3261 dir = BACK; // assume BACKWARD search 3269 3262 p = dot - 1; … … 3277 3270 // search rest of text[] starting at next char 3278 3271 // if search fails return orignal "p" not the "p+1" address 3279 if ( cmdcnt-- > 1) {3272 if (--cmdcnt > 0) { 3280 3273 do_cmd(c); 3281 } // repeat cnt3274 } 3282 3275 dc3: 3283 if (last_search_pattern == 0) { 3284 msg = "No previous regular expression"; 3285 goto dc2; 3286 } 3287 if (last_search_pattern[0] == '/') { 3288 dir = FORWARD; // assume FORWARD search 3289 p = dot + 1; 3290 } 3276 dir = FORWARD; // assume FORWARD search 3277 p = dot + 1; 3291 3278 if (last_search_pattern[0] == '?') { 3292 3279 dir = BACK; … … 3317 3304 dc2: 3318 3305 if (*msg) 3319 psbs("%s", msg);3306 status_line_bold("%s", msg); 3320 3307 break; 3321 3308 case '{': // {- move backward paragraph … … 3358 3345 if (cnt <= 0) 3359 3346 break; 3360 if (strnc asecmp(p, "quit", cnt) == 03361 || strnc asecmp(p, "q!", cnt) == 0 // delete lines3347 if (strncmp(p, "quit", cnt) == 0 3348 || strncmp(p, "q!", cnt) == 0 // delete lines 3362 3349 ) { 3363 3350 if (file_modified && p[1] != '!') { 3364 psbs("No write since last change (:quit! overrides)");3351 status_line_bold("No write since last change (:quit! overrides)"); 3365 3352 } else { 3366 3353 editing = 0; 3367 3354 } 3368 } else if (strnc asecmp(p, "write", cnt) == 03369 || strnc asecmp(p, "wq", cnt) == 03370 || strnc asecmp(p, "wn", cnt) == 03371 || strncasecmp(p, "x", cnt) == 03355 } else if (strncmp(p, "write", cnt) == 0 3356 || strncmp(p, "wq", cnt) == 0 3357 || strncmp(p, "wn", cnt) == 0 3358 || (p[0] == 'x' && !p[1]) 3372 3359 ) { 3373 3360 cnt = file_write(current_filename, text, end - 1); 3374 3361 if (cnt < 0) { 3375 3362 if (cnt == -1) 3376 psbs("Write error: %s", strerror(errno));3363 status_line_bold("Write error: %s", strerror(errno)); 3377 3364 } else { 3378 3365 file_modified = 0; 3379 3366 last_file_modified = -1; 3380 psb("\"%s\" %dL, %dC", current_filename, count_lines(text, end - 1), cnt);3367 status_line("\"%s\" %dL, %dC", current_filename, count_lines(text, end - 1), cnt); 3381 3368 if (p[0] == 'x' || p[1] == 'q' || p[1] == 'n' 3382 3369 || p[0] == 'X' || p[1] == 'Q' || p[1] == 'N' … … 3385 3372 } 3386 3373 } 3387 } else if (strnc asecmp(p, "file", cnt) == 0) {3374 } else if (strncmp(p, "file", cnt) == 0) { 3388 3375 last_status_cksum = 0; // force status update 3389 3376 } else if (sscanf(p, "%d", &j) > 0) { 3390 3377 dot = find_line(j); // go to line # j 3391 3378 dot_skip_over_ws(); 3392 } else { // unrecogni sed cmd3393 n i(p);3379 } else { // unrecognized cmd 3380 not_implemented(p); 3394 3381 } 3395 3382 #endif /* !FEATURE_VI_COLON */ … … 3427 3414 case 'A': // A- append at e-o-l 3428 3415 dot_end(); // go to e-o-l 3429 //**** fall thr uto ... 'a'3416 //**** fall through to ... 'a' 3430 3417 case 'a': // a- append after current char 3431 3418 if (*dot != '\n') … … 3436 3423 case 'E': // E- end of a blank-delimited word 3437 3424 case 'W': // W- forward a blank-delimited word 3438 if ( cmdcnt-- > 1) {3425 if (--cmdcnt > 0) { 3439 3426 do_cmd(c); 3440 } // repeat cnt3427 } 3441 3428 dir = FORWARD; 3442 3429 if (c == 'B') … … 3462 3449 #endif 3463 3450 break; 3451 case 'g': // 'gg' goto a line number (vim) (default: very first line) 3452 c1 = get_one_char(); 3453 if (c1 != 'g') { 3454 buf[0] = 'g'; 3455 buf[1] = c1; // TODO: if Unicode? 3456 buf[2] = '\0'; 3457 not_implemented(buf); 3458 break; 3459 } 3460 if (cmdcnt == 0) 3461 cmdcnt = 1; 3462 /* fall through */ 3464 3463 case 'G': // G- goto to a line number (default= E-O-F) 3465 3464 dot = end - 1; // assume E-O-F … … 3474 3473 cmdcnt = (rows - 1); 3475 3474 } 3476 if ( cmdcnt-- > 1) {3475 if (--cmdcnt > 0) { 3477 3476 do_cmd('+'); 3478 } // repeat cnt3477 } 3479 3478 dot_skip_over_ws(); 3480 3479 break; … … 3482 3481 dot_begin(); // 0 3483 3482 dot_skip_over_ws(); 3484 //**** fall thr uto ... 'i'3483 //**** fall through to ... 'i' 3485 3484 case 'i': // i- insert before current char 3486 case VI_K_INSERT: // Cursor Key Insert3485 case KEYCODE_INSERT: // Cursor Key Insert 3487 3486 dc_i: 3488 3487 cmd_mode = 1; // start insrting 3489 3488 break; 3490 3489 case 'J': // J- join current and next lines together 3491 if ( cmdcnt-- > 2) {3490 if (--cmdcnt > 1) { 3492 3491 do_cmd(c); 3493 } // repeat cnt3492 } 3494 3493 dot_end(); // move to NL 3495 3494 if (dot < end - 1) { // make sure not last char in text[] … … 3507 3506 cmdcnt = (rows - 1); 3508 3507 } 3509 if ( cmdcnt-- > 1) {3508 if (--cmdcnt > 0) { 3510 3509 do_cmd('-'); 3511 } // repeat cnt3510 } 3512 3511 dot_begin(); 3513 3512 dot_skip_over_ws(); … … 3537 3536 cmd_mode = 2; 3538 3537 break; 3538 case KEYCODE_DELETE: 3539 c = 'x'; 3540 // fall through 3539 3541 case 'X': // X- delete char before dot 3540 3542 case 'x': // x- delete the current char 3541 3543 case 's': // s- substitute the current char 3542 if ( cmdcnt-- > 1) {3544 if (--cmdcnt > 0) { 3543 3545 do_cmd(c); 3544 } // repeat cnt3546 } 3545 3547 dir = 0; 3546 3548 if (c == 'X') … … 3564 3566 if (file_modified) { 3565 3567 if (ENABLE_FEATURE_VI_READONLY && readonly_mode) { 3566 psbs("\"%s\" File is read only", current_filename);3568 status_line_bold("\"%s\" File is read only", current_filename); 3567 3569 break; 3568 3570 } … … 3570 3572 if (cnt < 0) { 3571 3573 if (cnt == -1) 3572 psbs("Write error: %s", strerror(errno));3574 status_line_bold("Write error: %s", strerror(errno)); 3573 3575 } else if (cnt == (end - 1 - text + 1)) { 3574 3576 editing = 0; … … 3584 3586 case 'b': // b- back a word 3585 3587 case 'e': // e- end of word 3586 if ( cmdcnt-- > 1) {3588 if (--cmdcnt > 0) { 3587 3589 do_cmd(c); 3588 } // repeat cnt3590 } 3589 3591 dir = FORWARD; 3590 3592 if (c == 'b') … … 3608 3610 case 'Y': // Y- Yank a line 3609 3611 #endif 3612 { 3613 int yf, ml, whole = 0; 3610 3614 yf = YANKDEL; // assume either "c" or "d" 3611 3615 #if ENABLE_FEATURE_VI_YANKMARK … … 3616 3620 if (c != 'Y') 3617 3621 c1 = get_one_char(); // get the type of thing to delete 3618 find_range(&p, &q, c1); 3622 // determine range, and whether it spans lines 3623 ml = find_range(&p, &q, c1); 3619 3624 if (c1 == 27) { // ESC- user changed mind and wants out 3620 3625 c = c1 = 27; // Escape- do nothing … … 3628 3633 } 3629 3634 } 3630 dot = yank_delete(p, q, 0, yf); // delete word 3631 } else if (strchr("^0bBeEft$", c1)) { 3632 // single line copy text into a register and delete 3633 dot = yank_delete(p, q, 0, yf); // delete word 3634 } else if (strchr("cdykjHL%+-{}\r\n", c1)) { 3635 // multiple line copy text into a register and delete 3636 dot = yank_delete(p, q, 1, yf); // delete lines 3635 dot = yank_delete(p, q, ml, yf); // delete word 3636 } else if (strchr("^0bBeEft%$ lh\b\177", c1)) { 3637 // partial line copy text into a register and delete 3638 dot = yank_delete(p, q, ml, yf); // delete word 3639 } else if (strchr("cdykjHL+-{}\r\n", c1)) { 3640 // whole line copy text into a register and delete 3641 dot = yank_delete(p, q, ml, yf); // delete lines 3642 whole = 1; 3643 } else { 3644 // could not recognize object 3645 c = c1 = 27; // error- 3646 ml = 0; 3647 indicate_error(c); 3648 } 3649 if (ml && whole) { 3637 3650 if (c == 'c') { 3638 3651 dot = char_insert(dot, '\n'); 3639 3652 // on the last line of file don't move to prev line 3640 if ( dot != (end-1)) {3653 if (whole && dot != (end-1)) { 3641 3654 dot_prev(); 3642 3655 } … … 3645 3658 dot_skip_over_ws(); 3646 3659 } 3647 } else {3648 // could not recognize object3649 c = c1 = 27; // error-3650 indicate_error(c);3651 3660 } 3652 3661 if (c1 != 27) { … … 3669 3678 cnt++; 3670 3679 } 3671 psb("%s %d lines (%d chars) using [%c]",3680 status_line("%s %d lines (%d chars) using [%c]", 3672 3681 buf, cnt, strlen(reg[YDreg]), what_reg()); 3673 3682 #endif … … 3675 3684 } 3676 3685 break; 3686 } 3677 3687 case 'k': // k- goto prev line, same col 3678 case VI_K_UP: // cursor key Up3679 if ( cmdcnt-- > 1) {3688 case KEYCODE_UP: // cursor key Up 3689 if (--cmdcnt > 0) { 3680 3690 do_cmd(c); 3681 } // repeat cnt3691 } 3682 3692 dot_prev(); 3683 3693 dot = move_to_col(dot, ccol + offset); // try stay in same col … … 3687 3697 if (*dot != '\n') { 3688 3698 *dot = c1; 3689 file_modified++; // has the file been modified3699 file_modified++; 3690 3700 } 3691 3701 end_cmd_q(); // stop adding to q … … 3696 3706 if (*dot == last_forward_char) 3697 3707 dot_left(); 3698 last_forward_char = 0;3708 last_forward_char = 0; 3699 3709 break; 3700 3710 case 'w': // w- forward a word 3701 if ( cmdcnt-- > 1) {3711 if (--cmdcnt > 0) { 3702 3712 do_cmd(c); 3703 } // repeat cnt3713 } 3704 3714 if (isalnum(*dot) || *dot == '_') { // we are on ALNUM 3705 3715 dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM); … … 3727 3737 break; 3728 3738 case '~': // ~- flip the case of letters a-z -> A-Z 3729 if ( cmdcnt-- > 1) {3739 if (--cmdcnt > 0) { 3730 3740 do_cmd(c); 3731 } // repeat cnt3741 } 3732 3742 if (islower(*dot)) { 3733 3743 *dot = toupper(*dot); 3734 file_modified++; // has the file been modified3744 file_modified++; 3735 3745 } else if (isupper(*dot)) { 3736 3746 *dot = tolower(*dot); 3737 file_modified++; // has the file been modified3747 file_modified++; 3738 3748 } 3739 3749 dot_right(); … … 3741 3751 break; 3742 3752 //----- The Cursor and Function Keys ----------------------------- 3743 case VI_K_HOME: // Cursor Key Home3753 case KEYCODE_HOME: // Cursor Key Home 3744 3754 dot_begin(); 3745 3755 break; 3746 3756 // The Fn keys could point to do_macro which could translate them 3747 case VI_K_FUN1: // Function Key F1 3748 case VI_K_FUN2: // Function Key F2 3749 case VI_K_FUN3: // Function Key F3 3750 case VI_K_FUN4: // Function Key F4 3751 case VI_K_FUN5: // Function Key F5 3752 case VI_K_FUN6: // Function Key F6 3753 case VI_K_FUN7: // Function Key F7 3754 case VI_K_FUN8: // Function Key F8 3755 case VI_K_FUN9: // Function Key F9 3756 case VI_K_FUN10: // Function Key F10 3757 case VI_K_FUN11: // Function Key F11 3758 case VI_K_FUN12: // Function Key F12 3759 break; 3757 #if 0 3758 case KEYCODE_FUN1: // Function Key F1 3759 case KEYCODE_FUN2: // Function Key F2 3760 case KEYCODE_FUN3: // Function Key F3 3761 case KEYCODE_FUN4: // Function Key F4 3762 case KEYCODE_FUN5: // Function Key F5 3763 case KEYCODE_FUN6: // Function Key F6 3764 case KEYCODE_FUN7: // Function Key F7 3765 case KEYCODE_FUN8: // Function Key F8 3766 case KEYCODE_FUN9: // Function Key F9 3767 case KEYCODE_FUN10: // Function Key F10 3768 case KEYCODE_FUN11: // Function Key F11 3769 case KEYCODE_FUN12: // Function Key F12 3770 break; 3771 #endif 3760 3772 } 3761 3773 … … 3782 3794 } 3783 3795 3796 /* NB! the CRASHME code is unmaintained, and doesn't currently build */ 3784 3797 #if ENABLE_FEATURE_VI_CRASHME 3785 3798 static int totalcmds = 0; … … 3791 3804 static int Pp = 99; // Put command Probability 3792 3805 static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0; 3793 const char chars[20] = "\t012345 abcdABCD-=.$";3794 const char *const words[20] = {3806 static const char chars[20] = "\t012345 abcdABCD-=.$"; 3807 static const char *const words[20] = { 3795 3808 "this", "is", "a", "test", 3796 3809 "broadcast", "the", "emergency", "of", … … 3799 3812 "back", "January", "Febuary", "March" 3800 3813 }; 3801 const char *const lines[20] = {3814 static const char *const lines[20] = { 3802 3815 "You should have received a copy of the GNU General Public License\n", 3803 3816 "char c, cm, *cmd, *cmd1;\n", … … 3821 3834 "This is too much english for a computer geek.\n", 3822 3835 }; 3823 char *multilines[20] = {3836 static char *multilines[20] = { 3824 3837 "You should have received a copy of the GNU General Public License\n", 3825 3838 "char c, cm, *cmd, *cmd1;\n", … … 3855 3868 3856 3869 // is there already a command running? 3857 if (read ed_for_parse> 0)3870 if (readbuffer[0] > 0) 3858 3871 goto cd1; 3859 3872 cd0: 3860 startrbi = rbi = 0; 3873 readbuffer[0] = 'X'; 3874 startrbi = rbi = 1; 3861 3875 sleeptime = 0; // how long to pause between commands 3862 memset(readbuffer, '\0', MAX_LINELEN); // clear the read buffer3876 memset(readbuffer, '\0', sizeof(readbuffer)); 3863 3877 // generate a command by percentages 3864 3878 percent = (int) lrand48() % 100; // get a number from 0-99 … … 3932 3946 strcat(readbuffer, "\033"); 3933 3947 } 3934 read ed_for_parse = strlen(readbuffer);3948 readbuffer[0] = strlen(readbuffer + 1); 3935 3949 cd1: 3936 3950 totalcmds++; … … 3945 3959 3946 3960 time_t tim; 3947 char d[2], msg[ MAX_LINELEN];3961 char d[2], msg[80]; 3948 3962 3949 3963 msg[0] = '\0'; … … 3968 3982 3969 3983 if (msg[0]) { 3970 alarm(0);3971 3984 printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s", 3972 3985 totalcmds, last_input_char, msg, SOs, SOn); 3973 fflush (stdout);3974 while ( read(0, d, 1) > 0) {3986 fflush_all(); 3987 while (safe_read(STDIN_FILENO, d, 1) > 0) { 3975 3988 if (d[0] == '\n' || d[0] == '\r') 3976 3989 break; 3977 3990 } 3978 alarm(3); 3979 } 3980 tim = (time_t) time((time_t *) 0); 3991 } 3992 tim = time(NULL); 3981 3993 if (tim >= (oldtim + 3)) { 3982 3994 sprintf(status_buffer,
Note:
See TracChangeset
for help on using the changeset viewer.