vi: trivial size optimization -65 bytes
[oweals/busybox.git] / editors / vi.c
index d9db943224527e83be04aa50840029f783fc2148..a01fa7c46328b1eb08728edc701445b242fabaea 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "libbb.h"
 
+/* the CRASHME code is unmaintained, and doesn't currently build */
 #define ENABLE_FEATURE_VI_CRASHME 0
 
 
@@ -111,11 +112,19 @@ enum {
        S_END_ALNUM = 5,        // used in skip_thing() for moving "dot"
 };
 
+
 /* vi.c expects chars to be unsigned. */
 /* busybox build system provides that, but it's better */
 /* to audit and fix the source */
 
-static smallint vi_setops;
+struct globals {
+       /* many references - keep near the top of globals */
+       char *text, *end;       // pointers to the user data in memory
+       char *dot;              // where all the action takes place
+       int text_size;          // size of the allocated buffer
+
+       /* the rest */
+       smallint vi_setops;
 #define VI_AUTOINDENT 1
 #define VI_SHOWMATCH  2
 #define VI_IGNORECASE 4
@@ -126,93 +135,92 @@ static smallint vi_setops;
 /* indicate error with beep or flash */
 #define err_method (vi_setops & VI_ERR_METHOD)
 
-
-static smallint editing;        // >0 while we are editing a file
-                                // [code audit says "can be 0 or 1 only"]
-static smallint cmd_mode;       // 0=command  1=insert 2=replace
-static smallint file_modified;  // buffer contents changed
-static smallint last_file_modified = -1;
-static int fn_start;            // index of first cmd line file name
-static int save_argc;           // how many file names on cmd line
-static int cmdcnt;              // repetition count
-static int rows, columns;       // the terminal screen is this size
-static int crow, ccol;          // cursor is on Crow x Ccol
-static int offset;              // chars scrolled off the screen to the left
-static char *status_buffer;     // mesages to the user
-#define STATUS_BUFFER_LEN  200
-static int have_status_msg;     // is default edit status needed?
-                                // [don't make smallint!]
-static int last_status_cksum;   // hash of current status line
-static char *current_filename;               // current file name
-//static char *text, *end;        // pointers to the user data in memory
-static char *screen;            // pointer to the virtual screen buffer
-static int screensize;          //            and its size
-static char *screenbegin;       // index into text[], of top line on the screen
-//static char *dot;               // where all the action takes place
-static int tabstop;
-static char erase_char;         // the users erase character
-static char last_input_char;    // last char read from user
-static char last_forward_char;  // last char searched for with 'f'
-
 #if ENABLE_FEATURE_VI_READONLY
-//static smallint vi_readonly, readonly;
-static smallint readonly_mode = 0;
+       smallint readonly_mode;
 #define SET_READONLY_FILE(flags)        ((flags) |= 0x01)
 #define SET_READONLY_MODE(flags)        ((flags) |= 0x02)
 #define UNSET_READONLY_FILE(flags)      ((flags) &= 0xfe)
 #else
-#define readonly_mode 0
-#define SET_READONLY_FILE(flags)
-#define SET_READONLY_MODE(flags)
-#define UNSET_READONLY_FILE(flags)
-#endif
+#define SET_READONLY_FILE(flags)        ((void)0)
+#define SET_READONLY_MODE(flags)        ((void)0)
+#define UNSET_READONLY_FILE(flags)      ((void)0)
+#endif
+
+       smallint editing;        // >0 while we are editing a file
+                                // [code audit says "can be 0, 1 or 2 only"]
+       smallint cmd_mode;       // 0=command  1=insert 2=replace
+       int file_modified;       // buffer contents changed (counter, not flag!)
+       int last_file_modified;  // = -1;
+       int fn_start;            // index of first cmd line file name
+       int save_argc;           // how many file names on cmd line
+       int cmdcnt;              // repetition count
+       unsigned rows, columns;  // the terminal screen is this size
+       int crow, ccol;          // cursor is on Crow x Ccol
+       int offset;              // chars scrolled off the screen to the left
+       int have_status_msg;     // is default edit status needed?
+                                // [don't make smallint!]
+       int last_status_cksum;   // hash of current status line
+       char *current_filename;
+       char *screenbegin;       // index into text[], of top line on the screen
+       char *screen;            // pointer to the virtual screen buffer
+       int screensize;          //            and its size
+       int tabstop;
+       char erase_char;         // the users erase character
+       char last_input_char;    // last char read from user
+       char last_forward_char;  // last char searched for with 'f'
 
 #if ENABLE_FEATURE_VI_DOT_CMD
-static smallint adding2q;              // are we currently adding user input to q
-static char *last_modifying_cmd;       // [MAX_INPUT_LEN] last modifying cmd for "."
-static smallint lmc_len;               // length of last_modifying_cmd
-static char *ioq, *ioq_start;           // pointer to string for get_one_char to "read"
+       smallint adding2q;       // are we currently adding user input to q
+       int lmc_len;             // length of last_modifying_cmd
+       char *ioq, *ioq_start;   // pointer to string for get_one_char to "read"
 #endif
 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
-static int last_row;           // where the cursor was last moved to
+       int last_row;            // where the cursor was last moved to
 #endif
 #if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME
-static int my_pid;
+       int my_pid;
 #endif
 #if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK
-static char *modifying_cmds;            // cmds that modify text[]
+       char *modifying_cmds;    // cmds that modify text[]
 #endif
 #if ENABLE_FEATURE_VI_SEARCH
-static char *last_search_pattern;      // last pattern from a '/' or '?' search
+       char *last_search_pattern; // last pattern from a '/' or '?' search
 #endif
+       int chars_to_parse;
+       /* former statics */
+#if ENABLE_FEATURE_VI_YANKMARK
+       char *edit_file__cur_line;
+#endif
+       int refresh__old_offset;
+       int format_edit_status__tot;
 
-/* Moving biggest data to malloced space... */
-struct globals {
-       /* many references - keep near the top of globals */
-       char *text, *end;       // pointers to the user data in memory
-       char *dot;              // where all the action takes place
-       int text_size;          // size of the allocated buffer
+       /* a few references only */
 #if ENABLE_FEATURE_VI_YANKMARK
        int YDreg, Ureg;        // default delete register and orig line for "U"
        char *reg[28];          // named register a-z, "D", and "U" 0-25,26,27
        char *mark[28];         // user marks points somewhere in text[]-  a-z and previous context ''
        char *context_start, *context_end;
 #endif
-       /* a few references only */
 #if ENABLE_FEATURE_VI_USE_SIGNALS
-       jmp_buf restart;        // catch_sig()
+       sigjmp_buf restart;     // catch_sig()
 #endif
-       struct termios term_orig, term_vi;      // remember what the cooked mode was
+       struct termios term_orig, term_vi; // remember what the cooked mode was
 #if ENABLE_FEATURE_VI_COLON
        char *initial_cmds[3];  // currently 2 entries, NULL terminated
 #endif
        // Should be just enough to hold a key sequence,
-       // but CRASME mode uses it as generated command buffer too
+       // but CRASHME mode uses it as generated command buffer too
 #if ENABLE_FEATURE_VI_CRASHME
-       char readbuffer[128];
+        char readbuffer[128];
 #else
-       char readbuffer[32];
+        char readbuffer[8];
+#endif
+#define STATUS_BUFFER_LEN  200
+       char status_buffer[STATUS_BUFFER_LEN]; // messages to the user
+#if ENABLE_FEATURE_VI_DOT_CMD
+       char last_modifying_cmd[MAX_INPUT_LEN]; // last modifying cmd for "."
 #endif
+       char get_input_line__buf[MAX_INPUT_LEN]; /* former static */
 
        char scr_out_buf[MAX_SCR_COLS + MAX_TABSTOP * 2];
 };
@@ -222,6 +230,50 @@ struct globals {
 #define end            (G.end           )
 #define dot            (G.dot           )
 #define reg            (G.reg           )
+
+#define vi_setops               (G.vi_setops          )
+#define editing                 (G.editing            )
+#define cmd_mode                (G.cmd_mode           )
+#define file_modified           (G.file_modified      )
+#define last_file_modified      (G.last_file_modified )
+#define fn_start                (G.fn_start           )
+#define save_argc               (G.save_argc          )
+#define cmdcnt                  (G.cmdcnt             )
+#define rows                    (G.rows               )
+#define columns                 (G.columns            )
+#define crow                    (G.crow               )
+#define ccol                    (G.ccol               )
+#define offset                  (G.offset             )
+#define status_buffer           (G.status_buffer      )
+#define have_status_msg         (G.have_status_msg    )
+#define last_status_cksum       (G.last_status_cksum  )
+#define current_filename        (G.current_filename   )
+#define screen                  (G.screen             )
+#define screensize              (G.screensize         )
+#define screenbegin             (G.screenbegin        )
+#define tabstop                 (G.tabstop            )
+#define erase_char              (G.erase_char         )
+#define last_input_char         (G.last_input_char    )
+#define last_forward_char       (G.last_forward_char  )
+#if ENABLE_FEATURE_VI_READONLY
+#define readonly_mode           (G.readonly_mode      )
+#else
+#define readonly_mode           0
+#endif
+#define adding2q                (G.adding2q           )
+#define lmc_len                 (G.lmc_len            )
+#define ioq                     (G.ioq                )
+#define ioq_start               (G.ioq_start          )
+#define last_row                (G.last_row           )
+#define my_pid                  (G.my_pid             )
+#define modifying_cmds          (G.modifying_cmds     )
+#define last_search_pattern     (G.last_search_pattern)
+#define chars_to_parse          (G.chars_to_parse     )
+
+#define edit_file__cur_line     (G.edit_file__cur_line)
+#define refresh__old_offset     (G.refresh__old_offset)
+#define format_edit_status__tot (G.format_edit_status__tot)
+
 #define YDreg          (G.YDreg         )
 #define Ureg           (G.Ureg          )
 #define mark           (G.mark          )
@@ -233,10 +285,15 @@ struct globals {
 #define initial_cmds   (G.initial_cmds  )
 #define readbuffer     (G.readbuffer    )
 #define scr_out_buf    (G.scr_out_buf   )
+#define last_modifying_cmd  (G.last_modifying_cmd )
+#define get_input_line__buf (G.get_input_line__buf)
+
 #define INIT_G() do { \
        SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+       last_file_modified = -1; \
 } while (0)
 
+
 static int init_text_buffer(char *); // init from file or create new
 static void edit_file(char *); // edit one file
 static void do_cmd(char);      // execute a command
@@ -291,6 +348,7 @@ static void place_cursor(int, int, int);
 static void screen_erase(void);
 static void clear_to_eol(void);
 static void clear_to_eos(void);
+static void go_bottom_and_clear_to_eol(void);
 static void standout_start(void);      // send "start reverse video" sequence
 static void standout_end(void);        // send "end reverse video" sequence
 static void flash(int);                // flash the terminal screen
@@ -300,7 +358,7 @@ static void status_line_bold(const char *, ...);
 static void not_implemented(const char *); // display "Not implemented" message
 static int format_edit_status(void);   // format file status on status line
 static void redraw(int);       // force a full screen refresh
-static char* format_line(char*, int);
+static char* format_line(char* /*, int*/);
 static void refresh(int);      // update the terminal from screen[]
 
 static void Indicate_Error(void);       // use flash or beep to indicate error
@@ -354,22 +412,15 @@ int vi_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int vi_main(int argc, char **argv)
 {
        int c;
-       RESERVE_CONFIG_BUFFER(STATUS_BUFFER, STATUS_BUFFER_LEN);
+
+       INIT_G();
 
 #if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME
        my_pid = getpid();
 #endif
-
-       INIT_G();
-
 #if ENABLE_FEATURE_VI_CRASHME
        srand((long) my_pid);
 #endif
-
-       status_buffer = STATUS_BUFFER;
-       last_status_cksum = 0;
-       text = NULL;
-
 #ifdef NO_SUCH_APPLET_YET
        /* If we aren't "vi", we are "view" */
        if (ENABLE_FEATURE_VI_READONLY && applet_name[2]) {
@@ -378,9 +429,6 @@ int vi_main(int argc, char **argv)
 #endif
 
        vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE;
-#if ENABLE_FEATURE_VI_YANKMARK
-       memset(reg, 0, sizeof(reg)); // init the yank regs
-#endif
 #if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK
        modifying_cmds = (char *) "aAcCdDiIJoOpPrRsxX<>~";      // cmds modifying text[]
 #endif
@@ -395,7 +443,7 @@ int vi_main(int argc, char **argv)
                        initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN);
        }
 #endif
-       while ((c = getopt(argc, argv, "hCR" USE_FEATURE_VI_COLON("c:"))) != -1) {
+       while ((c = getopt(argc, argv, "hCRH" USE_FEATURE_VI_COLON("c:"))) != -1) {
                switch (c) {
 #if ENABLE_FEATURE_VI_CRASHME
                case 'C':
@@ -407,18 +455,17 @@ int vi_main(int argc, char **argv)
                        SET_READONLY_MODE(readonly_mode);
                        break;
 #endif
-                       //case 'r':     // recover flag-  ignore- we don't use tmp file
-                       //case 'x':     // encryption flag- ignore
-                       //case 'c':     // execute command first
 #if ENABLE_FEATURE_VI_COLON
                case 'c':               // cmd line vi command
                        if (*optarg)
                                initial_cmds[initial_cmds[0] != 0] = xstrndup(optarg, MAX_INPUT_LEN);
                        break;
-                       //case 'h':     // help -- just use default
 #endif
-               default:
+               case 'H':
                        show_help();
+                       /* fall through */
+               default:
+                       bb_show_usage();
                        return 1;
                }
        }
@@ -450,9 +497,7 @@ static int init_text_buffer(char *fn)
 
        /* allocate/reallocate text buffer */
        free(text);
-       text_size = size * 2;
-       if (text_size < 10240)
-               text_size = 10240;      // have a minimum size for new files
+       text_size = size + 10240;
        screenbegin = dot = end = text = xzalloc(text_size);
 
        if (fn != current_filename) {
@@ -478,15 +523,14 @@ static int init_text_buffer(char *fn)
 
 static void edit_file(char *fn)
 {
+#if ENABLE_FEATURE_VI_YANKMARK
+#define cur_line edit_file__cur_line
+#endif
        char c;
        int size;
-
 #if ENABLE_FEATURE_VI_USE_SIGNALS
        int sig;
 #endif
-#if ENABLE_FEATURE_VI_YANKMARK
-       static char *cur_line;
-#endif
 
        editing = 1;    // 0 = exit, 1 = one file, 2 = multiple files
        rawmode();
@@ -515,7 +559,7 @@ static void edit_file(char *fn)
        catch_sig(0);
        signal(SIGWINCH, winch_sig);
        signal(SIGTSTP, suspend_sig);
-       sig = setjmp(restart);
+       sig = sigsetjmp(restart, 1);
        if (sig != 0) {
                screenbegin = dot = text;
        }
@@ -532,7 +576,6 @@ static void edit_file(char *fn)
        lmc_len = 0;
        adding2q = 0;
 #endif
-       redraw(FALSE);                  // dont force every col re-draw
 
 #if ENABLE_FEATURE_VI_COLON
        {
@@ -555,6 +598,7 @@ static void edit_file(char *fn)
                }
        }
 #endif
+       redraw(FALSE);                  // dont force every col re-draw
        //------This is the main Vi cmd handling loop -----------------------
        while (editing > 0) {
 #if ENABLE_FEATURE_VI_CRASHME
@@ -580,7 +624,7 @@ static void edit_file(char *fn)
                // These are commands that change text[].
                // Remember the input for the "." command
                if (!adding2q && ioq_start == NULL
-                && strchr(modifying_cmds, c)
+                && c != '\0' && strchr(modifying_cmds, c)
                ) {
                        start_new_cmd_q(c);
                }
@@ -602,9 +646,9 @@ static void edit_file(char *fn)
        }
        //-------------------------------------------------------------------
 
-       place_cursor(rows, 0, FALSE);   // go to bottom of screen
-       clear_to_eol();         // Erase to end of line
+       go_bottom_and_clear_to_eol();
        cookmode();
+#undef cur_line
 }
 
 //----- The Colon commands -------------------------------------
@@ -798,16 +842,13 @@ static void colon(char *buf)
        else if (strncmp(cmd, "!", 1) == 0) {   // run a cmd
                int retcode;
                // :!ls   run the <cmd>
-               alarm(0);               // wait for input- no alarms
-               place_cursor(rows - 1, 0, FALSE);       // go to Status line
-               clear_to_eol();                 // clear the line
+               go_bottom_and_clear_to_eol();
                cookmode();
                retcode = system(orig_buf + 1); // run the cmd
                if (retcode)
                        printf("\nshell returned %i\n\n", retcode);
                rawmode();
                Hit_Return();                   // let user see results
-               alarm(3);               // done waiting for input
        }
 #endif
        else if (strncmp(cmd, "=", i) == 0) {   // where is the address
@@ -878,8 +919,7 @@ static void colon(char *buf)
                }
        } else if (strncasecmp(cmd, "features", i) == 0) {      // what features are available
                // print out values of all features
-               place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
-               clear_to_eol(); // clear the line
+               go_bottom_and_clear_to_eol();
                cookmode();
                show_help();
                rawmode();
@@ -889,8 +929,7 @@ static void colon(char *buf)
                        q = begin_line(dot);    // assume .,. for the range
                        r = end_line(dot);
                }
-               place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
-               clear_to_eol(); // clear the line
+               go_bottom_and_clear_to_eol();
                puts("\r");
                for (; q <= r; q++) {
                        int c_is_no_print;
@@ -990,8 +1029,7 @@ static void colon(char *buf)
                // only blank is regarded as args delmiter. What about tab '\t' ?
                if (!args[0] || strcasecmp(args, "all") == 0) {
                        // print out values of all options
-                       place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
-                       clear_to_eol(); // clear the line
+                       go_bottom_and_clear_to_eol();
                        printf("----------------------------------------\r\n");
 #if ENABLE_FEATURE_VI_SETOPTS
                        if (!autoindent)
@@ -1082,7 +1120,7 @@ static void colon(char *buf)
                }
 #endif /* FEATURE_VI_SEARCH */
        } else if (strncasecmp(cmd, "version", i) == 0) {  // show software version
-               status_line("%s", BB_VER " " BB_BT);
+               status_line(BB_VER " " BB_BT);
        } else if (strncasecmp(cmd, "write", i) == 0  // write text to file
                || strncasecmp(cmd, "wq", i) == 0
                || strncasecmp(cmd, "wn", i) == 0
@@ -1232,9 +1270,8 @@ static void sync_cursor(char *d, int *row, int *col)
                        // handle tabs like real vi
                        if (d == tp && cmd_mode) {
                                break;
-                       } else {
-                               co = next_tabstop(co);
                        }
+                       co = next_tabstop(co);
                } else if ((unsigned char)*tp < ' ' || *tp == 0x7f) {
                        co++; // display as ^X, use 2 columns
                }
@@ -1284,7 +1321,7 @@ static char *begin_line(char *p) // return pointer to first char cur line
        return p;
 }
 
-static char *end_line(char *p) // return pointer to NL of cur line line
+static char *end_line(char *p) // return pointer to NL of cur line
 {
        if (p < end - 1) {
                p = memchr(p, '\n', end - p - 1);
@@ -1306,7 +1343,7 @@ static char *dollar_line(char *p) // return pointer to just before NL line
 static char *prev_line(char *p) // return pointer first char prev line
 {
        p = begin_line(p);      // goto begining of cur line
-       if (p[-1] == '\n' && p > text)
+       if (p > text && p[-1] == '\n')
                p--;                    // step to prev line
        p = begin_line(p);      // goto begining of prev line
        return p;
@@ -1315,7 +1352,7 @@ static char *prev_line(char *p) // return pointer first char prev line
 static char *next_line(char *p) // return pointer first char next line
 {
        p = end_line(p);
-       if (*p == '\n' && p < end - 1)
+       if (p < end - 1 && *p == '\n')
                p++;                    // step to next line
        return p;
 }
@@ -1498,7 +1535,7 @@ static char *new_screen(int ro, int co)
 }
 
 #if ENABLE_FEATURE_VI_SEARCH
-static int mycmp(const char * s1, const char * s2, int len)
+static int mycmp(const char *s1, const char *s2, int len)
 {
        int i;
 
@@ -1510,7 +1547,7 @@ static int mycmp(const char * s1, const char * s2, int len)
 }
 
 // search for pattern starting at p
-static char *char_search(char * p, const char * pat, int dir, int range)
+static char *char_search(char *p, const char *pat, int dir, int range)
 {
 #ifndef REGEX_SEARCH
        char *start, *stop;
@@ -1603,7 +1640,7 @@ static char *char_search(char * p, const char * pat, int dir, int range)
 }
 #endif /* FEATURE_VI_SEARCH */
 
-static char *char_insert(char * p, char c) // insert the char c at 'p'
+static char *char_insert(char *p, char c) // insert the char c at 'p'
 {
        if (c == 22) {          // Is this an ctrl-V?
                p = stupid_insert(p, '^');      // use ^ to indicate literal next
@@ -1612,7 +1649,7 @@ static char *char_insert(char * p, char c) // insert the char c at 'p'
                c = get_one_char();
                *p = c;
                p++;
-               file_modified++;        // has the file been modified
+               file_modified++;
        } else if (c == 27) {   // Is this an ESC?
                cmd_mode = 0;
                cmdcnt = 0;
@@ -1652,18 +1689,15 @@ static char *char_insert(char * p, char c) // insert the char c at 'p'
        return p;
 }
 
-static char *stupid_insert(char * p, char c) // stupidly insert the char c at 'p'
+static char *stupid_insert(char *p, char c) // stupidly insert the char c at 'p'
 {
        p = text_hole_make(p, 1);
-       if (p != 0) {
-               *p = c;
-               file_modified++;        // has the file been modified
-               p++;
-       }
-       return p;
+       *p = c;
+       //file_modified++; - done by text_hole_make()
+       return p + 1;
 }
 
-static int find_range(char ** start, char ** stop, char c)
+static int find_range(char **start, char **stop, char c)
 {
        char *save_dot, *p, *q, *t;
        int cnt, multiline = 0;
@@ -1719,7 +1753,7 @@ static int find_range(char ** start, char ** stop, char c)
                p = t;
        }
 
-       // backward char movements don't include start position 
+       // backward char movements don't include start position
        if (q > p && strchr("^0bBh\b\177", c)) q--;
 
        multiline = 0;
@@ -1736,7 +1770,7 @@ static int find_range(char ** start, char ** stop, char c)
        return multiline;
 }
 
-static int st_test(char * p, int type, int dir, char * tested)
+static int st_test(char *p, int type, int dir, char *tested)
 {
        char c, c0, ci;
        int test, inc;
@@ -1770,7 +1804,7 @@ static int st_test(char * p, int type, int dir, char * tested)
        return test;
 }
 
-static char *skip_thing(char * p, int linecnt, int dir, int type)
+static char *skip_thing(char *p, int linecnt, int dir, int type)
 {
        char c;
 
@@ -1788,7 +1822,7 @@ static char *skip_thing(char * p, int linecnt, int dir, int type)
 }
 
 // find matching char of pair  ()  []  {}
-static char *find_pair(char * p, const char c)
+static char *find_pair(char *p, const char c)
 {
        char match, *q;
        int dir, level;
@@ -1841,31 +1875,29 @@ static void showmatching(char *p)
 #endif /* FEATURE_VI_SETOPTS */
 
 //  open a hole in text[]
-static char *text_hole_make(char * p, int size)        // at "p", make a 'size' byte hole
+static char *text_hole_make(char *p, int size) // at "p", make a 'size' byte hole
 {
-       char *src, *dest;
-       int cnt;
-
        if (size <= 0)
-               goto thm0;
-       src = p;
-       dest = p + size;
-       cnt = end - src;        // the rest of buffer
-       if ( ((end + size) >= (text + text_size)) // TODO: realloc here
-                       || memmove(dest, src, cnt) != dest) {
-               status_line_bold("can't create room for new characters");
-               p = NULL;
-               goto thm0;
-       }
-       memset(p, ' ', size);   // clear new hole
+               return p;
        end += size;            // adjust the new END
-       file_modified++;        // has the file been modified
- thm0:
+       if (end >= (text + text_size)) {
+               char *new_text;
+               text_size += end - (text + text_size) + 10240;
+               new_text = xrealloc(text, text_size);
+               screenbegin = new_text + (screenbegin - text);
+               dot         = new_text + (dot         - text);
+               end         = new_text + (end         - text);
+               p           = new_text + (p           - text);
+               text = new_text;
+       }
+       memmove(p + size, p, end - size - p);
+       memset(p, ' ', size);   // clear new hole
+       file_modified++;
        return p;
 }
 
 //  close a hole in text[]
-static char *text_hole_delete(char * p, char * q) // delete "p" through "q", inclusive
+static char *text_hole_delete(char *p, char *q) // delete "p" through "q", inclusive
 {
        char *src, *dest;
        int cnt, hole_size;
@@ -1886,16 +1918,14 @@ static char *text_hole_delete(char * p, char * q) // delete "p" through "q", inc
                goto thd0;
        if (src >= end)
                goto thd_atend; // just delete the end of the buffer
-       if (memmove(dest, src, cnt) != dest) {
-               status_line_bold("can't delete the character");
-       }
+       memmove(dest, src, cnt);
  thd_atend:
        end = end - hole_size;  // adjust the new END
        if (dest >= end)
                dest = end - 1; // make sure dest in below end-1
        if (end <= text)
                dest = end = text;      // keep pointers valid
-       file_modified++;        // has the file been modified
+       file_modified++;
  thd0:
        return dest;
 }
@@ -1903,7 +1933,7 @@ static char *text_hole_delete(char * p, char * q) // delete "p" through "q", inc
 // copy text into register, then delete text.
 // if dist <= 0, do not include, or go past, a NewLine
 //
-static char *yank_delete(char * start, char * stop, int dist, int yf)
+static char *yank_delete(char *start, char *stop, int dist, int yf)
 {
        char *p;
 
@@ -1974,12 +2004,10 @@ static void show_help(void)
 static void start_new_cmd_q(char c)
 {
        // get buffer for new cmd
-       if (!last_modifying_cmd)
-               last_modifying_cmd = xzalloc(MAX_INPUT_LEN);
        // if there is a current cmd count put it in the buffer first
-       if (cmdcnt > 0)
+       if (cmdcnt > 0) {
                lmc_len = sprintf(last_modifying_cmd, "%d%c", cmdcnt, c);
-       else { // just save char c onto queue
+       else { // just save char c onto queue
                last_modifying_cmd[0] = c;
                lmc_len = 1;
        }
@@ -1998,27 +2026,26 @@ static void end_cmd_q(void)
 #if ENABLE_FEATURE_VI_YANKMARK \
  || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) \
  || ENABLE_FEATURE_VI_CRASHME
-static char *string_insert(char * p, char * s) // insert the string at 'p'
+static char *string_insert(char *p, char *s) // insert the string at 'p'
 {
        int cnt, i;
 
        i = strlen(s);
-       if (text_hole_make(p, i)) {
-               strncpy(p, s, i);
-               for (cnt = 0; *s != '\0'; s++) {
-                       if (*s == '\n')
-                               cnt++;
-               }
+       text_hole_make(p, i);
+       strncpy(p, s, i);
+       for (cnt = 0; *s != '\0'; s++) {
+               if (*s == '\n')
+                       cnt++;
+       }
 #if ENABLE_FEATURE_VI_YANKMARK
-               status_line("Put %d lines (%d chars) from [%c]", cnt, i, what_reg());
+       status_line("Put %d lines (%d chars) from [%c]", cnt, i, what_reg());
 #endif
-       }
        return p;
 }
 #endif
 
 #if ENABLE_FEATURE_VI_YANKMARK
-static char *text_yank(char * p, char * q, int dest)   // copy text into a register
+static char *text_yank(char *p, char *q, int dest)     // copy text into a register
 {
        char *t;
        int cnt;
@@ -2110,7 +2137,7 @@ static void cookmode(void)
 
 //----- Come here when we get a window resize signal ---------
 #if ENABLE_FEATURE_VI_USE_SIGNALS
-static void winch_sig(int sig ATTRIBUTE_UNUSED)
+static void winch_sig(int sig UNUSED_PARAM)
 {
        // FIXME: do it in main loop!!!
        signal(SIGWINCH, winch_sig);
@@ -2124,23 +2151,22 @@ static void winch_sig(int sig ATTRIBUTE_UNUSED)
 }
 
 //----- Come here when we get a continue signal -------------------
-static void cont_sig(int sig ATTRIBUTE_UNUSED)
+static void cont_sig(int sig UNUSED_PARAM)
 {
-       rawmode();                      // terminal to "raw"
-       last_status_cksum = 0;  // force status update
-       redraw(TRUE);           // re-draw the screen
+       rawmode(); // terminal to "raw"
+       last_status_cksum = 0; // force status update
+       redraw(TRUE); // re-draw the screen
 
        signal(SIGTSTP, suspend_sig);
        signal(SIGCONT, SIG_DFL);
-       kill(my_pid, SIGCONT);
+       kill(my_pid, SIGCONT); // huh? why? we are already "continued"...
 }
 
 //----- Come here when we get a Suspend signal -------------------
-static void suspend_sig(int sig ATTRIBUTE_UNUSED)
+static void suspend_sig(int sig UNUSED_PARAM)
 {
-       place_cursor(rows - 1, 0, FALSE);       // go to bottom of screen
-       clear_to_eol();         // Erase to end of line
-       cookmode();                     // terminal to "cooked"
+       go_bottom_and_clear_to_eol();
+       cookmode(); // terminal to "cooked"
 
        signal(SIGCONT, cont_sig);
        signal(SIGTSTP, SIG_DFL);
@@ -2152,7 +2178,7 @@ static void catch_sig(int sig)
 {
        signal(SIGINT, catch_sig);
        if (sig)
-               longjmp(restart, sig);
+               siglongjmp(restart, sig);
 }
 #endif /* FEATURE_VI_USE_SIGNALS */
 
@@ -2165,25 +2191,28 @@ static int mysleep(int hund)    // sleep for 'h' 1/100 seconds
        return safe_poll(pfd, 1, hund*10) > 0;
 }
 
-static int chars_to_parse;
-
 //----- IO Routines --------------------------------------------
 static char readit(void)       // read (maybe cursor) key from stdin
 {
        char c;
        int n;
-       struct esc_cmds {
+
+       // Known escape sequences for cursor and function keys.
+       static const struct esc_cmds {
                const char seq[4];
                char val;
-       };
-
-       static const struct esc_cmds esccmds[] = {
+       } esccmds[] = {
                {"OA"  , VI_K_UP      },   // cursor key Up
                {"OB"  , VI_K_DOWN    },   // cursor key Down
                {"OC"  , VI_K_RIGHT   },   // Cursor Key Right
                {"OD"  , VI_K_LEFT    },   // cursor key Left
                {"OH"  , VI_K_HOME    },   // Cursor Key Home
                {"OF"  , VI_K_END     },   // Cursor Key End
+               {"OP"  , VI_K_FUN1    },   // Function Key F1
+               {"OQ"  , VI_K_FUN2    },   // Function Key F2
+               {"OR"  , VI_K_FUN3    },   // Function Key F3
+               {"OS"  , VI_K_FUN4    },   // Function Key F4
+
                {"[A"  , VI_K_UP      },   // cursor key Up
                {"[B"  , VI_K_DOWN    },   // cursor key Down
                {"[C"  , VI_K_RIGHT   },   // Cursor Key Right
@@ -2196,10 +2225,6 @@ static char readit(void) // read (maybe cursor) key from stdin
                {"[4~" , VI_K_END     },   // Cursor Key End
                {"[5~" , VI_K_PAGEUP  },   // Cursor Key Page Up
                {"[6~" , VI_K_PAGEDOWN},   // Cursor Key Page Down
-               {"OP"  , VI_K_FUN1    },   // Function Key F1
-               {"OQ"  , VI_K_FUN2    },   // Function Key F2
-               {"OR"  , VI_K_FUN3    },   // Function Key F3
-               {"OS"  , VI_K_FUN4    },   // Function Key F4
                // careful: these have no terminating NUL!
                {"[11~", VI_K_FUN1    },   // Function Key F1
                {"[12~", VI_K_FUN2    },   // Function Key F2
@@ -2214,65 +2239,76 @@ static char readit(void)        // read (maybe cursor) key from stdin
                {"[23~", VI_K_FUN11   },   // Function Key F11
                {"[24~", VI_K_FUN12   },   // Function Key F12
        };
-       enum { ESCCMDS_COUNT = ARRAY_SIZE(esccmds) };
 
-       alarm(0);       // turn alarm OFF while we wait for input
        fflush(stdout);
+
        n = chars_to_parse;
-       // get input from User- are there already input chars in Q?
-       if (n <= 0) {
-               // the Q is empty, wait for a typed char
-               n = safe_read(0, readbuffer, sizeof(readbuffer));
-               if (n < 0) {
-                       if (errno == EBADF || errno == EFAULT || errno == EINVAL
-                        || errno == EIO)
-                               editing = 0; // want to exit
-                       errno = 0;
-               }
-               if (n <= 0)
-                       return 0;       // error
-               if (readbuffer[0] == 27) {
-                       // This is an ESC char. Is this Esc sequence?
-                       // Could be bare Esc key. See if there are any
-                       // more chars to read after the ESC. This would
-                       // be a Function or Cursor Key sequence.
-                       struct pollfd pfd[1];
-                       pfd[0].fd = 0;
-                       pfd[0].events = POLLIN;
-                       // keep reading while there are input chars, and room in buffer
-                       // for a complete ESC sequence (assuming 8 chars is enough)
-                       while (safe_poll(pfd, 1, 0) > 0 && n <= (sizeof(readbuffer) - 8)) {
-                               // read the rest of the ESC string
-                               int r = safe_read(0, readbuffer + n, sizeof(readbuffer) - n);
-                               if (r > 0)
-                                       n += r;
-                       }
+       if (n == 0) {
+               // If no data, block waiting for input.
+               n = safe_read(0, readbuffer, 1);
+               if (n <= 0) {
+ error:
+                       go_bottom_and_clear_to_eol();
+                       cookmode(); // terminal to "cooked"
+                       bb_error_msg_and_die("can't read user input");
                }
-               chars_to_parse = n;
        }
+
+       // Grab character to return from buffer
        c = readbuffer[0];
-       if (c == 27 && n > 1) {
-               // Maybe cursor or function key?
+       // Returning NUL from this routine would be bad.
+       if (c == '\0')
+               c = ' ';
+       n--;
+       if (n) memmove(readbuffer, readbuffer + 1, n);
+
+       // If it's an escape sequence, loop through known matches.
+       if (c == 27) {
                const struct esc_cmds *eindex;
 
-               for (eindex = esccmds; eindex < &esccmds[ESCCMDS_COUNT]; eindex++) {
+               for (eindex = esccmds; eindex < esccmds + ARRAY_SIZE(esccmds); eindex++) {
+                       // n - position in seq to read
+                       int i = 0; // position in seq to compare
                        int cnt = strnlen(eindex->seq, 4);
-                       if (n <= cnt)
-                               continue;
-                       if (strncmp(eindex->seq, readbuffer + 1, cnt) != 0)
-                               continue;
-                       c = eindex->val; // magic char value
-                       n = cnt + 1; // squeeze out the ESC sequence
-                       goto found;
-               }
-               // defined ESC sequence not found
-       }
-       n = 1;
- found:
-       // remove key sequence from Q
-       chars_to_parse -= n;
-       memmove(readbuffer, readbuffer + n, sizeof(readbuffer) - n);
-       alarm(3);       // we are done waiting for input, turn alarm ON
+
+                       // Loop through chars in this sequence.
+                       for (;;) {
+                               // We've matched this escape sequence up to [i-1]
+                               if (n <= i) {
+                                       // Need more chars, read another one if it wouldn't block.
+                                       // (Note that escape sequences come in as a unit,
+                                       // so if we would block it's not really an escape sequence.)
+                                       struct pollfd pfd;
+                                       pfd.fd = 0;
+                                       pfd.events = POLLIN;
+                                       // Rob needed 300ms timeout on qemu
+                                       if (safe_poll(&pfd, 1, /*timeout:*/ 300)) {
+                                               if (safe_read(0, readbuffer + n, 1) <= 0)
+                                                       goto error;
+                                               n++;
+                                       } else {
+                                               // No more data!
+                                               // Array is sorted from shortest to longest,
+                                               // we can't match anything later in array,
+                                               // break out of both loops.
+                                               goto loop_out;
+                                       }
+                               }
+                               if (readbuffer[i] != eindex->seq[i])
+                                       break; // try next seq
+                               if (++i == cnt) { // entire seq matched
+                                       c = eindex->val;
+                                       n = 0;
+                                       goto loop_out;
+                               }
+                       }
+               }
+               // We did not find matching sequence, it was a bare ESC.
+               // We possibly read and stored more input in readbuffer by now.
+       }
+loop_out:
+
+       chars_to_parse = n;
        return c;
 }
 
@@ -2301,13 +2337,11 @@ static char get_one_char(void)
        } else {
                // adding STDIN chars to q
                c = readit();   // get the users input
-               if (last_modifying_cmd != NULL) {
-                       if (lmc_len >= MAX_INPUT_LEN - 1) {
-                               status_line_bold("last_modifying_cmd overrun");
-                       } else {
-                               // add new char to q
-                               last_modifying_cmd[lmc_len++] = c;
-                       }
+               if (lmc_len >= MAX_INPUT_LEN - 1) {
+                       status_line_bold("last_modifying_cmd overrun");
+               } else {
+                       // add new char to q
+                       last_modifying_cmd[lmc_len++] = c;
                }
        }
 #else
@@ -2319,17 +2353,15 @@ static char get_one_char(void)
 // Get input line (uses "status line" area)
 static char *get_input_line(const char *prompt)
 {
-       static char *buf; // [MAX_INPUT_LEN]
+       // char [MAX_INPUT_LEN]
+#define buf get_input_line__buf
 
        char c;
        int i;
 
-       if (!buf) buf = xmalloc(MAX_INPUT_LEN);
-
        strcpy(buf, prompt);
        last_status_cksum = 0;  // force status update
-       place_cursor(rows - 1, 0, FALSE);       // go to Status line, bottom of screen
-       clear_to_eol();         // clear the line
+       go_bottom_and_clear_to_eol();
        write1(prompt);      // write out the :, /, or ? prompt
 
        i = strlen(buf);
@@ -2351,6 +2383,7 @@ static char *get_input_line(const char *prompt)
        }
        refresh(FALSE);
        return buf;
+#undef buf
 }
 
 static int file_size(const char *fn) // what is the byte size of "fn"
@@ -2364,7 +2397,7 @@ static int file_size(const char *fn) // what is the byte size of "fn"
        return cnt;
 }
 
-static int file_insert(const char * fn, char *p
+static int file_insert(const char *fn, char *p
                USE_FEATURE_VI_READONLY(, int update_ro_status))
 {
        int cnt = -1;
@@ -2376,18 +2409,11 @@ static int file_insert(const char * fn, char *p
                status_line_bold("\"%s\" %s", fn, strerror(errno));
                goto fi0;
        }
-       if ((statbuf.st_mode & S_IFREG) == 0) {
+       if (!S_ISREG(statbuf.st_mode)) {
                // This is not a regular file
                status_line_bold("\"%s\" Not a regular file", fn);
                goto fi0;
        }
-       /* // this check is done by open()
-       if ((statbuf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) {
-               // dont have any read permissions
-               status_line_bold("\"%s\" Not readable", fn);
-               goto fi0;
-       }
-       */
        if (p < text || p > end) {
                status_line_bold("Trying to insert file outside of memory");
                goto fi0;
@@ -2401,8 +2427,6 @@ static int file_insert(const char * fn, char *p
        }
        size = statbuf.st_size;
        p = text_hole_make(p, size);
-       if (p == NULL)
-               goto fi0;
        cnt = safe_read(fd, p, size);
        if (cnt < 0) {
                status_line_bold("\"%s\" %s", fn, strerror(errno));
@@ -2430,8 +2454,7 @@ static int file_insert(const char * fn, char *p
        return cnt;
 }
 
-
-static int file_write(char * fn, char * first, char * last)
+static int file_write(char *fn, char *first, char *last)
 {
        int fd, cnt, charcnt;
 
@@ -2440,14 +2463,19 @@ static int file_write(char * fn, char * first, char * last)
                return -2;
        }
        charcnt = 0;
-       fd = open(fn, (O_WRONLY | O_CREAT | O_TRUNC), 0666);
+       /* By popular request we do not open file with O_TRUNC,
+        * but instead ftruncate() it _after_ successful write.
+        * Might reduce amount of data lost on power fail etc.
+        */
+       fd = open(fn, (O_WRONLY | O_CREAT), 0666);
        if (fd < 0)
                return -1;
        cnt = last - first + 1;
        charcnt = full_write(fd, first, cnt);
+       ftruncate(fd, charcnt);
        if (charcnt == cnt) {
                // good write
-               //file_modified = FALSE; // the file has not been modified
+               //file_modified = FALSE;
        } else {
                charcnt = 0;
        }
@@ -2470,6 +2498,14 @@ static int file_write(char * fn, char * first, char * last)
 static void place_cursor(int row, int col, int optimize)
 {
        char cm1[sizeof(CMrc) + sizeof(int)*3 * 2];
+#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
+       enum {
+               SZ_UP = sizeof(CMup),
+               SZ_DN = sizeof(CMdown),
+               SEQ_SIZE = SZ_UP > SZ_DN ? SZ_UP : SZ_DN,
+       };
+       char cm2[SEQ_SIZE * 5 + 32]; // bigger than worst case size
+#endif
        char *cm;
 
        if (row < 0) row = 0;
@@ -2483,12 +2519,6 @@ static void place_cursor(int row, int col, int optimize)
 
 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
        if (optimize && col < 16) {
-               enum {
-                       SZ_UP = sizeof(CMup),
-                       SZ_DN = sizeof(CMdown),
-                       SEQ_SIZE = SZ_UP > SZ_DN ? SZ_UP : SZ_DN,
-               };
-               char cm2[SEQ_SIZE * 5 + 32]; // bigger than worst case size
                char *screenp;
                int Rrow = last_row;
                int diff = Rrow - row;
@@ -2535,6 +2565,12 @@ static void clear_to_eol(void)
        write1(Ceol);   // Erase from cursor to end of line
 }
 
+static void go_bottom_and_clear_to_eol(void)
+{
+       place_cursor(rows - 1, 0, FALSE); // go to bottom of screen
+       clear_to_eol(); // erase to end of line
+}
+
 //----- Erase from cursor to end of screen -----------------------
 static void clear_to_eos(void)
 {
@@ -2606,9 +2642,8 @@ static void show_status_line(void)
        }
        if (have_status_msg || ((cnt > 0 && last_status_cksum != cksum))) {
                last_status_cksum = cksum;              // remember if we have seen this line
-               place_cursor(rows - 1, 0, FALSE);       // put cursor on status line
+               go_bottom_and_clear_to_eol();
                write1(status_buffer);
-               clear_to_eol();
                if (have_status_msg) {
                        if (((int)strlen(status_buffer) - (have_status_msg - 1)) >
                                        (columns - 1) ) {
@@ -2697,8 +2732,10 @@ static void not_implemented(const char *s)
 // show file status on status line
 static int format_edit_status(void)
 {
-       static int tot;
        static const char cmd_mode_indicator[] ALIGN1 = "-IR-";
+
+#define tot format_edit_status__tot
+
        int cur, percent, ret, trunc_at;
 
        // file_modified is now a counter rather than a flag.  this
@@ -2749,13 +2786,14 @@ static int format_edit_status(void)
                return ret;  /* it all fit */
 
        return trunc_at;  /* had to truncate */
+#undef tot
 }
 
 //----- Force refresh of all Lines -----------------------------
 static void redraw(int full_screen)
 {
        place_cursor(0, 0, FALSE);      // put cursor in correct place
-       clear_to_eos();         // tel terminal to erase display
+       clear_to_eos();         // tell terminal to erase display
        screen_erase();         // erase the internal screen buffer
        last_status_cksum = 0;  // force status update
        refresh(full_screen);   // this will redraw the entire display
@@ -2763,7 +2801,7 @@ static void redraw(int full_screen)
 }
 
 //----- Format a text[] line into a buffer ---------------------
-static char* format_line(char *src, int li)
+static char* format_line(char *src /*, int li*/)
 {
        unsigned char c;
        int co;
@@ -2827,13 +2865,13 @@ static char* format_line(char *src, int li)
 //
 static void refresh(int full_screen)
 {
-       static int old_offset;
+#define old_offset refresh__old_offset
 
        int li, changed;
        char *tp, *sp;          // pointer into text[] and screen[]
 
        if (ENABLE_FEATURE_VI_WIN_RESIZE) {
-               int c = columns, r = rows;
+               unsigned c = columns, r = rows;
                get_terminal_width_height(0, &columns, &rows);
                if (rows > MAX_SCR_ROWS) rows = MAX_SCR_ROWS;
                if (columns > MAX_SCR_COLS) columns = MAX_SCR_COLS;
@@ -2847,7 +2885,7 @@ static void refresh(int full_screen)
                int cs, ce;                             // column start & end
                char *out_buf;
                // format current text line
-               out_buf = format_line(tp, li);
+               out_buf = format_line(tp /*, li*/);
 
                // skip to the end of the current text[] line
                if (tp < end) {
@@ -2915,6 +2953,7 @@ static void refresh(int full_screen)
        place_cursor(crow, ccol, TRUE);
 
        old_offset = offset;
+#undef old_offset
 }
 
 //---------------------------------------------------------------------
@@ -3053,14 +3092,6 @@ static void do_cmd(char c)
        case VI_K_PAGEUP:       // Cursor Key Page Up
                dot_scroll(rows - 2, -1);
                break;
-#if ENABLE_FEATURE_VI_USE_SIGNALS
-       case 0x03:                      // ctrl-C   interrupt
-               longjmp(restart, 1);
-               break;
-       case 26:                        // ctrl-Z suspend
-               suspend_sig(SIGTSTP);
-               break;
-#endif
        case 4:                 // ctrl-D  scroll down half screen
                dot_scroll((rows - 2) / 2, 1);
                break;
@@ -3280,7 +3311,7 @@ static void do_cmd(char c)
        case '.':                       // .- repeat the last modifying command
                // Stuff the last_modifying_cmd back into stdin
                // and let it be re-executed.
-               if (last_modifying_cmd != NULL && lmc_len > 0) {
+               if (lmc_len > 0) {
                        last_modifying_cmd[lmc_len] = 0;
                        ioq = ioq_start = xstrdup(last_modifying_cmd);
                }
@@ -3754,7 +3785,7 @@ static void do_cmd(char c)
                c1 = get_one_char();    // get the replacement char
                if (*dot != '\n') {
                        *dot = c1;
-                       file_modified++;        // has the file been modified
+                       file_modified++;
                }
                end_cmd_q();    // stop adding to q
                break;
@@ -3799,10 +3830,10 @@ static void do_cmd(char c)
                }                               // repeat cnt
                if (islower(*dot)) {
                        *dot = toupper(*dot);
-                       file_modified++;        // has the file been modified
+                       file_modified++;
                } else if (isupper(*dot)) {
                        *dot = tolower(*dot);
-                       file_modified++;        // has the file been modified
+                       file_modified++;
                }
                dot_right();
                end_cmd_q();    // stop adding to q
@@ -3849,6 +3880,7 @@ static void do_cmd(char c)
                dot--;
 }
 
+/* NB!  the CRASHME code is unmaintained, and doesn't currently build */
 #if ENABLE_FEATURE_VI_CRASHME
 static int totalcmds = 0;
 static int Mp = 85;             // Movement command Probability
@@ -4035,15 +4067,13 @@ static void crash_test()
        }
 
        if (msg[0]) {
-               alarm(0);
                printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",
                        totalcmds, last_input_char, msg, SOs, SOn);
                fflush(stdout);
-               while (safe_read(0, d, 1) > 0) {
+               while (safe_read(STDIN_FILENO, d, 1) > 0) {
                        if (d[0] == '\n' || d[0] == '\r')
                                break;
                }
-               alarm(3);
        }
        tim = time(NULL);
        if (tim >= (oldtim + 3)) {