diff options
Diffstat (limited to 'editors')
-rw-r--r-- | editors/awk.c | 38 | ||||
-rw-r--r-- | editors/sed.c | 97 | ||||
-rw-r--r-- | editors/vi.c | 201 |
3 files changed, 166 insertions, 170 deletions
diff --git a/editors/awk.c b/editors/awk.c index 71abca215..42f6ef866 100644 --- a/editors/awk.c +++ b/editors/awk.c | |||
@@ -696,6 +696,10 @@ static char nextchar(char **s) | |||
696 | pps = *s; | 696 | pps = *s; |
697 | if (c == '\\') | 697 | if (c == '\\') |
698 | c = bb_process_escape_sequence((const char**)s); | 698 | c = bb_process_escape_sequence((const char**)s); |
699 | /* Example awk statement: | ||
700 | * s = "abc\"def" | ||
701 | * we must treat \" as " | ||
702 | */ | ||
699 | if (c == '\\' && *s == pps) { /* unrecognized \z? */ | 703 | if (c == '\\' && *s == pps) { /* unrecognized \z? */ |
700 | c = *(*s); /* yes, fetch z */ | 704 | c = *(*s); /* yes, fetch z */ |
701 | if (c) | 705 | if (c) |
@@ -704,6 +708,15 @@ static char nextchar(char **s) | |||
704 | return c; | 708 | return c; |
705 | } | 709 | } |
706 | 710 | ||
711 | /* TODO: merge with strcpy_and_process_escape_sequences()? | ||
712 | */ | ||
713 | static void unescape_string_in_place(char *s1) | ||
714 | { | ||
715 | char *s = s1; | ||
716 | while ((*s1 = nextchar(&s)) != '\0') | ||
717 | s1++; | ||
718 | } | ||
719 | |||
707 | static ALWAYS_INLINE int isalnum_(int c) | 720 | static ALWAYS_INLINE int isalnum_(int c) |
708 | { | 721 | { |
709 | return (isalnum(c) || c == '_'); | 722 | return (isalnum(c) || c == '_'); |
@@ -1799,6 +1812,18 @@ static void handle_special(var *v) | |||
1799 | is_f0_split = FALSE; | 1812 | is_f0_split = FALSE; |
1800 | 1813 | ||
1801 | } else if (v == intvar[FS]) { | 1814 | } else if (v == intvar[FS]) { |
1815 | /* | ||
1816 | * The POSIX-2008 standard says that changing FS should have no effect on the | ||
1817 | * current input line, but only on the next one. The language is: | ||
1818 | * | ||
1819 | * > Before the first reference to a field in the record is evaluated, the record | ||
1820 | * > shall be split into fields, according to the rules in Regular Expressions, | ||
1821 | * > using the value of FS that was current at the time the record was read. | ||
1822 | * | ||
1823 | * So, split up current line before assignment to FS: | ||
1824 | */ | ||
1825 | split_f0(); | ||
1826 | |||
1802 | mk_splitter(getvar_s(v), &fsplitter); | 1827 | mk_splitter(getvar_s(v), &fsplitter); |
1803 | 1828 | ||
1804 | } else if (v == intvar[RS]) { | 1829 | } else if (v == intvar[RS]) { |
@@ -2992,7 +3017,7 @@ static int awk_exit(int r) | |||
2992 | * otherwise return 0 */ | 3017 | * otherwise return 0 */ |
2993 | static int is_assignment(const char *expr) | 3018 | static int is_assignment(const char *expr) |
2994 | { | 3019 | { |
2995 | char *exprc, *val, *s, *s1; | 3020 | char *exprc, *val; |
2996 | 3021 | ||
2997 | if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) { | 3022 | if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) { |
2998 | return FALSE; | 3023 | return FALSE; |
@@ -3002,10 +3027,7 @@ static int is_assignment(const char *expr) | |||
3002 | val = exprc + (val - expr); | 3027 | val = exprc + (val - expr); |
3003 | *val++ = '\0'; | 3028 | *val++ = '\0'; |
3004 | 3029 | ||
3005 | s = s1 = val; | 3030 | unescape_string_in_place(val); |
3006 | while ((*s1 = nextchar(&s)) != '\0') | ||
3007 | s1++; | ||
3008 | |||
3009 | setvar_u(newvar(exprc), val); | 3031 | setvar_u(newvar(exprc), val); |
3010 | free(exprc); | 3032 | free(exprc); |
3011 | return TRUE; | 3033 | return TRUE; |
@@ -3118,8 +3140,10 @@ int awk_main(int argc, char **argv) | |||
3118 | opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, NULL); | 3140 | opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, NULL); |
3119 | argv += optind; | 3141 | argv += optind; |
3120 | argc -= optind; | 3142 | argc -= optind; |
3121 | if (opt & 0x1) | 3143 | if (opt & 0x1) { /* -F */ |
3122 | setvar_s(intvar[FS], opt_F); // -F | 3144 | unescape_string_in_place(opt_F); |
3145 | setvar_s(intvar[FS], opt_F); | ||
3146 | } | ||
3123 | while (list_v) { /* -v */ | 3147 | while (list_v) { /* -v */ |
3124 | if (!is_assignment(llist_pop(&list_v))) | 3148 | if (!is_assignment(llist_pop(&list_v))) |
3125 | bb_show_usage(); | 3149 | bb_show_usage(); |
diff --git a/editors/sed.c b/editors/sed.c index a2df93165..070af611a 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
@@ -53,7 +53,9 @@ | |||
53 | * Todo: | 53 | * Todo: |
54 | * - Create a wrapper around regex to make libc's regex conform with sed | 54 | * - Create a wrapper around regex to make libc's regex conform with sed |
55 | * | 55 | * |
56 | * Reference http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html | 56 | * Reference |
57 | * http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html | ||
58 | * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html | ||
57 | */ | 59 | */ |
58 | 60 | ||
59 | //usage:#define sed_trivial_usage | 61 | //usage:#define sed_trivial_usage |
@@ -63,7 +65,7 @@ | |||
63 | //usage: " -e CMD Add CMD to sed commands to be executed" | 65 | //usage: " -e CMD Add CMD to sed commands to be executed" |
64 | //usage: "\n -f FILE Add FILE contents to sed commands to be executed" | 66 | //usage: "\n -f FILE Add FILE contents to sed commands to be executed" |
65 | //usage: "\n -i[SFX] Edit files in-place (otherwise sends to stdout)" | 67 | //usage: "\n -i[SFX] Edit files in-place (otherwise sends to stdout)" |
66 | //usage: "\n Optionally backs files up, appending SFX" | 68 | //usage: "\n Optionally back files up, appending SFX" |
67 | //usage: "\n -n Suppress automatic printing of pattern space" | 69 | //usage: "\n -n Suppress automatic printing of pattern space" |
68 | //usage: "\n -r Use extended regex syntax" | 70 | //usage: "\n -r Use extended regex syntax" |
69 | //usage: "\n" | 71 | //usage: "\n" |
@@ -492,8 +494,10 @@ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr) | |||
492 | } | 494 | } |
493 | /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ | 495 | /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ |
494 | else if (idx <= IDX_c) { /* a,i,c */ | 496 | else if (idx <= IDX_c) { /* a,i,c */ |
495 | if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c') | 497 | if (idx < IDX_c) { /* a,i */ |
496 | bb_error_msg_and_die("only a beginning address can be specified for edit commands"); | 498 | if (sed_cmd->end_line || sed_cmd->end_match) |
499 | bb_error_msg_and_die("command '%c' uses only one address", sed_cmd->cmd); | ||
500 | } | ||
497 | for (;;) { | 501 | for (;;) { |
498 | if (*cmdstr == '\n' || *cmdstr == '\\') { | 502 | if (*cmdstr == '\n' || *cmdstr == '\\') { |
499 | cmdstr++; | 503 | cmdstr++; |
@@ -510,8 +514,10 @@ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr) | |||
510 | } | 514 | } |
511 | /* handle file cmds: (r)ead */ | 515 | /* handle file cmds: (r)ead */ |
512 | else if (idx <= IDX_w) { /* r,w */ | 516 | else if (idx <= IDX_w) { /* r,w */ |
513 | if (sed_cmd->end_line || sed_cmd->end_match) | 517 | if (idx < IDX_w) { /* r */ |
514 | bb_error_msg_and_die("command only uses one address"); | 518 | if (sed_cmd->end_line || sed_cmd->end_match) |
519 | bb_error_msg_and_die("command '%c' uses only one address", sed_cmd->cmd); | ||
520 | } | ||
515 | cmdstr += parse_file_cmd(/*sed_cmd,*/ cmdstr, &sed_cmd->string); | 521 | cmdstr += parse_file_cmd(/*sed_cmd,*/ cmdstr, &sed_cmd->string); |
516 | if (sed_cmd->cmd == 'w') { | 522 | if (sed_cmd->cmd == 'w') { |
517 | sed_cmd->sw_file = xfopen_for_write(sed_cmd->string); | 523 | sed_cmd->sw_file = xfopen_for_write(sed_cmd->string); |
@@ -673,7 +679,7 @@ static void do_subst_w_backrefs(char *line, char *replace) | |||
673 | 679 | ||
674 | /* go through the replacement string */ | 680 | /* go through the replacement string */ |
675 | for (i = 0; replace[i]; i++) { | 681 | for (i = 0; replace[i]; i++) { |
676 | /* if we find a backreference (\1, \2, etc.) print the backref'ed * text */ | 682 | /* if we find a backreference (\1, \2, etc.) print the backref'ed text */ |
677 | if (replace[i] == '\\') { | 683 | if (replace[i] == '\\') { |
678 | unsigned backref = replace[++i] - '0'; | 684 | unsigned backref = replace[++i] - '0'; |
679 | if (backref <= 9) { | 685 | if (backref <= 9) { |
@@ -707,8 +713,10 @@ static void do_subst_w_backrefs(char *line, char *replace) | |||
707 | static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) | 713 | static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) |
708 | { | 714 | { |
709 | char *line = *line_p; | 715 | char *line = *line_p; |
710 | int altered = 0; | ||
711 | unsigned match_count = 0; | 716 | unsigned match_count = 0; |
717 | bool altered = 0; | ||
718 | bool prev_match_empty = 1; | ||
719 | bool tried_at_eol = 0; | ||
712 | regex_t *current_regex; | 720 | regex_t *current_regex; |
713 | 721 | ||
714 | current_regex = sed_cmd->sub_match; | 722 | current_regex = sed_cmd->sub_match; |
@@ -735,50 +743,75 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) | |||
735 | 743 | ||
736 | /* Now loop through, substituting for matches */ | 744 | /* Now loop through, substituting for matches */ |
737 | do { | 745 | do { |
746 | int start = G.regmatch[0].rm_so; | ||
747 | int end = G.regmatch[0].rm_eo; | ||
738 | int i; | 748 | int i; |
739 | 749 | ||
740 | /* Work around bug in glibc regexec, demonstrated by: | ||
741 | * echo " a.b" | busybox sed 's [^ .]* x g' | ||
742 | * The match_count check is so not to break | ||
743 | * echo "hi" | busybox sed 's/^/!/g' | ||
744 | */ | ||
745 | if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) { | ||
746 | pipe_putc(*line++); | ||
747 | goto next; | ||
748 | } | ||
749 | |||
750 | match_count++; | 750 | match_count++; |
751 | 751 | ||
752 | /* If we aren't interested in this match, output old line to | 752 | /* If we aren't interested in this match, output old line to |
753 | end of match and continue */ | 753 | * end of match and continue */ |
754 | if (sed_cmd->which_match | 754 | if (sed_cmd->which_match |
755 | && (sed_cmd->which_match != match_count) | 755 | && (sed_cmd->which_match != match_count) |
756 | ) { | 756 | ) { |
757 | for (i = 0; i < G.regmatch[0].rm_eo; i++) | 757 | for (i = 0; i < end; i++) |
758 | pipe_putc(*line++); | ||
759 | /* Null match? Print one more char */ | ||
760 | if (start == end && *line) | ||
758 | pipe_putc(*line++); | 761 | pipe_putc(*line++); |
759 | goto next; | 762 | goto next; |
760 | } | 763 | } |
761 | 764 | ||
762 | /* print everything before the match */ | 765 | /* Print everything before the match */ |
763 | for (i = 0; i < G.regmatch[0].rm_so; i++) | 766 | for (i = 0; i < start; i++) |
764 | pipe_putc(line[i]); | 767 | pipe_putc(line[i]); |
765 | 768 | ||
766 | /* then print the substitution string */ | 769 | /* Then print the substitution string, |
767 | do_subst_w_backrefs(line, sed_cmd->string); | 770 | * unless we just matched empty string after non-empty one. |
771 | * Example: string "cccd", pattern "c*", repl "R": | ||
772 | * result is "RdR", not "RRdR": first match "ccc", | ||
773 | * second is "" before "d", third is "" after "d". | ||
774 | * Second match is NOT replaced! | ||
775 | */ | ||
776 | if (prev_match_empty || start != 0 || start != end) { | ||
777 | //dbg("%d %d %d", prev_match_empty, start, end); | ||
778 | dbg("inserting replacement at %d in '%s'", start, line); | ||
779 | do_subst_w_backrefs(line, sed_cmd->string); | ||
780 | /* Flag that something has changed */ | ||
781 | altered = 1; | ||
782 | } else { | ||
783 | dbg("NOT inserting replacement at %d in '%s'", start, line); | ||
784 | } | ||
785 | |||
786 | /* If matched string is empty (f.e. "c*" pattern), | ||
787 | * copy verbatim one char after it before attempting more matches | ||
788 | */ | ||
789 | prev_match_empty = (start == end); | ||
790 | if (prev_match_empty) { | ||
791 | if (!line[end]) { | ||
792 | tried_at_eol = 1; | ||
793 | } else { | ||
794 | pipe_putc(line[end]); | ||
795 | end++; | ||
796 | } | ||
797 | } | ||
768 | 798 | ||
769 | /* advance past the match */ | 799 | /* Advance past the match */ |
770 | line += G.regmatch[0].rm_eo; | 800 | dbg("line += %d", end); |
771 | /* flag that something has changed */ | 801 | line += end; |
772 | altered++; | ||
773 | 802 | ||
774 | /* if we're not doing this globally, get out now */ | 803 | /* if we're not doing this globally, get out now */ |
775 | if (sed_cmd->which_match != 0) | 804 | if (sed_cmd->which_match != 0) |
776 | break; | 805 | break; |
777 | next: | 806 | next: |
778 | if (*line == '\0') | 807 | /* Exit if we are at EOL and already tried matching at it */ |
779 | break; | 808 | if (*line == '\0') { |
809 | if (tried_at_eol) | ||
810 | break; | ||
811 | tried_at_eol = 1; | ||
812 | } | ||
780 | 813 | ||
781 | //maybe (G.regmatch[0].rm_eo ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL? | 814 | //maybe (end ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL? |
782 | } while (regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); | 815 | } while (regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); |
783 | 816 | ||
784 | /* Copy rest of string into output pipeline */ | 817 | /* Copy rest of string into output pipeline */ |
@@ -1127,7 +1160,7 @@ static void process_files(void) | |||
1127 | case 's': | 1160 | case 's': |
1128 | if (!do_subst_command(sed_cmd, &pattern_space)) | 1161 | if (!do_subst_command(sed_cmd, &pattern_space)) |
1129 | break; | 1162 | break; |
1130 | dbg("do_subst_command succeeeded:'%s'", pattern_space); | 1163 | dbg("do_subst_command succeeded:'%s'", pattern_space); |
1131 | substituted |= 1; | 1164 | substituted |= 1; |
1132 | 1165 | ||
1133 | /* handle p option */ | 1166 | /* handle p option */ |
diff --git a/editors/vi.c b/editors/vi.c index 6fae221ac..821583ec1 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -136,14 +136,6 @@ | |||
136 | //config: cursor position using "ESC [ 6 n" escape sequence, then read stdin. | 136 | //config: cursor position using "ESC [ 6 n" escape sequence, then read stdin. |
137 | //config: | 137 | //config: |
138 | //config: This is not clean but helps a lot on serial lines and such. | 138 | //config: This is not clean but helps a lot on serial lines and such. |
139 | //config: | ||
140 | //config:config FEATURE_VI_OPTIMIZE_CURSOR | ||
141 | //config: bool "Optimize cursor movement" | ||
142 | //config: default y | ||
143 | //config: depends on VI | ||
144 | //config: help | ||
145 | //config: This will make the cursor movement faster, but requires more memory | ||
146 | //config: and it makes the applet a tiny bit larger. | ||
147 | 139 | ||
148 | //applet:IF_VI(APPLET(vi, BB_DIR_BIN, BB_SUID_DROP)) | 140 | //applet:IF_VI(APPLET(vi, BB_DIR_BIN, BB_SUID_DROP)) |
149 | 141 | ||
@@ -154,12 +146,12 @@ | |||
154 | //usage:#define vi_full_usage "\n\n" | 146 | //usage:#define vi_full_usage "\n\n" |
155 | //usage: "Edit FILE\n" | 147 | //usage: "Edit FILE\n" |
156 | //usage: IF_FEATURE_VI_COLON( | 148 | //usage: IF_FEATURE_VI_COLON( |
157 | //usage: "\n -c Initial command to run ($EXINIT also available)" | 149 | //usage: "\n -c CMD Initial command to run ($EXINIT also available)" |
158 | //usage: ) | 150 | //usage: ) |
159 | //usage: IF_FEATURE_VI_READONLY( | 151 | //usage: IF_FEATURE_VI_READONLY( |
160 | //usage: "\n -R Read-only" | 152 | //usage: "\n -R Read-only" |
161 | //usage: ) | 153 | //usage: ) |
162 | //usage: "\n -H Short help regarding available features" | 154 | //usage: "\n -H List available features" |
163 | 155 | ||
164 | #include "libbb.h" | 156 | #include "libbb.h" |
165 | /* Should be after libbb.h: on some systems regex.h needs sys/types.h: */ | 157 | /* Should be after libbb.h: on some systems regex.h needs sys/types.h: */ |
@@ -202,20 +194,29 @@ enum { | |||
202 | MAX_SCR_ROWS = CONFIG_FEATURE_VI_MAX_LEN, | 194 | MAX_SCR_ROWS = CONFIG_FEATURE_VI_MAX_LEN, |
203 | }; | 195 | }; |
204 | 196 | ||
205 | /* vt102 typical ESC sequence */ | 197 | /* VT102 ESC sequences. |
206 | /* terminal standout start/normal ESC sequence */ | 198 | * See "Xterm Control Sequences" |
207 | #define SOs "\033[7m" | 199 | * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html |
208 | #define SOn "\033[0m" | 200 | */ |
209 | /* terminal bell sequence */ | 201 | /* Inverse/Normal text */ |
210 | #define bell "\007" | 202 | #define ESC_BOLD_TEXT "\033[7m" |
211 | /* Clear-end-of-line and Clear-end-of-screen ESC sequence */ | 203 | #define ESC_NORM_TEXT "\033[0m" |
212 | #define Ceol "\033[K" | 204 | /* Bell */ |
213 | #define Ceos "\033[J" | 205 | #define ESC_BELL "\007" |
214 | /* Cursor motion arbitrary destination ESC sequence */ | 206 | /* Clear-to-end-of-line */ |
215 | #define CMrc "\033[%u;%uH" | 207 | #define ESC_CLEAR2EOL "\033[K" |
216 | /* Cursor motion up and down ESC sequence */ | 208 | /* Clear-to-end-of-screen. |
217 | #define CMup "\033[A" | 209 | * (We use default param here. |
218 | #define CMdown "\n" | 210 | * Full sequence is "ESC [ <num> J", |
211 | * <num> is 0/1/2 = "erase below/above/all".) | ||
212 | */ | ||
213 | #define ESC_CLEAR2EOS "\033[J" | ||
214 | /* Cursor to given coordinate (1,1: top left) */ | ||
215 | #define ESC_SET_CURSOR_POS "\033[%u;%uH" | ||
216 | //UNUSED | ||
217 | ///* Cursor up and down */ | ||
218 | //#define ESC_CURSOR_UP "\033[A" | ||
219 | //#define ESC_CURSOR_DOWN "\n" | ||
219 | 220 | ||
220 | #if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK | 221 | #if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK |
221 | // cmds modifying text[] | 222 | // cmds modifying text[] |
@@ -303,9 +304,6 @@ struct globals { | |||
303 | int lmc_len; // length of last_modifying_cmd | 304 | int lmc_len; // length of last_modifying_cmd |
304 | char *ioq, *ioq_start; // pointer to string for get_one_char to "read" | 305 | char *ioq, *ioq_start; // pointer to string for get_one_char to "read" |
305 | #endif | 306 | #endif |
306 | #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR | ||
307 | int last_row; // where the cursor was last moved to | ||
308 | #endif | ||
309 | #if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME | 307 | #if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME |
310 | int my_pid; | 308 | int my_pid; |
311 | #endif | 309 | #endif |
@@ -389,7 +387,6 @@ struct globals { | |||
389 | #define lmc_len (G.lmc_len ) | 387 | #define lmc_len (G.lmc_len ) |
390 | #define ioq (G.ioq ) | 388 | #define ioq (G.ioq ) |
391 | #define ioq_start (G.ioq_start ) | 389 | #define ioq_start (G.ioq_start ) |
392 | #define last_row (G.last_row ) | ||
393 | #define my_pid (G.my_pid ) | 390 | #define my_pid (G.my_pid ) |
394 | #define last_search_pattern (G.last_search_pattern) | 391 | #define last_search_pattern (G.last_search_pattern) |
395 | 392 | ||
@@ -470,10 +467,7 @@ static int file_size(const char *); // what is the byte size of "fn" | |||
470 | // file_insert might reallocate text[]! | 467 | // file_insert might reallocate text[]! |
471 | static int file_insert(const char *, char *, int); | 468 | static int file_insert(const char *, char *, int); |
472 | static int file_write(char *, char *, char *); | 469 | static int file_write(char *, char *, char *); |
473 | #if !ENABLE_FEATURE_VI_OPTIMIZE_CURSOR | 470 | static void place_cursor(int, int); |
474 | #define place_cursor(a, b, optimize) place_cursor(a, b) | ||
475 | #endif | ||
476 | static void place_cursor(int, int, int); | ||
477 | static void screen_erase(void); | 471 | static void screen_erase(void); |
478 | static void clear_to_eol(void); | 472 | static void clear_to_eol(void); |
479 | static void clear_to_eos(void); | 473 | static void clear_to_eos(void); |
@@ -558,7 +552,8 @@ int vi_main(int argc, char **argv) | |||
558 | } | 552 | } |
559 | #endif | 553 | #endif |
560 | 554 | ||
561 | vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE; | 555 | // autoindent is not default in vim 7.3 |
556 | vi_setops = /*VI_AUTOINDENT |*/ VI_SHOWMATCH | VI_IGNORECASE; | ||
562 | // 1- process $HOME/.exrc file (not inplemented yet) | 557 | // 1- process $HOME/.exrc file (not inplemented yet) |
563 | // 2- process EXINIT variable from environment | 558 | // 2- process EXINIT variable from environment |
564 | // 3- process command line args | 559 | // 3- process command line args |
@@ -584,7 +579,7 @@ int vi_main(int argc, char **argv) | |||
584 | #if ENABLE_FEATURE_VI_COLON | 579 | #if ENABLE_FEATURE_VI_COLON |
585 | case 'c': // cmd line vi command | 580 | case 'c': // cmd line vi command |
586 | if (*optarg) | 581 | if (*optarg) |
587 | initial_cmds[initial_cmds[0] != 0] = xstrndup(optarg, MAX_INPUT_LEN); | 582 | initial_cmds[initial_cmds[0] != NULL] = xstrndup(optarg, MAX_INPUT_LEN); |
588 | break; | 583 | break; |
589 | #endif | 584 | #endif |
590 | case 'H': | 585 | case 'H': |
@@ -599,15 +594,19 @@ int vi_main(int argc, char **argv) | |||
599 | // The argv array can be used by the ":next" and ":rewind" commands | 594 | // The argv array can be used by the ":next" and ":rewind" commands |
600 | argv += optind; | 595 | argv += optind; |
601 | argc -= optind; | 596 | argc -= optind; |
602 | save_argc = argc; | ||
603 | optind = 0; | ||
604 | 597 | ||
605 | //----- This is the main file handling loop -------------- | 598 | //----- This is the main file handling loop -------------- |
599 | save_argc = argc; | ||
600 | optind = 0; | ||
601 | // "Save cursor, use alternate screen buffer, clear screen" | ||
602 | write1("\033[?1049h"); | ||
606 | while (1) { | 603 | while (1) { |
607 | edit_file(argv[optind]); /* param might be NULL */ | 604 | edit_file(argv[optind]); /* param might be NULL */ |
608 | if (++optind >= argc) | 605 | if (++optind >= argc) |
609 | break; | 606 | break; |
610 | } | 607 | } |
608 | // "Use normal screen buffer, restore cursor" | ||
609 | write1("\033[?1049l"); | ||
611 | //----------------------------------------------------------- | 610 | //----------------------------------------------------------- |
612 | 611 | ||
613 | return 0; | 612 | return 0; |
@@ -1191,7 +1190,7 @@ static void colon(char *buf) | |||
1191 | char *argp; | 1190 | char *argp; |
1192 | #endif | 1191 | #endif |
1193 | i = 0; // offset into args | 1192 | i = 0; // offset into args |
1194 | // only blank is regarded as args delmiter. What about tab '\t' ? | 1193 | // only blank is regarded as args delimiter. What about tab '\t'? |
1195 | if (!args[0] || strcasecmp(args, "all") == 0) { | 1194 | if (!args[0] || strcasecmp(args, "all") == 0) { |
1196 | // print out values of all options | 1195 | // print out values of all options |
1197 | #if ENABLE_FEATURE_VI_SETOPTS | 1196 | #if ENABLE_FEATURE_VI_SETOPTS |
@@ -2176,7 +2175,7 @@ static void show_help(void) | |||
2176 | "\n\tPattern searches with / and ?" | 2175 | "\n\tPattern searches with / and ?" |
2177 | #endif | 2176 | #endif |
2178 | #if ENABLE_FEATURE_VI_DOT_CMD | 2177 | #if ENABLE_FEATURE_VI_DOT_CMD |
2179 | "\n\tLast command repeat with \'.\'" | 2178 | "\n\tLast command repeat with ." |
2180 | #endif | 2179 | #endif |
2181 | #if ENABLE_FEATURE_VI_YANKMARK | 2180 | #if ENABLE_FEATURE_VI_YANKMARK |
2182 | "\n\tLine marking with 'x" | 2181 | "\n\tLine marking with 'x" |
@@ -2187,7 +2186,7 @@ static void show_help(void) | |||
2187 | //redundant: usage text says this too: "\n\tReadonly with -R command line arg" | 2186 | //redundant: usage text says this too: "\n\tReadonly with -R command line arg" |
2188 | #endif | 2187 | #endif |
2189 | #if ENABLE_FEATURE_VI_SET | 2188 | #if ENABLE_FEATURE_VI_SET |
2190 | "\n\tSome colon mode commands with \':\'" | 2189 | "\n\tSome colon mode commands with :" |
2191 | #endif | 2190 | #endif |
2192 | #if ENABLE_FEATURE_VI_SETOPTS | 2191 | #if ENABLE_FEATURE_VI_SETOPTS |
2193 | "\n\tSettable options with \":set\"" | 2192 | "\n\tSettable options with \":set\"" |
@@ -2601,107 +2600,56 @@ static int file_write(char *fn, char *first, char *last) | |||
2601 | // 23,0 ... 23,79 <- status line | 2600 | // 23,0 ... 23,79 <- status line |
2602 | 2601 | ||
2603 | //----- Move the cursor to row x col (count from 0, not 1) ------- | 2602 | //----- Move the cursor to row x col (count from 0, not 1) ------- |
2604 | static void place_cursor(int row, int col, int optimize) | 2603 | static void place_cursor(int row, int col) |
2605 | { | 2604 | { |
2606 | char cm1[sizeof(CMrc) + sizeof(int)*3 * 2]; | 2605 | char cm1[sizeof(ESC_SET_CURSOR_POS) + sizeof(int)*3 * 2]; |
2607 | #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR | ||
2608 | enum { | ||
2609 | SZ_UP = sizeof(CMup), | ||
2610 | SZ_DN = sizeof(CMdown), | ||
2611 | SEQ_SIZE = SZ_UP > SZ_DN ? SZ_UP : SZ_DN, | ||
2612 | }; | ||
2613 | char cm2[SEQ_SIZE * 5 + 32]; // bigger than worst case size | ||
2614 | #endif | ||
2615 | char *cm; | ||
2616 | 2606 | ||
2617 | if (row < 0) row = 0; | 2607 | if (row < 0) row = 0; |
2618 | if (row >= rows) row = rows - 1; | 2608 | if (row >= rows) row = rows - 1; |
2619 | if (col < 0) col = 0; | 2609 | if (col < 0) col = 0; |
2620 | if (col >= columns) col = columns - 1; | 2610 | if (col >= columns) col = columns - 1; |
2621 | 2611 | ||
2622 | //----- 1. Try the standard terminal ESC sequence | 2612 | sprintf(cm1, ESC_SET_CURSOR_POS, row + 1, col + 1); |
2623 | sprintf(cm1, CMrc, row + 1, col + 1); | 2613 | write1(cm1); |
2624 | cm = cm1; | ||
2625 | |||
2626 | #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR | ||
2627 | if (optimize && col < 16) { | ||
2628 | char *screenp; | ||
2629 | int Rrow = last_row; | ||
2630 | int diff = Rrow - row; | ||
2631 | |||
2632 | if (diff < -5 || diff > 5) | ||
2633 | goto skip; | ||
2634 | |||
2635 | //----- find the minimum # of chars to move cursor ------------- | ||
2636 | //----- 2. Try moving with discreet chars (Newline, [back]space, ...) | ||
2637 | cm2[0] = '\0'; | ||
2638 | |||
2639 | // move to the correct row | ||
2640 | while (row < Rrow) { | ||
2641 | // the cursor has to move up | ||
2642 | strcat(cm2, CMup); | ||
2643 | Rrow--; | ||
2644 | } | ||
2645 | while (row > Rrow) { | ||
2646 | // the cursor has to move down | ||
2647 | strcat(cm2, CMdown); | ||
2648 | Rrow++; | ||
2649 | } | ||
2650 | |||
2651 | // now move to the correct column | ||
2652 | strcat(cm2, "\r"); // start at col 0 | ||
2653 | // just send out orignal source char to get to correct place | ||
2654 | screenp = &screen[row * columns]; // start of screen line | ||
2655 | strncat(cm2, screenp, col); | ||
2656 | |||
2657 | // pick the shortest cursor motion to send out | ||
2658 | if (strlen(cm2) < strlen(cm)) { | ||
2659 | cm = cm2; | ||
2660 | } | ||
2661 | skip: ; | ||
2662 | } | ||
2663 | last_row = row; | ||
2664 | #endif /* FEATURE_VI_OPTIMIZE_CURSOR */ | ||
2665 | write1(cm); | ||
2666 | } | 2614 | } |
2667 | 2615 | ||
2668 | //----- Erase from cursor to end of line ----------------------- | 2616 | //----- Erase from cursor to end of line ----------------------- |
2669 | static void clear_to_eol(void) | 2617 | static void clear_to_eol(void) |
2670 | { | 2618 | { |
2671 | write1(Ceol); // Erase from cursor to end of line | 2619 | write1(ESC_CLEAR2EOL); |
2672 | } | 2620 | } |
2673 | 2621 | ||
2674 | static void go_bottom_and_clear_to_eol(void) | 2622 | static void go_bottom_and_clear_to_eol(void) |
2675 | { | 2623 | { |
2676 | place_cursor(rows - 1, 0, FALSE); // go to bottom of screen | 2624 | place_cursor(rows - 1, 0); |
2677 | clear_to_eol(); // erase to end of line | 2625 | clear_to_eol(); |
2678 | } | 2626 | } |
2679 | 2627 | ||
2680 | //----- Erase from cursor to end of screen ----------------------- | 2628 | //----- Erase from cursor to end of screen ----------------------- |
2681 | static void clear_to_eos(void) | 2629 | static void clear_to_eos(void) |
2682 | { | 2630 | { |
2683 | write1(Ceos); // Erase from cursor to end of screen | 2631 | write1(ESC_CLEAR2EOS); |
2684 | } | 2632 | } |
2685 | 2633 | ||
2686 | //----- Start standout mode ------------------------------------ | 2634 | //----- Start standout mode ------------------------------------ |
2687 | static void standout_start(void) // send "start reverse video" sequence | 2635 | static void standout_start(void) |
2688 | { | 2636 | { |
2689 | write1(SOs); // Start reverse video mode | 2637 | write1(ESC_BOLD_TEXT); |
2690 | } | 2638 | } |
2691 | 2639 | ||
2692 | //----- End standout mode -------------------------------------- | 2640 | //----- End standout mode -------------------------------------- |
2693 | static void standout_end(void) // send "end reverse video" sequence | 2641 | static void standout_end(void) |
2694 | { | 2642 | { |
2695 | write1(SOn); // End reverse video mode | 2643 | write1(ESC_NORM_TEXT); |
2696 | } | 2644 | } |
2697 | 2645 | ||
2698 | //----- Flash the screen -------------------------------------- | 2646 | //----- Flash the screen -------------------------------------- |
2699 | static void flash(int h) | 2647 | static void flash(int h) |
2700 | { | 2648 | { |
2701 | standout_start(); // send "start reverse video" sequence | 2649 | standout_start(); |
2702 | redraw(TRUE); | 2650 | redraw(TRUE); |
2703 | mysleep(h); | 2651 | mysleep(h); |
2704 | standout_end(); // send "end reverse video" sequence | 2652 | standout_end(); |
2705 | redraw(TRUE); | 2653 | redraw(TRUE); |
2706 | } | 2654 | } |
2707 | 2655 | ||
@@ -2712,7 +2660,7 @@ static void Indicate_Error(void) | |||
2712 | return; // generate a random command | 2660 | return; // generate a random command |
2713 | #endif | 2661 | #endif |
2714 | if (!err_method) { | 2662 | if (!err_method) { |
2715 | write1(bell); // send out a bell character | 2663 | write1(ESC_BELL); |
2716 | } else { | 2664 | } else { |
2717 | flash(10); | 2665 | flash(10); |
2718 | } | 2666 | } |
@@ -2758,7 +2706,7 @@ static void show_status_line(void) | |||
2758 | } | 2706 | } |
2759 | have_status_msg = 0; | 2707 | have_status_msg = 0; |
2760 | } | 2708 | } |
2761 | place_cursor(crow, ccol, FALSE); // put cursor back in correct place | 2709 | place_cursor(crow, ccol); // put cursor back in correct place |
2762 | } | 2710 | } |
2763 | fflush_all(); | 2711 | fflush_all(); |
2764 | } | 2712 | } |
@@ -2770,12 +2718,12 @@ static void status_line_bold(const char *format, ...) | |||
2770 | va_list args; | 2718 | va_list args; |
2771 | 2719 | ||
2772 | va_start(args, format); | 2720 | va_start(args, format); |
2773 | strcpy(status_buffer, SOs); // Terminal standout mode on | 2721 | strcpy(status_buffer, ESC_BOLD_TEXT); |
2774 | vsprintf(status_buffer + sizeof(SOs)-1, format, args); | 2722 | vsprintf(status_buffer + sizeof(ESC_BOLD_TEXT)-1, format, args); |
2775 | strcat(status_buffer, SOn); // Terminal standout mode off | 2723 | strcat(status_buffer, ESC_NORM_TEXT); |
2776 | va_end(args); | 2724 | va_end(args); |
2777 | 2725 | ||
2778 | have_status_msg = 1 + sizeof(SOs) + sizeof(SOn) - 2; | 2726 | have_status_msg = 1 + sizeof(ESC_BOLD_TEXT) + sizeof(ESC_NORM_TEXT) - 2; |
2779 | } | 2727 | } |
2780 | 2728 | ||
2781 | // format status buffer | 2729 | // format status buffer |
@@ -2807,8 +2755,8 @@ static void print_literal(char *buf, const char *s) | |||
2807 | c = *s; | 2755 | c = *s; |
2808 | c_is_no_print = (c & 0x80) && !Isprint(c); | 2756 | c_is_no_print = (c & 0x80) && !Isprint(c); |
2809 | if (c_is_no_print) { | 2757 | if (c_is_no_print) { |
2810 | strcpy(d, SOn); | 2758 | strcpy(d, ESC_NORM_TEXT); |
2811 | d += sizeof(SOn)-1; | 2759 | d += sizeof(ESC_NORM_TEXT)-1; |
2812 | c = '.'; | 2760 | c = '.'; |
2813 | } | 2761 | } |
2814 | if (c < ' ' || c == 0x7f) { | 2762 | if (c < ' ' || c == 0x7f) { |
@@ -2820,8 +2768,8 @@ static void print_literal(char *buf, const char *s) | |||
2820 | *d++ = c; | 2768 | *d++ = c; |
2821 | *d = '\0'; | 2769 | *d = '\0'; |
2822 | if (c_is_no_print) { | 2770 | if (c_is_no_print) { |
2823 | strcpy(d, SOs); | 2771 | strcpy(d, ESC_BOLD_TEXT); |
2824 | d += sizeof(SOs)-1; | 2772 | d += sizeof(ESC_BOLD_TEXT)-1; |
2825 | } | 2773 | } |
2826 | if (*s == '\n') { | 2774 | if (*s == '\n') { |
2827 | *d++ = '$'; | 2775 | *d++ = '$'; |
@@ -2903,8 +2851,8 @@ static int format_edit_status(void) | |||
2903 | //----- Force refresh of all Lines ----------------------------- | 2851 | //----- Force refresh of all Lines ----------------------------- |
2904 | static void redraw(int full_screen) | 2852 | static void redraw(int full_screen) |
2905 | { | 2853 | { |
2906 | place_cursor(0, 0, FALSE); // put cursor in correct place | 2854 | place_cursor(0, 0); |
2907 | clear_to_eos(); // tell terminal to erase display | 2855 | clear_to_eos(); |
2908 | screen_erase(); // erase the internal screen buffer | 2856 | screen_erase(); // erase the internal screen buffer |
2909 | last_status_cksum = 0; // force status update | 2857 | last_status_cksum = 0; // force status update |
2910 | refresh(full_screen); // this will redraw the entire display | 2858 | refresh(full_screen); // this will redraw the entire display |
@@ -3044,22 +2992,13 @@ static void refresh(int full_screen) | |||
3044 | if (changed) { | 2992 | if (changed) { |
3045 | // copy changed part of buffer to virtual screen | 2993 | // copy changed part of buffer to virtual screen |
3046 | memcpy(sp+cs, out_buf+cs, ce-cs+1); | 2994 | memcpy(sp+cs, out_buf+cs, ce-cs+1); |
3047 | 2995 | place_cursor(li, cs); | |
3048 | // move cursor to column of first change | ||
3049 | //if (offset != old_offset) { | ||
3050 | // // place_cursor is still too stupid | ||
3051 | // // to handle offsets correctly | ||
3052 | // place_cursor(li, cs, FALSE); | ||
3053 | //} else { | ||
3054 | place_cursor(li, cs, TRUE); | ||
3055 | //} | ||
3056 | |||
3057 | // write line out to terminal | 2996 | // write line out to terminal |
3058 | fwrite(&sp[cs], ce - cs + 1, 1, stdout); | 2997 | fwrite(&sp[cs], ce - cs + 1, 1, stdout); |
3059 | } | 2998 | } |
3060 | } | 2999 | } |
3061 | 3000 | ||
3062 | place_cursor(crow, ccol, TRUE); | 3001 | place_cursor(crow, ccol); |
3063 | 3002 | ||
3064 | old_offset = offset; | 3003 | old_offset = offset; |
3065 | #undef old_offset | 3004 | #undef old_offset |
@@ -3229,9 +3168,9 @@ static void do_cmd(int c) | |||
3229 | break; | 3168 | break; |
3230 | case 12: // ctrl-L force redraw whole screen | 3169 | case 12: // ctrl-L force redraw whole screen |
3231 | case 18: // ctrl-R force redraw | 3170 | case 18: // ctrl-R force redraw |
3232 | place_cursor(0, 0, FALSE); // put cursor in correct place | 3171 | place_cursor(0, 0); |
3233 | clear_to_eos(); // tel terminal to erase display | 3172 | clear_to_eos(); |
3234 | mysleep(10); | 3173 | //mysleep(10); // why??? |
3235 | screen_erase(); // erase the internal screen buffer | 3174 | screen_erase(); // erase the internal screen buffer |
3236 | last_status_cksum = 0; // force status update | 3175 | last_status_cksum = 0; // force status update |
3237 | refresh(TRUE); // this will redraw the entire display | 3176 | refresh(TRUE); // this will redraw the entire display |
@@ -4150,7 +4089,7 @@ static void crash_test() | |||
4150 | 4089 | ||
4151 | if (msg[0]) { | 4090 | if (msg[0]) { |
4152 | printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s", | 4091 | printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s", |
4153 | totalcmds, last_input_char, msg, SOs, SOn); | 4092 | totalcmds, last_input_char, msg, ESC_BOLD_TEXT, ESC_NORM_TEXT); |
4154 | fflush_all(); | 4093 | fflush_all(); |
4155 | while (safe_read(STDIN_FILENO, d, 1) > 0) { | 4094 | while (safe_read(STDIN_FILENO, d, 1) > 0) { |
4156 | if (d[0] == '\n' || d[0] == '\r') | 4095 | if (d[0] == '\n' || d[0] == '\r') |