}
#endif
-//----- The Colon commands -------------------------------------
-#if ENABLE_FEATURE_VI_COLON
-static char *get_one_address(char *p, int *addr) // get colon addr, if present
+// sleep for 'h' 1/100 seconds, return 1/0 if stdin is (ready for read)/(not ready)
+static int mysleep(int hund)
{
- int st;
- char *q;
- IF_FEATURE_VI_YANKMARK(char c;)
- IF_FEATURE_VI_SEARCH(char *pat;)
+ struct pollfd pfd[1];
- *addr = -1; // assume no addr
- if (*p == '.') { // the current line
- p++;
- q = begin_line(dot);
- *addr = count_lines(text, q);
- }
-#if ENABLE_FEATURE_VI_YANKMARK
- else if (*p == '\'') { // is this a mark addr
- p++;
- c = tolower(*p);
- p++;
- if (c >= 'a' && c <= 'z') {
- // we have a mark
- c = c - 'a';
- q = mark[(unsigned char) c];
- if (q != NULL) { // is mark valid
- *addr = count_lines(text, q);
- }
- }
- }
-#endif
-#if ENABLE_FEATURE_VI_SEARCH
- else if (*p == '/') { // a search pattern
- q = strchrnul(++p, '/');
- pat = xstrndup(p, q - p); // save copy of pattern
- p = q;
- if (*p == '/')
- p++;
- q = char_search(dot, pat, (FORWARD << 1) | FULL);
- if (q != NULL) {
- *addr = count_lines(text, q);
- }
- free(pat);
- }
-#endif
- else if (*p == '$') { // the last line in file
- p++;
- q = begin_line(end - 1);
- *addr = count_lines(text, q);
- } else if (isdigit(*p)) { // specific line number
- sscanf(p, "%d%n", addr, &st);
- p += st;
- } else {
- // unrecognized address - assume -1
- *addr = -1;
+ if (hund != 0)
+ fflush_all();
+
+ pfd[0].fd = STDIN_FILENO;
+ pfd[0].events = POLLIN;
+ return safe_poll(pfd, 1, hund*10) > 0;
+}
+
+//----- Set terminal attributes --------------------------------
+static void rawmode(void)
+{
+ // no TERMIOS_CLEAR_ISIG: leave ISIG on - allow signals
+ set_termios_to_raw(STDIN_FILENO, &term_orig, TERMIOS_RAW_CRNL);
+ erase_char = term_orig.c_cc[VERASE];
+}
+
+static void cookmode(void)
+{
+ fflush_all();
+ tcsetattr_stdin_TCSANOW(&term_orig);
+}
+
+//----- Terminal Drawing ---------------------------------------
+// The terminal is made up of 'rows' line of 'columns' columns.
+// classically this would be 24 x 80.
+// screen coordinates
+// 0,0 ... 0,79
+// 1,0 ... 1,79
+// . ... .
+// . ... .
+// 22,0 ... 22,79
+// 23,0 ... 23,79 <- status line
+
+//----- Move the cursor to row x col (count from 0, not 1) -------
+static void place_cursor(int row, int col)
+{
+ char cm1[sizeof(ESC_SET_CURSOR_POS) + sizeof(int)*3 * 2];
+
+ if (row < 0) row = 0;
+ if (row >= rows) row = rows - 1;
+ if (col < 0) col = 0;
+ if (col >= columns) col = columns - 1;
+
+ sprintf(cm1, ESC_SET_CURSOR_POS, row + 1, col + 1);
+ write1(cm1);
+}
+
+//----- Erase from cursor to end of line -----------------------
+static void clear_to_eol(void)
+{
+ write1(ESC_CLEAR2EOL);
+}
+
+static void go_bottom_and_clear_to_eol(void)
+{
+ place_cursor(rows - 1, 0);
+ clear_to_eol();
+}
+
+//----- Start standout mode ------------------------------------
+static void standout_start(void)
+{
+ write1(ESC_BOLD_TEXT);
+}
+
+//----- End standout mode --------------------------------------
+static void standout_end(void)
+{
+ write1(ESC_NORM_TEXT);
+}
+
+//----- Text Movement Routines ---------------------------------
+static char *begin_line(char *p) // return pointer to first char cur line
+{
+ if (p > text) {
+ p = memrchr(text, '\n', p - text);
+ if (!p)
+ return text;
+ return p + 1;
}
return p;
}
-static char *get_address(char *p, int *b, int *e) // get two colon addrs, if present
+static char *end_line(char *p) // return pointer to NL of cur line
{
- //----- get the address' i.e., 1,3 'a,'b -----
- // get FIRST addr, if present
- while (isblank(*p))
- p++; // skip over leading spaces
- if (*p == '%') { // alias for 1,$
- p++;
- *b = 1;
- *e = count_lines(text, end-1);
- goto ga0;
- }
- p = get_one_address(p, b);
- while (isblank(*p))
- p++;
- if (*p == ',') { // is there a address separator
- p++;
- while (isblank(*p))
- p++;
- // get SECOND addr, if present
- p = get_one_address(p, e);
+ if (p < end - 1) {
+ p = memchr(p, '\n', end - p - 1);
+ if (!p)
+ return end - 1;
}
- ga0:
- while (isblank(*p))
- p++; // skip over trailing spaces
return p;
}
-#if ENABLE_FEATURE_VI_SET && ENABLE_FEATURE_VI_SETOPTS
-static void setops(const char *args, const char *opname, int flg_no,
- const char *short_opname, int opt)
+static char *dollar_line(char *p) // return pointer to just before NL line
{
- const char *a = args + flg_no;
- int l = strlen(opname) - 1; // opname have + ' '
+ p = end_line(p);
+ // Try to stay off of the Newline
+ if (*p == '\n' && (p - begin_line(p)) > 0)
+ p--;
+ return p;
+}
- // maybe strncmp? we had tons of erroneous strncasecmp's...
- if (strncasecmp(a, opname, l) == 0
- || strncasecmp(a, short_opname, 2) == 0
- ) {
- if (flg_no)
- vi_setops &= ~opt;
- else
- vi_setops |= opt;
- }
+static char *prev_line(char *p) // return pointer first char prev line
+{
+ p = begin_line(p); // goto beginning of cur line
+ if (p > text && p[-1] == '\n')
+ p--; // step to prev line
+ p = begin_line(p); // goto beginning of prev line
+ return p;
}
-#endif
-#endif /* FEATURE_VI_COLON */
+static char *next_line(char *p) // return pointer first char next line
+{
+ p = end_line(p);
+ if (p < end - 1 && *p == '\n')
+ p++; // step to next line
+ return p;
+}
-// buf must be no longer than MAX_INPUT_LEN!
-static void colon(char *buf)
+//----- Text Information Routines ------------------------------
+static char *end_screen(void)
{
-#if !ENABLE_FEATURE_VI_COLON
- // Simple ":cmd" handler with minimal set of commands
- char *p = buf;
+ char *q;
int cnt;
- if (*p == ':')
- p++;
- cnt = strlen(p);
- if (cnt == 0)
- return;
- if (strncmp(p, "quit", cnt) == 0
- || strncmp(p, "q!", cnt) == 0
- ) {
- if (modified_count && p[1] != '!') {
- status_line_bold("No write since last change (:%s! overrides)", p);
- } else {
- editing = 0;
- }
- return;
+ // find new bottom line
+ q = screenbegin;
+ for (cnt = 0; cnt < rows - 2; cnt++)
+ q = next_line(q);
+ q = end_line(q);
+ return q;
+}
+
+// count line from start to stop
+static int count_lines(char *start, char *stop)
+{
+ char *q;
+ int cnt;
+
+ if (stop < start) { // start and stop are backwards- reverse them
+ q = start;
+ start = stop;
+ stop = q;
}
- if (strncmp(p, "write", cnt) == 0
- || strncmp(p, "wq", cnt) == 0
- || strncmp(p, "wn", cnt) == 0
- || (p[0] == 'x' && !p[1])
- ) {
- if (modified_count != 0 || p[0] != 'x') {
- cnt = file_write(current_filename, text, end - 1);
- }
- if (cnt < 0) {
- if (cnt == -1)
- status_line_bold("Write error: "STRERROR_FMT STRERROR_ERRNO);
- } else {
- modified_count = 0;
- last_modified_count = -1;
- status_line("'%s' %dL, %dC",
- current_filename,
- count_lines(text, end - 1), cnt
- );
- if (p[0] == 'x'
- || p[1] == 'q' || p[1] == 'n'
- || p[1] == 'Q' || p[1] == 'N'
- ) {
- editing = 0;
- }
- }
- return;
- }
- if (strncmp(p, "file", cnt) == 0) {
- last_status_cksum = 0; // force status update
- return;
- }
- if (sscanf(p, "%d", &cnt) > 0) {
- dot = find_line(cnt);
- dot_skip_over_ws();
- return;
+ cnt = 0;
+ stop = end_line(stop);
+ while (start <= stop && start <= end - 1) {
+ start = end_line(start);
+ if (*start == '\n')
+ cnt++;
+ start++;
}
- not_implemented(p);
-#else
+ return cnt;
+}
- char c, *buf1, *q, *r;
- char *fn, cmd[MAX_INPUT_LEN], args[MAX_INPUT_LEN];
- int i, l, li, b, e;
- int useforce;
-# if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC
- char *orig_buf;
-# endif
+static char *find_line(int li) // find beginning of line #li
+{
+ char *q;
- // :3154 // if (-e line 3154) goto it else stay put
- // :4,33w! foo // write a portion of buffer to file "foo"
- // :w // write all of buffer to current file
- // :q // quit
- // :q! // quit- dont care about modified file
- // :'a,'z!sort -u // filter block through sort
- // :'f // goto mark "f"
- // :'fl // list literal the mark "f" line
- // :.r bar // read file "bar" into buffer before dot
- // :/123/,/abc/d // delete lines from "123" line to "abc" line
- // :/xyz/ // goto the "xyz" line
- // :s/find/replace/ // substitute pattern "find" with "replace"
- // :!<cmd> // run <cmd> then return
- //
+ for (q = text; li > 1; li--) {
+ q = next_line(q);
+ }
+ return q;
+}
- if (!buf[0])
- goto ret;
- if (*buf == ':')
- buf++; // move past the ':'
+static int next_tabstop(int col)
+{
+ return col + ((tabstop - 1) - (col % tabstop));
+}
- li = i = 0;
- b = e = -1;
- q = text; // assume 1,$ for the range
- r = end - 1;
- li = count_lines(text, end - 1);
- fn = current_filename;
+//----- Erase the Screen[] memory ------------------------------
+static void screen_erase(void)
+{
+ memset(screen, ' ', screensize); // clear new screen
+}
- // look for optional address(es) :. :1 :1,9 :'q,'a :%
- buf = get_address(buf, &b, &e);
+//----- Synchronize the cursor to Dot --------------------------
+static NOINLINE void sync_cursor(char *d, int *row, int *col)
+{
+ char *beg_cur; // begin and end of "d" line
+ char *tp;
+ int cnt, ro, co;
-# if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC
- // remember orig command line
- orig_buf = buf;
-# endif
+ beg_cur = begin_line(d); // first char of cur line
- // get the COMMAND into cmd[]
- buf1 = cmd;
- while (*buf != '\0') {
- if (isspace(*buf))
- break;
- *buf1++ = *buf++;
+ if (beg_cur < screenbegin) {
+ // "d" is before top line on screen
+ // how many lines do we have to move
+ cnt = count_lines(beg_cur, screenbegin);
+ sc1:
+ screenbegin = beg_cur;
+ if (cnt > (rows - 1) / 2) {
+ // we moved too many lines. put "dot" in middle of screen
+ for (cnt = 0; cnt < (rows - 1) / 2; cnt++) {
+ screenbegin = prev_line(screenbegin);
+ }
+ }
+ } else {
+ char *end_scr; // begin and end of screen
+ end_scr = end_screen(); // last char of screen
+ if (beg_cur > end_scr) {
+ // "d" is after bottom line on screen
+ // how many lines do we have to move
+ cnt = count_lines(end_scr, beg_cur);
+ if (cnt > (rows - 1) / 2)
+ goto sc1; // too many lines
+ for (ro = 0; ro < cnt - 1; ro++) {
+ // move screen begin the same amount
+ screenbegin = next_line(screenbegin);
+ // now, move the end of screen
+ end_scr = next_line(end_scr);
+ end_scr = end_line(end_scr);
+ }
+ }
}
- *buf1 = '\0';
- // get any ARGuments
- while (isblank(*buf))
- buf++;
- strcpy(args, buf);
- useforce = FALSE;
- buf1 = last_char_is(cmd, '!');
- if (buf1) {
- useforce = TRUE;
- *buf1 = '\0'; // get rid of !
+ // "d" is on screen- find out which row
+ tp = screenbegin;
+ for (ro = 0; ro < rows - 1; ro++) { // drive "ro" to correct row
+ if (tp == beg_cur)
+ break;
+ tp = next_line(tp);
}
- if (b >= 0) {
- // if there is only one addr, then the addr
- // is the line number of the single line the
- // user wants. So, reset the end
- // pointer to point at end of the "b" line
- q = find_line(b); // what line is #b
- r = end_line(q);
- li = 1;
+
+ // find out what col "d" is on
+ co = 0;
+ while (tp < d) { // drive "co" to correct column
+ if (*tp == '\n') //vda || *tp == '\0')
+ break;
+ if (*tp == '\t') {
+ // handle tabs like real vi
+ if (d == tp && cmd_mode) {
+ break;
+ }
+ co = next_tabstop(co);
+ } else if ((unsigned char)*tp < ' ' || *tp == 0x7f) {
+ co++; // display as ^X, use 2 columns
+ }
+ co++;
+ tp++;
}
- if (e >= 0) {
- // we were given two addrs. change the
- // end pointer to the addr given by user.
- r = find_line(e); // what line is #e
- r = end_line(r);
- li = e - b + 1;
+
+ // "co" is the column where "dot" is.
+ // The screen has "columns" columns.
+ // The currently displayed columns are 0+offset -- columns+ofset
+ // |-------------------------------------------------------------|
+ // ^ ^ ^
+ // offset | |------- columns ----------------|
+ //
+ // If "co" is already in this range then we do not have to adjust offset
+ // but, we do have to subtract the "offset" bias from "co".
+ // If "co" is outside this range then we have to change "offset".
+ // If the first char of a line is a tab the cursor will try to stay
+ // in column 7, but we have to set offset to 0.
+
+ if (co < 0 + offset) {
+ offset = co;
}
- // ------------ now look for the command ------------
- i = strlen(cmd);
- if (i == 0) { // :123CR goto line #123
- if (b >= 0) {
- dot = find_line(b); // what line is #b
- dot_skip_over_ws();
- }
+ if (co >= columns + offset) {
+ offset = co - columns + 1;
}
-# if ENABLE_FEATURE_ALLOW_EXEC
- else if (cmd[0] == '!') { // run a cmd
- int retcode;
- // :!ls run the <cmd>
- 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
+ // if the first char of the line is a tab, and "dot" is sitting on it
+ // force offset to 0.
+ if (d == beg_cur && *d == '\t') {
+ offset = 0;
}
-# endif
- else if (cmd[0] == '=' && !cmd[1]) { // where is the address
- if (b < 0) { // no addr given- use defaults
- b = e = count_lines(text, dot);
- }
- status_line("%d", b);
- } else if (strncmp(cmd, "delete", i) == 0) { // delete lines
- if (b < 0) { // no addr given- use defaults
- q = begin_line(dot); // assume .,. for the range
- r = end_line(dot);
- }
- dot = yank_delete(q, r, 1, YANKDEL, ALLOW_UNDO); // save, then delete lines
- dot_skip_over_ws();
- } else if (strncmp(cmd, "edit", i) == 0) { // Edit a file
- int size;
+ co -= offset;
- // don't edit, if the current file has been modified
- if (modified_count && !useforce) {
- status_line_bold("No write since last change (:%s! overrides)", cmd);
- goto ret;
- }
- if (args[0]) {
- // the user supplied a file name
- fn = args;
- } else if (current_filename && current_filename[0]) {
- // no user supplied name- use the current filename
- // fn = current_filename; was set by default
- } else {
- // no user file name, no current name- punt
- status_line_bold("No current filename");
- goto ret;
- }
+ *row = ro;
+ *col = co;
+}
- size = init_text_buffer(fn);
+//----- The Colon commands -------------------------------------
+#if ENABLE_FEATURE_VI_COLON
+static char *get_one_address(char *p, int *addr) // get colon addr, if present
+{
+ int st;
+ char *q;
+ IF_FEATURE_VI_YANKMARK(char c;)
+ IF_FEATURE_VI_SEARCH(char *pat;)
-# if ENABLE_FEATURE_VI_YANKMARK
- if (Ureg >= 0 && Ureg < 28) {
- free(reg[Ureg]); // free orig line reg- for 'U'
- reg[Ureg] = NULL;
- }
- if (YDreg >= 0 && YDreg < 28) {
- free(reg[YDreg]); // free default yank/delete register
- reg[YDreg] = NULL;
- }
-# endif
- // how many lines in text[]?
- li = count_lines(text, end - 1);
- status_line("'%s'%s"
- IF_FEATURE_VI_READONLY("%s")
- " %dL, %dC",
- current_filename,
- (size < 0 ? " [New file]" : ""),
- IF_FEATURE_VI_READONLY(
- ((readonly_mode) ? " [Readonly]" : ""),
- )
- li, (int)(end - text)
- );
- } else if (strncmp(cmd, "file", i) == 0) { // what File is this
- if (b != -1 || e != -1) {
- status_line_bold("No address allowed on this command");
- goto ret;
- }
- if (args[0]) {
- // user wants a new filename
- free(current_filename);
- current_filename = xstrdup(args);
- } else {
- // user wants file status info
- last_status_cksum = 0; // force status update
+ *addr = -1; // assume no addr
+ if (*p == '.') { // the current line
+ p++;
+ q = begin_line(dot);
+ *addr = count_lines(text, q);
+ }
+#if ENABLE_FEATURE_VI_YANKMARK
+ else if (*p == '\'') { // is this a mark addr
+ p++;
+ c = tolower(*p);
+ p++;
+ if (c >= 'a' && c <= 'z') {
+ // we have a mark
+ c = c - 'a';
+ q = mark[(unsigned char) c];
+ if (q != NULL) { // is mark valid
+ *addr = count_lines(text, q);
+ }
}
- } else if (strncmp(cmd, "features", i) == 0) { // what features are available
- // print out values of all features
- go_bottom_and_clear_to_eol();
- cookmode();
- show_help();
- rawmode();
- Hit_Return();
- } else if (strncmp(cmd, "list", i) == 0) { // literal print line
- if (b < 0) { // no addr given- use defaults
- q = begin_line(dot); // assume .,. for the range
- r = end_line(dot);
+ }
+#endif
+#if ENABLE_FEATURE_VI_SEARCH
+ else if (*p == '/') { // a search pattern
+ q = strchrnul(++p, '/');
+ pat = xstrndup(p, q - p); // save copy of pattern
+ p = q;
+ if (*p == '/')
+ p++;
+ q = char_search(dot, pat, (FORWARD << 1) | FULL);
+ if (q != NULL) {
+ *addr = count_lines(text, q);
}
- go_bottom_and_clear_to_eol();
- puts("\r");
- for (; q <= r; q++) {
- int c_is_no_print;
+ free(pat);
+ }
+#endif
+ else if (*p == '$') { // the last line in file
+ p++;
+ q = begin_line(end - 1);
+ *addr = count_lines(text, q);
+ } else if (isdigit(*p)) { // specific line number
+ sscanf(p, "%d%n", addr, &st);
+ p += st;
+ } else {
+ // unrecognized address - assume -1
+ *addr = -1;
+ }
+ return p;
+}
- c = *q;
- c_is_no_print = (c & 0x80) && !Isprint(c);
- if (c_is_no_print) {
- c = '.';
- standout_start();
- }
- if (c == '\n') {
- write1("$\r");
- } else if (c < ' ' || c == 127) {
- bb_putchar('^');
- if (c == 127)
- c = '?';
- else
- c += '@';
- }
- bb_putchar(c);
- if (c_is_no_print)
- standout_end();
- }
- Hit_Return();
- } else if (strncmp(cmd, "quit", i) == 0 // quit
- || strncmp(cmd, "next", i) == 0 // edit next file
- || strncmp(cmd, "prev", i) == 0 // edit previous file
+static char *get_address(char *p, int *b, int *e) // get two colon addrs, if present
+{
+ //----- get the address' i.e., 1,3 'a,'b -----
+ // get FIRST addr, if present
+ while (isblank(*p))
+ p++; // skip over leading spaces
+ if (*p == '%') { // alias for 1,$
+ p++;
+ *b = 1;
+ *e = count_lines(text, end-1);
+ goto ga0;
+ }
+ p = get_one_address(p, b);
+ while (isblank(*p))
+ p++;
+ if (*p == ',') { // is there a address separator
+ p++;
+ while (isblank(*p))
+ p++;
+ // get SECOND addr, if present
+ p = get_one_address(p, e);
+ }
+ ga0:
+ while (isblank(*p))
+ p++; // skip over trailing spaces
+ return p;
+}
+
+#if ENABLE_FEATURE_VI_SET && ENABLE_FEATURE_VI_SETOPTS
+static void setops(const char *args, const char *opname, int flg_no,
+ const char *short_opname, int opt)
+{
+ const char *a = args + flg_no;
+ int l = strlen(opname) - 1; // opname have + ' '
+
+ // maybe strncmp? we had tons of erroneous strncasecmp's...
+ if (strncasecmp(a, opname, l) == 0
+ || strncasecmp(a, short_opname, 2) == 0
) {
- int n;
- if (useforce) {
- if (*cmd == 'q') {
- // force end of argv list
- optind = save_argc;
- }
+ if (flg_no)
+ vi_setops &= ~opt;
+ else
+ vi_setops |= opt;
+ }
+}
+#endif
+
+#endif /* FEATURE_VI_COLON */
+
+// buf must be no longer than MAX_INPUT_LEN!
+static void colon(char *buf)
+{
+#if !ENABLE_FEATURE_VI_COLON
+ // Simple ":cmd" handler with minimal set of commands
+ char *p = buf;
+ int cnt;
+
+ if (*p == ':')
+ p++;
+ cnt = strlen(p);
+ if (cnt == 0)
+ return;
+ if (strncmp(p, "quit", cnt) == 0
+ || strncmp(p, "q!", cnt) == 0
+ ) {
+ if (modified_count && p[1] != '!') {
+ status_line_bold("No write since last change (:%s! overrides)", p);
+ } else {
editing = 0;
- goto ret;
- }
- // don't exit if the file been modified
- if (modified_count) {
- status_line_bold("No write since last change (:%s! overrides)", cmd);
- goto ret;
- }
- // are there other file to edit
- n = save_argc - optind - 1;
- if (*cmd == 'q' && n > 0) {
- status_line_bold("%d more file(s) to edit", n);
- goto ret;
}
- if (*cmd == 'n' && n <= 0) {
- status_line_bold("No more files to edit");
- goto ret;
+ return;
+ }
+ if (strncmp(p, "write", cnt) == 0
+ || strncmp(p, "wq", cnt) == 0
+ || strncmp(p, "wn", cnt) == 0
+ || (p[0] == 'x' && !p[1])
+ ) {
+ if (modified_count != 0 || p[0] != 'x') {
+ cnt = file_write(current_filename, text, end - 1);
}
- if (*cmd == 'p') {
- // are there previous files to edit
- if (optind < 1) {
- status_line_bold("No previous files to edit");
- goto ret;
+ if (cnt < 0) {
+ if (cnt == -1)
+ status_line_bold("Write error: "STRERROR_FMT STRERROR_ERRNO);
+ } else {
+ modified_count = 0;
+ last_modified_count = -1;
+ status_line("'%s' %dL, %dC",
+ current_filename,
+ count_lines(text, end - 1), cnt
+ );
+ if (p[0] == 'x'
+ || p[1] == 'q' || p[1] == 'n'
+ || p[1] == 'Q' || p[1] == 'N'
+ ) {
+ editing = 0;
}
- optind -= 2;
}
- editing = 0;
- } else if (strncmp(cmd, "read", i) == 0) { // read file into text[]
- int size;
+ return;
+ }
+ if (strncmp(p, "file", cnt) == 0) {
+ last_status_cksum = 0; // force status update
+ return;
+ }
+ if (sscanf(p, "%d", &cnt) > 0) {
+ dot = find_line(cnt);
+ dot_skip_over_ws();
+ return;
+ }
+ not_implemented(p);
+#else
- fn = args;
- if (!fn[0]) {
- status_line_bold("No filename given");
- goto ret;
- }
+ char c, *buf1, *q, *r;
+ char *fn, cmd[MAX_INPUT_LEN], args[MAX_INPUT_LEN];
+ int i, l, li, b, e;
+ int useforce;
+# if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC
+ char *orig_buf;
+# endif
+
+ // :3154 // if (-e line 3154) goto it else stay put
+ // :4,33w! foo // write a portion of buffer to file "foo"
+ // :w // write all of buffer to current file
+ // :q // quit
+ // :q! // quit- dont care about modified file
+ // :'a,'z!sort -u // filter block through sort
+ // :'f // goto mark "f"
+ // :'fl // list literal the mark "f" line
+ // :.r bar // read file "bar" into buffer before dot
+ // :/123/,/abc/d // delete lines from "123" line to "abc" line
+ // :/xyz/ // goto the "xyz" line
+ // :s/find/replace/ // substitute pattern "find" with "replace"
+ // :!<cmd> // run <cmd> then return
+ //
+
+ if (!buf[0])
+ goto ret;
+ if (*buf == ':')
+ buf++; // move past the ':'
+
+ li = i = 0;
+ b = e = -1;
+ q = text; // assume 1,$ for the range
+ r = end - 1;
+ li = count_lines(text, end - 1);
+ fn = current_filename;
+
+ // look for optional address(es) :. :1 :1,9 :'q,'a :%
+ buf = get_address(buf, &b, &e);
+
+# if ENABLE_FEATURE_VI_SEARCH || ENABLE_FEATURE_ALLOW_EXEC
+ // remember orig command line
+ orig_buf = buf;
+# endif
+
+ // get the COMMAND into cmd[]
+ buf1 = cmd;
+ while (*buf != '\0') {
+ if (isspace(*buf))
+ break;
+ *buf1++ = *buf++;
+ }
+ *buf1 = '\0';
+ // get any ARGuments
+ while (isblank(*buf))
+ buf++;
+ strcpy(args, buf);
+ useforce = FALSE;
+ buf1 = last_char_is(cmd, '!');
+ if (buf1) {
+ useforce = TRUE;
+ *buf1 = '\0'; // get rid of !
+ }
+ if (b >= 0) {
+ // if there is only one addr, then the addr
+ // is the line number of the single line the
+ // user wants. So, reset the end
+ // pointer to point at end of the "b" line
+ q = find_line(b); // what line is #b
+ r = end_line(q);
+ li = 1;
+ }
+ if (e >= 0) {
+ // we were given two addrs. change the
+ // end pointer to the addr given by user.
+ r = find_line(e); // what line is #e
+ r = end_line(r);
+ li = e - b + 1;
+ }
+ // ------------ now look for the command ------------
+ i = strlen(cmd);
+ if (i == 0) { // :123CR goto line #123
+ if (b >= 0) {
+ dot = find_line(b); // what line is #b
+ dot_skip_over_ws();
+ }
+ }
+# if ENABLE_FEATURE_ALLOW_EXEC
+ else if (cmd[0] == '!') { // run a cmd
+ int retcode;
+ // :!ls run the <cmd>
+ 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
+ }
+# endif
+ else if (cmd[0] == '=' && !cmd[1]) { // where is the address
+ if (b < 0) { // no addr given- use defaults
+ b = e = count_lines(text, dot);
+ }
+ status_line("%d", b);
+ } else if (strncmp(cmd, "delete", i) == 0) { // delete lines
+ if (b < 0) { // no addr given- use defaults
+ q = begin_line(dot); // assume .,. for the range
+ r = end_line(dot);
+ }
+ dot = yank_delete(q, r, 1, YANKDEL, ALLOW_UNDO); // save, then delete lines
+ dot_skip_over_ws();
+ } else if (strncmp(cmd, "edit", i) == 0) { // Edit a file
+ int size;
+
+ // don't edit, if the current file has been modified
+ if (modified_count && !useforce) {
+ status_line_bold("No write since last change (:%s! overrides)", cmd);
+ goto ret;
+ }
+ if (args[0]) {
+ // the user supplied a file name
+ fn = args;
+ } else if (current_filename && current_filename[0]) {
+ // no user supplied name- use the current filename
+ // fn = current_filename; was set by default
+ } else {
+ // no user file name, no current name- punt
+ status_line_bold("No current filename");
+ goto ret;
+ }
+
+ size = init_text_buffer(fn);
+
+# if ENABLE_FEATURE_VI_YANKMARK
+ if (Ureg >= 0 && Ureg < 28) {
+ free(reg[Ureg]); // free orig line reg- for 'U'
+ reg[Ureg] = NULL;
+ }
+ if (YDreg >= 0 && YDreg < 28) {
+ free(reg[YDreg]); // free default yank/delete register
+ reg[YDreg] = NULL;
+ }
+# endif
+ // how many lines in text[]?
+ li = count_lines(text, end - 1);
+ status_line("'%s'%s"
+ IF_FEATURE_VI_READONLY("%s")
+ " %dL, %dC",
+ current_filename,
+ (size < 0 ? " [New file]" : ""),
+ IF_FEATURE_VI_READONLY(
+ ((readonly_mode) ? " [Readonly]" : ""),
+ )
+ li, (int)(end - text)
+ );
+ } else if (strncmp(cmd, "file", i) == 0) { // what File is this
+ if (b != -1 || e != -1) {
+ status_line_bold("No address allowed on this command");
+ goto ret;
+ }
+ if (args[0]) {
+ // user wants a new filename
+ free(current_filename);
+ current_filename = xstrdup(args);
+ } else {
+ // user wants file status info
+ last_status_cksum = 0; // force status update
+ }
+ } else if (strncmp(cmd, "features", i) == 0) { // what features are available
+ // print out values of all features
+ go_bottom_and_clear_to_eol();
+ cookmode();
+ show_help();
+ rawmode();
+ Hit_Return();
+ } else if (strncmp(cmd, "list", i) == 0) { // literal print line
+ if (b < 0) { // no addr given- use defaults
+ q = begin_line(dot); // assume .,. for the range
+ r = end_line(dot);
+ }
+ go_bottom_and_clear_to_eol();
+ puts("\r");
+ for (; q <= r; q++) {
+ int c_is_no_print;
+
+ c = *q;
+ c_is_no_print = (c & 0x80) && !Isprint(c);
+ if (c_is_no_print) {
+ c = '.';
+ standout_start();
+ }
+ if (c == '\n') {
+ write1("$\r");
+ } else if (c < ' ' || c == 127) {
+ bb_putchar('^');
+ if (c == 127)
+ c = '?';
+ else
+ c += '@';
+ }
+ bb_putchar(c);
+ if (c_is_no_print)
+ standout_end();
+ }
+ Hit_Return();
+ } else if (strncmp(cmd, "quit", i) == 0 // quit
+ || strncmp(cmd, "next", i) == 0 // edit next file
+ || strncmp(cmd, "prev", i) == 0 // edit previous file
+ ) {
+ int n;
+ if (useforce) {
+ if (*cmd == 'q') {
+ // force end of argv list
+ optind = save_argc;
+ }
+ editing = 0;
+ goto ret;
+ }
+ // don't exit if the file been modified
+ if (modified_count) {
+ status_line_bold("No write since last change (:%s! overrides)", cmd);
+ goto ret;
+ }
+ // are there other file to edit
+ n = save_argc - optind - 1;
+ if (*cmd == 'q' && n > 0) {
+ status_line_bold("%d more file(s) to edit", n);
+ goto ret;
+ }
+ if (*cmd == 'n' && n <= 0) {
+ status_line_bold("No more files to edit");
+ goto ret;
+ }
+ if (*cmd == 'p') {
+ // are there previous files to edit
+ if (optind < 1) {
+ status_line_bold("No previous files to edit");
+ goto ret;
+ }
+ optind -= 2;
+ }
+ editing = 0;
+ } else if (strncmp(cmd, "read", i) == 0) { // read file into text[]
+ int size;
+
+ fn = args;
+ if (!fn[0]) {
+ status_line_bold("No filename given");
+ goto ret;
+ }
if (b < 0) { // no addr given- use defaults
q = begin_line(dot); // assume "dot"
}
int dont_chain_first_item = ALLOW_UNDO;
# endif
- // F points to the "find" pattern
- // R points to the "replace" pattern
- // replace the cmd line delimiters "/" with NULs
- c = orig_buf[1]; // what is the delimiter
- F = orig_buf + 2; // start of "find"
- R = strchr(F, c); // middle delimiter
- if (!R)
- goto colon_s_fail;
- len_F = R - F;
- *R++ = '\0'; // terminate "find"
- flags = strchr(R, c);
- if (!flags)
- goto colon_s_fail;
- len_R = flags - R;
- *flags++ = '\0'; // terminate "replace"
- gflag = *flags;
-
- q = begin_line(q);
- if (b < 0) { // maybe :s/foo/bar/
- q = begin_line(dot); // start with cur line
- b = count_lines(text, q); // cur line number
- }
- if (e < 0)
- e = b; // maybe :.s/foo/bar/
-
- for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0
- char *ls = q; // orig line start
- char *found;
- vc4:
- found = char_search(q, F, (FORWARD << 1) | LIMITED); // search cur line only for "find"
- if (found) {
- uintptr_t bias;
- // we found the "find" pattern - delete it
- // For undo support, the first item should not be chained
- text_hole_delete(found, found + len_F - 1, dont_chain_first_item);
-# if ENABLE_FEATURE_VI_UNDO
- dont_chain_first_item = ALLOW_UNDO_CHAIN;
-# endif
- // insert the "replace" patern
- bias = string_insert(found, R, ALLOW_UNDO_CHAIN);
- found += bias;
- ls += bias;
- /*q += bias; - recalculated anyway */
- // check for "global" :s/foo/bar/g
- if (gflag == 'g') {
- if ((found + len_R) < end_line(ls)) {
- q = found + len_R;
- goto vc4; // don't let q move past cur line
- }
- }
- }
- q = next_line(ls);
- }
-# endif /* FEATURE_VI_SEARCH */
- } else if (strncmp(cmd, "version", i) == 0) { // show software version
- status_line(BB_VER);
- } else if (strncmp(cmd, "write", i) == 0 // write text to file
- || strncmp(cmd, "wq", i) == 0
- || strncmp(cmd, "wn", i) == 0
- || (cmd[0] == 'x' && !cmd[1])
- ) {
- int size;
- //int forced = FALSE;
-
- // is there a file name to write to?
- if (args[0]) {
- fn = args;
- }
-# if ENABLE_FEATURE_VI_READONLY
- if (readonly_mode && !useforce) {
- status_line_bold("'%s' is read only", fn);
- goto ret;
- }
-# endif
- //if (useforce) {
- // if "fn" is not write-able, chmod u+w
- // sprintf(syscmd, "chmod u+w %s", fn);
- // system(syscmd);
- // forced = TRUE;
- //}
- if (modified_count != 0 || cmd[0] != 'x') {
- size = r - q + 1;
- l = file_write(fn, q, r);
- } else {
- size = 0;
- l = 0;
- }
- //if (useforce && forced) {
- // chmod u-w
- // sprintf(syscmd, "chmod u-w %s", fn);
- // system(syscmd);
- // forced = FALSE;
- //}
- if (l < 0) {
- if (l == -1)
- status_line_bold_errno(fn);
- } else {
- // how many lines written
- li = count_lines(q, q + l - 1);
- status_line("'%s' %dL, %dC", fn, li, l);
- if (l == size) {
- if (q == text && q + l == end) {
- modified_count = 0;
- last_modified_count = -1;
- }
- if (cmd[0] == 'x'
- || cmd[1] == 'q' || cmd[1] == 'n'
- || cmd[1] == 'Q' || cmd[1] == 'N'
- ) {
- editing = 0;
- }
- }
- }
-# if ENABLE_FEATURE_VI_YANKMARK
- } else if (strncmp(cmd, "yank", i) == 0) { // yank lines
- if (b < 0) { // no addr given- use defaults
- q = begin_line(dot); // assume .,. for the range
- r = end_line(dot);
- }
- text_yank(q, r, YDreg);
- li = count_lines(q, r);
- status_line("Yank %d lines (%d chars) into [%c]",
- li, strlen(reg[YDreg]), what_reg());
-# endif
- } else {
- // cmd unknown
- not_implemented(cmd);
- }
- ret:
- dot = bound_dot(dot); // make sure "dot" is valid
- return;
-# if ENABLE_FEATURE_VI_SEARCH
- colon_s_fail:
- status_line(":s expression missing delimiters");
-# endif
-#endif /* FEATURE_VI_COLON */
-}
-
-static void Hit_Return(void)
-{
- int c;
-
- standout_start();
- write1("[Hit return to continue]");
- standout_end();
- while ((c = get_one_char()) != '\n' && c != '\r')
- continue;
- redraw(TRUE); // force redraw all
-}
-
-static int next_tabstop(int col)
-{
- return col + ((tabstop - 1) - (col % tabstop));
-}
-
-//----- Synchronize the cursor to Dot --------------------------
-static NOINLINE void sync_cursor(char *d, int *row, int *col)
-{
- char *beg_cur; // begin and end of "d" line
- char *tp;
- int cnt, ro, co;
-
- beg_cur = begin_line(d); // first char of cur line
-
- if (beg_cur < screenbegin) {
- // "d" is before top line on screen
- // how many lines do we have to move
- cnt = count_lines(beg_cur, screenbegin);
- sc1:
- screenbegin = beg_cur;
- if (cnt > (rows - 1) / 2) {
- // we moved too many lines. put "dot" in middle of screen
- for (cnt = 0; cnt < (rows - 1) / 2; cnt++) {
- screenbegin = prev_line(screenbegin);
- }
- }
- } else {
- char *end_scr; // begin and end of screen
- end_scr = end_screen(); // last char of screen
- if (beg_cur > end_scr) {
- // "d" is after bottom line on screen
- // how many lines do we have to move
- cnt = count_lines(end_scr, beg_cur);
- if (cnt > (rows - 1) / 2)
- goto sc1; // too many lines
- for (ro = 0; ro < cnt - 1; ro++) {
- // move screen begin the same amount
- screenbegin = next_line(screenbegin);
- // now, move the end of screen
- end_scr = next_line(end_scr);
- end_scr = end_line(end_scr);
- }
- }
- }
- // "d" is on screen- find out which row
- tp = screenbegin;
- for (ro = 0; ro < rows - 1; ro++) { // drive "ro" to correct row
- if (tp == beg_cur)
- break;
- tp = next_line(tp);
- }
-
- // find out what col "d" is on
- co = 0;
- while (tp < d) { // drive "co" to correct column
- if (*tp == '\n') //vda || *tp == '\0')
- break;
- if (*tp == '\t') {
- // handle tabs like real vi
- if (d == tp && cmd_mode) {
- break;
- }
- co = next_tabstop(co);
- } else if ((unsigned char)*tp < ' ' || *tp == 0x7f) {
- co++; // display as ^X, use 2 columns
- }
- co++;
- tp++;
- }
-
- // "co" is the column where "dot" is.
- // The screen has "columns" columns.
- // The currently displayed columns are 0+offset -- columns+ofset
- // |-------------------------------------------------------------|
- // ^ ^ ^
- // offset | |------- columns ----------------|
- //
- // If "co" is already in this range then we do not have to adjust offset
- // but, we do have to subtract the "offset" bias from "co".
- // If "co" is outside this range then we have to change "offset".
- // If the first char of a line is a tab the cursor will try to stay
- // in column 7, but we have to set offset to 0.
-
- if (co < 0 + offset) {
- offset = co;
- }
- if (co >= columns + offset) {
- offset = co - columns + 1;
- }
- // if the first char of the line is a tab, and "dot" is sitting on it
- // force offset to 0.
- if (d == beg_cur && *d == '\t') {
- offset = 0;
- }
- co -= offset;
-
- *row = ro;
- *col = co;
-}
-
-//----- Text Movement Routines ---------------------------------
-static char *begin_line(char *p) // return pointer to first char cur line
-{
- if (p > text) {
- p = memrchr(text, '\n', p - text);
- if (!p)
- return text;
- return p + 1;
- }
- return p;
-}
-
-static char *end_line(char *p) // return pointer to NL of cur line
-{
- if (p < end - 1) {
- p = memchr(p, '\n', end - p - 1);
- if (!p)
- return end - 1;
- }
- return p;
-}
-
-static char *dollar_line(char *p) // return pointer to just before NL line
-{
- p = end_line(p);
- // Try to stay off of the Newline
- if (*p == '\n' && (p - begin_line(p)) > 0)
- p--;
- return p;
-}
-
-static char *prev_line(char *p) // return pointer first char prev line
-{
- p = begin_line(p); // goto beginning of cur line
- if (p > text && p[-1] == '\n')
- p--; // step to prev line
- p = begin_line(p); // goto beginning of prev line
- return p;
-}
-
-static char *next_line(char *p) // return pointer first char next line
-{
- p = end_line(p);
- if (p < end - 1 && *p == '\n')
- p++; // step to next line
- return p;
-}
-
-//----- Text Information Routines ------------------------------
-static char *end_screen(void)
-{
- char *q;
- int cnt;
+ // F points to the "find" pattern
+ // R points to the "replace" pattern
+ // replace the cmd line delimiters "/" with NULs
+ c = orig_buf[1]; // what is the delimiter
+ F = orig_buf + 2; // start of "find"
+ R = strchr(F, c); // middle delimiter
+ if (!R)
+ goto colon_s_fail;
+ len_F = R - F;
+ *R++ = '\0'; // terminate "find"
+ flags = strchr(R, c);
+ if (!flags)
+ goto colon_s_fail;
+ len_R = flags - R;
+ *flags++ = '\0'; // terminate "replace"
+ gflag = *flags;
- // find new bottom line
- q = screenbegin;
- for (cnt = 0; cnt < rows - 2; cnt++)
- q = next_line(q);
- q = end_line(q);
- return q;
-}
+ q = begin_line(q);
+ if (b < 0) { // maybe :s/foo/bar/
+ q = begin_line(dot); // start with cur line
+ b = count_lines(text, q); // cur line number
+ }
+ if (e < 0)
+ e = b; // maybe :.s/foo/bar/
-// count line from start to stop
-static int count_lines(char *start, char *stop)
-{
- char *q;
- int cnt;
+ for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0
+ char *ls = q; // orig line start
+ char *found;
+ vc4:
+ found = char_search(q, F, (FORWARD << 1) | LIMITED); // search cur line only for "find"
+ if (found) {
+ uintptr_t bias;
+ // we found the "find" pattern - delete it
+ // For undo support, the first item should not be chained
+ text_hole_delete(found, found + len_F - 1, dont_chain_first_item);
+# if ENABLE_FEATURE_VI_UNDO
+ dont_chain_first_item = ALLOW_UNDO_CHAIN;
+# endif
+ // insert the "replace" patern
+ bias = string_insert(found, R, ALLOW_UNDO_CHAIN);
+ found += bias;
+ ls += bias;
+ /*q += bias; - recalculated anyway */
+ // check for "global" :s/foo/bar/g
+ if (gflag == 'g') {
+ if ((found + len_R) < end_line(ls)) {
+ q = found + len_R;
+ goto vc4; // don't let q move past cur line
+ }
+ }
+ }
+ q = next_line(ls);
+ }
+# endif /* FEATURE_VI_SEARCH */
+ } else if (strncmp(cmd, "version", i) == 0) { // show software version
+ status_line(BB_VER);
+ } else if (strncmp(cmd, "write", i) == 0 // write text to file
+ || strncmp(cmd, "wq", i) == 0
+ || strncmp(cmd, "wn", i) == 0
+ || (cmd[0] == 'x' && !cmd[1])
+ ) {
+ int size;
+ //int forced = FALSE;
- if (stop < start) { // start and stop are backwards- reverse them
- q = start;
- start = stop;
- stop = q;
- }
- cnt = 0;
- stop = end_line(stop);
- while (start <= stop && start <= end - 1) {
- start = end_line(start);
- if (*start == '\n')
- cnt++;
- start++;
+ // is there a file name to write to?
+ if (args[0]) {
+ fn = args;
+ }
+# if ENABLE_FEATURE_VI_READONLY
+ if (readonly_mode && !useforce) {
+ status_line_bold("'%s' is read only", fn);
+ goto ret;
+ }
+# endif
+ //if (useforce) {
+ // if "fn" is not write-able, chmod u+w
+ // sprintf(syscmd, "chmod u+w %s", fn);
+ // system(syscmd);
+ // forced = TRUE;
+ //}
+ if (modified_count != 0 || cmd[0] != 'x') {
+ size = r - q + 1;
+ l = file_write(fn, q, r);
+ } else {
+ size = 0;
+ l = 0;
+ }
+ //if (useforce && forced) {
+ // chmod u-w
+ // sprintf(syscmd, "chmod u-w %s", fn);
+ // system(syscmd);
+ // forced = FALSE;
+ //}
+ if (l < 0) {
+ if (l == -1)
+ status_line_bold_errno(fn);
+ } else {
+ // how many lines written
+ li = count_lines(q, q + l - 1);
+ status_line("'%s' %dL, %dC", fn, li, l);
+ if (l == size) {
+ if (q == text && q + l == end) {
+ modified_count = 0;
+ last_modified_count = -1;
+ }
+ if (cmd[0] == 'x'
+ || cmd[1] == 'q' || cmd[1] == 'n'
+ || cmd[1] == 'Q' || cmd[1] == 'N'
+ ) {
+ editing = 0;
+ }
+ }
+ }
+# if ENABLE_FEATURE_VI_YANKMARK
+ } else if (strncmp(cmd, "yank", i) == 0) { // yank lines
+ if (b < 0) { // no addr given- use defaults
+ q = begin_line(dot); // assume .,. for the range
+ r = end_line(dot);
+ }
+ text_yank(q, r, YDreg);
+ li = count_lines(q, r);
+ status_line("Yank %d lines (%d chars) into [%c]",
+ li, strlen(reg[YDreg]), what_reg());
+# endif
+ } else {
+ // cmd unknown
+ not_implemented(cmd);
}
- return cnt;
+ ret:
+ dot = bound_dot(dot); // make sure "dot" is valid
+ return;
+# if ENABLE_FEATURE_VI_SEARCH
+ colon_s_fail:
+ status_line(":s expression missing delimiters");
+# endif
+#endif /* FEATURE_VI_COLON */
}
-static char *find_line(int li) // find beginning of line #li
+static void Hit_Return(void)
{
- char *q;
+ int c;
- for (q = text; li > 1; li--) {
- q = next_line(q);
- }
- return q;
+ standout_start();
+ write1("[Hit return to continue]");
+ standout_end();
+ while ((c = get_one_char()) != '\n' && c != '\r')
+ continue;
+ redraw(TRUE); // force redraw all
}
//----- Dot Movement Routines ----------------------------------
}
#endif /* FEATURE_VI_YANKMARK */
-//----- Set terminal attributes --------------------------------
-static void rawmode(void)
-{
- // no TERMIOS_CLEAR_ISIG: leave ISIG on - allow signals
- set_termios_to_raw(STDIN_FILENO, &term_orig, TERMIOS_RAW_CRNL);
- erase_char = term_orig.c_cc[VERASE];
-}
-
-static void cookmode(void)
-{
- fflush_all();
- tcsetattr_stdin_TCSANOW(&term_orig);
-}
-
-static int mysleep(int hund) // sleep for 'hund' 1/100 seconds or stdin ready
-{
- struct pollfd pfd[1];
-
- if (hund != 0)
- fflush_all();
-
- pfd[0].fd = STDIN_FILENO;
- pfd[0].events = POLLIN;
- return safe_poll(pfd, 1, hund*10) > 0;
-}
-
//----- IO Routines --------------------------------------------
static int readit(void) // read (maybe cursor) key from stdin
{
return charcnt;
}
-//----- Terminal Drawing ---------------------------------------
-// The terminal is made up of 'rows' line of 'columns' columns.
-// classically this would be 24 x 80.
-// screen coordinates
-// 0,0 ... 0,79
-// 1,0 ... 1,79
-// . ... .
-// . ... .
-// 22,0 ... 22,79
-// 23,0 ... 23,79 <- status line
-
-//----- Move the cursor to row x col (count from 0, not 1) -------
-static void place_cursor(int row, int col)
-{
- char cm1[sizeof(ESC_SET_CURSOR_POS) + sizeof(int)*3 * 2];
-
- if (row < 0) row = 0;
- if (row >= rows) row = rows - 1;
- if (col < 0) col = 0;
- if (col >= columns) col = columns - 1;
-
- sprintf(cm1, ESC_SET_CURSOR_POS, row + 1, col + 1);
- write1(cm1);
-}
-
-//----- Erase from cursor to end of line -----------------------
-static void clear_to_eol(void)
-{
- write1(ESC_CLEAR2EOL);
-}
-
-static void go_bottom_and_clear_to_eol(void)
-{
- place_cursor(rows - 1, 0);
- clear_to_eol();
-}
-
-//----- Start standout mode ------------------------------------
-static void standout_start(void)
-{
- write1(ESC_BOLD_TEXT);
-}
-
-//----- End standout mode --------------------------------------
-static void standout_end(void)
-{
- write1(ESC_NORM_TEXT);
-}
-
//----- Flash the screen --------------------------------------
static void flash(int h)
{
}
}
-//----- Screen[] Routines --------------------------------------
-//----- Erase the Screen[] memory ------------------------------
-static void screen_erase(void)
-{
- memset(screen, ' ', screensize); // clear new screen
-}
-
static int bufsum(char *buf, int count)
{
int sum = 0;