source: rtems/cpukit/libmisc/shell/main_edit.c @ d152024

4.115
Last change on this file since d152024 was d152024, checked in by Joel Sherrill <joel.sherrill@…>, on 11/24/14 at 23:11:55

shell/main_edit.c: Note return value not checked

Coverity Id 1255320 spotted an unchecked return value.

  • Property mode set to 100644
File size: 56.0 KB
Line 
1//
2// edit.c
3//
4// Text editor
5//
6// Copyright (C) 2002 Michael Ringgaard. All rights reserved.
7//
8// Redistribution and use in source and binary forms, with or without
9// modification, are permitted provided that the following conditions
10// are met:
11//
12// 1. Redistributions of source code must retain the above copyright
13//    notice, this list of conditions and the following disclaimer.
14// 2. Redistributions in binary form must reproduce the above copyright
15//    notice, this list of conditions and the following disclaimer in the
16//    documentation and/or other materials provided with the distribution.
17// 3. Neither the name of the project nor the names of its contributors
18//    may be used to endorse or promote products derived from this software
19//    without specific prior written permission.
20//
21// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
22// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24// ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
25// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31// SUCH DAMAGE.
32//
33
34#include <signal.h>
35#include <stdlib.h>
36#include <stdio.h>
37#include <stdarg.h>
38#include <string.h>
39#include <errno.h>
40#include <fcntl.h>
41#include <unistd.h>
42#include <sys/stat.h>
43
44#ifdef SANOS
45#include <os.h>
46#endif
47
48#ifdef __rtems__
49#include <rtems.h>
50#include <rtems/shell.h>
51#endif
52
53#if defined(__linux__) || defined(__rtems__)
54#include <sys/ioctl.h>
55#include <termios.h>
56#define O_BINARY 0
57static int linux_console;
58#endif
59
60#define MINEXTEND      32768
61#define LINEBUF_EXTRA  32
62
63#ifndef TABSIZE
64#define TABSIZE        8
65#endif
66
67#ifndef INDENT
68#define INDENT "  "
69#endif
70
71#define CLRSCR           "\033[0J\x1b[H\x1b[J"
72#define CLREOL           "\033[K"
73#define GOTOXY           "\033[%d;%dH"
74#define RESET_COLOR      "\033[0m"
75
76#ifdef COLOR
77#define TEXT_COLOR       "\033[44m\033[37m\033[1m"
78#define SELECT_COLOR     "\033[47m\033[37m\033[1m"
79#define STATUS_COLOR     "\033[0m\033[47m\033[30m"
80#else
81#define TEXT_COLOR       "\033[0m"
82#define SELECT_COLOR     "\033[7m\033[1m"
83#define STATUS_COLOR     "\033[1m\033[7m"
84#endif
85
86//
87// Key codes
88//
89
90#define KEY_BACKSPACE        0x101
91#define KEY_ESC              0x102
92#define KEY_INS              0x103
93#define KEY_DEL              0x104
94#define KEY_LEFT             0x105
95#define KEY_RIGHT            0x106
96#define KEY_UP               0x107
97#define KEY_DOWN             0x108
98#define KEY_HOME             0x109
99#define KEY_END              0x10A
100#define KEY_ENTER            0x10B
101#define KEY_TAB              0x10C
102#define KEY_PGUP             0x10D
103#define KEY_PGDN             0x10E
104
105#define KEY_CTRL_LEFT        0x10F
106#define KEY_CTRL_RIGHT       0x110
107#define KEY_CTRL_UP          0x111
108#define KEY_CTRL_DOWN        0x112
109#define KEY_CTRL_HOME        0x113
110#define KEY_CTRL_END         0x114
111#define KEY_CTRL_TAB         0x115
112
113#define KEY_SHIFT_LEFT       0x116
114#define KEY_SHIFT_RIGHT      0x117
115#define KEY_SHIFT_UP         0x118
116#define KEY_SHIFT_DOWN       0x119
117#define KEY_SHIFT_PGUP       0x11A
118#define KEY_SHIFT_PGDN       0x11B
119#define KEY_SHIFT_HOME       0x11C
120#define KEY_SHIFT_END        0x11D
121#define KEY_SHIFT_TAB        0x11E
122
123#define KEY_SHIFT_CTRL_LEFT  0x11F
124#define KEY_SHIFT_CTRL_RIGHT 0x120
125#define KEY_SHIFT_CTRL_UP    0x121
126#define KEY_SHIFT_CTRL_DOWN  0x122
127#define KEY_SHIFT_CTRL_HOME  0x123
128#define KEY_SHIFT_CTRL_END   0x124
129
130#define KEY_F1               0x125
131#define KEY_F2               0x126
132#define KEY_F3               0x127
133#define KEY_F4               0x128
134#define KEY_F5               0x129
135#define KEY_F6               0x12a
136#define KEY_F7               0x12b
137#define KEY_F8               0x12c
138#define KEY_F9               0x12d
139#define KEY_F10              0x12e
140
141#define KEY_UNKNOWN          0xFFF
142
143#define ctrl(c) ((c) - 0x60)
144
145//
146// Editor data block
147//
148// Structure of split buffer:
149//
150//    +------------------+------------------+------------------+
151//    | text before gap  |        gap       |  text after gap  |
152//    +------------------+------------------+------------------+
153//    ^                  ^                  ^                  ^
154//    |                  |                  |                  |
155//  start               gap                rest               end
156//
157
158struct env;
159
160struct undo {
161  int pos;                 // Editor position
162  int erased;              // Size of erased contents
163  int inserted;            // Size of inserted contents
164  unsigned char *undobuf;  // Erased contents for undo
165  unsigned char *redobuf;  // Inserted contents for redo
166  struct undo *next;       // Next undo buffer
167  struct undo *prev;       // Previous undo buffer
168};
169
170struct editor {
171  unsigned char *start;      // Start of text buffer
172  unsigned char *gap;        // Start of gap
173  unsigned char *rest;       // End of gap
174  unsigned char *end;        // End of text buffer
175
176  int toppos;                // Text position for current top screen line
177  int topline;               // Line number for top of screen
178  int margin;                // Position for leftmost column on screen
179
180  int linepos;               // Text position for current line
181  int line;                  // Current document line
182  int col;                   // Current document column
183  int lastcol;               // Remembered column from last horizontal navigation
184  int anchor;                // Anchor position for selection
185
186  struct undo *undohead;     // Start of undo buffer list
187  struct undo *undotail;     // End of undo buffer list
188  struct undo *undo;         // Undo/redo boundary
189
190  int refresh;               // Flag to trigger screen redraw
191  int lineupdate;            // Flag to trigger redraw of current line
192  int dirty;                 // Dirty flag is set when the editor buffer has been changed
193
194  int newfile;               // File is a new file
195  int permissions;           // File permissions
196
197  int selecting;             // Selecting active in the edtor.
198
199  struct env *env;           // Reference to global editor environment
200  struct editor *next;       // Next editor
201  struct editor *prev;       // Previous editor
202
203  char filename[FILENAME_MAX];
204};
205
206struct env {
207  struct editor *current;   // Current editor
208
209  unsigned char *clipboard; // Clipboard
210  int clipsize;             // Clipboard size
211
212  unsigned char *search;    // Search text
213  unsigned char *linebuf;   // Scratch buffer
214
215  int cols;                 // Console columns
216  int lines;                // Console lines
217
218  int untitled;             // Counter for untitled files
219};
220
221/*
222 * This is a hack to allow a simple way to inspect the keys to
223 * add extar decoding. It is not multi-user safe.
224 */
225#define KEY_HISTORY 1
226#if KEY_HISTORY
227int key_history[32];
228size_t key_history_in;
229#endif
230
231//
232// Editor buffer functions
233//
234
235static void clear_undo(struct editor *ed) {
236  struct undo *undo = ed->undohead;
237  while (undo) {
238    struct undo *next = undo->next;
239    free(undo->undobuf);
240    free(undo->redobuf);
241    free(undo);
242    undo = next;
243  }
244  ed->undohead = ed->undotail = ed->undo = NULL;
245}
246
247static void reset_undo(struct editor *ed) {
248  while (ed->undotail != ed->undo) {
249    struct undo *undo = ed->undotail;
250    if (!undo) {
251      ed->undohead = NULL;
252      ed->undotail = NULL;
253      break;
254    }
255    ed->undotail = undo->prev;
256    if (undo->prev) undo->prev->next = NULL;
257    free(undo->undobuf);
258    free(undo->redobuf);
259    free(undo);
260  }
261  ed->undo = ed->undotail;
262}
263
264static struct editor *create_editor(struct env *env) {
265  struct editor *ed = (struct editor *) malloc(sizeof(struct editor));
266  memset(ed, 0, sizeof(struct editor));
267  if (env->current) {
268    ed->next = env->current->next;
269    ed->prev = env->current;
270    env->current->next->prev = ed;
271    env->current->next = ed;
272  } else {
273    ed->next = ed->prev = ed;
274  }
275  ed->env = env;
276  env->current = ed;
277  return ed;
278}
279
280static void delete_editor(struct editor *ed) {
281  if (ed->next == ed) {
282    ed->env->current = NULL;
283  } else {
284    ed->env->current = ed->prev;
285  }
286  ed->next->prev = ed->prev;
287  ed->prev->next = ed->next;
288  if (ed->start) free(ed->start);
289  clear_undo(ed);
290  free(ed);
291}
292
293static struct editor *find_editor(struct env *env, char *filename) {
294  char fn[FILENAME_MAX];
295  struct editor *ed = env->current;
296  struct editor *start = ed;
297
298  if (!realpath(filename, fn)) strcpy(fn, filename);
299
300  do {
301    if (strcmp(fn, ed->filename) == 0) return ed;
302    ed = ed->next;
303  } while (ed != start);
304  return NULL;
305}
306
307static int new_file(struct editor *ed, char *filename) {
308  if (*filename) {
309    strcpy(ed->filename, filename);
310  } else {
311    sprintf(ed->filename, "Untitled-%d", ++ed->env->untitled);
312    ed->newfile = 1;
313  }
314  ed->permissions = 0644;
315
316  ed->start = (unsigned char *) malloc(MINEXTEND);
317  if (!ed->start) return -1;
318#ifdef DEBUG
319  memset(ed->start, 0, MINEXTEND);
320#endif
321
322  ed->gap = ed->start;
323  ed->rest = ed->end = ed->gap + MINEXTEND;
324  ed->anchor = -1;
325
326  return 0;
327}
328
329static int load_file(struct editor *ed, char *filename) {
330  struct stat statbuf;
331  int length;
332  int f;
333
334  if (!realpath(filename, ed->filename)) return -1;
335  f = open(ed->filename, O_RDONLY | O_BINARY);
336  if (f < 0) return -1;
337
338  if (fstat(f, &statbuf) < 0) goto err;
339  length = statbuf.st_size;
340  ed->permissions = statbuf.st_mode & 0777;
341
342  ed->start = (unsigned char *) malloc(length + MINEXTEND);
343  if (!ed->start) goto err;
344#ifdef DEBUG
345  memset(ed->start, 0, length + MINEXTEND);
346#endif
347  if (read(f, ed->start, length) != length) goto err;
348
349  ed->gap = ed->start + length;
350  ed->rest = ed->end = ed->gap + MINEXTEND;
351  ed->anchor = -1;
352
353  close(f);
354  return 0;
355
356err:
357  close(f);
358  if (ed->start) {
359    free(ed->start);
360    ed->start = NULL;
361  }
362  return -1;
363}
364
365static int save_file(struct editor *ed) {
366  int f;
367
368  f = open(ed->filename, O_CREAT | O_TRUNC | O_WRONLY, ed->permissions);
369  if (f < 0) return -1;
370
371  if (write(f, ed->start, ed->gap - ed->start) != ed->gap - ed->start) goto err;
372  if (write(f, ed->rest, ed->end - ed->rest) != ed->end - ed->rest) goto err;
373
374  close(f);
375  ed->dirty = 0;
376  clear_undo(ed);
377  return 0;
378
379err:
380  close(f);
381  return -1;
382}
383
384static int text_length(struct editor *ed) {
385  return (ed->gap - ed->start) + (ed->end - ed->rest);
386}
387
388static unsigned char *text_ptr(struct editor *ed, int pos) {
389  unsigned char *p = ed->start + pos;
390  if (p >= ed->gap) p += (ed->rest - ed->gap);
391  return p;
392}
393
394static void move_gap(struct editor *ed, int pos, int minsize) {
395  int gapsize = ed->rest - ed->gap;
396  unsigned char *p = text_ptr(ed, pos);
397  if (minsize < 0) minsize = 0;
398
399  if (minsize <= gapsize) {
400    if (p != ed->rest) {
401      if (p < ed->gap) {
402        memmove(p + gapsize, p, ed->gap - p);
403      } else {
404        memmove(ed->gap, ed->rest, p - ed->rest);
405      }
406      ed->gap = ed->start + pos;
407      ed->rest = ed->gap + gapsize;
408    }
409  } else {
410    int newsize;
411    unsigned char *start;
412    unsigned char *gap;
413    unsigned char *rest;
414    unsigned char *end;
415
416    if (gapsize + MINEXTEND > minsize) minsize = gapsize + MINEXTEND;
417    newsize = (ed->end - ed->start) - gapsize + minsize;
418    start = (unsigned char *) malloc(newsize); // TODO check for out of memory
419    gap = start + pos;
420    rest = gap + minsize;
421    end = start + newsize;
422
423    if (p < ed->gap) {
424      memcpy(start, ed->start, pos);
425      memcpy(rest, p, ed->gap - p);
426      memcpy(end - (ed->end - ed->rest), ed->rest, ed->end - ed->rest);
427    } else {
428      memcpy(start, ed->start, ed->gap - ed->start);
429      memcpy(start + (ed->gap - ed->start), ed->rest, p - ed->rest);
430      memcpy(rest, p, ed->end - p);
431    }
432
433    free(ed->start);
434    ed->start = start;
435    ed->gap = gap;
436    ed->rest = rest;
437    ed->end = end;
438  }
439
440#ifdef DEBUG
441  memset(ed->gap, 0, ed->rest - ed->gap);
442#endif
443}
444
445static void close_gap(struct editor *ed) {
446  int len = text_length(ed);
447  move_gap(ed, len, 1);
448  ed->start[len] = 0;
449}
450
451static int get(struct editor *ed, int pos) {
452  unsigned char *p = text_ptr(ed, pos);
453  if (p >= ed->end) return -1;
454  return *p;
455}
456
457static int compare(struct editor *ed, unsigned char *buf, int pos, int len) {
458  unsigned char *bufptr = buf;
459  unsigned char *p = ed->start + pos;
460  if (p >= ed->gap) p += (ed->rest - ed->gap);
461
462  while (len > 0) {
463    if (p == ed->end) return 0;
464    if (*bufptr++ != *p) return 0;
465    len--;
466    if (++p == ed->gap) p = ed->rest;
467  }
468
469  return 1;
470}
471
472static int copy(struct editor *ed, unsigned char *buf, int pos, int len) {
473  unsigned char *bufptr = buf;
474  unsigned char *p = ed->start + pos;
475  if (p >= ed->gap) p += (ed->rest - ed->gap);
476
477  while (len > 0) {
478    if (p == ed->end) break;
479    *bufptr++ = *p;
480    len--;
481    if (++p == ed->gap) p = ed->rest;
482  }
483
484  return bufptr - buf;
485}
486
487static void replace(struct editor *ed, int pos, int len, unsigned char *buf, int bufsize, int doundo) {
488  unsigned char *p;
489  struct undo *undo;
490
491  // Store undo information
492  if (doundo) {
493    reset_undo(ed);
494    undo = ed->undotail;
495    if (undo && len == 0 && bufsize == 1 && undo->erased == 0 && pos == undo->pos + undo->inserted) {
496      // Insert character at end of current redo buffer
497      undo->redobuf = realloc(undo->redobuf, undo->inserted + 1);
498      undo->redobuf[undo->inserted] = *buf;
499      undo->inserted++;
500    } else if (undo && len == 1 && bufsize == 0 && undo->inserted == 0 && pos == undo->pos) {
501      // Erase character at end of current undo buffer
502      undo->undobuf = realloc(undo->undobuf, undo->erased + 1);
503      undo->undobuf[undo->erased] = get(ed, pos);
504      undo->erased++;
505    } else if (undo && len == 1 && bufsize == 0 && undo->inserted == 0 && pos == undo->pos - 1) {
506      // Erase character at beginning of current undo buffer
507      undo->pos--;
508      undo->undobuf = realloc(undo->undobuf, undo->erased + 1);
509      memmove(undo->undobuf + 1, undo->undobuf, undo->erased);
510      undo->undobuf[0] = get(ed, pos);
511      undo->erased++;
512    } else {
513      // Create new undo buffer
514      undo = (struct undo *) malloc(sizeof(struct undo));
515      if (ed->undotail) ed->undotail->next = undo;
516      undo->prev = ed->undotail;
517      undo->next = NULL;
518      ed->undotail = ed->undo = undo;
519      if (!ed->undohead) ed->undohead = undo;
520
521      undo->pos = pos;
522      undo->erased = len;
523      undo->inserted = bufsize;
524      undo->undobuf = undo->redobuf = NULL;
525      if (len > 0) {
526        undo->undobuf = malloc(len);
527        copy(ed, undo->undobuf, pos, len);
528      }
529      if (bufsize > 0) {
530        undo->redobuf = malloc(bufsize);
531        memcpy(undo->redobuf, buf, bufsize);
532      }
533    }
534  }
535
536  p = ed->start + pos;
537  if (bufsize == 0 && p <= ed->gap && p + len >= ed->gap) {
538    // Handle deletions at the edges of the gap
539    ed->rest += len - (ed->gap - p);
540    ed->gap = p;
541  } else {
542    // Move the gap
543    move_gap(ed, pos + len, bufsize - len);
544
545    // Replace contents
546    memcpy(ed->start + pos, buf, bufsize);
547    ed->gap = ed->start + pos + bufsize;
548  }
549
550  // Mark buffer as dirty
551  ed->dirty = 1;
552}
553
554static void insert(struct editor *ed, int pos, unsigned char *buf, int bufsize) {
555  replace(ed, pos, 0, buf, bufsize, 1);
556}
557
558static void erase(struct editor *ed, int pos, int len) {
559  replace(ed, pos, len, NULL, 0, 1);
560}
561
562//
563// Navigation functions
564//
565
566static int line_length(struct editor *ed, int linepos) {
567  int pos = linepos;
568  while (1) {
569    int ch = get(ed, pos);
570    if (ch < 0 || ch == '\n' || ch == '\r') break;
571    pos++;
572  }
573
574  return pos - linepos;
575}
576
577static int line_start(struct editor *ed, int pos) {
578  while (1) {
579    if (pos == 0) break;
580    if (get(ed, pos - 1) == '\n') break;
581    pos--;
582  }
583
584  return pos;
585}
586
587static int next_line(struct editor *ed, int pos) {
588  while (1) {
589    int ch = get(ed, pos);
590    if (ch < 0) return -1;
591    pos++;
592    if (ch == '\n') return pos;
593  }
594}
595
596static int prev_line(struct editor *ed, int pos) {
597  if (pos == 0) return -1;
598
599  while (pos > 0) {
600    int ch = get(ed, --pos);
601    if (ch == '\n') break;
602  }
603
604  while (pos > 0) {
605    int ch = get(ed, --pos);
606    if (ch == '\n') return pos + 1;
607  }
608
609  return 0;
610}
611
612static int column(struct editor *ed, int linepos, int col) {
613  unsigned char *p = text_ptr(ed, linepos);
614  int c = 0;
615  while (col > 0) {
616    if (p == ed->end) break;
617    if (*p == '\t') {
618      int spaces = TABSIZE - c % TABSIZE;
619      c += spaces;
620    } else {
621      c++;
622    }
623    col--;
624    if (++p == ed->gap) p = ed->rest;
625  }
626  return c;
627}
628
629static void moveto(struct editor *ed, int pos, int center) {
630  int scroll = 0;
631  for (;;) {
632    int cur = ed->linepos + ed->col;
633    if (pos < cur) {
634      if (pos >= ed->linepos) {
635        ed->col = pos - ed->linepos;
636      } else {
637        ed->col = 0;
638        ed->linepos = prev_line(ed, ed->linepos);
639        ed->line--;
640
641        if (ed->topline > ed->line) {
642          ed->toppos = ed->linepos;
643          ed->topline--;
644          ed->refresh = 1;
645          scroll = 1;
646        }
647      }
648    } else if (pos > cur) {
649      int next = next_line(ed, ed->linepos);
650      if (next == -1) {
651        ed->col = line_length(ed, ed->linepos);
652        break;
653      } else if (pos < next) {
654        ed->col = pos - ed->linepos;
655      } else {
656        ed->col = 0;
657        ed->linepos = next;
658        ed->line++;
659
660        if (ed->line >= ed->topline + ed->env->lines) {
661          ed->toppos = next_line(ed, ed->toppos);
662          ed->topline++;
663          ed->refresh = 1;
664          scroll = 1;
665        }
666      }
667    } else {
668      break;
669    }
670  }
671
672  if (scroll && center) {
673    int tl = ed->line - ed->env->lines / 2;
674    if (tl < 0) tl = 0;
675    for (;;) {
676      if (ed->topline > tl) {
677        ed->toppos = prev_line(ed, ed->toppos);
678        ed->topline--;
679      } else if (ed->topline < tl) {
680        ed->toppos = next_line(ed, ed->toppos);
681        ed->topline++;
682      } else {
683        break;
684      }
685    }
686  }
687}
688
689//
690// Text selection
691//
692
693static int get_selection(struct editor *ed, int *start, int *end) {
694  if (ed->anchor == -1) {
695    *start = *end = -1;
696    return 0;
697  } else {
698    int pos = ed->linepos + ed->col;
699    if (pos == ed->anchor) {
700      *start = *end = -1;
701      return 0;
702    } else if (pos < ed->anchor) {
703      *start = pos;
704      *end = ed->anchor;
705    } else {
706      *start = ed->anchor;
707      *end = pos;
708    }
709  }
710  return 1;
711}
712
713static int get_selected_text(struct editor *ed, char *buffer, int size) {
714  int selstart, selend, len;
715
716  if (!get_selection(ed, &selstart, &selend)) return 0;
717  len = selend - selstart;
718  if (len >= size) return 0;
719  copy(ed, (unsigned char*) buffer, selstart, len);
720  buffer[len] = 0;
721  return len;
722}
723
724static void update_selection(struct editor *ed, int select) {
725  if (select) {
726    if (ed->anchor == -1) ed->anchor = ed->linepos + ed->col;
727    ed->refresh = 1;
728  } else {
729    if (ed->anchor != -1) ed->refresh = 1;
730    ed->anchor = -1;
731  }
732}
733
734static int erase_selection(struct editor *ed) {
735  int selstart, selend;
736
737  if (!get_selection(ed, &selstart, &selend)) return 0;
738  moveto(ed, selstart, 0);
739  erase(ed, selstart, selend - selstart);
740  ed->anchor = -1;
741  ed->refresh = 1;
742  return 1;
743}
744
745static void select_all(struct editor *ed) {
746  ed->anchor = 0;
747  ed->refresh = 1;
748  moveto(ed, text_length(ed), 0);
749}
750
751//
752// Screen functions
753//
754
755static void get_console_size(struct env *env) {
756#ifdef __linux__
757  struct winsize ws;
758  ioctl(0, TIOCGWINSZ, &ws);
759  env->cols = ws.ws_col;
760  env->lines = ws.ws_row - 1;
761#elif defined(__rtems__)
762  env->cols = 80;
763  env->lines = 25;
764#else
765  struct term *term = gettib()->proc->term;
766  env->cols = term->cols;
767  env->lines = term->lines - 1;
768#endif
769  env->linebuf = realloc(env->linebuf, env->cols + LINEBUF_EXTRA);
770}
771
772static void outch(char c) {
773  putchar(c);
774}
775
776static void outbuf(unsigned char *buf, int len) {
777  fwrite(buf, 1, len, stdout);
778}
779
780static void outstr(char *str) {
781  fputs(str, stdout);
782}
783
784static void clear_screen(void) {
785  outstr(CLRSCR);
786}
787
788static void gotoxy(int col, int line) {
789  char buf[32];
790
791  sprintf(buf, GOTOXY, line + 1, col + 1);
792  outstr(buf);
793}
794
795//
796// Keyboard functions
797//
798
799static void get_modifier_keys(int *shift, int *ctrl) {
800  *shift = *ctrl = 0;
801#ifdef __linux__
802  if (linux_console) {
803    char modifiers = 6;
804    if (ioctl(0, TIOCLINUX, &modifiers) >= 0) {
805      if (modifiers & 1) *shift = 1;
806      if (modifiers & 4) *ctrl = 1;
807    }
808  }
809#endif
810}
811
812static int getachar(void)
813{
814  int ch = getchar();
815#if KEY_HISTORY
816  if (key_history_in < sizeof(key_history)) {
817      key_history[key_history_in++] = ch;
818  } else {
819    memmove(&key_history[0], &key_history[1], sizeof(key_history) - sizeof(key_history[0]));
820    key_history[key_history_in - 1] = ch;
821  }
822#endif
823  return ch;
824}
825
826static int getkey(void) {
827  int ch, shift, ctrl;
828
829  ch = getachar();
830  if (ch < 0) return ch;
831
832  switch (ch) {
833    case 0x08: return KEY_BACKSPACE;
834    case 0x09:
835      get_modifier_keys(&shift, &ctrl);
836      if (shift) return KEY_SHIFT_TAB;
837      if (ctrl) return KEY_CTRL_TAB;
838      return KEY_TAB;
839#ifdef SANOS
840    case 0x0D: return gettib()->proc->term->type == TERM_CONSOLE ? KEY_ENTER : KEY_UNKNOWN;
841    case 0x0A: return gettib()->proc->term->type != TERM_CONSOLE ? KEY_ENTER : KEY_UNKNOWN;
842#else
843    case 0x0D: return KEY_ENTER;
844    case 0x0A: return KEY_ENTER;
845#endif
846    case 0x1B:
847      ch = getachar();
848      switch (ch) {
849        case 0x1B: return KEY_ESC;
850        case 0x4F:
851          ch = getachar();
852          switch (ch) {
853            case 0x46: return KEY_END;
854            case 0x48: return KEY_HOME;
855            case 0x50: return KEY_F1;
856            case 0x51: return KEY_F2;
857            case 0x52: return KEY_F3;
858            case 0x53: return KEY_F4;
859            case 0x54: return KEY_F5;
860            default: return KEY_UNKNOWN;
861          }
862          break;
863
864        case 0x5B:
865          get_modifier_keys(&shift, &ctrl);
866          ch = getachar();
867          if (ch == 0x31) {
868            ch = getachar();
869            switch (ch) {
870              case 0x35:
871                return getachar() == 0x7E ? KEY_F5 : KEY_UNKNOWN;
872              case 0x37:
873                return getachar() == 0x7E ? KEY_F6 : KEY_UNKNOWN;
874              case 0x3B:
875                ch = getachar();
876                if (ch == 0x7E) return KEY_F7;
877                if (ch == 0x32) shift = 1;
878                if (ch == 0x35) ctrl = 1;
879                if (ch == 0x36) shift = ctrl = 1;
880                ch = getachar();
881                break;
882              case 0x39:
883                return getachar() == 0x7E ? KEY_F8 : KEY_UNKNOWN;
884              case 0x7E:
885                if (shift && ctrl) return KEY_SHIFT_CTRL_HOME;
886                if (shift) return KEY_SHIFT_HOME;
887                if (ctrl) return KEY_CTRL_HOME;
888                return KEY_HOME;
889              default:
890                return KEY_UNKNOWN;
891            }
892          }
893
894          switch (ch) {
895            case 0x31:
896              ch = getachar();
897              if (ch != 0x7E) return KEY_UNKNOWN;
898              if (shift && ctrl) return KEY_SHIFT_CTRL_HOME;
899              if (shift) return KEY_SHIFT_HOME;
900              if (ctrl) return KEY_CTRL_HOME;
901              return KEY_HOME;
902            case 0x32:
903              ch = getachar();
904              switch (ch) {
905                case 0x30: ch = getachar(); return KEY_F9;
906                case 0x31: ch = getachar(); return KEY_F10;
907                case 0x7E: return KEY_INS;
908                default: break;
909              }
910              return KEY_UNKNOWN;
911            case 0x33: return getachar() == 0x7E ? KEY_DEL : KEY_UNKNOWN;
912            case 0x34:
913              if (getachar() != 0x7E) return KEY_UNKNOWN;
914              if (shift && ctrl) return KEY_SHIFT_CTRL_END;
915              if (shift) return KEY_SHIFT_END;
916              if (ctrl) return KEY_CTRL_END;
917              return KEY_END;
918            case 0x35:
919              if (getachar() != 0x7E) return KEY_UNKNOWN;
920              if (shift) return KEY_SHIFT_PGUP;
921              return KEY_PGUP;
922            case 0x36:
923              if (getachar() != 0x7E) return KEY_UNKNOWN;
924              if (shift) return KEY_SHIFT_PGDN;
925              return KEY_PGDN;
926            case 0x41:
927              if (shift && ctrl) return KEY_SHIFT_CTRL_UP;
928              if (shift) return KEY_SHIFT_UP;
929              if (ctrl) return KEY_CTRL_UP;
930              return KEY_UP;
931            case 0x42:
932              if (shift && ctrl) return KEY_SHIFT_CTRL_DOWN;
933              if (shift) return KEY_SHIFT_DOWN;
934              if (ctrl) return KEY_CTRL_DOWN;
935              return KEY_DOWN;
936            case 0x43:
937              if (shift && ctrl) return KEY_SHIFT_CTRL_RIGHT;
938              if (shift) return KEY_SHIFT_RIGHT;
939              if (ctrl) return KEY_CTRL_RIGHT;
940              return KEY_RIGHT;
941            case 0x44:
942              if (shift && ctrl) return KEY_SHIFT_CTRL_LEFT;
943              if (shift) return KEY_SHIFT_LEFT;
944              if (ctrl) return KEY_CTRL_LEFT;
945              return KEY_LEFT;
946            case 0x46:
947              if (shift && ctrl) return KEY_SHIFT_CTRL_END;
948              if (shift) return KEY_SHIFT_END;
949              if (ctrl) return KEY_CTRL_END;
950              return KEY_END;
951            case 0x48:
952              if (shift && ctrl) return KEY_SHIFT_CTRL_HOME;
953              if (shift) return KEY_SHIFT_HOME;
954              if (ctrl) return KEY_CTRL_HOME;
955              return KEY_HOME;
956            case 0x5A:
957              return KEY_SHIFT_TAB;
958            case 0x5B:
959              ch = getachar();
960              switch (ch) {
961                case 0x41: return KEY_F1;
962                case 0x43: return KEY_F3;
963                case 0x45: return KEY_F5;
964              }
965              return KEY_UNKNOWN;
966
967            default: return KEY_UNKNOWN;
968          }
969          break;
970
971        default: return KEY_UNKNOWN;
972      }
973      break;
974
975    case 0x00:
976    case 0xE0:
977      ch = getachar();
978      switch (ch) {
979        case 0x0F: return KEY_SHIFT_TAB;
980        case 0x3B: return KEY_F1;
981        case 0x3D: return KEY_F3;
982        case 0x3F: return KEY_F5;
983        case 0x47: return KEY_HOME;
984        case 0x48: return KEY_UP;
985        case 0x49: return KEY_PGUP;
986        case 0x4B: return KEY_LEFT;
987        case 0x4D: return KEY_RIGHT;
988        case 0x4F: return KEY_END;
989        case 0x50: return KEY_DOWN;
990        case 0x51: return KEY_PGDN;
991        case 0x52: return KEY_INS;
992        case 0x53: return KEY_DEL;
993        case 0x73: return KEY_CTRL_LEFT;
994        case 0x74: return KEY_CTRL_RIGHT;
995        case 0x75: return KEY_CTRL_END;
996        case 0x77: return KEY_CTRL_HOME;
997        case 0x8D: return KEY_CTRL_UP;
998        case 0x91: return KEY_CTRL_DOWN;
999        case 0x94: return KEY_CTRL_TAB;
1000        case 0xB8: return KEY_SHIFT_UP;
1001        case 0xB7: return KEY_SHIFT_HOME;
1002        case 0xBF: return KEY_SHIFT_END;
1003        case 0xB9: return KEY_SHIFT_PGUP;
1004        case 0xBB: return KEY_SHIFT_LEFT;
1005        case 0xBD: return KEY_SHIFT_RIGHT;
1006        case 0xC0: return KEY_SHIFT_DOWN;
1007        case 0xC1: return KEY_SHIFT_PGDN;
1008        case 0xDB: return KEY_SHIFT_CTRL_LEFT;
1009        case 0xDD: return KEY_SHIFT_CTRL_RIGHT;
1010        case 0xD8: return KEY_SHIFT_CTRL_UP;
1011        case 0xE0: return KEY_SHIFT_CTRL_DOWN;
1012        case 0xD7: return KEY_SHIFT_CTRL_HOME;
1013        case 0xDF: return KEY_SHIFT_CTRL_END;
1014
1015        default: return KEY_UNKNOWN;
1016      }
1017      break;
1018
1019    case 0x7F: return KEY_BACKSPACE;
1020
1021    default: return ch;
1022  }
1023}
1024
1025static int prompt(struct editor *ed, char *msg, int selection) {
1026  int maxlen, len, ch;
1027  char *buf = (char*) ed->env->linebuf;
1028
1029  gotoxy(0, ed->env->lines);
1030  outstr(STATUS_COLOR);
1031  outstr(msg);
1032  outstr(CLREOL);
1033
1034  len = 0;
1035  maxlen = ed->env->cols - strlen(msg) - 1;
1036  if (selection) {
1037    len = get_selected_text(ed, buf, maxlen);
1038    outbuf((unsigned char*) buf, len);
1039  }
1040
1041  for (;;) {
1042    fflush(stdout);
1043    ch = getkey();
1044    if (ch == KEY_ESC) {
1045      return 0;
1046    } else if (ch == KEY_ENTER) {
1047      buf[len] = 0;
1048      return len > 0;
1049    } else if (ch == KEY_BACKSPACE) {
1050      if (len > 0) {
1051        outstr("\b \b");
1052        len--;
1053      }
1054    } else if (ch >= ' ' && ch < 0x100 && len < maxlen) {
1055      outch(ch);
1056      buf[len++] = ch;
1057    }
1058  }
1059}
1060
1061static int ask(void) {
1062  int ch = getachar();
1063  return ch == 'y' || ch == 'Y';
1064}
1065
1066//
1067// Display functions
1068//
1069
1070static void display_message(struct editor *ed, char *fmt, ...) {
1071  va_list args;
1072
1073  va_start(args, fmt);
1074  gotoxy(0, ed->env->lines);
1075  outstr(STATUS_COLOR);
1076  vprintf(fmt, args);
1077  outstr(CLREOL TEXT_COLOR);
1078  fflush(stdout);
1079  va_end(args);
1080}
1081
1082static void draw_full_statusline(struct editor *ed) {
1083  struct env *env = ed->env;
1084  int namewidth = env->cols - 29;
1085  gotoxy(0, env->lines);
1086  sprintf((char*) env->linebuf, STATUS_COLOR "%*.*sF1=Help %c%c Ln %-6dCol %-4d" CLREOL TEXT_COLOR, -namewidth, namewidth, ed->filename, ed->selecting ? '+' : ' ', ed->dirty ? '*' : ' ', ed->line + 1, column(ed, ed->linepos, ed->col) + 1);
1087  outstr((char*) env->linebuf);
1088}
1089
1090static void draw_statusline(struct editor *ed) {
1091  gotoxy(ed->env->cols - 20, ed->env->lines);
1092  sprintf((char*) ed->env->linebuf, STATUS_COLOR "%c Ln %-6dCol %-4d" CLREOL TEXT_COLOR, ed->dirty ? '*' : ' ', ed->line + 1, column(ed, ed->linepos, ed->col) + 1);
1093  outstr((char*) ed->env->linebuf);
1094}
1095
1096static void display_line(struct editor *ed, int pos, int fullline) {
1097  int hilite = 0;
1098  int col = 0;
1099  int margin = ed->margin;
1100  int maxcol = ed->env->cols + margin;
1101  unsigned char *bufptr = ed->env->linebuf;
1102  unsigned char *p = text_ptr(ed, pos);
1103  int selstart, selend, ch;
1104  char *s;
1105
1106  get_selection(ed, &selstart, &selend);
1107  while (col < maxcol) {
1108    if (margin == 0) {
1109      if (!hilite && pos >= selstart && pos < selend) {
1110        for (s = SELECT_COLOR; *s; s++) *bufptr++ = *s;
1111        hilite = 1;
1112      } else if (hilite && pos >= selend) {
1113        for (s = TEXT_COLOR; *s; s++) *bufptr++ = *s;
1114        hilite = 0;
1115      }
1116    }
1117
1118    if (p == ed->end) break;
1119    ch = *p;
1120    if (ch == '\r' || ch == '\n') break;
1121
1122    if (ch == '\t') {
1123      int spaces = TABSIZE - col % TABSIZE;
1124      while (spaces > 0 && col < maxcol) {
1125        if (margin > 0) {
1126          margin--;
1127        } else {
1128          *bufptr++ = ' ';
1129        }
1130        col++;
1131        spaces--;
1132      }
1133    } else {
1134      if (margin > 0) {
1135        margin--;
1136      } else {
1137        *bufptr++ = ch;
1138      }
1139      col++;
1140    }
1141
1142    if (++p == ed->gap) p = ed->rest;
1143    pos++;
1144  }
1145
1146#if defined(__linux__)
1147  if (hilite) {
1148    while (col < maxcol) {
1149      *bufptr++ = ' ';
1150      col++;
1151    }
1152  } else {
1153    if (col == margin) *bufptr++ = ' ';
1154  }
1155#endif
1156
1157  if (col < maxcol) {
1158    for (s = CLREOL; *s; s++) *bufptr++ = *s;
1159    if (fullline) {
1160      memcpy(bufptr, "\r\n", 2);
1161      bufptr += 2;
1162    }
1163  }
1164
1165  if (hilite) {
1166    for (s = TEXT_COLOR; *s; s++) *bufptr++ = *s;
1167  }
1168
1169  outbuf(ed->env->linebuf, bufptr - ed->env->linebuf);
1170}
1171
1172static void update_line(struct editor *ed) {
1173  gotoxy(0, ed->line - ed->topline);
1174  display_line(ed, ed->linepos, 0);
1175}
1176
1177static void draw_screen(struct editor *ed) {
1178  int pos;
1179  int i;
1180
1181  gotoxy(0, 0);
1182  outstr(TEXT_COLOR);
1183  pos = ed->toppos;
1184  for (i = 0; i < ed->env->lines; i++) {
1185    if (pos < 0) {
1186      outstr(CLREOL "\r\n");
1187    } else {
1188      display_line(ed, pos, 1);
1189      pos = next_line(ed, pos);
1190    }
1191  }
1192}
1193
1194static void position_cursor(struct editor *ed) {
1195  int col = column(ed, ed->linepos, ed->col);
1196  gotoxy(col - ed->margin, ed->line - ed->topline);
1197}
1198
1199//
1200// Cursor movement
1201//
1202
1203static void adjust(struct editor *ed) {
1204  int col;
1205  int ll = line_length(ed, ed->linepos);
1206  ed->col = ed->lastcol;
1207  if (ed->col > ll) ed->col = ll;
1208
1209  col = column(ed, ed->linepos, ed->col);
1210  while (col < ed->margin) {
1211    ed->margin -= 4;
1212    if (ed->margin < 0) ed->margin = 0;
1213    ed->refresh = 1;
1214  }
1215
1216  while (col - ed->margin >= ed->env->cols) {
1217    ed->margin += 4;
1218    ed->refresh = 1;
1219  }
1220}
1221
1222static void select_toggle(struct editor *ed) {
1223  ed->selecting = ed->selecting ? 0 : 1;
1224  update_selection(ed, ed->selecting);
1225  adjust(ed);
1226}
1227
1228static void up(struct editor *ed, int select) {
1229  int newpos;
1230
1231  update_selection(ed, select);
1232
1233  newpos = prev_line(ed, ed->linepos);
1234  if (newpos < 0) return;
1235
1236  ed->linepos = newpos;
1237  ed->line--;
1238  if (ed->line < ed->topline) {
1239    ed->toppos = ed->linepos;
1240    ed->topline = ed->line;
1241    ed->refresh = 1;
1242  }
1243
1244  adjust(ed);
1245}
1246
1247static void down(struct editor *ed, int select) {
1248  int newpos;
1249
1250  update_selection(ed, select);
1251
1252  newpos = next_line(ed, ed->linepos);
1253  if (newpos < 0) return;
1254
1255  ed->linepos = newpos;
1256  ed->line++;
1257
1258  if (ed->line >= ed->topline + ed->env->lines) {
1259    ed->toppos = next_line(ed, ed->toppos);
1260    ed->topline++;
1261    ed->refresh = 1;
1262  }
1263
1264  adjust(ed);
1265}
1266
1267static void left(struct editor *ed, int select) {
1268  update_selection(ed, select);
1269  if (ed->col > 0) {
1270    ed->col--;
1271  } else {
1272    int newpos = prev_line(ed, ed->linepos);
1273    if (newpos < 0) return;
1274
1275    ed->col = line_length(ed, newpos);
1276    ed->linepos = newpos;
1277    ed->line--;
1278    if (ed->line < ed->topline) {
1279      ed->toppos = ed->linepos;
1280      ed->topline = ed->line;
1281      ed->refresh = 1;
1282    }
1283  }
1284
1285  ed->lastcol = ed->col;
1286  adjust(ed);
1287}
1288
1289static void right(struct editor *ed, int select) {
1290  update_selection(ed, select);
1291  if (ed->col < line_length(ed, ed->linepos)) {
1292    ed->col++;
1293  } else {
1294    int newpos = next_line(ed, ed->linepos);
1295    if (newpos < 0) return;
1296
1297    ed->col = 0;
1298    ed->linepos = newpos;
1299    ed->line++;
1300
1301    if (ed->line >= ed->topline + ed->env->lines) {
1302      ed->toppos = next_line(ed, ed->toppos);
1303      ed->topline++;
1304      ed->refresh = 1;
1305    }
1306  }
1307
1308  ed->lastcol = ed->col;
1309  adjust(ed);
1310}
1311
1312static int wordchar(int ch) {
1313  return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9');
1314}
1315
1316static void wordleft(struct editor *ed, int select) {
1317  int pos, phase;
1318
1319  update_selection(ed, select);
1320  pos = ed->linepos + ed->col;
1321  phase = 0;
1322  while (pos > 0) {
1323    int ch = get(ed, pos - 1);
1324    if (phase == 0) {
1325      if (wordchar(ch)) phase = 1;
1326    } else {
1327      if (!wordchar(ch)) break;
1328    }
1329
1330    pos--;
1331    if (pos < ed->linepos) {
1332      ed->linepos = prev_line(ed, ed->linepos);
1333      ed->line--;
1334      ed->refresh = 1;
1335    }
1336  }
1337  ed->col = pos - ed->linepos;
1338  if (ed->line < ed->topline) {
1339    ed->toppos = ed->linepos;
1340    ed->topline = ed->line;
1341  }
1342
1343  ed->lastcol = ed->col;
1344  adjust(ed);
1345}
1346
1347static void wordright(struct editor *ed, int select) {
1348  int pos, end, phase, next;
1349
1350  update_selection(ed, select);
1351  pos = ed->linepos + ed->col;
1352  end = text_length(ed);
1353  next = next_line(ed, ed->linepos);
1354  phase = 0;
1355  while (pos < end) {
1356    int ch = get(ed, pos);
1357    if (phase == 0) {
1358      if (wordchar(ch)) phase = 1;
1359    } else {
1360      if (!wordchar(ch)) break;
1361    }
1362
1363    pos++;
1364    if (pos == next) {
1365      ed->linepos = next;
1366      next = next_line(ed, ed->linepos);
1367      ed->line++;
1368      ed->refresh = 1;
1369    }
1370  }
1371  ed->col = pos - ed->linepos;
1372  if (ed->line >= ed->topline + ed->env->lines) {
1373    ed->toppos = next_line(ed, ed->toppos);
1374    ed->topline++;
1375  }
1376
1377  ed->lastcol = ed->col;
1378  adjust(ed);
1379}
1380
1381static void home(struct editor *ed, int select) {
1382  update_selection(ed, select);
1383  ed->col = ed->lastcol = 0;
1384  adjust(ed);
1385}
1386
1387static void end(struct editor *ed, int select) {
1388  update_selection(ed, select);
1389  ed->col = ed->lastcol = line_length(ed, ed->linepos);
1390  adjust(ed);
1391}
1392
1393static void top(struct editor *ed, int select) {
1394  update_selection(ed, select);
1395  ed->toppos = ed->topline = ed->margin = 0;
1396  ed->linepos = ed->line = ed->col = ed->lastcol = 0;
1397  ed->refresh = 1;
1398}
1399
1400static void bottom(struct editor *ed, int select) {
1401  update_selection(ed, select);
1402  for (;;) {
1403    int newpos = next_line(ed, ed->linepos);
1404    if (newpos < 0) break;
1405
1406    ed->linepos = newpos;
1407    ed->line++;
1408
1409    if (ed->line >= ed->topline + ed->env->lines) {
1410      ed->toppos = next_line(ed, ed->toppos);
1411      ed->topline++;
1412      ed->refresh = 1;
1413    }
1414  }
1415  ed->col = ed->lastcol = line_length(ed, ed->linepos);
1416  adjust(ed);
1417}
1418
1419static void pageup(struct editor *ed, int select) {
1420  int i;
1421
1422  update_selection(ed, select);
1423  if (ed->line < ed->env->lines) {
1424    ed->linepos = ed->toppos = 0;
1425    ed->line = ed->topline = 0;
1426  } else {
1427    for (i = 0; i < ed->env->lines; i++) {
1428      int newpos = prev_line(ed, ed->linepos);
1429      if (newpos < 0) return;
1430
1431      ed->linepos = newpos;
1432      ed->line--;
1433
1434      if (ed->topline > 0) {
1435        ed->toppos = prev_line(ed, ed->toppos);
1436        ed->topline--;
1437      }
1438    }
1439  }
1440
1441  ed->refresh = 1;
1442  adjust(ed);
1443}
1444
1445static void pagedown(struct editor *ed, int select) {
1446  int i;
1447
1448  update_selection(ed, select);
1449  for (i = 0; i < ed->env->lines; i++) {
1450    int newpos = next_line(ed, ed->linepos);
1451    if (newpos < 0) break;
1452
1453    ed->linepos = newpos;
1454    ed->line++;
1455
1456    ed->toppos = next_line(ed, ed->toppos);
1457    ed->topline++;
1458  }
1459
1460  ed->refresh = 1;
1461  adjust(ed);
1462}
1463
1464//
1465// Text editing
1466//
1467
1468static void insert_char(struct editor *ed, unsigned char ch) {
1469  erase_selection(ed);
1470  insert(ed, ed->linepos + ed->col, &ch, 1);
1471  ed->col++;
1472  ed->lastcol = ed->col;
1473  adjust(ed);
1474  if (!ed->refresh) ed->lineupdate = 1;
1475}
1476
1477static void newline(struct editor *ed) {
1478  int p;
1479  unsigned char ch;
1480
1481  erase_selection(ed);
1482#if defined(__linux__) || defined(__rtems__)
1483  insert(ed, ed->linepos + ed->col, (unsigned char*) "\n", 1);
1484#else
1485  insert(ed, ed->linepos + ed->col, "\r\n", 2);
1486#endif
1487  ed->col = ed->lastcol = 0;
1488  ed->line++;
1489  p = ed->linepos;
1490  ed->linepos = next_line(ed, ed->linepos);
1491  for (;;) {
1492    ch = get(ed, p++);
1493    if (ch == ' ' || ch == '\t') {
1494      insert(ed, ed->linepos + ed->col, &ch, 1);
1495      ed->col++;
1496    } else {
1497      break;
1498    }
1499  }
1500  ed->lastcol = ed->col;
1501
1502  ed->refresh = 1;
1503
1504  if (ed->line >= ed->topline + ed->env->lines) {
1505    ed->toppos = next_line(ed, ed->toppos);
1506    ed->topline++;
1507    ed->refresh = 1;
1508  }
1509
1510  adjust(ed);
1511}
1512
1513static void backspace(struct editor *ed) {
1514  if (erase_selection(ed)) return;
1515  if (ed->linepos + ed->col == 0) return;
1516  if (ed->col == 0) {
1517    int pos = ed->linepos;
1518    erase(ed, --pos, 1);
1519    if (get(ed, pos - 1) == '\r') erase(ed, --pos, 1);
1520
1521    ed->line--;
1522    ed->linepos = line_start(ed, pos);
1523    ed->col = pos - ed->linepos;
1524    ed->refresh = 1;
1525
1526    if (ed->line < ed->topline) {
1527      ed->toppos = ed->linepos;
1528      ed->topline = ed->line;
1529    }
1530  } else {
1531    ed->col--;
1532    erase(ed, ed->linepos + ed->col, 1);
1533    ed->lineupdate = 1;
1534  }
1535
1536  ed->lastcol = ed->col;
1537  adjust(ed);
1538}
1539
1540static void del(struct editor *ed) {
1541  int pos, ch;
1542
1543  if (erase_selection(ed)) return;
1544  pos = ed->linepos + ed->col;
1545  ch = get(ed, pos);
1546  if (ch < 0) return;
1547
1548  erase(ed, pos, 1);
1549  if (ch == '\r') {
1550    ch = get(ed, pos);
1551    if (ch == '\n') erase(ed, pos, 1);
1552  }
1553
1554  if (ch == '\n') {
1555    ed->refresh = 1;
1556  } else {
1557    ed->lineupdate = 1;
1558  }
1559}
1560
1561static void indent(struct editor *ed, unsigned char *indentation) {
1562  int start, end, i, lines, toplines, newline, ch;
1563  unsigned char *buffer, *p;
1564  int buflen;
1565  int width = strlen((const char*) indentation);
1566  int pos = ed->linepos + ed->col;
1567
1568  if (!get_selection(ed, &start, &end)) {
1569    insert_char(ed, '\t');
1570    return;
1571  }
1572
1573  lines = 0;
1574  toplines = 0;
1575  newline = 1;
1576  for (i = start; i < end; i++) {
1577    if (i == ed->toppos) toplines = lines;
1578    if (newline) {
1579      lines++;
1580      newline = 0;
1581    }
1582    if (get(ed, i) == '\n') newline = 1;
1583  }
1584  buflen = end - start + lines * width;
1585  buffer = malloc(buflen);
1586  if (!buffer) return;
1587
1588  newline = 1;
1589  p = buffer;
1590  for (i = start; i < end; i++) {
1591    if (newline) {
1592      memcpy(p, indentation, width);
1593      p += width;
1594      newline = 0;
1595    }
1596    ch = get(ed, i);
1597    *p++ = ch;
1598    if (ch == '\n') newline = 1;
1599  }
1600
1601  replace(ed, start, end - start, buffer, buflen, 1);
1602  free(buffer);
1603
1604  if (ed->anchor < pos) {
1605    pos += width * lines;
1606  } else {
1607    ed->anchor += width * lines;
1608  }
1609
1610  ed->toppos += width * toplines;
1611  ed->linepos = line_start(ed, pos);
1612  ed->col = ed->lastcol = pos - ed->linepos;
1613
1614  adjust(ed);
1615  ed->refresh = 1;
1616}
1617
1618static void unindent(struct editor *ed, unsigned char *indentation) {
1619  int start, end, i, newline, ch, shrinkage, topofs;
1620  unsigned char *buffer, *p;
1621  int width = strlen((const char*) indentation);
1622  int pos = ed->linepos + ed->col;
1623
1624  if (!get_selection(ed, &start, &end)) return;
1625
1626  buffer = malloc(end - start);
1627  if (!buffer) return;
1628
1629  newline = 1;
1630  p = buffer;
1631  i = start;
1632  shrinkage = 0;
1633  topofs = 0;
1634  while (i < end) {
1635    if (newline) {
1636      newline = 0;
1637      if (compare(ed, indentation, i, width)) {
1638        i += width;
1639        shrinkage += width;
1640        if (i < ed->toppos) topofs -= width;
1641        continue;
1642      }
1643    }
1644    ch = get(ed, i++);
1645    *p++ = ch;
1646    if (ch == '\n') newline = 1;
1647  }
1648
1649  if (!shrinkage) {
1650    free(buffer);
1651    return;
1652  }
1653
1654  replace(ed, start, end - start, buffer, p - buffer, 1);
1655  free(buffer);
1656
1657  if (ed->anchor < pos) {
1658    pos -= shrinkage;
1659  } else {
1660    ed->anchor -= shrinkage;
1661  }
1662
1663  ed->toppos += topofs;
1664  ed->linepos = line_start(ed, pos);
1665  ed->col = ed->lastcol = pos - ed->linepos;
1666
1667  ed->refresh = 1;
1668  adjust(ed);
1669}
1670
1671static void undo(struct editor *ed) {
1672  if (!ed->undo) return;
1673  moveto(ed, ed->undo->pos, 0);
1674  replace(ed, ed->undo->pos, ed->undo->inserted, ed->undo->undobuf, ed->undo->erased, 0);
1675  ed->undo = ed->undo->prev;
1676  if (!ed->undo) ed->dirty = 0;
1677  ed->anchor = -1;
1678  ed->lastcol = ed->col;
1679  ed->refresh = 1;
1680}
1681
1682static void redo(struct editor *ed) {
1683  if (ed->undo) {
1684    if (!ed->undo->next) return;
1685    ed->undo = ed->undo->next;
1686  } else {
1687    if (!ed->undohead) return;
1688    ed->undo = ed->undohead;
1689  }
1690  replace(ed, ed->undo->pos, ed->undo->erased, ed->undo->redobuf, ed->undo->inserted, 0);
1691  moveto(ed, ed->undo->pos, 0);
1692  ed->dirty = 1;
1693  ed->anchor = -1;
1694  ed->lastcol = ed->col;
1695  ed->refresh = 1;
1696}
1697
1698//
1699// Clipboard
1700//
1701
1702static void copy_selection(struct editor *ed) {
1703  int selstart, selend;
1704
1705  if (!get_selection(ed, &selstart, &selend)) return;
1706  ed->env->clipsize = selend - selstart;
1707  ed->env->clipboard = (unsigned char *) realloc(ed->env->clipboard, ed->env->clipsize);
1708  if (!ed->env->clipboard) return;
1709  copy(ed, ed->env->clipboard, selstart, ed->env->clipsize);
1710  select_toggle(ed);
1711}
1712
1713static void cut_selection(struct editor *ed) {
1714  copy_selection(ed);
1715  erase_selection(ed);
1716  select_toggle(ed);
1717}
1718
1719static void paste_selection(struct editor *ed) {
1720  erase_selection(ed);
1721  insert(ed, ed->linepos + ed->col, ed->env->clipboard, ed->env->clipsize);
1722  moveto(ed, ed->linepos + ed->col + ed->env->clipsize, 0);
1723  ed->refresh = 1;
1724}
1725
1726//
1727// Editor Commands
1728//
1729
1730static void open_editor(struct editor *ed) {
1731  int rc;
1732  char *filename;
1733  struct env *env = ed->env;
1734
1735  if (!prompt(ed, "Open file: ", 1)) {
1736    ed->refresh = 1;
1737    return;
1738  }
1739  filename = (char*) ed->env->linebuf;
1740
1741  ed = find_editor(ed->env, filename);
1742  if (ed) {
1743    env->current = ed;
1744  } else {
1745    ed = create_editor(env);
1746    rc = load_file(ed, filename);
1747    if (rc < 0) {
1748      display_message(ed, "Error %d opening %s (%s)", errno, filename, strerror(errno));
1749      sleep(5);
1750      delete_editor(ed);
1751      ed = env->current;
1752    }
1753  }
1754  ed->refresh = 1;
1755}
1756
1757static void new_editor(struct editor *ed) {
1758  ed = create_editor(ed->env);
1759  new_file(ed, "");
1760  ed->refresh = 1;
1761}
1762
1763static void read_from_stdin(struct editor *ed) {
1764  char buffer[512];
1765  int n, pos;
1766
1767  pos = 0;
1768  while ((n = fread(buffer, 1, sizeof(buffer), stdin)) > 0) {
1769    insert(ed, pos, (unsigned char*) buffer, n);
1770    pos += n;
1771  }
1772  strcpy(ed->filename, "<stdin>");
1773  ed->newfile = 1;
1774  ed->dirty = 0;
1775}
1776
1777static void save_editor(struct editor *ed) {
1778  int rc;
1779
1780  if (!ed->dirty && !ed->newfile) return;
1781
1782  if (ed->newfile) {
1783    if (!prompt(ed, "Save as: ", 1)) {
1784      ed->refresh = 1;
1785      return;
1786    }
1787
1788    if (access((const char*) ed->env->linebuf, F_OK) == 0) {
1789      display_message(ed, "Overwrite %s (y/n)? ", ed->env->linebuf);
1790      if (!ask()) {
1791        ed->refresh = 1;
1792        return;
1793      }
1794    }
1795    strcpy(ed->filename, (const char*) ed->env->linebuf);
1796    ed->newfile = 0;
1797  }
1798
1799  rc = save_file(ed);
1800  if (rc < 0) {
1801    display_message(ed, "Error %d saving document (%s)", errno, strerror(errno));
1802    sleep(5);
1803  }
1804
1805  ed->refresh = 1;
1806}
1807
1808static void close_editor(struct editor *ed) {
1809  struct env *env = ed->env;
1810
1811  if (ed->dirty) {
1812    display_message(ed, "Close %s without saving changes (y/n)? ", ed->filename);
1813    if (!ask()) {
1814      ed->refresh = 1;
1815      return;
1816    }
1817  }
1818
1819  delete_editor(ed);
1820
1821  ed = env->current;
1822  if (!ed) {
1823    ed = create_editor(env);
1824    new_file(ed, "");
1825  }
1826  ed->refresh = 1;
1827}
1828
1829static void pipe_command(struct editor *ed) {
1830#ifdef __rtems__
1831    display_message(ed, "Not supported");
1832    sleep(3);
1833#else
1834  FILE *f;
1835  char buffer[512];
1836  int n;
1837  int pos;
1838
1839  if (!prompt(ed, "Command: ", 1)) {
1840    ed->refresh = 1;
1841    return;
1842  }
1843
1844#ifdef SANOS
1845  f = popen(ed->env->linebuf, "r2");
1846#else
1847  f = popen(ed->env->linebuf, "r");
1848#endif
1849  if (!f) {
1850    display_message(ed, "Error %d running command (%s)", errno, strerror(errno));
1851    sleep(5);
1852  } else {
1853    erase_selection(ed);
1854    pos = ed->linepos + ed->col;
1855    while ((n = fread(buffer, 1, sizeof(buffer), f)) > 0) {
1856      insert(ed, pos, buffer, n);
1857      pos += n;
1858    }
1859    moveto(ed, pos, 0);
1860    pclose(f);
1861  }
1862  ed->refresh = 1;
1863#endif
1864}
1865
1866static void find_text(struct editor *ed, int next) {
1867  int slen;
1868
1869  if (!next) {
1870    if (!prompt(ed, "Find: ", 1)) {
1871      ed->refresh = 1;
1872      return;
1873    }
1874    if (ed->env->search) free(ed->env->search);
1875    ed->env->search = (unsigned char*) strdup((const char*) ed->env->linebuf);
1876  }
1877
1878  if (!ed->env->search) return;
1879  slen = strlen((const char*) ed->env->search);
1880  if (slen > 0) {
1881    unsigned char *match;
1882
1883    close_gap(ed);
1884    match = (unsigned char*) strstr((char*) ed->start + ed->linepos + ed->col, (char*) ed->env->search);
1885    if (match != NULL) {
1886      int pos = match - ed->start;
1887      ed->anchor = pos;
1888      moveto(ed, pos + slen, 1);
1889    } else {
1890      outch('\007');
1891    }
1892  }
1893  ed->refresh = 1;
1894}
1895
1896static void goto_line(struct editor *ed) {
1897  int lineno, l, pos;
1898
1899  ed->anchor = -1;
1900  if (prompt(ed, "Goto line: ", 1)) {
1901    lineno = atoi((char*) ed->env->linebuf);
1902    if (lineno > 0) {
1903      pos = 0;
1904      for (l = 0; l < lineno - 1; l++) {
1905        pos = next_line(ed, pos);
1906        if (pos < 0) break;
1907      }
1908    } else {
1909      pos = -1;
1910    }
1911
1912    if (pos >= 0) {
1913      moveto(ed, pos, 1);
1914    } else {
1915      outch('\007');
1916    }
1917  }
1918  ed->refresh = 1;
1919}
1920
1921static struct editor *next_file(struct editor *ed) {
1922  ed = ed->env->current = ed->next;
1923  ed->refresh = 1;
1924  return ed;
1925}
1926
1927static void jump_to_editor(struct editor *ed) {
1928  struct env *env = ed->env;
1929  char filename[FILENAME_MAX];
1930  int lineno = 0;
1931
1932  if (!get_selected_text(ed, filename, FILENAME_MAX)) {
1933    int pos = ed->linepos + ed->col;
1934    char *p = filename;
1935    int left = FILENAME_MAX - 1;
1936    while (left > 0) {
1937      int ch = get(ed, pos);
1938      if (ch < 0) break;
1939      if (strchr("!@\"'#%&()[]{}*?+:;\r\n\t ", ch)) break;
1940      *p++ = ch;
1941      left--;
1942      pos++;
1943    }
1944    *p = 0;
1945
1946    if (get(ed, pos) == ':') {
1947      pos++;
1948      for (;;) {
1949        int ch = get(ed, pos);
1950        if (ch < 0) break;
1951        if (ch >= '0' && ch <= '9') {
1952          lineno = lineno * 10 + (ch - '0');
1953        } else {
1954          break;
1955        }
1956        pos++;
1957      }
1958    }
1959  }
1960  if (!*filename) return;
1961
1962  ed = find_editor(env, filename);
1963  if (ed) {
1964    env->current = ed;
1965  } else {
1966    ed = create_editor(env);
1967    if (load_file(ed, filename) < 0) {
1968      outch('\007');
1969      delete_editor(ed);
1970      ed = env->current;
1971    }
1972  }
1973
1974  if (lineno > 0) {
1975    int pos = 0;
1976    while (--lineno > 0) {
1977      pos = next_line(ed, pos);
1978      if (pos < 0) break;
1979    }
1980    if (pos >= 0) moveto(ed, pos, 1);
1981  }
1982
1983  ed->refresh = 1;
1984}
1985
1986static void redraw_screen(struct editor *ed) {
1987  get_console_size(ed->env);
1988  draw_screen(ed);
1989}
1990
1991static int quit(struct env *env) {
1992  struct editor *ed = env->current;
1993  struct editor *start = ed;
1994
1995  do {
1996    if (ed->dirty) {
1997      display_message(ed, "Close %s without saving changes (y/n)? ", ed->filename);
1998      if (!ask()) return 0;
1999    }
2000    ed = ed->next;
2001  } while (ed != start);
2002
2003  return 1;
2004}
2005
2006static void help(struct editor *ed) {
2007  gotoxy(0, 0);
2008  clear_screen();
2009  outstr("Editor Command Summary\r\n");
2010  outstr("======================\r\n\r\n");
2011  outstr("<up>         Move one line up (*)         Ctrl+N  New editor\r\n");
2012  outstr("<down>       Move one line down (*)       Ctrl+O  Open file\r\n");
2013  outstr("<left>       Move one character left (*)  Ctrl+S  Save file\r\n");
2014  outstr("<right>      Move one character right (*) Ctrl+W  Close file\r\n");
2015  outstr("<pgup>       Move one page up (*)         Ctrl+Q  Quit\r\n");
2016  outstr("<pgdn>       Move one page down (*)       Ctrl+P  Pipe command\r\n");
2017  outstr("Ctrl+<left>  Move to previous word (*)    Ctrl+A  Select all\r\n");
2018  outstr("Ctrl+<right> Move to next word (*)        Ctrl+C  Copy selection to clipboard\r\n");
2019  outstr("<home>       Move to start of line (*)    Ctrl+X  Cut selection to clipboard\r\n");
2020  outstr("<end>        Move to end of line (*)      Ctrl+V  Paste from clipboard\r\n");
2021  outstr("Ctrl+<home>  Move to start of file (*)    Ctrl+Z  Undo\r\n");
2022  outstr("Ctrl+<end>   Move to end of file (*)      Ctrl+R  Redo\r\n");
2023  outstr("<backspace>  Delete previous character    Ctrl+F  Find text\r\n");
2024  outstr("<delete>     Delete current character     Ctrl+G  Find next\r\n");
2025  outstr("Ctrl+<tab>   Next editor                  Ctrl+L  Goto line\r\n");
2026  outstr("<tab>        Indent selection             F1      Help\r\n");
2027  outstr("Shift+<tab>  Unindent selection           F2      Select toggle\r\n");
2028  outstr(" (*) Extends selection, F2 toggles.       F3      Navigate to file\r\n");
2029  outstr("                                          F4      Copy selection to clipboard\r\n");
2030  outstr("  Ctrl-Q/S may not work over              F5      Redraw screen\r\n");
2031  outstr("  serial links, use funcions keys         F9      Save file\r\n");
2032  outstr("                                          F10     Quit\r\n");
2033  outstr("Press any key to continue...");
2034  fflush(stdout);
2035
2036  getkey();
2037  draw_screen(ed);
2038  draw_full_statusline(ed);
2039}
2040
2041//
2042// Editor
2043//
2044
2045static void edit(struct editor *ed) {
2046  int done = 0;
2047  int key;
2048
2049  ed->refresh = 1;
2050  while (!done) {
2051    if (ed->refresh) {
2052      draw_screen(ed);
2053      draw_full_statusline(ed);
2054      ed->refresh = 0;
2055      ed->lineupdate = 0;
2056    } else if (ed->lineupdate) {
2057      update_line(ed);
2058      ed->lineupdate = 0;
2059      draw_statusline(ed);
2060    } else {
2061      draw_statusline(ed);
2062    }
2063
2064    position_cursor(ed);
2065    fflush(stdout);
2066    key = getkey();
2067
2068    if (key >= ' ' && key <= 0x7F) {
2069#ifdef LESS
2070      switch (key) {
2071        case 'q': done = 1; break;
2072        case '/': find_text(ed, 0); break;
2073      }
2074#else
2075      insert_char(ed, (unsigned char) key);
2076#endif
2077    } else {
2078      switch (key) {
2079        case KEY_F1: help(ed); break;
2080        case KEY_F2: select_toggle(ed); break;
2081        case KEY_F3: jump_to_editor(ed); ed = ed->env->current; break;
2082        case KEY_F4: copy_selection(ed); break;
2083        case KEY_F5: redraw_screen(ed); break;
2084        case KEY_F9: save_editor(ed); break;
2085        case KEY_F10: done = 1; break;
2086
2087#if defined(__linux__) || defined(__rtems__)
2088        case ctrl('y'): help(ed); break;
2089        case ctrl('t'): top(ed, 0); break;
2090        case ctrl('b'): bottom(ed, 0); break;
2091#endif
2092
2093        case KEY_UP: up(ed, ed->selecting); break;
2094        case KEY_DOWN: down(ed, ed->selecting); break;
2095        case KEY_LEFT: left(ed, ed->selecting); break;
2096        case KEY_RIGHT: right(ed, ed->selecting); break;
2097        case KEY_HOME: home(ed, ed->selecting); break;
2098        case KEY_END: end(ed, ed->selecting); break;
2099        case KEY_PGUP: pageup(ed, ed->selecting); break;
2100        case KEY_PGDN: pagedown(ed, ed->selecting); break;
2101
2102        case KEY_CTRL_RIGHT: wordright(ed, ed->selecting); break;
2103        case KEY_CTRL_LEFT: wordleft(ed, ed->selecting); break;
2104        case KEY_CTRL_HOME: top(ed, ed->selecting); break;
2105        case KEY_CTRL_END: bottom(ed, ed->selecting); break;
2106
2107#if SHIFT_SELECT
2108        case KEY_SHIFT_UP: up(ed, 1); break;
2109        case KEY_SHIFT_DOWN: down(ed, 1); break;
2110        case KEY_SHIFT_LEFT: left(ed, 1); break;
2111        case KEY_SHIFT_RIGHT: right(ed, 1); break;
2112        case KEY_SHIFT_PGUP: pageup(ed, 1); break;
2113        case KEY_SHIFT_PGDN: pagedown(ed, 1); break;
2114        case KEY_SHIFT_HOME: home(ed, 1); break;
2115        case KEY_SHIFT_END: end(ed, 1); break;
2116
2117        case KEY_SHIFT_CTRL_RIGHT: wordright(ed, 1); break;
2118        case KEY_SHIFT_CTRL_LEFT: wordleft(ed, 1); break;
2119        case KEY_SHIFT_CTRL_HOME: top(ed, 1); break;
2120        case KEY_SHIFT_CTRL_END: bottom(ed, 1); break;
2121#endif
2122
2123        case KEY_CTRL_TAB: ed = next_file(ed); break;
2124
2125        case ctrl('e'): select_toggle(ed); break;
2126        case ctrl('a'): select_all(ed); break;
2127        case ctrl('c'): copy_selection(ed); break;
2128        case ctrl('f'): find_text(ed, 0); break;
2129        case ctrl('l'): goto_line(ed); break;
2130        case ctrl('g'): find_text(ed, 1); break;
2131        case ctrl('q'): done = 1; break;
2132#ifdef LESS
2133        case KEY_ESC: done = 1; break;
2134#else
2135        case KEY_TAB: indent(ed, (unsigned char*) INDENT); break;
2136        case KEY_SHIFT_TAB: unindent(ed, (unsigned char*) INDENT); break;
2137
2138        case KEY_ENTER: newline(ed); break;
2139        case KEY_BACKSPACE: backspace(ed); break;
2140        case KEY_DEL: del(ed); break;
2141        case ctrl('x'): cut_selection(ed); break;
2142        case ctrl('z'): undo(ed); break;
2143        case ctrl('r'): redo(ed); break;
2144        case ctrl('v'): paste_selection(ed); break;
2145        case ctrl('o'): open_editor(ed); ed = ed->env->current; break;
2146        case ctrl('n'): new_editor(ed); ed = ed->env->current; break;
2147        case ctrl('s'): save_editor(ed); break;
2148        case ctrl('p'): pipe_command(ed); break;
2149#endif
2150#if defined(__rtems__)
2151        /*
2152         * Coverity spotted this as using ed after free() so changing
2153         * the order of the statements.
2154         */
2155        case ctrl('w'): ed = ed->env->current; close_editor(ed); break;
2156#else
2157        case ctrl('w'): close_editor(ed); ed = ed->env->current; break;
2158#endif
2159      }
2160    }
2161  }
2162}
2163
2164//
2165// main
2166//
2167static int rtems_shell_main_edit(int argc, char *argv[])
2168{
2169  struct env env;
2170  int rc;
2171  int i;
2172  sigset_t blocked_sigmask, orig_sigmask;
2173#if defined(__linux__)
2174  struct termios tio;
2175#endif
2176#if defined(__linux__) || defined(__rtems__)
2177  struct termios orig_tio;
2178#endif
2179#ifdef SANOS
2180  struct term *term;
2181#endif
2182
2183  memset(&env, 0, sizeof(env));
2184  for (i = 1; i < argc; i++) {
2185    struct editor *ed = create_editor(&env);
2186    rc = load_file(ed, argv[i]);
2187    if (rc < 0 && errno == ENOENT) rc = new_file(ed, argv[i]);
2188    if (rc < 0) {
2189      perror(argv[i]);
2190      return 0;
2191    }
2192  }
2193  if (env.current == NULL) {
2194    struct editor *ed = create_editor(&env);
2195    if (isatty(fileno(stdin))) {
2196      new_file(ed, "");
2197    } else {
2198      read_from_stdin(ed);
2199    }
2200  }
2201  env.current = env.current->next;
2202
2203#ifdef SANOS
2204  term = gettib()->proc->term;
2205  if (fdin != term->ttyin) dup2(term->ttyin, fdin);
2206  if (fdout != term->ttyout) dup2(term->ttyout, fdout);
2207#elif !defined(__rtems__)
2208  if (!isatty(fileno(stdin))) {
2209    if (!freopen("/dev/tty", "r", stdin)) perror("/dev/tty");
2210  }
2211#endif
2212
2213  setvbuf(stdout, NULL, 0, 8192);
2214
2215#if defined(__linux__) || defined(__rtems__)
2216  (void) tcgetattr(0, &orig_tio);
2217#if !defined(__rtems__)
2218  cfmakeraw(&tio);
2219  tcsetattr(0, TCSANOW, &tio);
2220#endif
2221  if (getenv("TERM") && strcmp(getenv("TERM"), "linux") == 0) {
2222    linux_console = 1;
2223  } else {
2224    outstr(CLRSCR);
2225    outstr("\033[3 q");  // xterm
2226    outstr("\033]50;CursorShape=2\a");  // KDE
2227  }
2228#endif
2229
2230  get_console_size(&env);
2231
2232  sigemptyset(&blocked_sigmask);
2233  sigaddset(&blocked_sigmask, SIGINT);
2234  sigaddset(&blocked_sigmask, SIGTSTP);
2235  sigaddset(&blocked_sigmask, SIGABRT);
2236  sigprocmask(SIG_BLOCK, &blocked_sigmask, &orig_sigmask);
2237
2238  for (;;) {
2239    if (!env.current) break;
2240    edit(env.current);
2241    if (quit(&env)) break;
2242  }
2243
2244  gotoxy(0, env.lines + 1);
2245  outstr(RESET_COLOR CLREOL);
2246#if defined(__linux__) || defined(__rtems__)
2247  tcsetattr(0, TCSANOW, &orig_tio);
2248#endif
2249
2250  while (env.current) delete_editor(env.current);
2251
2252  if (env.clipboard) free(env.clipboard);
2253  if (env.search) free(env.search);
2254  if (env.linebuf) free(env.linebuf);
2255
2256  setbuf(stdout, NULL);
2257  sigprocmask(SIG_SETMASK, &orig_sigmask, NULL);
2258
2259  return 0;
2260}
2261
2262rtems_shell_cmd_t rtems_shell_EDIT_Command = {
2263  "edit",                /* name */
2264  "edit [file ...]",     /* usage */
2265  "files",               /* topic */
2266  rtems_shell_main_edit, /* command */
2267  NULL,                  /* alias */
2268  NULL                   /* next */
2269};
Note: See TracBrowser for help on using the repository browser.