Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/editors/vi.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/editors/vi.c
r821 r1770 14 14 * add :help command 15 15 * :map macros 16 * how about mode lines: vi: set sw=8 ts=8:17 16 * if mark[] values were line numbers rather than pointers 18 17 * it would be easier to change the mark when add/delete lines … … 23 22 */ 24 23 25 26 #include "busybox.h" 27 #include <string.h> 28 #include <strings.h> 29 #include <unistd.h> 30 #include <sys/ioctl.h> 31 #include <time.h> 32 #include <fcntl.h> 33 #include <signal.h> 34 #include <setjmp.h> 35 #include <regex.h> 36 #include <ctype.h> 37 #include <errno.h> 38 #define vi_Version BB_VER " " BB_BT 39 40 #ifdef CONFIG_LOCALE_SUPPORT 24 #include "libbb.h" 25 26 #define ENABLE_FEATURE_VI_CRASHME 0 27 28 #if ENABLE_LOCALE_SUPPORT 41 29 #define Isprint(c) isprint((c)) 42 30 #else 43 #define Isprint(c) ( (c) >= ' ' && (c) != 127 && (c) != ((unsigned char)'\233') ) 44 #endif 45 46 #define MAX_SCR_COLS BUFSIZ 31 /* 0x9b is Meta-ESC */ 32 #define Isprint(c) ((unsigned char)(c) >= ' ' && (c) != 0x7f && (unsigned char)(c) != 0x9b) 33 #endif 34 35 enum { 36 MAX_LINELEN = CONFIG_FEATURE_VI_MAX_LEN, 37 MAX_SCR_COLS = CONFIG_FEATURE_VI_MAX_LEN, 38 }; 47 39 48 40 // Misc. non-Ascii keys that report an escape sequence 49 #define VI_K_UP 128 // cursor key Up50 #define VI_K_DOWN 129 // cursor key Down51 #define VI_K_RIGHT 130 // Cursor Key Right52 #define VI_K_LEFT 131 // cursor key Left53 #define VI_K_HOME 132 // Cursor Key Home54 #define VI_K_END 133 // Cursor Key End55 #define VI_K_INSERT 134 // Cursor Key Insert56 #define VI_K_PAGEUP 135 // Cursor Key Page Up57 #define VI_K_PAGEDOWN 136 // Cursor Key Page Down58 #define VI_K_FUN1 137 // Function Key F159 #define VI_K_FUN2 138 // Function Key F260 #define VI_K_FUN3 139 // Function Key F361 #define VI_K_FUN4 140 // Function Key F462 #define VI_K_FUN5 141 // Function Key F563 #define VI_K_FUN6 142 // Function Key F664 #define VI_K_FUN7 143 // Function Key F765 #define VI_K_FUN8 144 // Function Key F866 #define VI_K_FUN9 145 // Function Key F967 #define VI_K_FUN10 146 // Function Key F1068 #define VI_K_FUN11 147 // Function Key F1169 #define VI_K_FUN12 148 // Function Key F1241 #define VI_K_UP (char)128 // cursor key Up 42 #define VI_K_DOWN (char)129 // cursor key Down 43 #define VI_K_RIGHT (char)130 // Cursor Key Right 44 #define VI_K_LEFT (char)131 // cursor key Left 45 #define VI_K_HOME (char)132 // Cursor Key Home 46 #define VI_K_END (char)133 // Cursor Key End 47 #define VI_K_INSERT (char)134 // Cursor Key Insert 48 #define VI_K_PAGEUP (char)135 // Cursor Key Page Up 49 #define VI_K_PAGEDOWN (char)136 // Cursor Key Page Down 50 #define VI_K_FUN1 (char)137 // Function Key F1 51 #define VI_K_FUN2 (char)138 // Function Key F2 52 #define VI_K_FUN3 (char)139 // Function Key F3 53 #define VI_K_FUN4 (char)140 // Function Key F4 54 #define VI_K_FUN5 (char)141 // Function Key F5 55 #define VI_K_FUN6 (char)142 // Function Key F6 56 #define VI_K_FUN7 (char)143 // Function Key F7 57 #define VI_K_FUN8 (char)144 // Function Key F8 58 #define VI_K_FUN9 (char)145 // Function Key F9 59 #define VI_K_FUN10 (char)146 // Function Key F10 60 #define VI_K_FUN11 (char)147 // Function Key F11 61 #define VI_K_FUN12 (char)148 // Function Key F12 70 62 71 63 /* vt102 typical ESC sequence */ 72 64 /* terminal standout start/normal ESC sequence */ 73 static const char SOs[] = "\033[7m";74 static const char SOn[] = "\033[0m";65 static const char SOs[] ALIGN1 = "\033[7m"; 66 static const char SOn[] ALIGN1 = "\033[0m"; 75 67 /* terminal bell sequence */ 76 static const char bell[] = "\007";68 static const char bell[] ALIGN1 = "\007"; 77 69 /* Clear-end-of-line and Clear-end-of-screen ESC sequence */ 78 static const char Ceol[] = "\033[0K";79 static const char Ceos []= "\033[0J";70 static const char Ceol[] ALIGN1 = "\033[0K"; 71 static const char Ceos[] ALIGN1 = "\033[0J"; 80 72 /* Cursor motion arbitrary destination ESC sequence */ 81 static const char CMrc[] = "\033[%d;%dH";73 static const char CMrc[] ALIGN1 = "\033[%d;%dH"; 82 74 /* Cursor motion up and down ESC sequence */ 83 static const char CMup[] = "\033[A";84 static const char CMdown[] = "\n";75 static const char CMup[] ALIGN1 = "\033[A"; 76 static const char CMdown[] ALIGN1 = "\n"; 85 77 86 78 … … 97 89 S_OVER_WS = 3, // used in skip_thing() for moving "dot" 98 90 S_END_PUNCT = 4, // used in skip_thing() for moving "dot" 99 S_END_ALNUM = 5 91 S_END_ALNUM = 5, // used in skip_thing() for moving "dot" 100 92 }; 101 93 102 typedef unsigned char Byte; 103 104 static int vi_setops; 94 /* vi.c expects chars to be unsigned. */ 95 /* busybox build system provides that, but it's better */ 96 /* to audit and fix the source */ 97 98 static smallint vi_setops; 105 99 #define VI_AUTOINDENT 1 106 100 #define VI_SHOWMATCH 2 … … 114 108 115 109 116 static int editing; // >0 while we are editing a file 117 static int cmd_mode; // 0=command 1=insert 2=replace 118 static int file_modified; // buffer contents changed 119 static int last_file_modified = -1; 120 static int fn_start; // index of first cmd line file name 121 static int save_argc; // how many file names on cmd line 122 static int cmdcnt; // repetition count 123 static fd_set rfds; // use select() for small sleeps 124 static struct timeval tv; // use select() for small sleeps 125 static int rows, columns; // the terminal screen is this size 126 static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset 127 static Byte *status_buffer; // mesages to the user 110 static smallint editing; // >0 while we are editing a file 111 // [code audit says "can be 0 or 1 only"] 112 static smallint cmd_mode; // 0=command 1=insert 2=replace 113 static smallint file_modified; // buffer contents changed 114 static smallint last_file_modified = -1; 115 static int fn_start; // index of first cmd line file name 116 static int save_argc; // how many file names on cmd line 117 static int cmdcnt; // repetition count 118 static int rows, columns; // the terminal screen is this size 119 static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset 120 static char *status_buffer; // mesages to the user 128 121 #define STATUS_BUFFER_LEN 200 129 122 static int have_status_msg; // is default edit status needed? 123 // [don't make smallint!] 130 124 static int last_status_cksum; // hash of current status line 131 static Byte *cfn; // previous, current, and next file name132 static Byte *text, *end, *textend;// pointers to the user data in memory133 static Byte *screen;// pointer to the virtual screen buffer134 static int screensize; 135 static Byte *screenbegin;// index into text[], of top line on the screen136 static Byte *dot;// where all the action takes place125 static char *current_filename; // current file name 126 //static char *text, *end; // pointers to the user data in memory 127 static char *screen; // pointer to the virtual screen buffer 128 static int screensize; // and its size 129 static char *screenbegin; // index into text[], of top line on the screen 130 //static char *dot; // where all the action takes place 137 131 static int tabstop; 138 static struct termios term_orig, term_vi; // remember what the cooked mode was 139 static Byte erase_char; // the users erase character 140 static Byte last_input_char; // last char read from user 141 static Byte last_forward_char; // last char searched for with 'f' 142 143 #ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR 132 static char erase_char; // the users erase character 133 static char last_input_char; // last char read from user 134 static char last_forward_char; // last char searched for with 'f' 135 136 #if ENABLE_FEATURE_VI_READONLY 137 //static smallint vi_readonly, readonly; 138 static smallint readonly_mode = 0; 139 #define SET_READONLY_FILE(flags) ((flags) |= 0x01) 140 #define SET_READONLY_MODE(flags) ((flags) |= 0x02) 141 #define UNSET_READONLY_FILE(flags) ((flags) &= 0xfe) 142 #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 148 149 #if ENABLE_FEATURE_VI_DOT_CMD 150 static smallint adding2q; // are we currently adding user input to q 151 static char *last_modifying_cmd; // last modifying cmd for "." 152 static char *ioq, *ioq_start; // pointer to string for get_one_char to "read" 153 #endif 154 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 144 155 static int last_row; // where the cursor was last moved to 145 #endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */ 146 #ifdef CONFIG_FEATURE_VI_USE_SIGNALS 147 static jmp_buf restart; // catch_sig() 148 #endif /* CONFIG_FEATURE_VI_USE_SIGNALS */ 149 #if defined(CONFIG_FEATURE_VI_USE_SIGNALS) || defined(CONFIG_FEATURE_VI_CRASHME) 156 #endif 157 #if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME 150 158 static int my_pid; 151 159 #endif 152 #ifdef CONFIG_FEATURE_VI_DOT_CMD 153 static int adding2q; // are we currently adding user input to q 154 static Byte *last_modifying_cmd; // last modifying cmd for "." 155 static Byte *ioq, *ioq_start; // pointer to string for get_one_char to "read" 156 #endif /* CONFIG_FEATURE_VI_DOT_CMD */ 157 #if defined(CONFIG_FEATURE_VI_DOT_CMD) || defined(CONFIG_FEATURE_VI_YANKMARK) 158 static Byte *modifying_cmds; // cmds that modify text[] 159 #endif /* CONFIG_FEATURE_VI_DOT_CMD || CONFIG_FEATURE_VI_YANKMARK */ 160 #ifdef CONFIG_FEATURE_VI_READONLY 161 static int vi_readonly, readonly; 162 #endif /* CONFIG_FEATURE_VI_READONLY */ 163 #ifdef CONFIG_FEATURE_VI_YANKMARK 164 static Byte *reg[28]; // named register a-z, "D", and "U" 0-25,26,27 165 static int YDreg, Ureg; // default delete register and orig line for "U" 166 static Byte *mark[28]; // user marks points somewhere in text[]- a-z and previous context '' 167 static Byte *context_start, *context_end; 168 #endif /* CONFIG_FEATURE_VI_YANKMARK */ 169 #ifdef CONFIG_FEATURE_VI_SEARCH 170 static Byte *last_search_pattern; // last pattern from a '/' or '?' search 171 #endif /* CONFIG_FEATURE_VI_SEARCH */ 172 173 174 static void edit_file(Byte *); // edit one file 175 static void do_cmd(Byte); // execute a command 176 static void sync_cursor(Byte *, int *, int *); // synchronize the screen cursor to dot 177 static Byte *begin_line(Byte *); // return pointer to cur line B-o-l 178 static Byte *end_line(Byte *); // return pointer to cur line E-o-l 179 static Byte *prev_line(Byte *); // return pointer to prev line B-o-l 180 static Byte *next_line(Byte *); // return pointer to next line B-o-l 181 static Byte *end_screen(void); // get pointer to last char on screen 182 static int count_lines(Byte *, Byte *); // count line from start to stop 183 static Byte *find_line(int); // find begining of line #li 184 static Byte *move_to_col(Byte *, int); // move "p" to column l 185 static int isblnk(Byte); // is the char a blank or tab 160 #if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK 161 static char *modifying_cmds; // cmds that modify text[] 162 #endif 163 #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 173 #if ENABLE_FEATURE_VI_YANKMARK 174 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 char *mark[28]; // user marks points somewhere in text[]- a-z and previous context '' 177 char *context_start, *context_end; 178 #endif 179 /* a few references only */ 180 #if ENABLE_FEATURE_VI_USE_SIGNALS 181 jmp_buf restart; // catch_sig() 182 #endif 183 struct termios term_orig, term_vi; // remember what the cooked mode was 184 #if ENABLE_FEATURE_VI_COLON 185 char *initial_cmds[3]; // currently 2 entries, NULL terminated 186 #endif 187 }; 188 #define G (*ptr_to_globals) 189 #define text (G.text ) 190 #define text_size (G.text_size ) 191 #define end (G.end ) 192 #define dot (G.dot ) 193 #define reg (G.reg ) 194 #define YDreg (G.YDreg ) 195 #define Ureg (G.Ureg ) 196 #define mark (G.mark ) 197 #define context_start (G.context_start ) 198 #define context_end (G.context_end ) 199 #define restart (G.restart ) 200 #define term_orig (G.term_orig ) 201 #define term_vi (G.term_vi ) 202 #define initial_cmds (G.initial_cmds ) 203 204 static int init_text_buffer(char *); // init from file or create new 205 static void edit_file(char *); // edit one file 206 static void do_cmd(char); // execute a command 207 static int next_tabstop(int); 208 static void sync_cursor(char *, int *, int *); // synchronize the screen cursor to dot 209 static char *begin_line(char *); // return pointer to cur line B-o-l 210 static char *end_line(char *); // return pointer to cur line E-o-l 211 static char *prev_line(char *); // return pointer to prev line B-o-l 212 static char *next_line(char *); // return pointer to next line B-o-l 213 static char *end_screen(void); // get pointer to last char on screen 214 static int count_lines(char *, char *); // count line from start to stop 215 static char *find_line(int); // find begining of line #li 216 static char *move_to_col(char *, int); // move "p" to column l 186 217 static void dot_left(void); // move dot left- dont leave line 187 218 static void dot_right(void); // move dot right- dont leave line … … 193 224 static void dot_skip_over_ws(void); // move dot pat WS 194 225 static void dot_delete(void); // delete the char at 'dot' 195 static Byte *bound_dot(Byte *); // make sure text[0] <= P < "end" 196 static Byte *new_screen(int, int); // malloc virtual screen memory 197 static Byte *new_text(int); // malloc memory for text[] buffer 198 static Byte *char_insert(Byte *, Byte); // insert the char c at 'p' 199 static Byte *stupid_insert(Byte *, Byte); // stupidly insert the char c at 'p' 200 static Byte find_range(Byte **, Byte **, Byte); // return pointers for an object 201 static int st_test(Byte *, int, int, Byte *); // helper for skip_thing() 202 static Byte *skip_thing(Byte *, int, int, int); // skip some object 203 static Byte *find_pair(Byte *, Byte); // find matching pair () [] {} 204 static Byte *text_hole_delete(Byte *, Byte *); // at "p", delete a 'size' byte hole 205 static Byte *text_hole_make(Byte *, int); // at "p", make a 'size' byte hole 206 static Byte *yank_delete(Byte *, Byte *, int, int); // yank text[] into register then delete 226 static char *bound_dot(char *); // make sure text[0] <= P < "end" 227 static char *new_screen(int, int); // malloc virtual screen memory 228 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 231 static int st_test(char *, int, int, char *); // helper for skip_thing() 232 static char *skip_thing(char *, int, int, int); // skip some object 233 static char *find_pair(char *, char); // find matching pair () [] {} 234 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 236 static char *yank_delete(char *, char *, int, int); // yank text[] into register then delete 207 237 static void show_help(void); // display some help info 208 238 static void rawmode(void); // set "raw" mode on tty 209 239 static void cookmode(void); // return to "cooked" mode on tty 210 240 static int mysleep(int); // sleep for 'h' 1/100 seconds 211 static Byte readit(void); // read (maybe cursor) key from stdin 212 static Byte get_one_char(void); // read 1 char from stdin 213 static int file_size(const Byte *); // what is the byte size of "fn" 214 static int file_insert(Byte *, Byte *, int); 215 static int file_write(Byte *, Byte *, Byte *); 241 static char readit(void); // read (maybe cursor) key from stdin 242 static char get_one_char(void); // read 1 char from stdin 243 static int file_size(const char *); // what is the byte size of "fn" 244 #if ENABLE_FEATURE_VI_READONLY 245 static int file_insert(const char *, char *, int); 246 #else 247 static int file_insert(const char *, char *); 248 #endif 249 static int file_write(char *, char *, char *); 216 250 static void place_cursor(int, int, int); 217 251 static void screen_erase(void); … … 224 258 static void psb(const char *, ...); // Print Status Buf 225 259 static void psbs(const char *, ...); // Print Status Buf in standout mode 226 static void ni( Byte*); // display messages260 static void ni(const char *); // display messages 227 261 static int format_edit_status(void); // format file status on status line 228 262 static void redraw(int); // force a full screen refresh 229 static void format_line( Byte*, Byte*, int);263 static void format_line(char*, char*, int); 230 264 static void refresh(int); // update the terminal from screen[] 231 265 … … 234 268 static void Hit_Return(void); 235 269 236 #if def CONFIG_FEATURE_VI_SEARCH237 static Byte *char_search(Byte *, Byte*, int, int); // search for pattern starting at p238 static int mycmp( Byte *, Byte*, int); // string cmp based in "ignorecase"239 #endif /* CONFIG_FEATURE_VI_SEARCH */240 #if def CONFIG_FEATURE_VI_COLON241 static Byte *get_one_address(Byte*, int *); // get colon addr, if present242 static Byte *get_address(Byte*, int *, int *); // get two colon addrs, if present243 static void colon( Byte*); // execute the "colon" mode cmds244 #endif /* CONFIG_FEATURE_VI_COLON */245 #if def CONFIG_FEATURE_VI_USE_SIGNALS270 #if ENABLE_FEATURE_VI_SEARCH 271 static char *char_search(char *, const char *, int, int); // search for pattern starting at p 272 static int mycmp(const char *, const char *, int); // string cmp based in "ignorecase" 273 #endif 274 #if ENABLE_FEATURE_VI_COLON 275 static char *get_one_address(char *, int *); // get colon addr, if present 276 static char *get_address(char *, int *, int *); // get two colon addrs, if present 277 static void colon(char *); // execute the "colon" mode cmds 278 #endif 279 #if ENABLE_FEATURE_VI_USE_SIGNALS 246 280 static void winch_sig(int); // catch window size changes 247 281 static void suspend_sig(int); // catch ctrl-Z 248 282 static void catch_sig(int); // catch ctrl-C and alarm time-outs 249 #endif /* CONFIG_FEATURE_VI_USE_SIGNALS */250 #if def CONFIG_FEATURE_VI_DOT_CMD251 static void start_new_cmd_q( Byte); // new queue for command283 #endif 284 #if ENABLE_FEATURE_VI_DOT_CMD 285 static void start_new_cmd_q(char); // new queue for command 252 286 static void end_cmd_q(void); // stop saving input chars 253 #else /* CONFIG_FEATURE_VI_DOT_CMD */254 #define end_cmd_q() 255 #endif /* CONFIG_FEATURE_VI_DOT_CMD */256 #if def CONFIG_FEATURE_VI_SETOPTS257 static void showmatching( Byte*); // show the matching pair () [] {}258 #endif /* CONFIG_FEATURE_VI_SETOPTS */259 #if defined(CONFIG_FEATURE_VI_YANKMARK) || (defined(CONFIG_FEATURE_VI_COLON) && defined(CONFIG_FEATURE_VI_SEARCH)) || defined(CONFIG_FEATURE_VI_CRASHME)260 static Byte *string_insert(Byte *, Byte*); // insert the string at 'p'261 #endif /* CONFIG_FEATURE_VI_YANKMARK || CONFIG_FEATURE_VI_SEARCH || CONFIG_FEATURE_VI_CRASHME */262 #if def CONFIG_FEATURE_VI_YANKMARK263 static Byte *text_yank(Byte *, Byte*, int); // save copy of "p" into a register264 static Bytewhat_reg(void); // what is letter of current YDreg265 static void check_context( Byte); // remember context for '' command266 #endif /* CONFIG_FEATURE_VI_YANKMARK */267 #if def CONFIG_FEATURE_VI_CRASHME287 #else 288 #define end_cmd_q() ((void)0) 289 #endif 290 #if ENABLE_FEATURE_VI_SETOPTS 291 static void showmatching(char *); // show the matching pair () [] {} 292 #endif 293 #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' 295 #endif 296 #if ENABLE_FEATURE_VI_YANKMARK 297 static char *text_yank(char *, char *, int); // save copy of "p" into a register 298 static char what_reg(void); // what is letter of current YDreg 299 static void check_context(char); // remember context for '' command 300 #endif 301 #if ENABLE_FEATURE_VI_CRASHME 268 302 static void crash_dummy(); 269 303 static void crash_test(); 270 304 static int crashme = 0; 271 #endif /* CONFIG_FEATURE_VI_CRASHME */305 #endif 272 306 273 307 … … 277 311 } 278 312 313 int vi_main(int argc, char **argv); 279 314 int vi_main(int argc, char **argv) 280 315 { … … 282 317 RESERVE_CONFIG_BUFFER(STATUS_BUFFER, STATUS_BUFFER_LEN); 283 318 284 #ifdef CONFIG_FEATURE_VI_YANKMARK 285 int i; 286 #endif /* CONFIG_FEATURE_VI_YANKMARK */ 287 #if defined(CONFIG_FEATURE_VI_USE_SIGNALS) || defined(CONFIG_FEATURE_VI_CRASHME) 319 #if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME 288 320 my_pid = getpid(); 289 321 #endif 290 #ifdef CONFIG_FEATURE_VI_CRASHME 291 (void) srand((long) my_pid); 292 #endif /* CONFIG_FEATURE_VI_CRASHME */ 293 294 status_buffer = (Byte *)STATUS_BUFFER; 322 323 PTR_TO_GLOBALS = xzalloc(sizeof(G)); 324 325 #if ENABLE_FEATURE_VI_CRASHME 326 srand((long) my_pid); 327 #endif 328 329 status_buffer = STATUS_BUFFER; 295 330 last_status_cksum = 0; 296 297 #ifdef CONFIG_FEATURE_VI_READONLY 298 vi_readonly = readonly = FALSE; 299 if (strncmp(argv[0], "view", 4) == 0) { 300 readonly = TRUE; 301 vi_readonly = TRUE; 302 } 303 #endif /* CONFIG_FEATURE_VI_READONLY */ 331 text = NULL; 332 333 #ifdef NO_SUCH_APPLET_YET 334 /* If we aren't "vi", we are "view" */ 335 if (ENABLE_FEATURE_VI_READONLY && applet_name[2]) { 336 SET_READONLY_MODE(readonly_mode); 337 } 338 #endif 339 304 340 vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE | VI_ERR_METHOD; 305 #ifdef CONFIG_FEATURE_VI_YANKMARK 306 for (i = 0; i < 28; i++) { 307 reg[i] = 0; 308 } // init the yank regs 309 #endif /* CONFIG_FEATURE_VI_YANKMARK */ 310 #if defined(CONFIG_FEATURE_VI_DOT_CMD) || defined(CONFIG_FEATURE_VI_YANKMARK) 311 modifying_cmds = (Byte *) "aAcCdDiIJoOpPrRsxX<>~"; // cmds modifying text[] 312 #endif /* CONFIG_FEATURE_VI_DOT_CMD */ 313 314 // 1- process $HOME/.exrc file 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 348 // 1- process $HOME/.exrc file (not inplemented yet) 315 349 // 2- process EXINIT variable from environment 316 350 // 3- process command line args 317 while ((c = getopt(argc, argv, "hCR")) != -1) { 351 #if ENABLE_FEATURE_VI_COLON 352 { 353 char *p = getenv("EXINIT"); 354 if (p && *p) 355 initial_cmds[0] = xstrdup(p); 356 } 357 #endif 358 while ((c = getopt(argc, argv, "hCR" USE_FEATURE_VI_COLON("c:"))) != -1) { 318 359 switch (c) { 319 #if def CONFIG_FEATURE_VI_CRASHME360 #if ENABLE_FEATURE_VI_CRASHME 320 361 case 'C': 321 362 crashme = 1; 322 363 break; 323 #endif /* CONFIG_FEATURE_VI_CRASHME */324 #if def CONFIG_FEATURE_VI_READONLY364 #endif 365 #if ENABLE_FEATURE_VI_READONLY 325 366 case 'R': // Read-only flag 326 readonly = TRUE; 327 vi_readonly = TRUE; 367 SET_READONLY_MODE(readonly_mode); 328 368 break; 329 #endif /* CONFIG_FEATURE_VI_READONLY */369 #endif 330 370 //case 'r': // recover flag- ignore- we don't use tmp file 331 371 //case 'x': // encryption flag- ignore 332 372 //case 'c': // execute command first 373 #if ENABLE_FEATURE_VI_COLON 374 case 'c': // cmd line vi command 375 if (*optarg) 376 initial_cmds[initial_cmds[0] != 0] = xstrdup(optarg); 377 break; 333 378 //case 'h': // help -- just use default 379 #endif 334 380 default: 335 381 show_help(); … … 345 391 //----- This is the main file handling loop -------------- 346 392 if (optind >= argc) { 347 editing = 1; // 0= exit, 1= one file, 2= multiple files348 393 edit_file(0); 349 394 } else { 350 395 for (; optind < argc; optind++) { 351 editing = 1; // 0=exit, 1=one file, 2+ =many files 352 free(cfn); 353 cfn = (Byte *) bb_xstrdup(argv[optind]); 354 edit_file(cfn); 396 edit_file(argv[optind]); 355 397 } 356 398 } 357 399 //----------------------------------------------------------- 358 400 359 return (0); 360 } 361 362 static void edit_file(Byte * fn) 363 { 364 Byte c; 365 int cnt, size, ch; 366 367 #ifdef CONFIG_FEATURE_VI_USE_SIGNALS 401 return 0; 402 } 403 404 /* read text from file or create an empty buf */ 405 /* will also update current_filename */ 406 static int init_text_buffer(char *fn) 407 { 408 int rc; 409 int size = file_size(fn); // file size. -1 means does not exist. 410 411 /* allocate/reallocate text buffer */ 412 free(text); 413 text_size = size * 2; 414 if (text_size < 10240) 415 text_size = 10240; // have a minimum size for new files 416 screenbegin = dot = end = text = xzalloc(text_size); 417 418 if (fn != current_filename) { 419 free(current_filename); 420 current_filename = xstrdup(fn); 421 } 422 if (size < 0) { 423 // file dont exist. Start empty buf with dummy line 424 char_insert(text, '\n'); 425 rc = 0; 426 } else { 427 rc = file_insert(fn, text 428 USE_FEATURE_VI_READONLY(, 1)); 429 } 430 file_modified = 0; 431 last_file_modified = -1; 432 #if ENABLE_FEATURE_VI_YANKMARK 433 /* init the marks. */ 434 memset(mark, 0, sizeof(mark)); 435 #endif 436 return rc; 437 } 438 439 static void edit_file(char * fn) 440 { 441 char c; 442 int size; 443 444 #if ENABLE_FEATURE_VI_USE_SIGNALS 368 445 int sig; 369 #endif /* CONFIG_FEATURE_VI_USE_SIGNALS */ 370 #ifdef CONFIG_FEATURE_VI_YANKMARK 371 static Byte *cur_line; 372 #endif /* CONFIG_FEATURE_VI_YANKMARK */ 373 446 #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 374 452 rawmode(); 375 453 rows = 24; 376 454 columns = 80; 377 ch= -1;455 size = 0; 378 456 if (ENABLE_FEATURE_VI_WIN_RESIZE) 379 457 get_terminal_width_height(0, &columns, &rows); 380 458 new_screen(rows, columns); // get memory for virtual screen 381 382 cnt = file_size(fn); // file size 383 size = 2 * cnt; // 200% of file size 384 new_text(size); // get a text[] buffer 385 screenbegin = dot = end = text; 386 if (fn != 0) { 387 ch= file_insert(fn, text, cnt); 388 } 389 if (ch < 1) { 390 (void) char_insert(text, '\n'); // start empty buf with dummy line 391 } 392 file_modified = 0; 393 last_file_modified = -1; 394 #ifdef CONFIG_FEATURE_VI_YANKMARK 459 init_text_buffer(fn); 460 461 #if ENABLE_FEATURE_VI_YANKMARK 395 462 YDreg = 26; // default Yank/Delete reg 396 463 Ureg = 27; // hold orig line for "U" cmd 397 for (cnt = 0; cnt < 28; cnt++) {398 mark[cnt] = 0;399 } // init the marks400 464 mark[26] = mark[27] = text; // init "previous context" 401 #endif /* CONFIG_FEATURE_VI_YANKMARK */465 #endif 402 466 403 467 last_forward_char = last_input_char = '\0'; … … 405 469 ccol = 0; 406 470 407 #if def CONFIG_FEATURE_VI_USE_SIGNALS471 #if ENABLE_FEATURE_VI_USE_SIGNALS 408 472 catch_sig(0); 409 473 signal(SIGWINCH, winch_sig); … … 413 477 screenbegin = dot = text; 414 478 } 415 #endif /* CONFIG_FEATURE_VI_USE_SIGNALS */ 416 417 editing = 1; 479 #endif 480 418 481 cmd_mode = 0; // 0=command 1=insert 2='R'eplace 419 482 cmdcnt = 0; … … 421 484 offset = 0; // no horizontal offset 422 485 c = '\0'; 423 #if def CONFIG_FEATURE_VI_DOT_CMD486 #if ENABLE_FEATURE_VI_DOT_CMD 424 487 free(last_modifying_cmd); 425 488 free(ioq_start); 426 ioq = ioq_start = last_modifying_cmd = 0;489 ioq = ioq_start = last_modifying_cmd = NULL; 427 490 adding2q = 0; 428 #endif /* CONFIG_FEATURE_VI_DOT_CMD */491 #endif 429 492 redraw(FALSE); // dont force every col re-draw 430 show_status_line(); 431 493 494 #if ENABLE_FEATURE_VI_COLON 495 { 496 char *p, *q; 497 int n = 0; 498 499 while ((p = initial_cmds[n])) { 500 do { 501 q = p; 502 p = strchr(q,'\n'); 503 if (p) 504 while (*p == '\n') 505 *p++ = '\0'; 506 if (*q) 507 colon(q); 508 } while (p); 509 free(initial_cmds[n]); 510 initial_cmds[n] = NULL; 511 n++; 512 } 513 } 514 #endif 432 515 //------This is the main Vi cmd handling loop ----------------------- 433 516 while (editing > 0) { 434 #if def CONFIG_FEATURE_VI_CRASHME517 #if ENABLE_FEATURE_VI_CRASHME 435 518 if (crashme > 0) { 436 519 if ((end - text) > 1) { … … 438 521 } else { 439 522 crashme = 0; 440 dot = 441 string_insert(text, (Byte *) "\n\n##### Ran out of text to work on. #####\n\n"); // insert the string 523 dot = string_insert(text, "\n\n##### Ran out of text to work on. #####\n\n"); // insert the string 442 524 refresh(FALSE); 443 525 } 444 526 } 445 #endif /* CONFIG_FEATURE_VI_CRASHME */527 #endif 446 528 last_input_char = c = get_one_char(); // get a cmd from user 447 #if def CONFIG_FEATURE_VI_YANKMARK529 #if ENABLE_FEATURE_VI_YANKMARK 448 530 // save a copy of the current line- for the 'U" command 449 531 if (begin_line(dot) != cur_line) { … … 451 533 text_yank(begin_line(dot), end_line(dot), Ureg); 452 534 } 453 #endif /* CONFIG_FEATURE_VI_YANKMARK */454 #if def CONFIG_FEATURE_VI_DOT_CMD535 #endif 536 #if ENABLE_FEATURE_VI_DOT_CMD 455 537 // These are commands that change text[]. 456 538 // Remember the input for the "." command 457 539 if (!adding2q && ioq_start == 0 458 && strchr((char *) modifying_cmds, c) != NULL) { 540 && strchr(modifying_cmds, c) 541 ) { 459 542 start_new_cmd_q(c); 460 543 } 461 #endif /* CONFIG_FEATURE_VI_DOT_CMD */544 #endif 462 545 do_cmd(c); // execute the user command 463 546 // … … 470 553 show_status_line(); 471 554 } 472 #if def CONFIG_FEATURE_VI_CRASHME555 #if ENABLE_FEATURE_VI_CRASHME 473 556 if (crashme > 0) 474 557 crash_test(); // test editor variables 475 #endif /* CONFIG_FEATURE_VI_CRASHME */558 #endif 476 559 } 477 560 //------------------------------------------------------------------- … … 483 566 484 567 //----- The Colon commands ------------------------------------- 485 #if def CONFIG_FEATURE_VI_COLON486 static Byte *get_one_address(Byte* p, int *addr) // get colon addr, if present568 #if ENABLE_FEATURE_VI_COLON 569 static char *get_one_address(char * p, int *addr) // get colon addr, if present 487 570 { 488 571 int st; 489 Byte*q;490 491 #if def CONFIG_FEATURE_VI_YANKMARK492 Bytec;493 #endif /* CONFIG_FEATURE_VI_YANKMARK */494 #if def CONFIG_FEATURE_VI_SEARCH495 Byte *pat, buf[BUFSIZ];496 #endif /* CONFIG_FEATURE_VI_SEARCH */572 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 497 580 498 581 *addr = -1; // assume no addr … … 501 584 q = begin_line(dot); 502 585 *addr = count_lines(text, q); 503 #if def CONFIG_FEATURE_VI_YANKMARK586 #if ENABLE_FEATURE_VI_YANKMARK 504 587 } else if (*p == '\'') { // is this a mark addr 505 588 p++; … … 509 592 // we have a mark 510 593 c = c - 'a'; 511 q = mark[( int) c];594 q = mark[(unsigned char) c]; 512 595 if (q != NULL) { // is mark valid 513 596 *addr = count_lines(text, q); // count lines 514 597 } 515 598 } 516 #endif /* CONFIG_FEATURE_VI_YANKMARK */517 #if def CONFIG_FEATURE_VI_SEARCH599 #endif 600 #if ENABLE_FEATURE_VI_SEARCH 518 601 } else if (*p == '/') { // a search pattern 519 602 q = buf; … … 524 607 *q = '\0'; 525 608 } 526 pat = (Byte *) bb_xstrdup((char *)buf); // save copy of pattern609 pat = xstrdup(buf); // save copy of pattern 527 610 if (*p == '/') 528 611 p++; … … 532 615 } 533 616 free(pat); 534 #endif /* CONFIG_FEATURE_VI_SEARCH */617 #endif 535 618 } else if (*p == '$') { // the last line in file 536 619 p++; … … 538 621 *addr = count_lines(text, q); 539 622 } else if (isdigit(*p)) { // specific line number 540 sscanf( (char *)p, "%d%n", addr, &st);623 sscanf(p, "%d%n", addr, &st); 541 624 p += st; 542 625 } else { // I don't reconise this … … 544 627 *addr = -1; 545 628 } 546 return (p);547 } 548 549 static Byte *get_address(Byte*p, int *b, int *e) // get two colon addrs, if present629 return p; 630 } 631 632 static char *get_address(char *p, int *b, int *e) // get two colon addrs, if present 550 633 { 551 634 //----- get the address' i.e., 1,3 'a,'b ----- 552 635 // get FIRST addr, if present 553 while (isbl nk(*p))636 while (isblank(*p)) 554 637 p++; // skip over leading spaces 555 638 if (*p == '%') { // alias for 1,$ … … 560 643 } 561 644 p = get_one_address(p, b); 562 while (isbl nk(*p))645 while (isblank(*p)) 563 646 p++; 564 647 if (*p == ',') { // is there a address separator 565 648 p++; 566 while (isbl nk(*p))649 while (isblank(*p)) 567 650 p++; 568 651 // get SECOND addr, if present 569 652 p = get_one_address(p, e); 570 653 } 571 ga0:572 while (isbl nk(*p))654 ga0: 655 while (isblank(*p)) 573 656 p++; // skip over trailing spaces 574 return (p);575 } 576 577 #if def CONFIG_FEATURE_VI_SETOPTS578 static void setops(const Byte*args, const char *opname, int flg_no,657 return p; 658 } 659 660 #if ENABLE_FEATURE_VI_SET && ENABLE_FEATURE_VI_SETOPTS 661 static void setops(const char *args, const char *opname, int flg_no, 579 662 const char *short_opname, int opt) 580 663 { 581 const char *a = (char *)args + flg_no;664 const char *a = args + flg_no; 582 665 int l = strlen(opname) - 1; /* opname have + ' ' */ 583 666 584 if (strncasecmp(a, opname, l) == 0 || 585 strncasecmp(a, short_opname, 2) == 0) { 586 if(flg_no) 667 if (strncasecmp(a, opname, l) == 0 668 || strncasecmp(a, short_opname, 2) == 0 669 ) { 670 if (flg_no) 587 671 vi_setops &= ~opt; 588 672 else 589 673 vi_setops |= opt; 590 674 } … … 592 676 #endif 593 677 594 static void colon( Byte* buf)595 { 596 Bytec, *orig_buf, *buf1, *q, *r;597 Byte *fn, cmd[BUFSIZ], args[BUFSIZ];598 int i, l, li, ch, st,b, e;678 static void colon(char * buf) 679 { 680 char c, *orig_buf, *buf1, *q, *r; 681 char *fn, cmd[MAX_LINELEN], args[MAX_LINELEN]; 682 int i, l, li, ch, b, e; 599 683 int useforce = FALSE, forced = FALSE; 600 struct stat st_buf;601 684 602 685 // :3154 // if (-e line 3154) goto it else stay put … … 615 698 // 616 699 617 if ( strlen((char *) buf) <= 0)700 if (!buf[0]) 618 701 goto vc1; 619 702 if (*buf == ':') 620 703 buf++; // move past the ':' 621 704 622 li = st =ch = i = 0;705 li = ch = i = 0; 623 706 b = e = -1; 624 707 q = text; // assume 1,$ for the range 625 708 r = end - 1; 626 709 li = count_lines(text, end - 1); 627 fn = c fn; // default to current file628 memset(cmd, '\0', BUFSIZ); // clear cmd[]629 memset(args, '\0', BUFSIZ); // clear args[]710 fn = current_filename; // default to current file 711 memset(cmd, '\0', MAX_LINELEN); // clear cmd[] 712 memset(args, '\0', MAX_LINELEN); // clear args[] 630 713 631 714 // look for optional address(es) :. :1 :1,9 :'q,'a :% … … 643 726 } 644 727 // get any ARGuments 645 while (isbl nk(*buf))728 while (isblank(*buf)) 646 729 buf++; 647 strcpy( (char *) args, (char *)buf);648 buf1 = (Byte*)last_char_is((char *)cmd, '!');730 strcpy(args, buf); 731 buf1 = last_char_is(cmd, '!'); 649 732 if (buf1) { 650 733 useforce = TRUE; … … 668 751 } 669 752 // ------------ now look for the command ------------ 670 i = strlen( (char *)cmd);753 i = strlen(cmd); 671 754 if (i == 0) { // :123CR goto line #123 672 755 if (b >= 0) { … … 674 757 dot_skip_over_ws(); 675 758 } 676 } else if (strncmp((char *) cmd, "!", 1) == 0) { // run a cmd 759 } 760 #if ENABLE_FEATURE_ALLOW_EXEC 761 else if (strncmp(cmd, "!", 1) == 0) { // run a cmd 762 int retcode; 677 763 // :!ls run the <cmd> 678 (void)alarm(0); // wait for input- no alarms764 alarm(0); // wait for input- no alarms 679 765 place_cursor(rows - 1, 0, FALSE); // go to Status line 680 766 clear_to_eol(); // clear the line 681 767 cookmode(); 682 system((char*)(orig_buf+1)); // run the cmd 768 retcode = system(orig_buf + 1); // run the cmd 769 if (retcode) 770 printf("\nshell returned %i\n\n", retcode); 683 771 rawmode(); 684 772 Hit_Return(); // let user see results 685 (void) alarm(3); // done waiting for input 686 } else if (strncmp((char *) cmd, "=", i) == 0) { // where is the address 773 alarm(3); // done waiting for input 774 } 775 #endif 776 else if (strncmp(cmd, "=", i) == 0) { // where is the address 687 777 if (b < 0) { // no addr given- use defaults 688 778 b = e = count_lines(text, dot); 689 779 } 690 780 psb("%d", b); 691 } else if (strncasecmp( (char *)cmd, "delete", i) == 0) { // delete lines781 } else if (strncasecmp(cmd, "delete", i) == 0) { // delete lines 692 782 if (b < 0) { // no addr given- use defaults 693 783 q = begin_line(dot); // assume .,. for the range … … 696 786 dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines 697 787 dot_skip_over_ws(); 698 } else if (strncasecmp((char *) cmd, "edit", i) == 0) { // Edit a file 699 int sr; 700 sr= 0; 788 } else if (strncasecmp(cmd, "edit", i) == 0) { // Edit a file 701 789 // don't edit, if the current file has been modified 702 790 if (file_modified && ! useforce) { … … 704 792 goto vc1; 705 793 } 706 if ( strlen((char*)args) > 0) {794 if (args[0]) { 707 795 // the user supplied a file name 708 fn = args;709 } else if (c fn != 0 && strlen((char*)cfn) > 0) {796 fn = args; 797 } else if (current_filename && current_filename[0]) { 710 798 // no user supplied name- use the current filename 711 fn= cfn; 712 goto vc5; 799 // fn = current_filename; was set by default 713 800 } else { 714 801 // no user file name, no current name- punt … … 717 804 } 718 805 719 // see if file exists- if not, its just a new file request 720 if ((sr=stat((char*)fn, &st_buf)) < 0) { 721 // This is just a request for a new file creation. 722 // The file_insert below will fail but we get 723 // an empty buffer with a file name. Then the "write" 724 // command can do the create. 725 } else { 726 if ((st_buf.st_mode & (S_IFREG)) == 0) { 727 // This is not a regular file 728 psbs("\"%s\" is not a regular file", fn); 729 goto vc1; 730 } 731 if ((st_buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) { 732 // dont have any read permissions 733 psbs("\"%s\" is not readable", fn); 734 goto vc1; 735 } 736 } 737 738 // There is a read-able regular file 739 // make this the current file 740 q = (Byte *) bb_xstrdup((char *) fn); // save the cfn 741 free(cfn); // free the old name 742 cfn = q; // remember new cfn 743 744 vc5: 745 // delete all the contents of text[] 746 new_text(2 * file_size(fn)); 747 screenbegin = dot = end = text; 748 749 // insert new file 750 ch = file_insert(fn, text, file_size(fn)); 751 752 if (ch < 1) { 753 // start empty buf with dummy line 754 (void) char_insert(text, '\n'); 755 ch= 1; 756 } 757 file_modified = 0; 758 last_file_modified = -1; 759 #ifdef CONFIG_FEATURE_VI_YANKMARK 806 if (init_text_buffer(fn) < 0) 807 goto vc1; 808 809 #if ENABLE_FEATURE_VI_YANKMARK 760 810 if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) { 761 811 free(reg[Ureg]); // free orig line reg- for 'U' … … 766 816 reg[YDreg]= 0; 767 817 } 768 for (li = 0; li < 28; li++) { 769 mark[li] = 0; 770 } // init the marks 771 #endif /* CONFIG_FEATURE_VI_YANKMARK */ 818 #endif 772 819 // how many lines in text[]? 773 820 li = count_lines(text, end - 1); 774 821 psb("\"%s\"%s" 775 #ifdef CONFIG_FEATURE_VI_READONLY 776 "%s" 777 #endif /* CONFIG_FEATURE_VI_READONLY */ 778 " %dL, %dC", cfn, 779 (sr < 0 ? " [New file]" : ""), 780 #ifdef CONFIG_FEATURE_VI_READONLY 781 ((vi_readonly || readonly) ? " [Read only]" : ""), 782 #endif /* CONFIG_FEATURE_VI_READONLY */ 822 USE_FEATURE_VI_READONLY("%s") 823 " %dL, %dC", current_filename, 824 (file_size(fn) < 0 ? " [New file]" : ""), 825 USE_FEATURE_VI_READONLY( 826 ((readonly_mode) ? " [Readonly]" : ""), 827 ) 783 828 li, ch); 784 } else if (strncasecmp( (char *)cmd, "file", i) == 0) { // what File is this829 } else if (strncasecmp(cmd, "file", i) == 0) { // what File is this 785 830 if (b != -1 || e != -1) { 786 ni( (Byte *)"No address allowed on this command");831 ni("No address allowed on this command"); 787 832 goto vc1; 788 833 } 789 if ( strlen((char *) args) > 0) {834 if (args[0]) { 790 835 // user wants a new filename 791 free(c fn);792 c fn = (Byte *) bb_xstrdup((char *)args);836 free(current_filename); 837 current_filename = xstrdup(args); 793 838 } else { 794 839 // user wants file status info 795 840 last_status_cksum = 0; // force status update 796 841 } 797 } else if (strncasecmp( (char *)cmd, "features", i) == 0) { // what features are available842 } else if (strncasecmp(cmd, "features", i) == 0) { // what features are available 798 843 // print out values of all features 799 844 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen … … 803 848 rawmode(); 804 849 Hit_Return(); 805 } else if (strncasecmp( (char *)cmd, "list", i) == 0) { // literal print line850 } else if (strncasecmp(cmd, "list", i) == 0) { // literal print line 806 851 if (b < 0) { // no addr given- use defaults 807 852 q = begin_line(dot); // assume .,. for the range … … 815 860 816 861 c = *q; 817 c_is_no_print = c > 127&& !Isprint(c);862 c_is_no_print = (c & 0x80) && !Isprint(c); 818 863 if (c_is_no_print) { 819 864 c = '.'; … … 824 869 } else if (c < ' ' || c == 127) { 825 870 putchar('^'); 826 if (c == 127)871 if (c == 127) 827 872 c = '?'; 828 829 c += '@';873 else 874 c += '@'; 830 875 } 831 876 putchar(c); … … 833 878 standout_end(); 834 879 } 835 #if def CONFIG_FEATURE_VI_SET836 837 #endif /* CONFIG_FEATURE_VI_SET */880 #if ENABLE_FEATURE_VI_SET 881 vc2: 882 #endif 838 883 Hit_Return(); 839 } else if ((strncasecmp((char *) cmd, "quit", i) == 0) || // Quit 840 (strncasecmp((char *) cmd, "next", i) == 0)) { // edit next file 884 } else if (strncasecmp(cmd, "quit", i) == 0 // Quit 885 || strncasecmp(cmd, "next", i) == 0 // edit next file 886 ) { 841 887 if (useforce) { 842 888 // force end of argv list … … 863 909 } 864 910 editing = 0; 865 } else if (strncasecmp( (char *)cmd, "read", i) == 0) { // read file into text[]911 } else if (strncasecmp(cmd, "read", i) == 0) { // read file into text[] 866 912 fn = args; 867 if ( strlen((char *) fn) <= 0) {913 if (!fn[0]) { 868 914 psbs("No filename given"); 869 915 goto vc1; … … 875 921 if (b != 0) 876 922 q = next_line(q); 877 #ifdef CONFIG_FEATURE_VI_READONLY 878 l= readonly; // remember current files' status 879 #endif 880 ch = file_insert(fn, q, file_size(fn)); 881 #ifdef CONFIG_FEATURE_VI_READONLY 882 readonly= l; 883 #endif 923 ch = file_insert(fn, q USE_FEATURE_VI_READONLY(, 0)); 884 924 if (ch < 0) 885 925 goto vc1; // nothing was inserted … … 887 927 li = count_lines(q, q + ch - 1); 888 928 psb("\"%s\"" 889 #ifdef CONFIG_FEATURE_VI_READONLY 890 "%s" 891 #endif /* CONFIG_FEATURE_VI_READONLY */ 929 USE_FEATURE_VI_READONLY("%s") 892 930 " %dL, %dC", fn, 893 #ifdef CONFIG_FEATURE_VI_READONLY 894 ((vi_readonly || readonly) ? " [Read only]" : ""), 895 #endif /* CONFIG_FEATURE_VI_READONLY */ 931 USE_FEATURE_VI_READONLY((readonly_mode ? " [Readonly]" : ""),) 896 932 li, ch); 897 933 if (ch > 0) { … … 901 937 file_modified++; 902 938 } 903 } else if (strncasecmp( (char *)cmd, "rewind", i) == 0) { // rewind cmd line args939 } else if (strncasecmp(cmd, "rewind", i) == 0) { // rewind cmd line args 904 940 if (file_modified && ! useforce) { 905 941 psbs("No write since last change (:rewind! overrides)"); … … 909 945 editing = 0; 910 946 } 911 #ifdef CONFIG_FEATURE_VI_SET 912 } else if (strncasecmp((char *) cmd, "set", i) == 0) { // set or clear features 947 #if ENABLE_FEATURE_VI_SET 948 } else if (strncasecmp(cmd, "set", i) == 0) { // set or clear features 949 #if ENABLE_FEATURE_VI_SETOPTS 950 char *argp; 951 #endif 913 952 i = 0; // offset into args 914 if (strlen((char *) args) == 0) { 953 // only blank is regarded as args delmiter. What about tab '\t' ? 954 if (!args[0] || strcasecmp(args, "all") == 0) { 915 955 // print out values of all options 916 956 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen 917 957 clear_to_eol(); // clear the line 918 958 printf("----------------------------------------\r\n"); 919 #if def CONFIG_FEATURE_VI_SETOPTS959 #if ENABLE_FEATURE_VI_SETOPTS 920 960 if (!autoindent) 921 961 printf("no"); … … 931 971 printf("showmatch "); 932 972 printf("tabstop=%d ", tabstop); 933 #endif /* CONFIG_FEATURE_VI_SETOPTS */973 #endif 934 974 printf("\r\n"); 935 975 goto vc2; 936 976 } 937 if (strncasecmp((char *) args, "no", 2) == 0) 938 i = 2; // ":set noautoindent" 939 #ifdef CONFIG_FEATURE_VI_SETOPTS 940 setops(args, "autoindent ", i, "ai", VI_AUTOINDENT); 941 setops(args, "flash ", i, "fl", VI_ERR_METHOD); 942 setops(args, "ignorecase ", i, "ic", VI_IGNORECASE); 943 setops(args, "showmatch ", i, "ic", VI_SHOWMATCH); 944 if (strncasecmp((char *) args + i, "tabstop=%d ", 7) == 0) { 945 sscanf(strchr((char *) args + i, '='), "=%d", &ch); 946 if (ch > 0 && ch < columns - 1) 947 tabstop = ch; 948 } 949 #endif /* CONFIG_FEATURE_VI_SETOPTS */ 950 #endif /* CONFIG_FEATURE_VI_SET */ 951 #ifdef CONFIG_FEATURE_VI_SEARCH 952 } else if (strncasecmp((char *) cmd, "s", 1) == 0) { // substitute a pattern with a replacement pattern 953 Byte *ls, *F, *R; 977 #if ENABLE_FEATURE_VI_SETOPTS 978 argp = args; 979 while (*argp) { 980 if (strncasecmp(argp, "no", 2) == 0) 981 i = 2; // ":set noautoindent" 982 setops(argp, "autoindent ", i, "ai", VI_AUTOINDENT); 983 setops(argp, "flash ", i, "fl", VI_ERR_METHOD); 984 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; 991 } 992 while (*argp && *argp != ' ') 993 argp++; // skip to arg delimiter (i.e. blank) 994 while (*argp && *argp == ' ') 995 argp++; // skip all delimiting blanks 996 } 997 #endif /* FEATURE_VI_SETOPTS */ 998 #endif /* FEATURE_VI_SET */ 999 #if ENABLE_FEATURE_VI_SEARCH 1000 } else if (strncasecmp(cmd, "s", 1) == 0) { // substitute a pattern with a replacement pattern 1001 char *ls, *F, *R; 954 1002 int gflag; 955 1003 … … 960 1008 c = orig_buf[1]; // what is the delimiter 961 1009 F = orig_buf + 2; // start of "find" 962 R = (Byte *) strchr((char *)F, c); // middle delimiter1010 R = strchr(F, c); // middle delimiter 963 1011 if (!R) goto colon_s_fail; 964 1012 *R++ = '\0'; // terminate "find" 965 buf1 = (Byte *) strchr((char *)R, c);1013 buf1 = strchr(R, c); 966 1014 if (!buf1) goto colon_s_fail; 967 1015 *buf1++ = '\0'; // terminate "replace" … … 979 1027 for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 980 1028 ls = q; // orig line start 981 1029 vc4: 982 1030 buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" 983 if (buf1 != NULL) {984 // we found the "find" pattern - delete it985 (void) text_hole_delete(buf1, buf1 + strlen((char *)F) - 1);1031 if (buf1) { 1032 // we found the "find" pattern - delete it 1033 text_hole_delete(buf1, buf1 + strlen(F) - 1); 986 1034 // inset the "replace" patern 987 (void)string_insert(buf1, R); // insert the string1035 string_insert(buf1, R); // insert the string 988 1036 // check for "global" :s/foo/bar/g 989 1037 if (gflag == 1) { 990 if ((buf1 + strlen( (char *)R)) < end_line(ls)) {991 q = buf1 + strlen( (char *)R);1038 if ((buf1 + strlen(R)) < end_line(ls)) { 1039 q = buf1 + strlen(R); 992 1040 goto vc4; // don't let q move past cur line 993 1041 } … … 996 1044 q = next_line(ls); 997 1045 } 998 #endif /* CONFIG_FEATURE_VI_SEARCH */ 999 } else if (strncasecmp((char *) cmd, "version", i) == 0) { // show software version 1000 psb("%s", vi_Version); 1001 } else if (strncasecmp((char *) cmd, "write", i) == 0 // write text to file 1002 || strncasecmp((char *) cmd, "wq", i) == 0 1003 || strncasecmp((char *) cmd, "wn", i) == 0 1004 || strncasecmp((char *) cmd, "x", i) == 0) { 1046 #endif /* FEATURE_VI_SEARCH */ 1047 } else if (strncasecmp(cmd, "version", i) == 0) { // show software version 1048 psb("%s", BB_VER " " BB_BT); 1049 } else if (strncasecmp(cmd, "write", i) == 0 // write text to file 1050 || strncasecmp(cmd, "wq", i) == 0 1051 || strncasecmp(cmd, "wn", i) == 0 1052 || strncasecmp(cmd, "x", i) == 0 1053 ) { 1005 1054 // is there a file name to write to? 1006 if ( strlen((char *) args) > 0) {1055 if (args[0]) { 1007 1056 fn = args; 1008 1057 } 1009 #if def CONFIG_FEATURE_VI_READONLY1010 if ( (vi_readonly || readonly) && !useforce) {1058 #if ENABLE_FEATURE_VI_READONLY 1059 if (readonly_mode && !useforce) { 1011 1060 psbs("\"%s\" File is read only", fn); 1012 1061 goto vc3; 1013 1062 } 1014 #endif /* CONFIG_FEATURE_VI_READONLY */1063 #endif 1015 1064 // how many lines in text[]? 1016 1065 li = count_lines(q, r); … … 1032 1081 if (l < 0) { 1033 1082 if (l == -1) 1034 psbs(" Write error: %s", strerror(errno));1083 psbs("\"%s\" %s", fn, strerror(errno)); 1035 1084 } else { 1036 1085 psb("\"%s\" %dL, %dC", fn, li, l); … … 1045 1094 } 1046 1095 } 1047 #if def CONFIG_FEATURE_VI_READONLY1048 1049 #endif /* CONFIG_FEATURE_VI_READONLY */1050 #if def CONFIG_FEATURE_VI_YANKMARK1051 } else if (strncasecmp( (char *)cmd, "yank", i) == 0) { // yank lines1096 #if ENABLE_FEATURE_VI_READONLY 1097 vc3:; 1098 #endif 1099 #if ENABLE_FEATURE_VI_YANKMARK 1100 } else if (strncasecmp(cmd, "yank", i) == 0) { // yank lines 1052 1101 if (b < 0) { // no addr given- use defaults 1053 1102 q = begin_line(dot); // assume .,. for the range … … 1057 1106 li = count_lines(q, r); 1058 1107 psb("Yank %d lines (%d chars) into [%c]", 1059 li, strlen((char *)reg[YDreg]), what_reg());1060 #endif /* CONFIG_FEATURE_VI_YANKMARK */1108 li, strlen(reg[YDreg]), what_reg()); 1109 #endif 1061 1110 } else { 1062 1111 // cmd unknown 1063 ni( (Byte *)cmd);1064 } 1065 1112 ni(cmd); 1113 } 1114 vc1: 1066 1115 dot = bound_dot(dot); // make sure "dot" is valid 1067 1116 return; 1068 #if def CONFIG_FEATURE_VI_SEARCH1069 colon_s_fail:1117 #if ENABLE_FEATURE_VI_SEARCH 1118 colon_s_fail: 1070 1119 psb(":s expression missing delimiters"); 1071 1120 #endif 1072 1121 } 1073 1122 1074 #endif /* CONFIG_FEATURE_VI_COLON */1123 #endif /* FEATURE_VI_COLON */ 1075 1124 1076 1125 static void Hit_Return(void) … … 1086 1135 } 1087 1136 1137 static int next_tabstop(int col) 1138 { 1139 return col + ((tabstop - 1) - (col % tabstop)); 1140 } 1141 1088 1142 //----- Synchronize the cursor to Dot -------------------------- 1089 static void sync_cursor( Byte* d, int *row, int *col)1090 { 1091 Byte *beg_cur;// begin and end of "d" line1092 Byte *beg_scr,*end_scr; // begin and end of screen1093 Byte*tp;1143 static void sync_cursor(char * d, int *row, int *col) 1144 { 1145 char *beg_cur; // begin and end of "d" line 1146 char *end_scr; // begin and end of screen 1147 char *tp; 1094 1148 int cnt, ro, co; 1095 1149 1096 1150 beg_cur = begin_line(d); // first char of cur line 1097 1151 1098 beg_scr = end_scr = screenbegin; // first char of screen1099 1152 end_scr = end_screen(); // last char of screen 1100 1153 … … 1103 1156 // how many lines do we have to move 1104 1157 cnt = count_lines(beg_cur, screenbegin); 1105 1158 sc1: 1106 1159 screenbegin = beg_cur; 1107 1160 if (cnt > (rows - 1) / 2) { … … 1139 1192 break; 1140 1193 if (*tp == '\t') { 1141 // 7 - (co % 8 ) 1142 co += ((tabstop - 1) - (co % tabstop)); 1194 if (d == tp && cmd_mode) { /* handle tabs like real vi */ 1195 break; 1196 } else { 1197 co = next_tabstop(co); 1198 } 1143 1199 } else if (*tp < ' ' || *tp == 127) { 1144 1200 co++; // display as ^X, use 2 columns … … 1177 1233 1178 1234 //----- Text Movement Routines --------------------------------- 1179 static Byte *begin_line(Byte* p) // return pointer to first char cur line1235 static char *begin_line(char * p) // return pointer to first char cur line 1180 1236 { 1181 1237 while (p > text && p[-1] != '\n') 1182 1238 p--; // go to cur line B-o-l 1183 return (p);1184 } 1185 1186 static Byte *end_line(Byte* p) // return pointer to NL of cur line line1239 return p; 1240 } 1241 1242 static char *end_line(char * p) // return pointer to NL of cur line line 1187 1243 { 1188 1244 while (p < end - 1 && *p != '\n') 1189 1245 p++; // go to cur line E-o-l 1190 return (p);1191 } 1192 1193 static inline Byte *dollar_line(Byte* p) // return pointer to just before NL line1246 return p; 1247 } 1248 1249 static inline char *dollar_line(char * p) // return pointer to just before NL line 1194 1250 { 1195 1251 while (p < end - 1 && *p != '\n') … … 1198 1254 if (*p == '\n' && (p - begin_line(p)) > 0) 1199 1255 p--; 1200 return (p);1201 } 1202 1203 static Byte *prev_line(Byte* p) // return pointer first char prev line1256 return p; 1257 } 1258 1259 static char *prev_line(char * p) // return pointer first char prev line 1204 1260 { 1205 1261 p = begin_line(p); // goto begining of cur line … … 1207 1263 p--; // step to prev line 1208 1264 p = begin_line(p); // goto begining of prev line 1209 return (p);1210 } 1211 1212 static Byte *next_line(Byte* p) // return pointer first char next line1265 return p; 1266 } 1267 1268 static char *next_line(char * p) // return pointer first char next line 1213 1269 { 1214 1270 p = end_line(p); 1215 1271 if (*p == '\n' && p < end - 1) 1216 1272 p++; // step to next line 1217 return (p);1273 return p; 1218 1274 } 1219 1275 1220 1276 //----- Text Information Routines ------------------------------ 1221 static Byte*end_screen(void)1222 { 1223 Byte*q;1277 static char *end_screen(void) 1278 { 1279 char *q; 1224 1280 int cnt; 1225 1281 … … 1229 1285 q = next_line(q); 1230 1286 q = end_line(q); 1231 return (q);1232 } 1233 1234 static int count_lines( Byte * start, Byte* stop) // count line from start to stop1235 { 1236 Byte*q;1287 return q; 1288 } 1289 1290 static int count_lines(char * start, char * stop) // count line from start to stop 1291 { 1292 char *q; 1237 1293 int cnt; 1238 1294 … … 1248 1304 cnt++; 1249 1305 } 1250 return (cnt);1251 } 1252 1253 static Byte*find_line(int li) // find begining of line #li1254 { 1255 Byte*q;1306 return cnt; 1307 } 1308 1309 static char *find_line(int li) // find begining of line #li 1310 { 1311 char *q; 1256 1312 1257 1313 for (q = text; li > 1; li--) { 1258 1314 q = next_line(q); 1259 1315 } 1260 return (q);1316 return q; 1261 1317 } 1262 1318 … … 1284 1340 } 1285 1341 1286 static Byte *move_to_col(Byte* p, int l)1342 static char *move_to_col(char * p, int l) 1287 1343 { 1288 1344 int co; … … 1294 1350 break; 1295 1351 if (*p == '\t') { 1296 // 7 - (co % 8 ) 1297 co += ((tabstop - 1) - (co % tabstop)); 1352 co = next_tabstop(co); 1298 1353 } else if (*p < ' ' || *p == 127) { 1299 1354 co++; // display as ^X, use 2 columns 1300 1355 } 1301 1356 } while (++co <= l && p++ < end); 1302 return (p);1357 return p; 1303 1358 } 1304 1359 … … 1315 1370 static void dot_scroll(int cnt, int dir) 1316 1371 { 1317 Byte*q;1372 char *q; 1318 1373 1319 1374 for (; cnt > 0; cnt--) { … … 1346 1401 static void dot_delete(void) // delete the char at 'dot' 1347 1402 { 1348 (void)text_hole_delete(dot, dot);1349 } 1350 1351 static Byte *bound_dot(Byte* p) // make sure text[0] <= P < "end"1403 text_hole_delete(dot, dot); 1404 } 1405 1406 static char *bound_dot(char * p) // make sure text[0] <= P < "end" 1352 1407 { 1353 1408 if (p >= end && end > text) { … … 1359 1414 indicate_error('2'); 1360 1415 } 1361 return (p);1416 return p; 1362 1417 } 1363 1418 … … 1375 1430 */ 1376 1431 1377 static Byte*new_screen(int ro, int co)1432 static char *new_screen(int ro, int co) 1378 1433 { 1379 1434 int li; … … 1381 1436 free(screen); 1382 1437 screensize = ro * co + 8; 1383 screen = (Byte *)xmalloc(screensize);1438 screen = xmalloc(screensize); 1384 1439 // initialize the new screen. assume this will be a empty file. 1385 1440 screen_erase(); … … 1388 1443 screen[(li * co) + 0] = '~'; 1389 1444 } 1390 return (screen); 1391 } 1392 1393 static Byte *new_text(int size) 1394 { 1395 if (size < 10240) 1396 size = 10240; // have a minimum size for new files 1397 free(text); 1398 text = (Byte *) xmalloc(size + 8); 1399 memset(text, '\0', size); // clear new text[] 1400 //text += 4; // leave some room for "oops" 1401 textend = text + size - 1; 1402 //textend -= 4; // leave some root for "oops" 1403 return (text); 1404 } 1405 1406 #ifdef CONFIG_FEATURE_VI_SEARCH 1407 static int mycmp(Byte * s1, Byte * s2, int len) 1445 return screen; 1446 } 1447 1448 #if ENABLE_FEATURE_VI_SEARCH 1449 static int mycmp(const char * s1, const char * s2, int len) 1408 1450 { 1409 1451 int i; 1410 1452 1411 i = strncmp((char *) s1, (char *) s2, len); 1412 #ifdef CONFIG_FEATURE_VI_SETOPTS 1413 if (ignorecase) { 1414 i = strncasecmp((char *) s1, (char *) s2, len); 1415 } 1416 #endif /* CONFIG_FEATURE_VI_SETOPTS */ 1417 return (i); 1418 } 1419 1420 static Byte *char_search(Byte * p, Byte * pat, int dir, int range) // search for pattern starting at p 1453 i = strncmp(s1, s2, len); 1454 if (ENABLE_FEATURE_VI_SETOPTS && ignorecase) { 1455 i = strncasecmp(s1, s2, len); 1456 } 1457 return i; 1458 } 1459 1460 // search for pattern starting at p 1461 static char *char_search(char * p, const char * pat, int dir, int range) 1421 1462 { 1422 1463 #ifndef REGEX_SEARCH 1423 Byte*start, *stop;1464 char *start, *stop; 1424 1465 int len; 1425 1466 1426 len = strlen( (char *)pat);1467 len = strlen(pat); 1427 1468 if (dir == FORWARD) { 1428 1469 stop = end - 1; // assume range is p - end-1 … … 1431 1472 for (start = p; start < stop; start++) { 1432 1473 if (mycmp(start, pat, len) == 0) { 1433 return (start);1474 return start; 1434 1475 } 1435 1476 } … … 1440 1481 for (start = p - len; start >= stop; start--) { 1441 1482 if (mycmp(start, pat, len) == 0) { 1442 return (start);1483 return start; 1443 1484 } 1444 1485 } 1445 1486 } 1446 1487 // pattern not found 1447 return (NULL);1448 #else /*REGEX_SEARCH */1488 return NULL; 1489 #else /* REGEX_SEARCH */ 1449 1490 char *q; 1450 1491 struct re_pattern_buffer preg; … … 1473 1514 range = q - p; 1474 1515 1475 q = (char *) re_compile_pattern(pat, strlen((char *)pat), &preg);1516 q = re_compile_pattern(pat, strlen(pat), &preg); 1476 1517 if (q != 0) { 1477 1518 // The pattern was not compiled … … 1500 1541 i = 0; // return NULL if pattern not found 1501 1542 } 1502 1543 cs1: 1503 1544 if (dir == FORWARD) { 1504 1545 p = p + i; … … 1506 1547 p = p - i; 1507 1548 } 1508 return (p);1509 #endif /*REGEX_SEARCH */1510 } 1511 #endif /* CONFIG_FEATURE_VI_SEARCH */1512 1513 static Byte *char_insert(Byte * p, Bytec) // insert the char c at 'p'1549 return p; 1550 #endif /* REGEX_SEARCH */ 1551 } 1552 #endif /* FEATURE_VI_SEARCH */ 1553 1554 static char *char_insert(char * p, char c) // insert the char c at 'p' 1514 1555 { 1515 1556 if (c == 22) { // Is this an ctrl-V? … … 1526 1567 end_cmd_q(); // stop adding to q 1527 1568 last_status_cksum = 0; // force status update 1528 if ((p[-1] != '\n') && (dot >text)) {1569 if ((p[-1] != '\n') && (dot > text)) { 1529 1570 p--; 1530 1571 } … … 1537 1578 } else { 1538 1579 // insert a char into text[] 1539 Byte*sp; // "save p"1580 char *sp; // "save p" 1540 1581 1541 1582 if (c == 13) … … 1543 1584 sp = p; // remember addr of insert 1544 1585 p = stupid_insert(p, c); // insert the char 1545 #if def CONFIG_FEATURE_VI_SETOPTS1586 #if ENABLE_FEATURE_VI_SETOPTS 1546 1587 if (showmatch && strchr(")]}", *sp) != NULL) { 1547 1588 showmatching(sp); 1548 1589 } 1549 1590 if (autoindent && c == '\n') { // auto indent the new line 1550 Byte*q;1591 char *q; 1551 1592 1552 1593 q = prev_line(p); // use prev line as templet 1553 for (; isbl nk(*q); q++) {1594 for (; isblank(*q); q++) { 1554 1595 p = stupid_insert(p, *q); // insert the char 1555 1596 } 1556 1597 } 1557 #endif /* CONFIG_FEATURE_VI_SETOPTS */1558 } 1559 return (p);1560 } 1561 1562 static Byte *stupid_insert(Byte * p, Bytec) // stupidly insert the char c at 'p'1598 #endif 1599 } 1600 return p; 1601 } 1602 1603 static char *stupid_insert(char * p, char c) // stupidly insert the char c at 'p' 1563 1604 { 1564 1605 p = text_hole_make(p, 1); … … 1568 1609 p++; 1569 1610 } 1570 return (p);1571 } 1572 1573 static Byte find_range(Byte ** start, Byte ** stop, Bytec)1574 { 1575 Byte*save_dot, *p, *q;1611 return p; 1612 } 1613 1614 static char find_range(char ** start, char ** stop, char c) 1615 { 1616 char *save_dot, *p, *q; 1576 1617 int cnt; 1577 1618 … … 1625 1666 } 1626 1667 dot = save_dot; 1627 return (c);1628 } 1629 1630 static int st_test( Byte * p, int type, int dir, Byte* tested)1631 { 1632 Bytec, c0, ci;1668 return c; 1669 } 1670 1671 static int st_test(char * p, int type, int dir, char * tested) 1672 { 1673 char c, c0, ci; 1633 1674 int test, inc; 1634 1675 … … 1659 1700 } 1660 1701 *tested = c; 1661 return (test);1662 } 1663 1664 static Byte *skip_thing(Byte* p, int linecnt, int dir, int type)1665 { 1666 Bytec;1702 return test; 1703 } 1704 1705 static char *skip_thing(char * p, int linecnt, int dir, int type) 1706 { 1707 char c; 1667 1708 1668 1709 while (st_test(p, type, dir, &c)) { … … 1676 1717 p += dir; // move to next char 1677 1718 } 1678 return (p);1719 return p; 1679 1720 } 1680 1721 1681 1722 // find matching char of pair () [] {} 1682 static Byte *find_pair(Byte * p, Bytec)1683 { 1684 Bytematch, *q;1723 static char *find_pair(char * p, char c) 1724 { 1725 char match, *q; 1685 1726 int dir, level; 1686 1727 … … 1722 1763 if (level != 0) 1723 1764 q = NULL; // indicate no match 1724 return (q);1725 } 1726 1727 #if def CONFIG_FEATURE_VI_SETOPTS1765 return q; 1766 } 1767 1768 #if ENABLE_FEATURE_VI_SETOPTS 1728 1769 // show the matching char of a pair, () [] {} 1729 static void showmatching( Byte* p)1730 { 1731 Byte*q, *save_dot;1770 static void showmatching(char * p) 1771 { 1772 char *q, *save_dot; 1732 1773 1733 1774 // we found half of a pair … … 1740 1781 dot = q; // go to new loc 1741 1782 refresh(FALSE); // let the user see it 1742 (void)mysleep(40); // give user some time1783 mysleep(40); // give user some time 1743 1784 dot = save_dot; // go back to old loc 1744 1785 refresh(FALSE); 1745 1786 } 1746 1787 } 1747 #endif /* CONFIG_FEATURE_VI_SETOPTS */1788 #endif /* FEATURE_VI_SETOPTS */ 1748 1789 1749 1790 // open a hole in text[] 1750 static Byte *text_hole_make(Byte* p, int size) // at "p", make a 'size' byte hole1751 { 1752 Byte*src, *dest;1791 static char *text_hole_make(char * p, int size) // at "p", make a 'size' byte hole 1792 { 1793 char *src, *dest; 1753 1794 int cnt; 1754 1795 … … 1758 1799 dest = p + size; 1759 1800 cnt = end - src; // the rest of buffer 1760 if (memmove(dest, src, cnt) != dest) { 1801 if ( ((end + size) >= (text + text_size)) // TODO: realloc here 1802 || memmove(dest, src, cnt) != dest) { 1761 1803 psbs("can't create room for new characters"); 1804 p = NULL; 1805 goto thm0; 1762 1806 } 1763 1807 memset(p, ' ', size); // clear new hole 1764 end = end + size;// adjust the new END1808 end += size; // adjust the new END 1765 1809 file_modified++; // has the file been modified 1766 1767 return (p);1810 thm0: 1811 return p; 1768 1812 } 1769 1813 1770 1814 // close a hole in text[] 1771 static Byte *text_hole_delete(Byte * p, Byte* q) // delete "p" thru "q", inclusive1772 { 1773 Byte*src, *dest;1815 static char *text_hole_delete(char * p, char * q) // delete "p" thru "q", inclusive 1816 { 1817 char *src, *dest; 1774 1818 int cnt, hole_size; 1775 1819 … … 1793 1837 psbs("can't delete the character"); 1794 1838 } 1795 1839 thd_atend: 1796 1840 end = end - hole_size; // adjust the new END 1797 1841 if (dest >= end) … … 1800 1844 dest = end = text; // keep pointers valid 1801 1845 file_modified++; // has the file been modified 1802 1803 return (dest);1846 thd0: 1847 return dest; 1804 1848 } 1805 1849 … … 1807 1851 // if dist <= 0, do not include, or go past, a NewLine 1808 1852 // 1809 static Byte *yank_delete(Byte * start, Byte* stop, int dist, int yf)1810 { 1811 Byte*p;1853 static char *yank_delete(char * start, char * stop, int dist, int yf) 1854 { 1855 char *p; 1812 1856 1813 1857 // make sure start <= stop … … 1819 1863 } 1820 1864 if (dist <= 0) { 1821 // we can 1865 // we cannot cross NL boundaries 1822 1866 p = start; 1823 1867 if (*p == '\n') 1824 return (p);1868 return p; 1825 1869 // dont go past a NewLine 1826 1870 for (; p + 1 <= stop; p++) { … … 1832 1876 } 1833 1877 p = start; 1834 #if def CONFIG_FEATURE_VI_YANKMARK1878 #if ENABLE_FEATURE_VI_YANKMARK 1835 1879 text_yank(start, stop, YDreg); 1836 #endif /* CONFIG_FEATURE_VI_YANKMARK */1880 #endif 1837 1881 if (yf == YANKDEL) { 1838 1882 p = text_hole_delete(start, stop); 1839 1883 } // delete lines 1840 return (p);1884 return p; 1841 1885 } 1842 1886 … … 1844 1888 { 1845 1889 puts("These features are available:" 1846 #if def CONFIG_FEATURE_VI_SEARCH1890 #if ENABLE_FEATURE_VI_SEARCH 1847 1891 "\n\tPattern searches with / and ?" 1848 #endif /* CONFIG_FEATURE_VI_SEARCH */1849 #if def CONFIG_FEATURE_VI_DOT_CMD1892 #endif 1893 #if ENABLE_FEATURE_VI_DOT_CMD 1850 1894 "\n\tLast command repeat with \'.\'" 1851 #endif /* CONFIG_FEATURE_VI_DOT_CMD */1852 #if def CONFIG_FEATURE_VI_YANKMARK1895 #endif 1896 #if ENABLE_FEATURE_VI_YANKMARK 1853 1897 "\n\tLine marking with 'x" 1854 1898 "\n\tNamed buffers with \"x" 1855 #endif /* CONFIG_FEATURE_VI_YANKMARK */1856 #if def CONFIG_FEATURE_VI_READONLY1899 #endif 1900 #if ENABLE_FEATURE_VI_READONLY 1857 1901 "\n\tReadonly if vi is called as \"view\"" 1858 1902 "\n\tReadonly with -R command line arg" 1859 #endif /* CONFIG_FEATURE_VI_READONLY */1860 #if def CONFIG_FEATURE_VI_SET1903 #endif 1904 #if ENABLE_FEATURE_VI_SET 1861 1905 "\n\tSome colon mode commands with \':\'" 1862 #endif /* CONFIG_FEATURE_VI_SET */1863 #if def CONFIG_FEATURE_VI_SETOPTS1906 #endif 1907 #if ENABLE_FEATURE_VI_SETOPTS 1864 1908 "\n\tSettable options with \":set\"" 1865 #endif /* CONFIG_FEATURE_VI_SETOPTS */1866 #if def CONFIG_FEATURE_VI_USE_SIGNALS1909 #endif 1910 #if ENABLE_FEATURE_VI_USE_SIGNALS 1867 1911 "\n\tSignal catching- ^C" 1868 1912 "\n\tJob suspend and resume with ^Z" 1869 #endif /* CONFIG_FEATURE_VI_USE_SIGNALS */1870 #if def CONFIG_FEATURE_VI_WIN_RESIZE1913 #endif 1914 #if ENABLE_FEATURE_VI_WIN_RESIZE 1871 1915 "\n\tAdapt to window re-sizes" 1872 #endif /* CONFIG_FEATURE_VI_WIN_RESIZE */1916 #endif 1873 1917 ); 1874 1918 } 1875 1919 1876 static inline void print_literal(Byte * buf, Byte * s) // copy s to buf, convert unprintable 1877 { 1878 Byte c, b[2]; 1920 static inline void print_literal(char * buf, const char * s) // copy s to buf, convert unprintable 1921 { 1922 unsigned char c; 1923 char b[2]; 1879 1924 1880 1925 b[1] = '\0'; 1881 strcpy((char *) buf, ""); // init buf1882 if ( strlen((char *) s) <= 0)1883 s = (Byte *)"(NULL)";1884 for (; *s > '\0'; s++) {1926 buf[0] = '\0'; 1927 if (!s[0]) 1928 s = "(NULL)"; 1929 for (; *s; s++) { 1885 1930 int c_is_no_print; 1886 1931 1887 1932 c = *s; 1888 c_is_no_print = c > 127&& !Isprint(c);1933 c_is_no_print = (c & 0x80) && !Isprint(c); 1889 1934 if (c_is_no_print) { 1890 strcat( (char *)buf, SOn);1935 strcat(buf, SOn); 1891 1936 c = '.'; 1892 1937 } 1893 1938 if (c < ' ' || c == 127) { 1894 strcat( (char *)buf, "^");1895 if (c == 127)1939 strcat(buf, "^"); 1940 if (c == 127) 1896 1941 c = '?'; 1897 1898 c += '@';1942 else 1943 c += '@'; 1899 1944 } 1900 1945 b[0] = c; 1901 strcat( (char *) buf, (char *)b);1946 strcat(buf, b); 1902 1947 if (c_is_no_print) 1903 strcat((char *) buf, SOs); 1904 if (*s == '\n') { 1905 strcat((char *) buf, "$"); 1906 } 1907 } 1908 } 1909 1910 #ifdef CONFIG_FEATURE_VI_DOT_CMD 1911 static void start_new_cmd_q(Byte c) 1948 strcat(buf, SOs); 1949 if (*s == '\n') 1950 strcat(buf, "$"); 1951 } 1952 } 1953 1954 #if ENABLE_FEATURE_VI_DOT_CMD 1955 static void start_new_cmd_q(char c) 1912 1956 { 1913 1957 // release old cmd 1914 1958 free(last_modifying_cmd); 1915 1959 // get buffer for new cmd 1916 last_modifying_cmd = (Byte *) xmalloc(BUFSIZ); 1917 memset(last_modifying_cmd, '\0', BUFSIZ); // clear new cmd queue 1960 last_modifying_cmd = xzalloc(MAX_LINELEN); 1918 1961 // if there is a current cmd count put it in the buffer first 1919 1962 if (cmdcnt > 0) 1920 sprintf( (char *)last_modifying_cmd, "%d%c", cmdcnt, c);1963 sprintf(last_modifying_cmd, "%d%c", cmdcnt, c); 1921 1964 else // just save char c onto queue 1922 1965 last_modifying_cmd[0] = c; … … 1926 1969 static void end_cmd_q(void) 1927 1970 { 1928 #if def CONFIG_FEATURE_VI_YANKMARK1971 #if ENABLE_FEATURE_VI_YANKMARK 1929 1972 YDreg = 26; // go back to default Yank/Delete reg 1930 #endif /* CONFIG_FEATURE_VI_YANKMARK */1973 #endif 1931 1974 adding2q = 0; 1932 return; 1933 } 1934 #endif /* CONFIG_FEATURE_VI_DOT_CMD */ 1935 1936 #if defined(CONFIG_FEATURE_VI_YANKMARK) || (defined(CONFIG_FEATURE_VI_COLON) && defined(CONFIG_FEATURE_VI_SEARCH)) || defined(CONFIG_FEATURE_VI_CRASHME) 1937 static Byte *string_insert(Byte * p, Byte * s) // insert the string at 'p' 1975 } 1976 #endif /* FEATURE_VI_DOT_CMD */ 1977 1978 #if ENABLE_FEATURE_VI_YANKMARK \ 1979 || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) \ 1980 || ENABLE_FEATURE_VI_CRASHME 1981 static char *string_insert(char * p, char * s) // insert the string at 'p' 1938 1982 { 1939 1983 int cnt, i; 1940 1984 1941 i = strlen((char *) s); 1942 p = text_hole_make(p, i); 1943 strncpy((char *) p, (char *) s, i); 1944 for (cnt = 0; *s != '\0'; s++) { 1945 if (*s == '\n') 1946 cnt++; 1947 } 1948 #ifdef CONFIG_FEATURE_VI_YANKMARK 1949 psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg()); 1950 #endif /* CONFIG_FEATURE_VI_YANKMARK */ 1951 return (p); 1952 } 1953 #endif /* CONFIG_FEATURE_VI_YANKMARK || CONFIG_FEATURE_VI_COLON || CONFIG_FEATURE_VI_CRASHME */ 1954 1955 #ifdef CONFIG_FEATURE_VI_YANKMARK 1956 static Byte *text_yank(Byte * p, Byte * q, int dest) // copy text into a register 1957 { 1958 Byte *t; 1985 i = strlen(s); 1986 if (text_hole_make(p, i)) { 1987 strncpy(p, s, i); 1988 for (cnt = 0; *s != '\0'; s++) { 1989 if (*s == '\n') 1990 cnt++; 1991 } 1992 #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; 1959 2004 int cnt; 1960 2005 … … 1967 2012 t = reg[dest]; 1968 2013 free(t); // if already a yank register, free it 1969 t = (Byte *)xmalloc(cnt + 1); // get a new register2014 t = xmalloc(cnt + 1); // get a new register 1970 2015 memset(t, '\0', cnt + 1); // clear new text[] 1971 strncpy( (char *) t, (char *)p, cnt); // copy text[] into bufer2016 strncpy(t, p, cnt); // copy text[] into bufer 1972 2017 reg[dest] = t; 1973 return (p); 1974 } 1975 1976 static Byte what_reg(void) 1977 { 1978 Byte c; 1979 int i; 1980 1981 i = 0; 2018 return p; 2019 } 2020 2021 static char what_reg(void) 2022 { 2023 char c; 2024 1982 2025 c = 'D'; // default to D-reg 1983 2026 if (0 <= YDreg && YDreg <= 25) 1984 c = 'a' + ( Byte) YDreg;2027 c = 'a' + (char) YDreg; 1985 2028 if (YDreg == 26) 1986 2029 c = 'D'; 1987 2030 if (YDreg == 27) 1988 2031 c = 'U'; 1989 return (c);1990 } 1991 1992 static void check_context( Bytecmd)2032 return c; 2033 } 2034 2035 static void check_context(char cmd) 1993 2036 { 1994 2037 // A context is defined to be "modifying text" … … 1996 2039 1997 2040 if (dot < context_start || dot > context_end) { 1998 if (strchr( (char *)modifying_cmds, cmd) != NULL) {2041 if (strchr(modifying_cmds, cmd) != NULL) { 1999 2042 // we are trying to modify text[]- make this the current context 2000 2043 mark[27] = mark[26]; // move cur to prev … … 2005 2048 } 2006 2049 } 2007 return; 2008 } 2009 2010 static inline Byte *swap_context(Byte * p) // goto new context for '' command make this the current context 2011 { 2012 Byte *tmp; 2050 } 2051 2052 static inline char *swap_context(char * p) // goto new context for '' command make this the current context 2053 { 2054 char *tmp; 2013 2055 2014 2056 // the current context is in mark[26] … … 2023 2065 context_end = next_line(next_line(next_line(p))); 2024 2066 } 2025 return (p); 2026 } 2027 #endif /* CONFIG_FEATURE_VI_YANKMARK */ 2028 2029 static int isblnk(Byte c) // is the char a blank or tab 2030 { 2031 return (c == ' ' || c == '\t'); 2032 } 2067 return p; 2068 } 2069 #endif /* FEATURE_VI_YANKMARK */ 2033 2070 2034 2071 //----- Set terminal attributes -------------------------------- … … 2053 2090 2054 2091 //----- Come here when we get a window resize signal --------- 2055 #if def CONFIG_FEATURE_VI_USE_SIGNALS2092 #if ENABLE_FEATURE_VI_USE_SIGNALS 2056 2093 static void winch_sig(int sig ATTRIBUTE_UNUSED) 2057 2094 { 2058 2095 signal(SIGWINCH, winch_sig); 2059 2096 if (ENABLE_FEATURE_VI_WIN_RESIZE) 2060 2097 get_terminal_width_height(0, &columns, &rows); 2061 2098 new_screen(rows, columns); // get memory for virtual screen 2062 2099 redraw(TRUE); // re-draw the screen … … 2091 2128 { 2092 2129 signal(SIGINT, catch_sig); 2093 if (sig)2130 if (sig) 2094 2131 longjmp(restart, sig); 2095 2132 } 2096 #endif /* CONFIG_FEATURE_VI_USE_SIGNALS */2133 #endif /* FEATURE_VI_USE_SIGNALS */ 2097 2134 2098 2135 static int mysleep(int hund) // sleep for 'h' 1/100 seconds 2099 2136 { 2137 fd_set rfds; 2138 struct timeval tv; 2139 2100 2140 // Don't hang- Wait 5/100 seconds- 1 Sec= 1000000 2101 2141 fflush(stdout); … … 2105 2145 tv.tv_usec = hund * 10000; 2106 2146 select(1, &rfds, NULL, NULL, &tv); 2107 return (FD_ISSET(0, &rfds));2147 return FD_ISSET(0, &rfds); 2108 2148 } 2109 2149 … … 2113 2153 2114 2154 //----- IO Routines -------------------------------------------- 2115 static Bytereadit(void) // read (maybe cursor) key from stdin2116 { 2117 Bytec;2155 static char readit(void) // read (maybe cursor) key from stdin 2156 { 2157 char c; 2118 2158 int n; 2119 2159 struct esc_cmds { 2120 2160 const char *seq; 2121 Byteval;2161 char val; 2122 2162 }; 2123 2163 2124 2164 static const struct esc_cmds esccmds[] = { 2125 {"OA", (Byte)VI_K_UP}, // cursor key Up2126 {"OB", (Byte)VI_K_DOWN}, // cursor key Down2127 {"OC", (Byte)VI_K_RIGHT}, // Cursor Key Right2128 {"OD", (Byte)VI_K_LEFT}, // cursor key Left2129 {"OH", (Byte)VI_K_HOME}, // Cursor Key Home2130 {"OF", (Byte)VI_K_END}, // Cursor Key End2131 {"[A", (Byte)VI_K_UP}, // cursor key Up2132 {"[B", (Byte)VI_K_DOWN}, // cursor key Down2133 {"[C", (Byte)VI_K_RIGHT}, // Cursor Key Right2134 {"[D", (Byte)VI_K_LEFT}, // cursor key Left2135 {"[H", (Byte)VI_K_HOME}, // Cursor Key Home2136 {"[F", (Byte)VI_K_END}, // Cursor Key End2137 {"[1~", (Byte) VI_K_HOME},// Cursor Key Home2138 {"[2~", (Byte)VI_K_INSERT}, // Cursor Key Insert2139 {"[4~", (Byte) VI_K_END},// Cursor Key End2140 {"[5~", (Byte)VI_K_PAGEUP}, // Cursor Key Page Up2141 {"[6~", (Byte) VI_K_PAGEDOWN},// Cursor Key Page Down2142 {"OP", (Byte)VI_K_FUN1}, // Function Key F12143 {"OQ", (Byte)VI_K_FUN2}, // Function Key F22144 {"OR", (Byte)VI_K_FUN3}, // Function Key F32145 {"OS", (Byte)VI_K_FUN4}, // Function Key F42146 {"[15~", (Byte)VI_K_FUN5}, // Function Key F52147 {"[17~", (Byte)VI_K_FUN6}, // Function Key F62148 {"[18~", (Byte)VI_K_FUN7}, // Function Key F72149 {"[19~", (Byte)VI_K_FUN8}, // Function Key F82150 {"[20~", (Byte)VI_K_FUN9}, // Function Key F92151 {"[21~", (Byte)VI_K_FUN10}, // Function Key F102152 {"[23~", (Byte)VI_K_FUN11}, // Function Key F112153 {"[24~", (Byte)VI_K_FUN12}, // Function Key F122154 {"[11~", (Byte)VI_K_FUN1}, // Function Key F12155 {"[12~", (Byte)VI_K_FUN2}, // Function Key F22156 {"[13~", (Byte)VI_K_FUN3}, // Function Key F32157 {"[14~", (Byte)VI_K_FUN4}, // Function Key F42165 {"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 2158 2198 }; 2159 2160 #define ESCCMDS_COUNT (sizeof(esccmds)/sizeof(struct esc_cmds)) 2161 2162 (void) alarm(0); // turn alarm OFF while we wait for input 2199 enum { ESCCMDS_COUNT = ARRAY_SIZE(esccmds) }; 2200 2201 alarm(0); // turn alarm OFF while we wait for input 2163 2202 fflush(stdout); 2164 2203 n = readed_for_parse; 2165 2204 // get input from User- are there already input chars in Q? 2166 2205 if (n <= 0) { 2167 2206 ri0: 2168 2207 // the Q is empty, wait for a typed char 2169 n = read(0, readbuffer, BUFSIZ- 1);2208 n = read(0, readbuffer, MAX_LINELEN - 1); 2170 2209 if (n < 0) { 2171 2210 if (errno == EINTR) 2172 2211 goto ri0; // interrupted sys call 2173 if (errno == EBADF) 2174 editing = 0; 2175 if (errno == EFAULT) 2176 editing = 0; 2177 if (errno == EINVAL) 2178 editing = 0; 2179 if (errno == EIO) 2212 if (errno == EBADF || errno == EFAULT || errno == EINVAL 2213 || errno == EIO) 2180 2214 editing = 0; 2181 2215 errno = 0; 2182 2216 } 2183 if (n <= 0)2217 if (n <= 0) 2184 2218 return 0; // error 2185 2219 if (readbuffer[0] == 27) { 2186 // This is an ESC char. Is this Esc sequence? 2187 // Could be bare Esc key. See if there are any 2188 // more chars to read after the ESC. This would 2189 // be a Function or Cursor Key sequence. 2190 FD_ZERO(&rfds); 2191 FD_SET(0, &rfds); 2192 tv.tv_sec = 0; 2193 tv.tv_usec = 50000; // Wait 5/100 seconds- 1 Sec=1000000 2194 2195 // keep reading while there are input chars and room in buffer 2196 while (select(1, &rfds, NULL, NULL, &tv) > 0 && n <= (BUFSIZ - 5)) { 2197 // read the rest of the ESC string 2198 int r = read(0, (void *) (readbuffer + n), BUFSIZ - n); 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); 2199 2236 if (r > 0) { 2200 2237 n += r; … … 2205 2242 } 2206 2243 c = readbuffer[0]; 2207 if (c == 27 && n > 1) {2208 // Maybe cursor or function key?2244 if (c == 27 && n > 1) { 2245 // Maybe cursor or function key? 2209 2246 const struct esc_cmds *eindex; 2210 2247 … … 2212 2249 int cnt = strlen(eindex->seq); 2213 2250 2214 if (n <= cnt)2251 if (n <= cnt) 2215 2252 continue; 2216 if (strncmp(eindex->seq, (char *)readbuffer + 1, cnt))2253 if (strncmp(eindex->seq, readbuffer + 1, cnt)) 2217 2254 continue; 2218 2255 // is a Cursor key- put derived value back into Q … … 2222 2259 break; 2223 2260 } 2224 if (eindex == &esccmds[ESCCMDS_COUNT]) {2261 if (eindex == &esccmds[ESCCMDS_COUNT]) { 2225 2262 /* defined ESC sequence not found, set only one ESC */ 2226 2263 n = 1; … … 2231 2268 // remove key sequence from Q 2232 2269 readed_for_parse -= n; 2233 memmove(readbuffer, readbuffer + n, BUFSIZ- n);2234 (void)alarm(3); // we are done waiting for input, turn alarm ON2235 return (c);2270 memmove(readbuffer, readbuffer + n, MAX_LINELEN - n); 2271 alarm(3); // we are done waiting for input, turn alarm ON 2272 return c; 2236 2273 } 2237 2274 2238 2275 //----- IO Routines -------------------------------------------- 2239 static Byteget_one_char(void)2240 { 2241 static Bytec;2242 2243 #if def CONFIG_FEATURE_VI_DOT_CMD2276 static char get_one_char(void) 2277 { 2278 static char c; 2279 2280 #if ENABLE_FEATURE_VI_DOT_CMD 2244 2281 // ! adding2q && ioq == 0 read() 2245 2282 // ! adding2q && ioq != 0 *ioq … … 2265 2302 c = readit(); // get the users input 2266 2303 if (last_modifying_cmd != 0) { 2267 int len = strlen( (char *)last_modifying_cmd);2268 if (len + 1 >= BUFSIZ) {2304 int len = strlen(last_modifying_cmd); 2305 if (len >= MAX_LINELEN - 1) { 2269 2306 psbs("last_modifying_cmd overrun"); 2270 2307 } else { … … 2274 2311 } 2275 2312 } 2276 #else /* CONFIG_FEATURE_VI_DOT_CMD */2313 #else 2277 2314 c = readit(); // get the users input 2278 #endif /* CONFIG_FEATURE_VI_DOT_CMD */ 2279 return (c); // return the char, where ever it came from 2280 } 2281 2282 static Byte *get_input_line(Byte * prompt) // get input line- use "status line" 2283 { 2284 Byte buf[BUFSIZ]; 2285 Byte c; 2315 #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; 2286 2325 int i; 2287 static Byte *obufp = NULL; 2288 2289 strcpy((char *) buf, (char *) prompt); 2326 2327 strcpy(buf, prompt); 2290 2328 last_status_cksum = 0; // force status update 2291 2329 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen 2292 2330 clear_to_eol(); // clear the line 2293 write1((char *) prompt); // write out the :, /, or ? prompt 2294 2295 for (i = strlen((char *) buf); i < BUFSIZ;) { 2331 write1(prompt); // write out the :, /, or ? prompt 2332 2333 i = strlen(buf); 2334 while (i < MAX_LINELEN) { 2296 2335 c = get_one_char(); // read user input 2297 2336 if (c == '\n' || c == '\r' || c == 27) … … 2315 2354 refresh(FALSE); 2316 2355 free(obufp); 2317 obufp = (Byte *) bb_xstrdup((char *)buf);2318 return (obufp);2319 } 2320 2321 static int file_size(const Byte *fn) // what is the byte size of "fn"2356 obufp = xstrdup(buf); 2357 return obufp; 2358 } 2359 2360 static int file_size(const char *fn) // what is the byte size of "fn" 2322 2361 { 2323 2362 struct stat st_buf; 2324 int cnt, sr; 2325 2326 if (fn == 0 || strlen((char *)fn) <= 0) 2327 return (-1); 2363 int cnt; 2364 2328 2365 cnt = -1; 2329 sr = stat((char *) fn, &st_buf); // see if file exists 2330 if (sr >= 0) { 2366 if (fn && fn[0] && stat(fn, &st_buf) == 0) // see if file exists 2331 2367 cnt = (int) st_buf.st_size; 2332 } 2333 return (cnt); 2334 } 2335 2336 static int file_insert(Byte * fn, Byte * p, int size) 2337 { 2338 int fd, cnt; 2339 2340 cnt = -1; 2341 #ifdef CONFIG_FEATURE_VI_READONLY 2342 readonly = FALSE; 2343 #endif /* CONFIG_FEATURE_VI_READONLY */ 2344 if (fn == 0 || strlen((char*) fn) <= 0) { 2345 psbs("No filename given"); 2368 return cnt; 2369 } 2370 2371 static int file_insert(const char * fn, char *p 2372 USE_FEATURE_VI_READONLY(, int update_ro_status)) 2373 { 2374 int cnt = -1; 2375 int fd, size; 2376 struct stat statbuf; 2377 2378 /* Validate file */ 2379 if (stat(fn, &statbuf) < 0) { 2380 psbs("\"%s\" %s", fn, strerror(errno)); 2346 2381 goto fi0; 2347 2382 } 2348 if ( size== 0) {2349 // OK- this is just a no-op2350 cnt = 0;2383 if ((statbuf.st_mode & S_IFREG) == 0) { 2384 // This is not a regular file 2385 psbs("\"%s\" Not a regular file", fn); 2351 2386 goto fi0; 2352 2387 } 2353 if (size < 0) { 2354 psbs("Trying to insert a negative number (%d) of characters", size); 2388 /* // this check is done by open() 2389 if ((statbuf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) { 2390 // dont have any read permissions 2391 psbs("\"%s\" Not readable", fn); 2355 2392 goto fi0; 2356 2393 } 2394 */ 2357 2395 if (p < text || p > end) { 2358 2396 psbs("Trying to insert file outside of memory"); … … 2360 2398 } 2361 2399 2362 // see if we can open the file 2363 #ifdef CONFIG_FEATURE_VI_READONLY 2364 if (vi_readonly) goto fi1; // do not try write-mode 2365 #endif 2366 fd = open((char *) fn, O_RDWR); // assume read & write 2400 // read file to buffer 2401 fd = open(fn, O_RDONLY); 2367 2402 if (fd < 0) { 2368 // could not open for writing- maybe file is read only 2369 #ifdef CONFIG_FEATURE_VI_READONLY 2370 fi1: 2371 #endif 2372 fd = open((char *) fn, O_RDONLY); // try read-only 2373 if (fd < 0) { 2374 psbs("\"%s\" %s", fn, "could not open file"); 2375 goto fi0; 2376 } 2377 #ifdef CONFIG_FEATURE_VI_READONLY 2378 // got the file- read-only 2379 readonly = TRUE; 2380 #endif /* CONFIG_FEATURE_VI_READONLY */ 2381 } 2403 psbs("\"%s\" %s", fn, strerror(errno)); 2404 goto fi0; 2405 } 2406 size = statbuf.st_size; 2382 2407 p = text_hole_make(p, size); 2408 if (p == NULL) 2409 goto fi0; 2383 2410 cnt = read(fd, p, size); 2384 close(fd);2385 2411 if (cnt < 0) { 2386 cnt = -1;2412 psbs("\"%s\" %s", fn, strerror(errno)); 2387 2413 p = text_hole_delete(p, p + size - 1); // un-do buffer insert 2388 psbs("could not read file \"%s\"", fn);2389 2414 } else if (cnt < size) { 2390 2415 // There was a partial read, shrink unused space text[] 2391 2416 p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert 2392 psbs("c ouldnot read all of file \"%s\"", fn);2417 psbs("cannot read all of file \"%s\"", fn); 2393 2418 } 2394 2419 if (cnt >= size) 2395 2420 file_modified++; 2396 fi0: 2397 return (cnt); 2398 } 2399 2400 static int file_write(Byte * fn, Byte * first, Byte * last) 2421 close(fd); 2422 fi0: 2423 #if ENABLE_FEATURE_VI_READONLY 2424 if (update_ro_status 2425 && ((access(fn, W_OK) < 0) || 2426 /* root will always have access() 2427 * so we check fileperms too */ 2428 !(statbuf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)) 2429 ) 2430 ) { 2431 SET_READONLY_FILE(readonly_mode); 2432 } 2433 #endif 2434 return cnt; 2435 } 2436 2437 2438 static int file_write(char * fn, char * first, char * last) 2401 2439 { 2402 2440 int fd, cnt, charcnt; … … 2404 2442 if (fn == 0) { 2405 2443 psbs("No current filename"); 2406 return (-2);2444 return -2; 2407 2445 } 2408 2446 charcnt = 0; 2409 2447 // FIXIT- use the correct umask() 2410 fd = open( (char *)fn, (O_WRONLY | O_CREAT | O_TRUNC), 0664);2448 fd = open(fn, (O_WRONLY | O_CREAT | O_TRUNC), 0664); 2411 2449 if (fd < 0) 2412 return (-1);2450 return -1; 2413 2451 cnt = last - first + 1; 2414 2452 charcnt = write(fd, first, cnt); 2415 2453 if (charcnt == cnt) { 2416 2454 // good write 2417 //file_modified = FALSE; // the file has not been modified2455 //file_modified = FALSE; // the file has not been modified 2418 2456 } else { 2419 2457 charcnt = 0; 2420 2458 } 2421 2459 close(fd); 2422 return (charcnt);2460 return charcnt; 2423 2461 } 2424 2462 … … 2438 2476 static void place_cursor(int row, int col, int opti) 2439 2477 { 2440 char cm1[ BUFSIZ];2478 char cm1[MAX_LINELEN]; 2441 2479 char *cm; 2442 #if def CONFIG_FEATURE_VI_OPTIMIZE_CURSOR2443 char cm2[ BUFSIZ];2444 Byte*screenp;2445 // char cm3[ BUFSIZ];2446 int Rrow = last_row;2447 #endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */2448 2449 memset(cm1, '\0', BUFSIZ - 1); // clear the buffer2480 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2481 char cm2[MAX_LINELEN]; 2482 char *screenp; 2483 // char cm3[MAX_LINELEN]; 2484 int Rrow = last_row; 2485 #endif 2486 2487 memset(cm1, '\0', MAX_LINELEN); // clear the buffer 2450 2488 2451 2489 if (row < 0) row = 0; … … 2455 2493 2456 2494 //----- 1. Try the standard terminal ESC sequence 2457 sprintf((char *) cm1, CMrc, row + 1, col + 1); 2458 cm= cm1; 2459 if (! opti) goto pc0; 2460 2461 #ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR 2495 sprintf(cm1, CMrc, row + 1, col + 1); 2496 cm = cm1; 2497 if (!opti) 2498 goto pc0; 2499 2500 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2462 2501 //----- find the minimum # of chars to move cursor ------------- 2463 2502 //----- 2. Try moving with discreet chars (Newline, [back]space, ...) 2464 memset(cm2, '\0', BUFSIZ - 1); // clear the buffer2503 memset(cm2, '\0', MAX_LINELEN); // clear the buffer 2465 2504 2466 2505 // move to the correct row … … 2480 2519 // just send out orignal source char to get to correct place 2481 2520 screenp = &screen[row * columns]; // start of screen line 2482 strncat(cm2, (char* )screenp, col);2521 strncat(cm2, screenp, col); 2483 2522 2484 2523 //----- 3. Try some other way of moving cursor … … 2486 2525 2487 2526 // pick the shortest cursor motion to send out 2488 cm = cm1;2527 cm = cm1; 2489 2528 if (strlen(cm2) < strlen(cm)) { 2490 cm = cm2;2529 cm = cm2; 2491 2530 } /* else if (strlen(cm3) < strlen(cm)) { 2492 2531 cm= cm3; 2493 2532 } */ 2494 #endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */2495 2533 #endif /* FEATURE_VI_OPTIMIZE_CURSOR */ 2534 pc0: 2496 2535 write1(cm); // move the cursor 2497 2536 } … … 2526 2565 standout_start(); // send "start reverse video" sequence 2527 2566 redraw(TRUE); 2528 (void)mysleep(h);2567 mysleep(h); 2529 2568 standout_end(); // send "end reverse video" sequence 2530 2569 redraw(TRUE); … … 2533 2572 static void Indicate_Error(void) 2534 2573 { 2535 #if def CONFIG_FEATURE_VI_CRASHME2574 #if ENABLE_FEATURE_VI_CRASHME 2536 2575 if (crashme > 0) 2537 2576 return; // generate a random command 2538 #endif /* CONFIG_FEATURE_VI_CRASHME */2577 #endif 2539 2578 if (!err_method) { 2540 2579 write1(bell); // send out a bell character … … 2551 2590 } 2552 2591 2553 static int bufsum( unsignedchar *buf, int count)2592 static int bufsum(char *buf, int count) 2554 2593 { 2555 2594 int sum = 0; 2556 unsigned char *e = buf + count; 2595 char *e = buf + count; 2596 2557 2597 while (buf < e) 2558 sum += *buf++;2598 sum += (unsigned char) *buf++; 2559 2599 return sum; 2560 2600 } … … 2574 2614 last_status_cksum= cksum; // remember if we have seen this line 2575 2615 place_cursor(rows - 1, 0, FALSE); // put cursor on status line 2576 write1( (char*)status_buffer);2616 write1(status_buffer); 2577 2617 clear_to_eol(); 2578 2618 if (have_status_msg) { 2579 if (((int)strlen( (char*)status_buffer) - (have_status_msg - 1)) >2619 if (((int)strlen(status_buffer) - (have_status_msg - 1)) > 2580 2620 (columns - 1) ) { 2581 2621 have_status_msg = 0; … … 2596 2636 2597 2637 va_start(args, format); 2598 strcpy( (char *)status_buffer, SOs); // Terminal standout mode on2599 vsprintf( (char *) status_buffer + strlen((char *)status_buffer), format, args);2600 strcat( (char *)status_buffer, SOn); // Terminal standout mode off2638 strcpy(status_buffer, SOs); // Terminal standout mode on 2639 vsprintf(status_buffer + strlen(status_buffer), format, args); 2640 strcat(status_buffer, SOn); // Terminal standout mode off 2601 2641 va_end(args); 2602 2642 2603 2643 have_status_msg = 1 + sizeof(SOs) + sizeof(SOn) - 2; 2604 2605 return;2606 2644 } 2607 2645 … … 2612 2650 2613 2651 va_start(args, format); 2614 vsprintf( (char *)status_buffer, format, args);2652 vsprintf(status_buffer, format, args); 2615 2653 va_end(args); 2616 2654 2617 2655 have_status_msg = 1; 2618 2619 return; 2620 } 2621 2622 static void ni(Byte * s) // display messages 2623 { 2624 Byte buf[BUFSIZ]; 2656 } 2657 2658 static void ni(const char * s) // display messages 2659 { 2660 char buf[MAX_LINELEN]; 2625 2661 2626 2662 print_literal(buf, s); … … 2630 2666 static int format_edit_status(void) // show file status on status line 2631 2667 { 2668 static int tot; 2669 static const char cmd_mode_indicator[] ALIGN1 = "-IR-"; 2632 2670 int cur, percent, ret, trunc_at; 2633 static int tot;2634 2671 2635 2672 // file_modified is now a counter rather than a flag. this … … 2663 2700 columns : STATUS_BUFFER_LEN-1; 2664 2701 2665 ret = snprintf( (char *)status_buffer, trunc_at+1,2666 #if def CONFIG_FEATURE_VI_READONLY2702 ret = snprintf(status_buffer, trunc_at+1, 2703 #if ENABLE_FEATURE_VI_READONLY 2667 2704 "%c %s%s%s %d/%d %d%%", 2668 2705 #else 2669 2706 "%c %s%s %d/%d %d%%", 2670 2707 #endif 2671 (cmd_mode ? (cmd_mode == 2 ? 'R':'I'):'-'),2672 (c fn != 0 ? (char *) cfn: "No file"),2673 #if def CONFIG_FEATURE_VI_READONLY2674 ( (vi_readonly || readonly) ? " [Read-only]" : ""),2675 #endif 2676 (file_modified ? " [ modified]" : ""),2708 cmd_mode_indicator[cmd_mode & 3], 2709 (current_filename != NULL ? current_filename : "No file"), 2710 #if ENABLE_FEATURE_VI_READONLY 2711 (readonly_mode ? " [Readonly]" : ""), 2712 #endif 2713 (file_modified ? " [Modified]" : ""), 2677 2714 cur, tot, percent); 2678 2715 … … 2695 2732 2696 2733 //----- Format a text[] line into a buffer --------------------- 2697 static void format_line( Byte *dest, Byte*src, int li)2734 static void format_line(char *dest, char *src, int li) 2698 2735 { 2699 2736 int co; 2700 Bytec;2701 2702 for (co = 0; co < MAX_SCR_COLS; co++) {2703 c = ' '; // assume blank2737 char c; 2738 2739 for (co = 0; co < MAX_SCR_COLS; co++) { 2740 c = ' '; // assume blank 2704 2741 if (li > 0 && co == 0) { 2705 2742 c = '~'; // not first line, assume Tilde … … 2711 2748 if (c == '\n') 2712 2749 break; 2713 if ( c > 127&& !Isprint(c)) {2750 if ((c & 0x80) && !Isprint(c)) { 2714 2751 c = '.'; 2715 2752 } 2716 if ( c < ' ' || c == 127) {2753 if ((unsigned char)(c) < ' ' || c == 0x7f) { 2717 2754 if (c == '\t') { 2718 2755 c = ' '; … … 2723 2760 } else { 2724 2761 dest[co++] = '^'; 2725 if (c == 127)2762 if (c == 0x7f) 2726 2763 c = '?'; 2727 2764 else 2728 2765 c += '@'; // make it visible 2729 2766 } … … 2745 2782 { 2746 2783 static int old_offset; 2784 2747 2785 int li, changed; 2748 Bytebuf[MAX_SCR_COLS];2749 Byte*tp, *sp; // pointer into text[] and screen[]2750 #if def CONFIG_FEATURE_VI_OPTIMIZE_CURSOR2751 int last_li = -2;// last line that changed- for optimizing cursor movement2752 #endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */2786 char buf[MAX_SCR_COLS]; 2787 char *tp, *sp; // pointer into text[] and screen[] 2788 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2789 int last_li = -2; // last line that changed- for optimizing cursor movement 2790 #endif 2753 2791 2754 2792 if (ENABLE_FEATURE_VI_WIN_RESIZE) … … 2766 2804 2767 2805 // skip to the end of the current text[] line 2768 while (tp < end && *tp++ != '\n') /*no-op*/ 2806 while (tp < end && *tp++ != '\n') /*no-op*/; 2769 2807 2770 2808 // see if there are any changes between vitual screen and buf … … 2779 2817 // compare newly formatted buffer with virtual screen 2780 2818 // look forward for first difference between buf and screen 2781 for ( 2819 for (; cs <= ce; cs++) { 2782 2820 if (buf[cs + offset] != sp[cs]) { 2783 2821 changed = TRUE; // mark for redraw … … 2797 2835 // if horz offset has changed, force a redraw 2798 2836 if (offset != old_offset) { 2799 2837 re0: 2800 2838 changed = TRUE; 2801 2839 } … … 2816 2854 place_cursor(li, cs, FALSE); 2817 2855 } else { 2818 #if def CONFIG_FEATURE_VI_OPTIMIZE_CURSOR2856 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2819 2857 // if this just the next line 2820 2858 // try to optimize cursor movement … … 2822 2860 place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE); 2823 2861 last_li= li; 2824 #else /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */2862 #else 2825 2863 place_cursor(li, cs, FALSE); // use standard ESC sequence 2826 #endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */2864 #endif /* FEATURE_VI_OPTIMIZE_CURSOR */ 2827 2865 } 2828 2866 2829 2867 // write line out to terminal 2830 2868 { 2831 int nic = ce -cs+1;2832 char *out = (char*)sp+cs;2833 2834 while (nic-- > 0) {2869 int nic = ce - cs + 1; 2870 char *out = sp + cs; 2871 2872 while (nic-- > 0) { 2835 2873 putchar(*out); 2836 2874 out++; 2837 2875 } 2838 2876 } 2839 #if def CONFIG_FEATURE_VI_OPTIMIZE_CURSOR2877 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2840 2878 last_row = li; 2841 #endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */2842 } 2843 } 2844 2845 #if def CONFIG_FEATURE_VI_OPTIMIZE_CURSOR2879 #endif 2880 } 2881 } 2882 2883 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2846 2884 place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE); 2847 2885 last_row = crow; 2848 2886 #else 2849 2887 place_cursor(crow, ccol, FALSE); 2850 #endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */2888 #endif 2851 2889 2852 2890 if (offset != old_offset) … … 2876 2914 2877 2915 //----- Execute a Vi Command ----------------------------------- 2878 static void do_cmd(Byte c) 2879 { 2880 Byte c1, *p, *q, *msg, buf[9], *save_dot; 2916 static void do_cmd(char c) 2917 { 2918 const char *msg; 2919 char c1, *p, *q, buf[9], *save_dot; 2881 2920 int cnt, i, j, dir, yf; 2882 2921 2883 2922 c1 = c; // quiet the compiler 2884 2923 cnt = yf = dir = 0; // quiet the compiler 2885 p = q = save_dot = msg= buf; // quiet the compiler2924 msg = p = q = save_dot = buf; // quiet the compiler 2886 2925 memset(buf, '\0', 9); // clear buf 2887 2926 … … 2903 2942 if (cmd_mode == 2) { 2904 2943 // flip-flop Insert/Replace mode 2905 if (c == VI_K_INSERT) goto dc_i; 2944 if (c == VI_K_INSERT) 2945 goto dc_i; 2906 2946 // we are 'R'eplacing the current *dot with new char 2907 2947 if (*dot == '\n') { … … 2927 2967 } 2928 2968 2929 key_cmd_mode:2969 key_cmd_mode: 2930 2970 switch (c) { 2931 2971 //case 0x01: // soh … … 2937 2977 //case 0x11: // dc1 2938 2978 //case 0x13: // dc3 2939 #if def CONFIG_FEATURE_VI_CRASHME2979 #if ENABLE_FEATURE_VI_CRASHME 2940 2980 case 0x14: // dc4 ctrl-T 2941 2981 crashme = (crashme == 0) ? 1 : 0; 2942 2982 break; 2943 #endif /* CONFIG_FEATURE_VI_CRASHME */2983 #endif 2944 2984 //case 0x16: // syn 2945 2985 //case 0x17: // etb … … 2980 3020 buf[2] = '\0'; 2981 3021 } 2982 ni( (Byte *)buf);3022 ni(buf); 2983 3023 end_cmd_q(); // stop adding to q 2984 3024 case 0x00: // nul- ignore … … 2988 3028 dot_scroll(rows - 2, -1); 2989 3029 break; 2990 #if def CONFIG_FEATURE_VI_USE_SIGNALS3030 #if ENABLE_FEATURE_VI_USE_SIGNALS 2991 3031 case 0x03: // ctrl-C interrupt 2992 3032 longjmp(restart, 1); … … 2995 3035 suspend_sig(SIGTSTP); 2996 3036 break; 2997 #endif /* CONFIG_FEATURE_VI_USE_SIGNALS */3037 #endif 2998 3038 case 4: // ctrl-D scroll down half screen 2999 3039 dot_scroll((rows - 2) / 2, 1); … … 3012 3052 case VI_K_LEFT: // cursor key Left 3013 3053 case 8: // ctrl-H- move left (This may be ERASE char) 3014 case 127: // DEL- move left (This may be ERASE char)3054 case 0x7f: // DEL- move left (This may be ERASE char) 3015 3055 if (cmdcnt-- > 1) { 3016 3056 do_cmd(c); … … 3031 3071 place_cursor(0, 0, FALSE); // put cursor in correct place 3032 3072 clear_to_eos(); // tel terminal to erase display 3033 (void)mysleep(10);3073 mysleep(10); 3034 3074 screen_erase(); // erase the internal screen buffer 3035 3075 last_status_cksum = 0; // force status update … … 3065 3105 dot_right(); 3066 3106 break; 3067 #if def CONFIG_FEATURE_VI_YANKMARK3107 #if ENABLE_FEATURE_VI_YANKMARK 3068 3108 case '"': // "- name a register to use for Delete/Yank 3069 3109 c1 = get_one_char(); … … 3081 3121 c1 = c1 - 'a'; 3082 3122 // get the b-o-l 3083 q = mark[( int) c1];3123 q = mark[(unsigned char) c1]; 3084 3124 if (text <= q && q < end) { 3085 3125 dot = q; … … 3118 3158 } 3119 3159 // are we putting whole lines or strings 3120 if (strchr( (char *)p, '\n') != NULL) {3160 if (strchr(p, '\n') != NULL) { 3121 3161 if (c == 'P') { 3122 3162 dot_begin(); // putting lines- Put above … … 3147 3187 } 3148 3188 break; 3149 #endif /* CONFIG_FEATURE_VI_YANKMARK */3189 #endif /* FEATURE_VI_YANKMARK */ 3150 3190 case '$': // $- goto end of line 3151 3191 case VI_K_END: // Cursor Key End … … 3181 3221 do_cmd(';'); 3182 3222 } // repeat cnt 3183 if (last_forward_char == 0) break; 3223 if (last_forward_char == 0) 3224 break; 3184 3225 q = dot + 1; 3185 3226 while (q < end - 1 && *q != '\n' && *q != last_forward_char) { … … 3196 3237 dot_skip_over_ws(); 3197 3238 break; 3198 #if def CONFIG_FEATURE_VI_DOT_CMD3239 #if ENABLE_FEATURE_VI_DOT_CMD 3199 3240 case '.': // .- repeat the last modifying command 3200 3241 // Stuff the last_modifying_cmd back into stdin 3201 3242 // and let it be re-executed. 3202 3243 if (last_modifying_cmd != 0) { 3203 ioq = ioq_start = (Byte *) bb_xstrdup((char *)last_modifying_cmd);3204 } 3205 break; 3206 #endif /* CONFIG_FEATURE_VI_DOT_CMD */3207 #if def CONFIG_FEATURE_VI_SEARCH3244 ioq = ioq_start = xstrdup(last_modifying_cmd); 3245 } 3246 break; 3247 #endif 3248 #if ENABLE_FEATURE_VI_SEARCH 3208 3249 case '?': // /- search for a pattern 3209 3250 case '/': // /- search for a pattern … … 3211 3252 buf[1] = '\0'; 3212 3253 q = get_input_line(buf); // get input line- use "status line" 3213 if ( strlen((char *) q) == 1)3214 goto dc3; 3215 if ( strlen((char *) q) > 1) { //new pat- save it and find3254 if (q[0] && !q[1]) 3255 goto dc3; // if no pat re-use old pat 3256 if (q[0]) { // strlen(q) > 1: new pat- save it and find 3216 3257 // there is a new pat 3217 3258 free(last_search_pattern); 3218 last_search_pattern = (Byte *) bb_xstrdup((char *)q);3259 last_search_pattern = xstrdup(q); 3219 3260 goto dc3; // now find the pattern 3220 3261 } … … 3239 3280 do_cmd(c); 3240 3281 } // repeat cnt 3241 3282 dc3: 3242 3283 if (last_search_pattern == 0) { 3243 msg = (Byte *)"No previous regular expression";3284 msg = "No previous regular expression"; 3244 3285 goto dc2; 3245 3286 } … … 3252 3293 p = dot - 1; 3253 3294 } 3254 3295 dc4: 3255 3296 q = char_search(p, last_search_pattern + 1, dir, FULL); 3256 3297 if (q != NULL) { 3257 3298 dot = q; // good search, update "dot" 3258 msg = (Byte *)"";3299 msg = ""; 3259 3300 goto dc2; 3260 3301 } … … 3267 3308 if (q != NULL) { // found something 3268 3309 dot = q; // found new pattern- goto it 3269 msg = (Byte *)"search hit BOTTOM, continuing at TOP";3310 msg = "search hit BOTTOM, continuing at TOP"; 3270 3311 if (dir == BACK) { 3271 msg = (Byte *)"search hit TOP, continuing at BOTTOM";3312 msg = "search hit TOP, continuing at BOTTOM"; 3272 3313 } 3273 3314 } else { 3274 msg = (Byte *) "Pattern not found"; 3275 } 3276 dc2: 3277 if (*msg) psbs("%s", msg); 3315 msg = "Pattern not found"; 3316 } 3317 dc2: 3318 if (*msg) 3319 psbs("%s", msg); 3278 3320 break; 3279 3321 case '{': // {- move backward paragraph 3280 q = char_search(dot, (Byte *)"\n\n", BACK, FULL);3322 q = char_search(dot, "\n\n", BACK, FULL); 3281 3323 if (q != NULL) { // found blank line 3282 3324 dot = next_line(q); // move to next blank line … … 3284 3326 break; 3285 3327 case '}': // }- move forward paragraph 3286 q = char_search(dot, (Byte *)"\n\n", FORWARD, FULL);3328 q = char_search(dot, "\n\n", FORWARD, FULL); 3287 3329 if (q != NULL) { // found blank line 3288 3330 dot = next_line(q); // move to next blank line 3289 3331 } 3290 3332 break; 3291 #endif /* CONFIG_FEATURE_VI_SEARCH */3333 #endif /* FEATURE_VI_SEARCH */ 3292 3334 case '0': // 0- goto begining of line 3293 3335 case '1': // 1- … … 3307 3349 break; 3308 3350 case ':': // :- the colon mode commands 3309 p = get_input_line( (Byte *)":"); // get input line- use "status line"3310 #if def CONFIG_FEATURE_VI_COLON3351 p = get_input_line(":"); // get input line- use "status line" 3352 #if ENABLE_FEATURE_VI_COLON 3311 3353 colon(p); // execute the command 3312 #else /* CONFIG_FEATURE_VI_COLON */3354 #else 3313 3355 if (*p == ':') 3314 3356 p++; // move past the ':' 3315 cnt = strlen( (char *)p);3357 cnt = strlen(p); 3316 3358 if (cnt <= 0) 3317 3359 break; 3318 if (strncasecmp((char *) p, "quit", cnt) == 0 || 3319 strncasecmp((char *) p, "q!", cnt) == 0) { // delete lines 3360 if (strncasecmp(p, "quit", cnt) == 0 3361 || strncasecmp(p, "q!", cnt) == 0 // delete lines 3362 ) { 3320 3363 if (file_modified && p[1] != '!') { 3321 3364 psbs("No write since last change (:quit! overrides)"); … … 3323 3366 editing = 0; 3324 3367 } 3325 } else if (strncasecmp((char *) p, "write", cnt) == 0 3326 || strncasecmp((char *) p, "wq", cnt) == 0 3327 || strncasecmp((char *) p, "wn", cnt) == 0 3328 || strncasecmp((char *) p, "x", cnt) == 0) { 3329 cnt = file_write(cfn, text, end - 1); 3368 } else if (strncasecmp(p, "write", cnt) == 0 3369 || strncasecmp(p, "wq", cnt) == 0 3370 || strncasecmp(p, "wn", cnt) == 0 3371 || strncasecmp(p, "x", cnt) == 0 3372 ) { 3373 cnt = file_write(current_filename, text, end - 1); 3330 3374 if (cnt < 0) { 3331 3375 if (cnt == -1) … … 3334 3378 file_modified = 0; 3335 3379 last_file_modified = -1; 3336 psb("\"%s\" %dL, %dC", cfn, count_lines(text, end - 1), cnt); 3337 if (p[0] == 'x' || p[1] == 'q' || p[1] == 'n' || 3338 p[0] == 'X' || p[1] == 'Q' || p[1] == 'N') { 3380 psb("\"%s\" %dL, %dC", current_filename, count_lines(text, end - 1), cnt); 3381 if (p[0] == 'x' || p[1] == 'q' || p[1] == 'n' 3382 || p[0] == 'X' || p[1] == 'Q' || p[1] == 'N' 3383 ) { 3339 3384 editing = 0; 3340 3385 } 3341 3386 } 3342 } else if (strncasecmp( (char *) p, "file", cnt) == 0) {3387 } else if (strncasecmp(p, "file", cnt) == 0) { 3343 3388 last_status_cksum = 0; // force status update 3344 } else if (sscanf( (char *)p, "%d", &j) > 0) {3389 } else if (sscanf(p, "%d", &j) > 0) { 3345 3390 dot = find_line(j); // go to line # j 3346 3391 dot_skip_over_ws(); 3347 3392 } else { // unrecognised cmd 3348 ni( (Byte *)p);3349 } 3350 #endif /* CONFIG_FEATURE_VI_COLON */3393 ni(p); 3394 } 3395 #endif /* !FEATURE_VI_COLON */ 3351 3396 break; 3352 3397 case '<': // <- Left shift something … … 3355 3400 c1 = get_one_char(); // get the type of thing to delete 3356 3401 find_range(&p, &q, c1); 3357 (void)yank_delete(p, q, 1, YANKONLY); // save copy before change3402 yank_delete(p, q, 1, YANKONLY); // save copy before change 3358 3403 p = begin_line(p); 3359 3404 q = end_line(q); … … 3364 3409 if (*p == '\t') { 3365 3410 // shrink buffer 1 char 3366 (void)text_hole_delete(p, p);3411 text_hole_delete(p, p); 3367 3412 } else if (*p == ' ') { 3368 3413 // we should be calculating columns, not just SPACE 3369 3414 for (j = 0; *p == ' ' && j < tabstop; j++) { 3370 (void)text_hole_delete(p, p);3415 text_hole_delete(p, p); 3371 3416 } 3372 3417 } 3373 3418 } else if (c == '>') { 3374 3419 // shift right -- add tab or 8 spaces 3375 (void)char_insert(p, '\t');3420 char_insert(p, '\t'); 3376 3421 } 3377 3422 } … … 3412 3457 if (c == 'C') 3413 3458 goto dc_i; // start inserting 3414 #if def CONFIG_FEATURE_VI_DOT_CMD3459 #if ENABLE_FEATURE_VI_DOT_CMD 3415 3460 if (c == 'D') 3416 3461 end_cmd_q(); // stop adding to q 3417 #endif /* CONFIG_FEATURE_VI_DOT_CMD */3462 #endif 3418 3463 break; 3419 3464 case 'G': // G- goto to a line number (default= E-O-F) … … 3440 3485 case 'i': // i- insert before current char 3441 3486 case VI_K_INSERT: // Cursor Key Insert 3442 3487 dc_i: 3443 3488 cmd_mode = 1; // start insrting 3444 3489 break; … … 3451 3496 *dot++ = ' '; // replace NL with space 3452 3497 file_modified++; 3453 while (isbl nk(*dot)) { // delete leading WS3498 while (isblank(*dot)) { // delete leading WS 3454 3499 dot_delete(); 3455 3500 } … … 3489 3534 break; 3490 3535 case 'R': // R- continuous Replace char 3491 3536 dc5: 3492 3537 cmd_mode = 2; 3493 3538 break; … … 3518 3563 } 3519 3564 if (file_modified) { 3520 #ifdef CONFIG_FEATURE_VI_READONLY 3521 if (vi_readonly || readonly) { 3522 psbs("\"%s\" File is read only", cfn); 3523 break; 3524 } 3525 #endif /* CONFIG_FEATURE_VI_READONLY */ 3526 cnt = file_write(cfn, text, end - 1); 3565 if (ENABLE_FEATURE_VI_READONLY && readonly_mode) { 3566 psbs("\"%s\" File is read only", current_filename); 3567 break; 3568 } 3569 cnt = file_write(current_filename, text, end - 1); 3527 3570 if (cnt < 0) { 3528 3571 if (cnt == -1) … … 3561 3604 case 'c': // c- change something 3562 3605 case 'd': // d- delete something 3563 #if def CONFIG_FEATURE_VI_YANKMARK3606 #if ENABLE_FEATURE_VI_YANKMARK 3564 3607 case 'y': // y- yank something 3565 3608 case 'Y': // Y- Yank a line 3566 #endif /* CONFIG_FEATURE_VI_YANKMARK */3609 #endif 3567 3610 yf = YANKDEL; // assume either "c" or "d" 3568 #if def CONFIG_FEATURE_VI_YANKMARK3611 #if ENABLE_FEATURE_VI_YANKMARK 3569 3612 if (c == 'y' || c == 'Y') 3570 3613 yf = YANKONLY; 3571 #endif /* CONFIG_FEATURE_VI_YANKMARK */3614 #endif 3572 3615 c1 = 'y'; 3573 3616 if (c != 'Y') … … 3579 3622 if (c == 'c') { 3580 3623 // don't include trailing WS as part of word 3581 while (isbl nk(*q)) {3624 while (isblank(*q)) { 3582 3625 if (q <= text || q[-1] == '\n') 3583 3626 break; … … 3610 3653 // if CHANGING, not deleting, start inserting after the delete 3611 3654 if (c == 'c') { 3612 strcpy( (char *)buf, "Change");3655 strcpy(buf, "Change"); 3613 3656 goto dc_i; // start inserting 3614 3657 } 3615 3658 if (c == 'd') { 3616 strcpy( (char *)buf, "Delete");3617 } 3618 #if def CONFIG_FEATURE_VI_YANKMARK3659 strcpy(buf, "Delete"); 3660 } 3661 #if ENABLE_FEATURE_VI_YANKMARK 3619 3662 if (c == 'y' || c == 'Y') { 3620 strcpy( (char *)buf, "Yank");3663 strcpy(buf, "Yank"); 3621 3664 } 3622 3665 p = reg[YDreg]; 3623 q = p + strlen( (char *)p);3666 q = p + strlen(p); 3624 3667 for (cnt = 0; p <= q; p++) { 3625 3668 if (*p == '\n') … … 3627 3670 } 3628 3671 psb("%s %d lines (%d chars) using [%c]", 3629 buf, cnt, strlen( (char *)reg[YDreg]), what_reg());3630 #endif /* CONFIG_FEATURE_VI_YANKMARK */3672 buf, cnt, strlen(reg[YDreg]), what_reg()); 3673 #endif 3631 3674 end_cmd_q(); // stop adding to q 3632 3675 } … … 3717 3760 } 3718 3761 3719 3762 dc1: 3720 3763 // if text[] just became empty, add back an empty line 3721 3764 if (end == text) { 3722 (void)char_insert(text, '\n'); // start empty buf with dummy line3765 char_insert(text, '\n'); // start empty buf with dummy line 3723 3766 dot = text; 3724 3767 } … … 3727 3770 dot = bound_dot(dot); // make sure "dot" is valid 3728 3771 } 3729 #if def CONFIG_FEATURE_VI_YANKMARK3772 #if ENABLE_FEATURE_VI_YANKMARK 3730 3773 check_context(c); // update the current context 3731 #endif /* CONFIG_FEATURE_VI_YANKMARK */3774 #endif 3732 3775 3733 3776 if (!isdigit(c)) … … 3739 3782 } 3740 3783 3741 #if def CONFIG_FEATURE_VI_CRASHME3784 #if ENABLE_FEATURE_VI_CRASHME 3742 3785 static int totalcmds = 0; 3743 3786 static int Mp = 85; // Movement command Probability … … 3748 3791 static int Pp = 99; // Put command Probability 3749 3792 static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0; 3750 char chars[20] = "\t012345 abcdABCD-=.$"; 3751 char *words[20] = { "this", "is", "a", "test", 3793 const char chars[20] = "\t012345 abcdABCD-=.$"; 3794 const char *const words[20] = { 3795 "this", "is", "a", "test", 3752 3796 "broadcast", "the", "emergency", "of", 3753 3797 "system", "quick", "brown", "fox", … … 3755 3799 "back", "January", "Febuary", "March" 3756 3800 }; 3757 c har *lines[20] = {3801 const char *const lines[20] = { 3758 3802 "You should have received a copy of the GNU General Public License\n", 3759 3803 "char c, cm, *cmd, *cmd1;\n", … … 3813 3857 if (readed_for_parse > 0) 3814 3858 goto cd1; 3815 3859 cd0: 3816 3860 startrbi = rbi = 0; 3817 3861 sleeptime = 0; // how long to pause between commands 3818 memset(readbuffer, '\0', BUFSIZ); // clear the read buffer3862 memset(readbuffer, '\0', MAX_LINELEN); // clear the read buffer 3819 3863 // generate a command by percentages 3820 3864 percent = (int) lrand48() % 100; // get a number from 0-99 … … 3875 3919 readbuffer[rbi++] = chars[((int) lrand48() % strlen(chars))]; 3876 3920 } else if (thing == 1) { // insert words 3877 strcat( (char *)readbuffer, words[(int) lrand48() % 20]);3878 strcat( (char *)readbuffer, " ");3921 strcat(readbuffer, words[(int) lrand48() % 20]); 3922 strcat(readbuffer, " "); 3879 3923 sleeptime = 0; // how fast to type 3880 3924 } else if (thing == 2) { // insert lines 3881 strcat( (char *)readbuffer, lines[(int) lrand48() % 20]);3925 strcat(readbuffer, lines[(int) lrand48() % 20]); 3882 3926 sleeptime = 0; // how fast to type 3883 3927 } else { // insert multi-lines 3884 strcat( (char *)readbuffer, multilines[(int) lrand48() % 20]);3928 strcat(readbuffer, multilines[(int) lrand48() % 20]); 3885 3929 sleeptime = 0; // how fast to type 3886 3930 } 3887 3931 } 3888 strcat( (char *)readbuffer, "\033");3932 strcat(readbuffer, "\033"); 3889 3933 } 3890 3934 readed_for_parse = strlen(readbuffer); 3891 3935 cd1: 3892 3936 totalcmds++; 3893 3937 if (sleeptime > 0) 3894 (void)mysleep(sleeptime); // sleep 1/100 sec3938 mysleep(sleeptime); // sleep 1/100 sec 3895 3939 } 3896 3940 … … 3899 3943 { 3900 3944 static time_t oldtim; 3945 3901 3946 time_t tim; 3902 char d[2], msg[ BUFSIZ];3947 char d[2], msg[MAX_LINELEN]; 3903 3948 3904 3949 msg[0] = '\0'; 3905 3950 if (end < text) { 3906 strcat( (char *)msg, "end<text ");3951 strcat(msg, "end<text "); 3907 3952 } 3908 3953 if (end > textend) { 3909 strcat( (char *)msg, "end>textend ");3954 strcat(msg, "end>textend "); 3910 3955 } 3911 3956 if (dot < text) { 3912 strcat( (char *)msg, "dot<text ");3957 strcat(msg, "dot<text "); 3913 3958 } 3914 3959 if (dot > end) { 3915 strcat( (char *)msg, "dot>end ");3960 strcat(msg, "dot>end "); 3916 3961 } 3917 3962 if (screenbegin < text) { 3918 strcat( (char *)msg, "screenbegin<text ");3963 strcat(msg, "screenbegin<text "); 3919 3964 } 3920 3965 if (screenbegin > end - 1) { 3921 strcat( (char *)msg, "screenbegin>end-1 ");3922 } 3923 3924 if ( strlen(msg) > 0) {3966 strcat(msg, "screenbegin>end-1 "); 3967 } 3968 3969 if (msg[0]) { 3925 3970 alarm(0); 3926 3971 printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s", … … 3935 3980 tim = (time_t) time((time_t *) 0); 3936 3981 if (tim >= (oldtim + 3)) { 3937 sprintf( (char *)status_buffer,3982 sprintf(status_buffer, 3938 3983 "Tot=%d: M=%d N=%d I=%d D=%d Y=%d P=%d U=%d size=%d", 3939 3984 totalcmds, M, N, I, D, Y, P, U, end - text + 1); 3940 3985 oldtim = tim; 3941 3986 } 3942 return; 3943 } 3944 #endif /* CONFIG_FEATURE_VI_CRASHME */ 3987 } 3988 #endif
Note:
See TracChangeset
for help on using the changeset viewer.