aboutsummaryrefslogtreecommitdiff
path: root/editors
diff options
context:
space:
mode:
Diffstat (limited to 'editors')
-rw-r--r--editors/awk.c41
-rw-r--r--editors/diff.c48
-rw-r--r--editors/sed.c21
-rw-r--r--editors/vi.c193
4 files changed, 301 insertions, 2 deletions
diff --git a/editors/awk.c b/editors/awk.c
index 64e752f4b..1feb49da1 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -970,7 +970,7 @@ static double my_strtod_or_hexoct(char **pp)
970static const char *fmt_num(const char *format, double n) 970static const char *fmt_num(const char *format, double n)
971{ 971{
972 if (n == (long long)n) { 972 if (n == (long long)n) {
973 snprintf(g_buf, MAXVARFMT, "%lld", (long long)n); 973 snprintf(g_buf, MAXVARFMT, "%"LL_FMT"d", (long long)n);
974 } else { 974 } else {
975 const char *s = format; 975 const char *s = format;
976 char c; 976 char c;
@@ -2929,6 +2929,15 @@ static int try_to_assign(const char *expr)
2929 return TRUE; 2929 return TRUE;
2930} 2930}
2931 2931
2932
2933#if ENABLE_PLATFORM_MINGW32
2934static void set_text_mode(FILE *f)
2935{
2936 if (f)
2937 _setmode(fileno(f), _O_TEXT);
2938}
2939#endif
2940
2932/* switch to next input file */ 2941/* switch to next input file */
2933static int next_input_file(void) 2942static int next_input_file(void)
2934{ 2943{
@@ -2972,6 +2981,9 @@ static int next_input_file(void)
2972 break; 2981 break;
2973 } 2982 }
2974 } 2983 }
2984#if ENABLE_PLATFORM_MINGW32
2985 set_text_mode(iF.F);
2986#endif
2975 2987
2976 setvar_s(intvar[FILENAME], fname); 2988 setvar_s(intvar[FILENAME], fname);
2977 input_file_seen = TRUE; 2989 input_file_seen = TRUE;
@@ -2980,6 +2992,17 @@ static int next_input_file(void)
2980#undef input_file_seen 2992#undef input_file_seen
2981} 2993}
2982 2994
2995#if ENABLE_PLATFORM_MINGW32
2996static unsigned triple32(unsigned x)
2997{
2998 x ^= x >> 17; x *= 0xed5ad4bb;
2999 x ^= x >> 11; x *= 0xac4c1b51;
3000 x ^= x >> 15; x *= 0x31848bab;
3001 x ^= x >> 14;
3002 return x;
3003}
3004#endif
3005
2983/* 3006/*
2984 * Evaluate node - the heart of the program. Supplied with subtree 3007 * Evaluate node - the heart of the program. Supplied with subtree
2985 * and "res" variable to assign the result to if we evaluate an expression. 3008 * and "res" variable to assign the result to if we evaluate an expression.
@@ -3361,6 +3384,9 @@ static var *evaluate(node *op, var *res)
3361 } else { 3384 } else {
3362 rsm->F = fopen_for_read(L.s); /* not xfopen! */ 3385 rsm->F = fopen_for_read(L.s); /* not xfopen! */
3363 } 3386 }
3387#if ENABLE_PLATFORM_MINGW32
3388 set_text_mode(rsm->F);
3389#endif
3364 } 3390 }
3365 } else { 3391 } else {
3366 if (!iF.F) 3392 if (!iF.F)
@@ -3412,6 +3438,12 @@ static var *evaluate(node *op, var *res)
3412 v &= 0x7fffffffffffffffULL; 3438 v &= 0x7fffffffffffffffULL;
3413# endif 3439# endif
3414 R_d = (double)v / 0x8000000000000000ULL; 3440 R_d = (double)v / 0x8000000000000000ULL;
3441#elif ENABLE_PLATFORM_MINGW32 && RAND_MAX == 0x7fff
3442 /* 45 bits of randomness ought to be enough for anyone */
3443 uint64_t v = ((uint64_t)rand() << 18) |
3444 ((uint64_t)rand() << 33) |
3445 ((uint64_t)rand() << 48);
3446 R_d = (double)v / 0x8000000000000000ULL;
3415#else 3447#else
3416# error Not implemented for this value of RAND_MAX 3448# error Not implemented for this value of RAND_MAX
3417#endif 3449#endif
@@ -3453,7 +3485,11 @@ static var *evaluate(node *op, var *res)
3453 case F_sr: 3485 case F_sr:
3454 R_d = (double)seed; 3486 R_d = (double)seed;
3455 seed = op1 ? (unsigned)L_d : (unsigned)time(NULL); 3487 seed = op1 ? (unsigned)L_d : (unsigned)time(NULL);
3488#if ENABLE_PLATFORM_MINGW32
3489 srand(seed == 1 ? 1 : triple32(seed));
3490#else
3456 srand(seed); 3491 srand(seed);
3492#endif
3457 break; 3493 break;
3458 3494
3459 case F_ti: /*systime*/ 3495 case F_ti: /*systime*/
@@ -3797,6 +3833,9 @@ int awk_main(int argc UNUSED_PARAM, char **argv)
3797 char *s; 3833 char *s;
3798 g_progname = optarg; 3834 g_progname = optarg;
3799 fd = xopen_stdin(g_progname); 3835 fd = xopen_stdin(g_progname);
3836#if ENABLE_PLATFORM_MINGW32
3837 _setmode(fd, _O_TEXT);
3838#endif
3800 s = xmalloc_read(fd, NULL); /* it's NUL-terminated */ 3839 s = xmalloc_read(fd, NULL); /* it's NUL-terminated */
3801 if (!s) 3840 if (!s)
3802 bb_perror_msg_and_die("read error from '%s'", g_progname); 3841 bb_perror_msg_and_die("read error from '%s'", g_progname);
diff --git a/editors/diff.c b/editors/diff.c
index 1adc4cbc7..b324feaa5 100644
--- a/editors/diff.c
+++ b/editors/diff.c
@@ -119,6 +119,9 @@
119//usage: "\n -t Expand tabs to spaces in output" 119//usage: "\n -t Expand tabs to spaces in output"
120//usage: "\n -U Output LINES lines of context" 120//usage: "\n -U Output LINES lines of context"
121//usage: "\n -w Ignore all whitespace" 121//usage: "\n -w Ignore all whitespace"
122//usage: IF_PLATFORM_MINGW32(IF_FEATURE_DIFF_LONG_OPTIONS(
123//usage: "\n --binary Treat input as binary, not text"
124//usage: ))
122 125
123#include "libbb.h" 126#include "libbb.h"
124#include "common_bufsiz.h" 127#include "common_bufsiz.h"
@@ -154,6 +157,9 @@ enum { /* Commandline flags */
154 FLAG_p, /* not implemented */ 157 FLAG_p, /* not implemented */
155 FLAG_B, 158 FLAG_B,
156 FLAG_E, /* not implemented */ 159 FLAG_E, /* not implemented */
160#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_DIFF_LONG_OPTIONS
161 FLAG_binary,
162#endif
157}; 163};
158#define FLAG(x) (1 << FLAG_##x) 164#define FLAG(x) (1 << FLAG_##x)
159 165
@@ -217,6 +223,9 @@ static int read_token(FILE_and_pos_t *ft, token_t tok)
217 int t; 223 int t;
218 224
219 t = fgetc(ft->ft_fp); 225 t = fgetc(ft->ft_fp);
226#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_DIFF_LONG_OPTIONS
227 newline:
228#endif
220 if (t != EOF) 229 if (t != EOF)
221 ft->ft_pos++; 230 ft->ft_pos++;
222 is_space = (t == EOF || isspace(t)); 231 is_space = (t == EOF || isspace(t));
@@ -232,6 +241,16 @@ static int read_token(FILE_and_pos_t *ft, token_t tok)
232 241
233 if ((option_mask32 & FLAG(w)) && is_space) 242 if ((option_mask32 & FLAG(w)) && is_space)
234 continue; 243 continue;
244#if ENABLE_PLATFORM_MINGW32 && ENABLE_FEATURE_DIFF_LONG_OPTIONS
245 if (!(option_mask32 & FLAG(binary)) && t == '\r') {
246 int t2 = fgetc(ft->ft_fp);
247 if (t2 == '\n') {
248 t = t2;
249 goto newline;
250 }
251 ungetc(t2, ft->ft_fp);
252 }
253#endif
235 254
236 /* Trim char value to low 9 bits */ 255 /* Trim char value to low 9 bits */
237 t &= CHAR_MASK; 256 t &= CHAR_MASK;
@@ -709,6 +728,10 @@ static int diffreg(char *file[2])
709 FILE *fp[2]; 728 FILE *fp[2];
710 bool binary = false, differ = false; 729 bool binary = false, differ = false;
711 int status = STATUS_SAME, i; 730 int status = STATUS_SAME, i;
731#if ENABLE_PLATFORM_MINGW32
732 char *tmpfile[2] = { NULL, NULL };
733 char *tmpdir;
734#endif
712 735
713 fp[0] = stdin; 736 fp[0] = stdin;
714 fp[1] = stdin; 737 fp[1] = stdin;
@@ -730,10 +753,19 @@ static int diffreg(char *file[2])
730 * When we meet non-seekable file, we must make a temp copy. 753 * When we meet non-seekable file, we must make a temp copy.
731 */ 754 */
732 if (lseek(fd, 0, SEEK_SET) == -1 && errno == ESPIPE) { 755 if (lseek(fd, 0, SEEK_SET) == -1 && errno == ESPIPE) {
756#if !ENABLE_PLATFORM_MINGW32
733 char name[] = "/tmp/difXXXXXX"; 757 char name[] = "/tmp/difXXXXXX";
734 int fd_tmp = xmkstemp(name); 758 int fd_tmp = xmkstemp(name);
735 759
736 unlink(name); 760 unlink(name);
761#else
762 int fd_tmp;
763
764 if (!(tmpdir=getenv("TMPDIR")))
765 goto out;
766 tmpfile[i] = xasprintf("%s/difXXXXXX", tmpdir);
767 fd_tmp = xmkstemp(tmpfile[i]);
768#endif
737 if (bb_copyfd_eof(fd, fd_tmp) < 0) 769 if (bb_copyfd_eof(fd, fd_tmp) < 0)
738 xfunc_die(); 770 xfunc_die();
739 if (fd != STDIN_FILENO) 771 if (fd != STDIN_FILENO)
@@ -776,6 +808,14 @@ static int diffreg(char *file[2])
776out: 808out:
777 fclose_if_not_stdin(fp[0]); 809 fclose_if_not_stdin(fp[0]);
778 fclose_if_not_stdin(fp[1]); 810 fclose_if_not_stdin(fp[1]);
811#if ENABLE_PLATFORM_MINGW32
812 for (i = 0; i < 2; i++) {
813 if (tmpfile[i]) {
814 unlink(tmpfile[i]);
815 free(tmpfile[i]);
816 }
817 }
818#endif
779 819
780 return status; 820 return status;
781} 821}
@@ -964,6 +1004,9 @@ static const char diff_longopts[] ALIGN1 =
964 "report-identical-files\0" No_argument "s" 1004 "report-identical-files\0" No_argument "s"
965 "starting-file\0" Required_argument "S" 1005 "starting-file\0" Required_argument "S"
966 "minimal\0" No_argument "d" 1006 "minimal\0" No_argument "d"
1007#if ENABLE_PLATFORM_MINGW32
1008 "binary\0" No_argument "\xff"
1009#endif
967 ; 1010 ;
968# define GETOPT32 getopt32long 1011# define GETOPT32 getopt32long
969# define LONGOPTS ,diff_longopts 1012# define LONGOPTS ,diff_longopts
@@ -1019,6 +1062,11 @@ int diff_main(int argc UNUSED_PARAM, char **argv)
1019 * 255, or if a local inode number (st_ino) exceeds 16777215. 1062 * 255, or if a local inode number (st_ino) exceeds 16777215.
1020 */ 1063 */
1021 if (ENABLE_DESKTOP 1064 if (ENABLE_DESKTOP
1065 && (ENABLE_PLATFORM_POSIX || ENABLE_FEATURE_EXTRA_FILE_DATA)
1066#if ENABLE_FEATURE_EXTRA_FILE_DATA
1067 /* ignore invalid inode numbers */
1068 && stb[0].st_ino != 0
1069#endif
1022 && stb[0].st_ino == stb[1].st_ino 1070 && stb[0].st_ino == stb[1].st_ino
1023 && stb[0].st_dev == stb[1].st_dev 1071 && stb[0].st_dev == stb[1].st_dev
1024 && stb[0].st_size == stb[1].st_size 1072 && stb[0].st_size == stb[1].st_size
diff --git a/editors/sed.c b/editors/sed.c
index 6179c5e80..107e664a0 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -74,6 +74,9 @@
74//usage: "\n Optionally back files up, appending SFX" 74//usage: "\n Optionally back files up, appending SFX"
75//usage: "\n -n Suppress automatic printing of pattern space" 75//usage: "\n -n Suppress automatic printing of pattern space"
76//usage: "\n -r,-E Use extended regex syntax" 76//usage: "\n -r,-E Use extended regex syntax"
77//usage: IF_PLATFORM_MINGW32(
78//usage: "\n -b Keep CR/LF (Windows-only)"
79//usage: )
77//usage: "\n" 80//usage: "\n"
78//usage: "\nIf no -e or -f, the first non-option argument is the sed command string." 81//usage: "\nIf no -e or -f, the first non-option argument is the sed command string."
79//usage: "\nRemaining arguments are input files (stdin if none)." 82//usage: "\nRemaining arguments are input files (stdin if none)."
@@ -138,6 +141,9 @@ static const char semicolon_whitespace[] ALIGN1 = "; \n\r\t\v";
138struct globals { 141struct globals {
139 /* options */ 142 /* options */
140 int be_quiet, regex_type; 143 int be_quiet, regex_type;
144#if ENABLE_PLATFORM_MINGW32
145 int keep_cr;
146#endif
141 147
142 FILE *nonstdout; 148 FILE *nonstdout;
143 char *outname, *hold_space; 149 char *outname, *hold_space;
@@ -1065,6 +1071,11 @@ static char *get_next_line(char *gets_char, char *last_puts_char)
1065 char c = temp[len-1]; 1071 char c = temp[len-1];
1066 if (c == '\n' || c == '\0') { 1072 if (c == '\n' || c == '\0') {
1067 temp[len-1] = '\0'; 1073 temp[len-1] = '\0';
1074#if ENABLE_PLATFORM_MINGW32
1075 if (!G.keep_cr && c == '\n' && len > 1 && temp[len-2] == '\r') {
1076 temp[len-2] = '\0';
1077 }
1078#endif
1068 gc = c; 1079 gc = c;
1069 if (c == '\0') { 1080 if (c == '\0') {
1070 int ch = fgetc(fp); 1081 int ch = fgetc(fp);
@@ -1541,7 +1552,12 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1541 "quiet\0" No_argument "n" 1552 "quiet\0" No_argument "n"
1542 "silent\0" No_argument "n" 1553 "silent\0" No_argument "n"
1543 "expression\0" Required_argument "e" 1554 "expression\0" Required_argument "e"
1555# if !ENABLE_PLATFORM_MINGW32
1544 "file\0" Required_argument "f"; 1556 "file\0" Required_argument "f";
1557# else
1558 "file\0" Required_argument "f"
1559 "binary\0" No_argument "b";
1560# endif
1545#endif 1561#endif
1546 1562
1547 INIT_G(); 1563 INIT_G();
@@ -1565,6 +1581,7 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1565 */ 1581 */
1566 opt = getopt32long(argv, "^" 1582 opt = getopt32long(argv, "^"
1567 "i::rEne:*f:*" 1583 "i::rEne:*f:*"
1584 IF_PLATFORM_MINGW32("b")
1568 "\0" "nn"/*count -n*/, 1585 "\0" "nn"/*count -n*/,
1569 sed_longopts, 1586 sed_longopts,
1570 &opt_i, &opt_e, &opt_f, 1587 &opt_i, &opt_e, &opt_f,
@@ -1578,6 +1595,10 @@ int sed_main(int argc UNUSED_PARAM, char **argv)
1578 G.regex_type |= REG_EXTENDED; // -r or -E 1595 G.regex_type |= REG_EXTENDED; // -r or -E
1579 //if (opt & 8) 1596 //if (opt & 8)
1580 // G.be_quiet++; // -n (implemented with a counter instead) 1597 // G.be_quiet++; // -n (implemented with a counter instead)
1598#if ENABLE_PLATFORM_MINGW32
1599 if (opt & 0x40)
1600 G.keep_cr = 1;
1601#endif
1581 while (opt_e) { // -e 1602 while (opt_e) { // -e
1582 add_cmd_block(llist_pop(&opt_e)); 1603 add_cmd_block(llist_pop(&opt_e));
1583 } 1604 }
diff --git a/editors/vi.c b/editors/vi.c
index 34932f60c..e59083ddb 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -112,6 +112,19 @@
112//config: help 112//config: help
113//config: Enable the editor to set some (ai, ic, showmatch) options. 113//config: Enable the editor to set some (ai, ic, showmatch) options.
114//config: 114//config:
115//config:config FEATURE_VI_FILE_FORMAT
116//config: bool "Enable detection of file format"
117//config: default y
118//config: depends on VI && FEATURE_VI_SETOPTS && PLATFORM_MINGW32
119//config: help
120//config: Enable the editor to detect the format of files it reads
121//config: so they can be written out with the appropriate line
122//config: endings. Also allow files to be edited in binary mode.
123//config:
124//config: This enables the 'fileformat', 'fileformats' and 'binary'
125//config: options and the '-b' command line flag.
126//config:
127//config:
115//config:config FEATURE_VI_SET 128//config:config FEATURE_VI_SET
116//config: bool "Support :set" 129//config: bool "Support :set"
117//config: default y 130//config: default y
@@ -181,9 +194,12 @@
181//kbuild:lib-$(CONFIG_VI) += vi.o 194//kbuild:lib-$(CONFIG_VI) += vi.o
182 195
183//usage:#define vi_trivial_usage 196//usage:#define vi_trivial_usage
184//usage: IF_FEATURE_VI_COLON("[-c CMD] ")IF_FEATURE_VI_READONLY("[-R] ")"[-H] [FILE]..." 197//usage: IF_FEATURE_VI_FILE_FORMAT("[-b] ")IF_FEATURE_VI_COLON("[-c CMD] ")IF_FEATURE_VI_READONLY("[-R] ")"[-H] [FILE]..."
185//usage:#define vi_full_usage "\n\n" 198//usage:#define vi_full_usage "\n\n"
186//usage: "Edit FILE\n" 199//usage: "Edit FILE\n"
200//usage: IF_FEATURE_VI_FILE_FORMAT(
201//usage: "\n -b Edit file in binary mode"
202//usage: )
187//usage: IF_FEATURE_VI_COLON( 203//usage: IF_FEATURE_VI_COLON(
188//usage: "\n -c CMD Initial command to run ($EXINIT and ~/.exrc also available)" 204//usage: "\n -c CMD Initial command to run ($EXINIT and ~/.exrc also available)"
189//usage: ) 205//usage: )
@@ -198,6 +214,9 @@
198#if ENABLE_FEATURE_VI_REGEX_SEARCH 214#if ENABLE_FEATURE_VI_REGEX_SEARCH
199# include <regex.h> 215# include <regex.h>
200#endif 216#endif
217#if ENABLE_PLATFORM_MINGW32
218# include "BB_VER.h"
219#endif
201 220
202// the CRASHME code is unmaintained, and doesn't currently build 221// the CRASHME code is unmaintained, and doesn't currently build
203#define ENABLE_FEATURE_VI_CRASHME 0 222#define ENABLE_FEATURE_VI_CRASHME 0
@@ -224,7 +243,11 @@
224 243
225#endif 244#endif
226 245
246#if !ENABLE_PLATFORM_MINGW32
227#define isbackspace(c) ((c) == term_orig.c_cc[VERASE] || (c) == 8 || (c) == 127) 247#define isbackspace(c) ((c) == term_orig.c_cc[VERASE] || (c) == 8 || (c) == 127)
248#else
249#define isbackspace(c) ((c) == 8 || (c) == 127)
250#endif
228 251
229enum { 252enum {
230 MAX_TABSTOP = 32, // sanity limit 253 MAX_TABSTOP = 32, // sanity limit
@@ -298,6 +321,7 @@ struct globals {
298 321
299 // the rest 322 // the rest
300#if ENABLE_FEATURE_VI_SETOPTS 323#if ENABLE_FEATURE_VI_SETOPTS
324#if !ENABLE_FEATURE_VI_FILE_FORMAT
301 smallint vi_setops; // set by setops() 325 smallint vi_setops; // set by setops()
302#define VI_AUTOINDENT (1 << 0) 326#define VI_AUTOINDENT (1 << 0)
303#define VI_EXPANDTAB (1 << 1) 327#define VI_EXPANDTAB (1 << 1)
@@ -305,6 +329,19 @@ struct globals {
305#define VI_IGNORECASE (1 << 3) 329#define VI_IGNORECASE (1 << 3)
306#define VI_SHOWMATCH (1 << 4) 330#define VI_SHOWMATCH (1 << 4)
307#define VI_TABSTOP (1 << 5) 331#define VI_TABSTOP (1 << 5)
332#else
333 int vi_setops; // set by setops()
334#define VI_AUTOINDENT (1 << 0)
335#define VI_BINARY (1 << 1)
336#define VI_EXPANDTAB (1 << 2)
337#define VI_FILEFORMAT (1 << 3)
338#define VI_FILEFORMATS (1 << 4)
339#define VI_ERR_METHOD (1 << 5)
340#define VI_IGNORECASE (1 << 6)
341#define VI_SHOWMATCH (1 << 7)
342#define VI_TABSTOP (1 << 8)
343#define binary (vi_setops & VI_BINARY )
344#endif
308#define autoindent (vi_setops & VI_AUTOINDENT) 345#define autoindent (vi_setops & VI_AUTOINDENT)
309#define expandtab (vi_setops & VI_EXPANDTAB ) 346#define expandtab (vi_setops & VI_EXPANDTAB )
310#define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash 347#define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash
@@ -313,11 +350,25 @@ struct globals {
313// order of constants and strings must match 350// order of constants and strings must match
314#define OPTS_STR \ 351#define OPTS_STR \
315 "ai\0""autoindent\0" \ 352 "ai\0""autoindent\0" \
353 IF_FEATURE_VI_FILE_FORMAT("bin\0""binary\0") \
316 "et\0""expandtab\0" \ 354 "et\0""expandtab\0" \
355 IF_FEATURE_VI_FILE_FORMAT("ff\0""fileformat\0") \
356 IF_FEATURE_VI_FILE_FORMAT("ffs\0""fileformats\0") \
317 "fl\0""flash\0" \ 357 "fl\0""flash\0" \
318 "ic\0""ignorecase\0" \ 358 "ic\0""ignorecase\0" \
319 "sm\0""showmatch\0" \ 359 "sm\0""showmatch\0" \
320 "ts\0""tabstop\0" 360 "ts\0""tabstop\0"
361
362#define FF_DOS 0
363#define FF_UNIX 1
364
365#define FF_STR \
366 "dos\0" \
367 "unix\0"
368
369#define FFS_STR \
370 "dos,unix\0" \
371 "unix,dos\0"
321#else 372#else
322#define autoindent (0) 373#define autoindent (0)
323#define expandtab (0) 374#define expandtab (0)
@@ -384,6 +435,10 @@ struct globals {
384 int newindent; // autoindent value for 'O'/'cc' commands 435 int newindent; // autoindent value for 'O'/'cc' commands
385 // or -1 to use indent from previous line 436 // or -1 to use indent from previous line
386#endif 437#endif
438#if ENABLE_FEATURE_VI_FILE_FORMAT
439 smallint fileformat;
440 smallint fileformats;
441#endif
387 smallint cmd_error; 442 smallint cmd_error;
388 443
389 // former statics 444 // former statics
@@ -511,6 +566,8 @@ struct globals {
511#define last_search_pattern (G.last_search_pattern) 566#define last_search_pattern (G.last_search_pattern)
512#define char_insert__indentcol (G.char_insert__indentcol) 567#define char_insert__indentcol (G.char_insert__indentcol)
513#define newindent (G.newindent ) 568#define newindent (G.newindent )
569#define fileformat (G.fileformat )
570#define fileformats (G.fileformats )
514#define cmd_error (G.cmd_error ) 571#define cmd_error (G.cmd_error )
515 572
516#define edit_file__cur_line (G.edit_file__cur_line) 573#define edit_file__cur_line (G.edit_file__cur_line)
@@ -615,6 +672,23 @@ static ALWAYS_INLINE int query_screen_dimensions(void)
615// sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready) 672// sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready)
616static int mysleep(int hund) 673static int mysleep(int hund)
617{ 674{
675#if ENABLE_PLATFORM_MINGW32
676 HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
677 DWORD ret;
678
679 if (hund == 0) {
680 // Allow two events in the queue. Otherwise pasted test isn't
681 // displayed because there's still a key release event waiting
682 // after the last character is processed.
683 DWORD nevent_out;
684
685 ret = GetNumberOfConsoleInputEvents(h, &nevent_out);
686 return ret != 0 ? (nevent_out > 2) : 0;
687 }
688 fflush_all();
689 ret = WaitForSingleObject(h, hund*10);
690 return ret != WAIT_TIMEOUT;
691#else
618 struct pollfd pfd[1]; 692 struct pollfd pfd[1];
619 693
620 if (hund != 0) 694 if (hund != 0)
@@ -623,6 +697,7 @@ static int mysleep(int hund)
623 pfd[0].fd = STDIN_FILENO; 697 pfd[0].fd = STDIN_FILENO;
624 pfd[0].events = POLLIN; 698 pfd[0].events = POLLIN;
625 return safe_poll(pfd, 1, hund*10) > 0; 699 return safe_poll(pfd, 1, hund*10) > 0;
700#endif
626} 701}
627 702
628//----- Set terminal attributes -------------------------------- 703//----- Set terminal attributes --------------------------------
@@ -1978,6 +2053,18 @@ static char *yank_delete(char *start, char *stop, int buftype, int yf, int undo)
1978 return p; 2053 return p;
1979} 2054}
1980 2055
2056#if ENABLE_PLATFORM_MINGW32
2057static int count_cr(char *p, int len)
2058{
2059 int i, cnt;
2060
2061 for (i = cnt = 0; i < len; ++i)
2062 if (p[i] == '\n')
2063 ++cnt;
2064 return cnt;
2065}
2066#endif
2067
1981// might reallocate text[]! 2068// might reallocate text[]!
1982static int file_insert(const char *fn, char *p, int initial) 2069static int file_insert(const char *fn, char *p, int initial)
1983{ 2070{
@@ -1990,7 +2077,13 @@ static int file_insert(const char *fn, char *p, int initial)
1990 if (p > end) 2077 if (p > end)
1991 p = end; 2078 p = end;
1992 2079
2080#if !ENABLE_PLATFORM_MINGW32
1993 fd = open(fn, O_RDONLY); 2081 fd = open(fn, O_RDONLY);
2082#elif ENABLE_FEATURE_VI_FILE_FORMAT
2083 fd = open(fn, O_RDONLY | (!binary ? _O_TEXT : 0));
2084#else
2085 fd = open(fn, O_RDONLY | _O_TEXT);
2086#endif
1994 if (fd < 0) { 2087 if (fd < 0) {
1995 if (!initial) 2088 if (!initial)
1996 status_line_bold_errno(fn); 2089 status_line_bold_errno(fn);
@@ -2013,8 +2106,15 @@ static int file_insert(const char *fn, char *p, int initial)
2013 status_line_bold_errno(fn); 2106 status_line_bold_errno(fn);
2014 p = text_hole_delete(p, p + size - 1, NO_UNDO); // un-do buffer insert 2107 p = text_hole_delete(p, p + size - 1, NO_UNDO); // un-do buffer insert
2015 } else if (cnt < size) { 2108 } else if (cnt < size) {
2109#if ENABLE_PLATFORM_MINGW32
2110 // On WIN32 a partial read might just mean CRs have been removed
2111 int cnt_cr = cnt + count_cr(p, cnt);
2112#endif
2016 // There was a partial read, shrink unused space 2113 // There was a partial read, shrink unused space
2017 p = text_hole_delete(p + cnt, p + size - 1, NO_UNDO); 2114 p = text_hole_delete(p + cnt, p + size - 1, NO_UNDO);
2115#if ENABLE_PLATFORM_MINGW32
2116 if (cnt_cr < size)
2117#endif
2018 status_line_bold("can't read '%s'", fn); 2118 status_line_bold("can't read '%s'", fn);
2019 } 2119 }
2020# if ENABLE_FEATURE_VI_UNDO 2120# if ENABLE_FEATURE_VI_UNDO
@@ -2022,6 +2122,10 @@ static int file_insert(const char *fn, char *p, int initial)
2022 undo_push_insert(p, size, ALLOW_UNDO); 2122 undo_push_insert(p, size, ALLOW_UNDO);
2023 } 2123 }
2024# endif 2124# endif
2125#if ENABLE_FEATURE_VI_FILE_FORMAT
2126 if (initial && cnt > 0)
2127 fileformat = cnt == size ? FF_UNIX : FF_DOS;
2128#endif
2025 fi: 2129 fi:
2026 close(fd); 2130 close(fd);
2027 2131
@@ -2312,6 +2416,9 @@ static int init_text_buffer(char *fn)
2312 free(text); 2416 free(text);
2313 text_size = 10240; 2417 text_size = 10240;
2314 screenbegin = dot = end = text = xzalloc(text_size); 2418 screenbegin = dot = end = text = xzalloc(text_size);
2419#if ENABLE_FEATURE_VI_FILE_FORMAT
2420 fileformat = fileformats;
2421#endif
2315 2422
2316 update_filename(fn); 2423 update_filename(fn);
2317 rc = file_insert(fn, text, 1); 2424 rc = file_insert(fn, text, 1);
@@ -2358,6 +2465,13 @@ static uintptr_t string_insert(char *p, const char *s, int undo) // insert the s
2358static int file_write(char *fn, char *first, char *last) 2465static int file_write(char *fn, char *first, char *last)
2359{ 2466{
2360 int fd, cnt, charcnt; 2467 int fd, cnt, charcnt;
2468#if ENABLE_PLATFORM_MINGW32
2469# if ENABLE_FEATURE_VI_FILE_FORMAT
2470# define dos (!binary && fileformat == FF_DOS)
2471# else
2472# define dos (1)
2473# endif
2474#endif
2361 2475
2362 if (fn == 0) { 2476 if (fn == 0) {
2363 status_line_bold("No current filename"); 2477 status_line_bold("No current filename");
@@ -2366,12 +2480,22 @@ static int file_write(char *fn, char *first, char *last)
2366 // By popular request we do not open file with O_TRUNC, 2480 // By popular request we do not open file with O_TRUNC,
2367 // but instead ftruncate() it _after_ successful write. 2481 // but instead ftruncate() it _after_ successful write.
2368 // Might reduce amount of data lost on power fail etc. 2482 // Might reduce amount of data lost on power fail etc.
2483#if !ENABLE_PLATFORM_MINGW32
2369 fd = open(fn, (O_WRONLY | O_CREAT), 0666); 2484 fd = open(fn, (O_WRONLY | O_CREAT), 0666);
2485#else
2486 fd = open(fn, (O_WRONLY | O_CREAT | (dos ? _O_TEXT : 0)), 0666);
2487#endif
2370 if (fd < 0) 2488 if (fd < 0)
2371 return -1; 2489 return -1;
2372 cnt = last - first + 1; 2490 cnt = last - first + 1;
2373 charcnt = full_write(fd, first, cnt); 2491 charcnt = full_write(fd, first, cnt);
2492#if !ENABLE_PLATFORM_MINGW32
2374 ftruncate(fd, charcnt); 2493 ftruncate(fd, charcnt);
2494#else
2495 // If file was written in text mode it will be bigger so adjust
2496 // the truncation to match.
2497 ftruncate(fd, charcnt + (dos ? count_cr(first, cnt) : 0));
2498#endif
2375 if (charcnt == cnt) { 2499 if (charcnt == cnt) {
2376 // good write 2500 // good write
2377 //modified_count = FALSE; 2501 //modified_count = FALSE;
@@ -2660,6 +2784,7 @@ static void setops(char *args, int flg_no)
2660 2784
2661 index = 1 << (index >> 1); // convert to VI_bit 2785 index = 1 << (index >> 1); // convert to VI_bit
2662 2786
2787#if !ENABLE_FEATURE_VI_FILE_FORMAT
2663 if (index & VI_TABSTOP) { 2788 if (index & VI_TABSTOP) {
2664 int t; 2789 int t;
2665 if (!eq || flg_no) // no "=NNN" or it is "notabstop"? 2790 if (!eq || flg_no) // no "=NNN" or it is "notabstop"?
@@ -2670,11 +2795,43 @@ static void setops(char *args, int flg_no)
2670 tabstop = t; 2795 tabstop = t;
2671 return; 2796 return;
2672 } 2797 }
2798#else
2799 if (index & (VI_TABSTOP | VI_FILEFORMAT | VI_FILEFORMATS)) {
2800 if (!eq || flg_no) // no "=NNN" or it is "notabstop"?
2801 goto bad;
2802 if (index & VI_TABSTOP) {
2803 int t = bb_strtou(eq + 1, NULL, 10);
2804 if (t <= 0 || t > MAX_TABSTOP)
2805 goto bad;
2806 tabstop = t;
2807 return;
2808 } else if (index & VI_FILEFORMAT) {
2809 int t = index_in_strings(FF_STR, eq + 1);
2810 if (t < 0)
2811 goto bad;
2812 if (fileformat != t)
2813 modified_count++;
2814 fileformat = t;
2815 return;
2816 } else { // VI_FILEFORMATS
2817 int t = index_in_strings(FFS_STR, eq + 1);
2818 if (t < 0)
2819 goto bad;
2820 fileformats = t;
2821 return;
2822 }
2823 }
2824#endif
2673 if (eq) goto bad; // boolean option has "="? 2825 if (eq) goto bad; // boolean option has "="?
2674 if (flg_no) { 2826 if (flg_no) {
2675 vi_setops &= ~index; 2827 vi_setops &= ~index;
2676 } else { 2828 } else {
2677 vi_setops |= index; 2829 vi_setops |= index;
2830#if ENABLE_FEATURE_VI_FILE_FORMAT
2831 if (index == VI_BINARY) {
2832 vi_setops &= ~VI_EXPANDTAB;
2833 }
2834#endif
2678 } 2835 }
2679} 2836}
2680# endif 2837# endif
@@ -3166,6 +3323,7 @@ static void colon(char *buf)
3166 if (!args[0] || strcmp(args, "all") == 0) { 3323 if (!args[0] || strcmp(args, "all") == 0) {
3167 // print out values of all options 3324 // print out values of all options
3168# if ENABLE_FEATURE_VI_SETOPTS 3325# if ENABLE_FEATURE_VI_SETOPTS
3326# if !ENABLE_FEATURE_VI_FILE_FORMAT
3169 status_line_bold( 3327 status_line_bold(
3170 "%sautoindent " 3328 "%sautoindent "
3171 "%sexpandtab " 3329 "%sexpandtab "
@@ -3180,6 +3338,28 @@ static void colon(char *buf)
3180 showmatch ? "" : "no", 3338 showmatch ? "" : "no",
3181 tabstop 3339 tabstop
3182 ); 3340 );
3341# else // ENABLE_FEATURE_VI_FILE_FORMAT
3342 unsigned int mask = 1, j = 0;
3343 go_bottom_and_clear_to_eol();
3344 for (;;) {
3345 const char *name = nth_string(OPTS_STR, 2 * j + 1);
3346 if (!name[0])
3347 break;
3348 if (mask == VI_FILEFORMAT)
3349 printf("%s=%s ", name, nth_string(FF_STR, fileformat));
3350 else if (mask == VI_FILEFORMATS)
3351 printf("%s=%s ", name, nth_string(FFS_STR, fileformats));
3352 else if (mask == VI_TABSTOP)
3353 printf("%s=%u ", name, tabstop);
3354 else
3355 printf("%s%s ", vi_setops & mask ? "" : "no", name);
3356 if (j++ == 4)
3357 bb_putchar('\n');
3358 mask <<= 1;
3359 }
3360 bb_putchar('\n');
3361 Hit_Return();
3362# endif
3183# endif 3363# endif
3184 goto ret; 3364 goto ret;
3185 } 3365 }
@@ -4934,17 +5114,20 @@ static void edit_file(char *fn)
4934} 5114}
4935 5115
4936#define VI_OPTSTR \ 5116#define VI_OPTSTR \
5117 IF_FEATURE_VI_FILE_FORMAT("b") \
4937 IF_FEATURE_VI_CRASHME("C") \ 5118 IF_FEATURE_VI_CRASHME("C") \
4938 IF_FEATURE_VI_COLON("c:*") \ 5119 IF_FEATURE_VI_COLON("c:*") \
4939 "Hh" \ 5120 "Hh" \
4940 IF_FEATURE_VI_READONLY("R") 5121 IF_FEATURE_VI_READONLY("R")
4941 5122
4942enum { 5123enum {
5124 IF_FEATURE_VI_FILE_FORMAT(OPTBIT_b,)
4943 IF_FEATURE_VI_CRASHME(OPTBIT_C,) 5125 IF_FEATURE_VI_CRASHME(OPTBIT_C,)
4944 IF_FEATURE_VI_COLON(OPTBIT_c,) 5126 IF_FEATURE_VI_COLON(OPTBIT_c,)
4945 OPTBIT_H, 5127 OPTBIT_H,
4946 OPTBIT_h, 5128 OPTBIT_h,
4947 IF_FEATURE_VI_READONLY(OPTBIT_R,) 5129 IF_FEATURE_VI_READONLY(OPTBIT_R,)
5130 OPT_b = IF_FEATURE_VI_FILE_FORMAT( (1 << OPTBIT_b)) + 0,
4948 OPT_C = IF_FEATURE_VI_CRASHME( (1 << OPTBIT_C)) + 0, 5131 OPT_C = IF_FEATURE_VI_CRASHME( (1 << OPTBIT_C)) + 0,
4949 OPT_c = IF_FEATURE_VI_COLON( (1 << OPTBIT_c)) + 0, 5132 OPT_c = IF_FEATURE_VI_COLON( (1 << OPTBIT_c)) + 0,
4950 OPT_H = 1 << OPTBIT_H, 5133 OPT_H = 1 << OPTBIT_H,
@@ -4981,6 +5164,10 @@ int vi_main(int argc, char **argv)
4981 //vi_setops = 0; 5164 //vi_setops = 0;
4982 opts = getopt32(argv, VI_OPTSTR IF_FEATURE_VI_COLON(, &initial_cmds)); 5165 opts = getopt32(argv, VI_OPTSTR IF_FEATURE_VI_COLON(, &initial_cmds));
4983 5166
5167#if ENABLE_FEATURE_VI_FILE_FORMAT
5168 if (opts & OPT_b)
5169 vi_setops |= VI_BINARY;
5170#endif
4984#if ENABLE_FEATURE_VI_CRASHME 5171#if ENABLE_FEATURE_VI_CRASHME
4985 if (opts & OPT_C) 5172 if (opts & OPT_C)
4986 crashme = 1; 5173 crashme = 1;
@@ -5016,7 +5203,11 @@ int vi_main(int argc, char **argv)
5016 5203
5017 // .exrc must belong to and only be writable by user 5204 // .exrc must belong to and only be writable by user
5018 if (stat(exrc, &st) == 0) { 5205 if (stat(exrc, &st) == 0) {
5206# if !ENABLE_PLATFORM_MINGW32
5019 if ((st.st_mode & (S_IWGRP|S_IWOTH)) == 0 5207 if ((st.st_mode & (S_IWGRP|S_IWOTH)) == 0
5208# else
5209 if (1
5210# endif
5020 && st.st_uid == getuid() 5211 && st.st_uid == getuid()
5021 ) { 5212 ) {
5022 cmds = xmalloc_open_read_close(exrc, NULL); 5213 cmds = xmalloc_open_read_close(exrc, NULL);