source: rtems/cpukit/libmisc/shell/main_edit.c @ 3bd0cd1

4.115
Last change on this file since 3bd0cd1 was 3bd0cd1, checked in by Joel Sherrill <joel.sherrill@…>, on 11/24/14 at 19:54:26

main_edit.c: Do not reference beyond end of array

  • Property mode set to 100644
File size: 56.2 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#if defined(__rtems__)
819  } if (key_history_in > sizeof(key_history)) {
820    /* eliminate possibility of using index above array bounds */
821   assert( key_history_in > sizeof(key_history));
822#endif
823  } else {
824    memmove(&key_history[0], &key_history[1], sizeof(key_history) - sizeof(key_history[0]));
825    key_history[key_history_in - 1] = ch;
826  }
827#endif
828  return ch;
829}
830
831static int getkey(void) {
832  int ch, shift, ctrl;
833
834  ch = getachar();
835  if (ch < 0) return ch;
836
837  switch (ch) {
838    case 0x08: return KEY_BACKSPACE;
839    case 0x09:
840      get_modifier_keys(&shift, &ctrl);
841      if (shift) return KEY_SHIFT_TAB;
842      if (ctrl) return KEY_CTRL_TAB;
843      return KEY_TAB;
844#ifdef SANOS
845    case 0x0D: return gettib()->proc->term->type == TERM_CONSOLE ? KEY_ENTER : KEY_UNKNOWN;
846    case 0x0A: return gettib()->proc->term->type != TERM_CONSOLE ? KEY_ENTER : KEY_UNKNOWN;
847#else
848    case 0x0D: return KEY_ENTER;
849    case 0x0A: return KEY_ENTER;
850#endif
851    case 0x1B:
852      ch = getachar();
853      switch (ch) {
854        case 0x1B: return KEY_ESC;
855        case 0x4F:
856          ch = getachar();
857          switch (ch) {
858            case 0x46: return KEY_END;
859            case 0x48: return KEY_HOME;
860            case 0x50: return KEY_F1;
861            case 0x51: return KEY_F2;
862            case 0x52: return KEY_F3;
863            case 0x53: return KEY_F4;
864            case 0x54: return KEY_F5;
865            default: return KEY_UNKNOWN;
866          }
867          break;
868
869        case 0x5B:
870          get_modifier_keys(&shift, &ctrl);
871          ch = getachar();
872          if (ch == 0x31) {
873            ch = getachar();
874            switch (ch) {
875              case 0x35:
876                return getachar() == 0x7E ? KEY_F5 : KEY_UNKNOWN;
877              case 0x37:
878                return getachar() == 0x7E ? KEY_F6 : KEY_UNKNOWN;
879              case 0x3B:
880                ch = getachar();
881                if (ch == 0x7E) return KEY_F7;
882                if (ch == 0x32) shift = 1;
883                if (ch == 0x35) ctrl = 1;
884                if (ch == 0x36) shift = ctrl = 1;
885                ch = getachar();
886                break;
887              case 0x39:
888                return getachar() == 0x7E ? KEY_F8 : KEY_UNKNOWN;
889              case 0x7E:
890                if (shift && ctrl) return KEY_SHIFT_CTRL_HOME;
891                if (shift) return KEY_SHIFT_HOME;
892                if (ctrl) return KEY_CTRL_HOME;
893                return KEY_HOME;
894              default:
895                return KEY_UNKNOWN;
896            }
897          }
898
899          switch (ch) {
900            case 0x31:
901              ch = getachar();
902              if (ch != 0x7E) return KEY_UNKNOWN;
903              if (shift && ctrl) return KEY_SHIFT_CTRL_HOME;
904              if (shift) return KEY_SHIFT_HOME;
905              if (ctrl) return KEY_CTRL_HOME;
906              return KEY_HOME;
907            case 0x32:
908              ch = getachar();
909              switch (ch) {
910                case 0x30: ch = getachar(); return KEY_F9;
911                case 0x31: ch = getachar(); return KEY_F10;
912                case 0x7E: return KEY_INS;
913                default: break;
914              }
915              return KEY_UNKNOWN;
916            case 0x33: return getachar() == 0x7E ? KEY_DEL : KEY_UNKNOWN;
917            case 0x34:
918              if (getachar() != 0x7E) return KEY_UNKNOWN;
919              if (shift && ctrl) return KEY_SHIFT_CTRL_END;
920              if (shift) return KEY_SHIFT_END;
921              if (ctrl) return KEY_CTRL_END;
922              return KEY_END;
923            case 0x35:
924              if (getachar() != 0x7E) return KEY_UNKNOWN;
925              if (shift) return KEY_SHIFT_PGUP;
926              return KEY_PGUP;
927            case 0x36:
928              if (getachar() != 0x7E) return KEY_UNKNOWN;
929              if (shift) return KEY_SHIFT_PGDN;
930              return KEY_PGDN;
931            case 0x41:
932              if (shift && ctrl) return KEY_SHIFT_CTRL_UP;
933              if (shift) return KEY_SHIFT_UP;
934              if (ctrl) return KEY_CTRL_UP;
935              return KEY_UP;
936            case 0x42:
937              if (shift && ctrl) return KEY_SHIFT_CTRL_DOWN;
938              if (shift) return KEY_SHIFT_DOWN;
939              if (ctrl) return KEY_CTRL_DOWN;
940              return KEY_DOWN;
941            case 0x43:
942              if (shift && ctrl) return KEY_SHIFT_CTRL_RIGHT;
943              if (shift) return KEY_SHIFT_RIGHT;
944              if (ctrl) return KEY_CTRL_RIGHT;
945              return KEY_RIGHT;
946            case 0x44:
947              if (shift && ctrl) return KEY_SHIFT_CTRL_LEFT;
948              if (shift) return KEY_SHIFT_LEFT;
949              if (ctrl) return KEY_CTRL_LEFT;
950              return KEY_LEFT;
951            case 0x46:
952              if (shift && ctrl) return KEY_SHIFT_CTRL_END;
953              if (shift) return KEY_SHIFT_END;
954              if (ctrl) return KEY_CTRL_END;
955              return KEY_END;
956            case 0x48:
957              if (shift && ctrl) return KEY_SHIFT_CTRL_HOME;
958              if (shift) return KEY_SHIFT_HOME;
959              if (ctrl) return KEY_CTRL_HOME;
960              return KEY_HOME;
961            case 0x5A:
962              return KEY_SHIFT_TAB;
963            case 0x5B:
964              ch = getachar();
965              switch (ch) {
966                case 0x41: return KEY_F1;
967                case 0x43: return KEY_F3;
968                case 0x45: return KEY_F5;
969              }
970              return KEY_UNKNOWN;
971
972            default: return KEY_UNKNOWN;
973          }
974          break;
975
976        default: return KEY_UNKNOWN;
977      }
978      break;
979
980    case 0x00:
981    case 0xE0:
982      ch = getachar();
983      switch (ch) {
984        case 0x0F: return KEY_SHIFT_TAB;
985        case 0x3B: return KEY_F1;
986        case 0x3D: return KEY_F3;
987        case 0x3F: return KEY_F5;
988        case 0x47: return KEY_HOME;
989        case 0x48: return KEY_UP;
990        case 0x49: return KEY_PGUP;
991        case 0x4B: return KEY_LEFT;
992        case 0x4D: return KEY_RIGHT;
993        case 0x4F: return KEY_END;
994        case 0x50: return KEY_DOWN;
995        case 0x51: return KEY_PGDN;
996        case 0x52: return KEY_INS;
997        case 0x53: return KEY_DEL;
998        case 0x73: return KEY_CTRL_LEFT;
999        case 0x74: return KEY_CTRL_RIGHT;
1000        case 0x75: return KEY_CTRL_END;
1001        case 0x77: return KEY_CTRL_HOME;
1002        case 0x8D: return KEY_CTRL_UP;
1003        case 0x91: return KEY_CTRL_DOWN;
1004        case 0x94: return KEY_CTRL_TAB;
1005        case 0xB8: return KEY_SHIFT_UP;
1006        case 0xB7: return KEY_SHIFT_HOME;
1007        case 0xBF: return KEY_SHIFT_END;
1008        case 0xB9: return KEY_SHIFT_PGUP;
1009        case 0xBB: return KEY_SHIFT_LEFT;
1010        case 0xBD: return KEY_SHIFT_RIGHT;
1011        case 0xC0: return KEY_SHIFT_DOWN;
1012        case 0xC1: return KEY_SHIFT_PGDN;
1013        case 0xDB: return KEY_SHIFT_CTRL_LEFT;
1014        case 0xDD: return KEY_SHIFT_CTRL_RIGHT;
1015        case 0xD8: return KEY_SHIFT_CTRL_UP;
1016        case 0xE0: return KEY_SHIFT_CTRL_DOWN;
1017        case 0xD7: return KEY_SHIFT_CTRL_HOME;
1018        case 0xDF: return KEY_SHIFT_CTRL_END;
1019
1020        default: return KEY_UNKNOWN;
1021      }
1022      break;
1023
1024    case 0x7F: return KEY_BACKSPACE;
1025
1026    default: return ch;
1027  }
1028}
1029
1030static int prompt(struct editor *ed, char *msg, int selection) {
1031  int maxlen, len, ch;
1032  char *buf = (char*) ed->env->linebuf;
1033
1034  gotoxy(0, ed->env->lines);
1035  outstr(STATUS_COLOR);
1036  outstr(msg);
1037  outstr(CLREOL);
1038
1039  len = 0;
1040  maxlen = ed->env->cols - strlen(msg) - 1;
1041  if (selection) {
1042    len = get_selected_text(ed, buf, maxlen);
1043    outbuf((unsigned char*) buf, len);
1044  }
1045
1046  for (;;) {
1047    fflush(stdout);
1048    ch = getkey();
1049    if (ch == KEY_ESC) {
1050      return 0;
1051    } else if (ch == KEY_ENTER) {
1052      buf[len] = 0;
1053      return len > 0;
1054    } else if (ch == KEY_BACKSPACE) {
1055      if (len > 0) {
1056        outstr("\b \b");
1057        len--;
1058      }
1059    } else if (ch >= ' ' && ch < 0x100 && len < maxlen) {
1060      outch(ch);
1061      buf[len++] = ch;
1062    }
1063  }
1064}
1065
1066static int ask(void) {
1067  int ch = getachar();
1068  return ch == 'y' || ch == 'Y';
1069}
1070
1071//
1072// Display functions
1073//
1074
1075static void display_message(struct editor *ed, char *fmt, ...) {
1076  va_list args;
1077
1078  va_start(args, fmt);
1079  gotoxy(0, ed->env->lines);
1080  outstr(STATUS_COLOR);
1081  vprintf(fmt, args);
1082  outstr(CLREOL TEXT_COLOR);
1083  fflush(stdout);
1084  va_end(args);
1085}
1086
1087static void draw_full_statusline(struct editor *ed) {
1088  struct env *env = ed->env;
1089  int namewidth = env->cols - 29;
1090  gotoxy(0, env->lines);
1091  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);
1092  outstr((char*) env->linebuf);
1093}
1094
1095static void draw_statusline(struct editor *ed) {
1096  gotoxy(ed->env->cols - 20, ed->env->lines);
1097  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);
1098  outstr((char*) ed->env->linebuf);
1099}
1100
1101static void display_line(struct editor *ed, int pos, int fullline) {
1102  int hilite = 0;
1103  int col = 0;
1104  int margin = ed->margin;
1105  int maxcol = ed->env->cols + margin;
1106  unsigned char *bufptr = ed->env->linebuf;
1107  unsigned char *p = text_ptr(ed, pos);
1108  int selstart, selend, ch;
1109  char *s;
1110
1111  get_selection(ed, &selstart, &selend);
1112  while (col < maxcol) {
1113    if (margin == 0) {
1114      if (!hilite && pos >= selstart && pos < selend) {
1115        for (s = SELECT_COLOR; *s; s++) *bufptr++ = *s;
1116        hilite = 1;
1117      } else if (hilite && pos >= selend) {
1118        for (s = TEXT_COLOR; *s; s++) *bufptr++ = *s;
1119        hilite = 0;
1120      }
1121    }
1122
1123    if (p == ed->end) break;
1124    ch = *p;
1125    if (ch == '\r' || ch == '\n') break;
1126
1127    if (ch == '\t') {
1128      int spaces = TABSIZE - col % TABSIZE;
1129      while (spaces > 0 && col < maxcol) {
1130        if (margin > 0) {
1131          margin--;
1132        } else {
1133          *bufptr++ = ' ';
1134        }
1135        col++;
1136        spaces--;
1137      }
1138    } else {
1139      if (margin > 0) {
1140        margin--;
1141      } else {
1142        *bufptr++ = ch;
1143      }
1144      col++;
1145    }
1146
1147    if (++p == ed->gap) p = ed->rest;
1148    pos++;
1149  }
1150
1151#if defined(__linux__)
1152  if (hilite) {
1153    while (col < maxcol) {
1154      *bufptr++ = ' ';
1155      col++;
1156    }
1157  } else {
1158    if (col == margin) *bufptr++ = ' ';
1159  }
1160#endif
1161
1162  if (col < maxcol) {
1163    for (s = CLREOL; *s; s++) *bufptr++ = *s;
1164    if (fullline) {
1165      memcpy(bufptr, "\r\n", 2);
1166      bufptr += 2;
1167    }
1168  }
1169
1170  if (hilite) {
1171    for (s = TEXT_COLOR; *s; s++) *bufptr++ = *s;
1172  }
1173
1174  outbuf(ed->env->linebuf, bufptr - ed->env->linebuf);
1175}
1176
1177static void update_line(struct editor *ed) {
1178  gotoxy(0, ed->line - ed->topline);
1179  display_line(ed, ed->linepos, 0);
1180}
1181
1182static void draw_screen(struct editor *ed) {
1183  int pos;
1184  int i;
1185
1186  gotoxy(0, 0);
1187  outstr(TEXT_COLOR);
1188  pos = ed->toppos;
1189  for (i = 0; i < ed->env->lines; i++) {
1190    if (pos < 0) {
1191      outstr(CLREOL "\r\n");
1192    } else {
1193      display_line(ed, pos, 1);
1194      pos = next_line(ed, pos);
1195    }
1196  }
1197}
1198
1199static void position_cursor(struct editor *ed) {
1200  int col = column(ed, ed->linepos, ed->col);
1201  gotoxy(col - ed->margin, ed->line - ed->topline);
1202}
1203
1204//
1205// Cursor movement
1206//
1207
1208static void adjust(struct editor *ed) {
1209  int col;
1210  int ll = line_length(ed, ed->linepos);
1211  ed->col = ed->lastcol;
1212  if (ed->col > ll) ed->col = ll;
1213
1214  col = column(ed, ed->linepos, ed->col);
1215  while (col < ed->margin) {
1216    ed->margin -= 4;
1217    if (ed->margin < 0) ed->margin = 0;
1218    ed->refresh = 1;
1219  }
1220
1221  while (col - ed->margin >= ed->env->cols) {
1222    ed->margin += 4;
1223    ed->refresh = 1;
1224  }
1225}
1226
1227static void select_toggle(struct editor *ed) {
1228  ed->selecting = ed->selecting ? 0 : 1;
1229  update_selection(ed, ed->selecting);
1230  adjust(ed);
1231}
1232
1233static void up(struct editor *ed, int select) {
1234  int newpos;
1235
1236  update_selection(ed, select);
1237
1238  newpos = prev_line(ed, ed->linepos);
1239  if (newpos < 0) return;
1240
1241  ed->linepos = newpos;
1242  ed->line--;
1243  if (ed->line < ed->topline) {
1244    ed->toppos = ed->linepos;
1245    ed->topline = ed->line;
1246    ed->refresh = 1;
1247  }
1248
1249  adjust(ed);
1250}
1251
1252static void down(struct editor *ed, int select) {
1253  int newpos;
1254
1255  update_selection(ed, select);
1256
1257  newpos = next_line(ed, ed->linepos);
1258  if (newpos < 0) return;
1259
1260  ed->linepos = newpos;
1261  ed->line++;
1262
1263  if (ed->line >= ed->topline + ed->env->lines) {
1264    ed->toppos = next_line(ed, ed->toppos);
1265    ed->topline++;
1266    ed->refresh = 1;
1267  }
1268
1269  adjust(ed);
1270}
1271
1272static void left(struct editor *ed, int select) {
1273  update_selection(ed, select);
1274  if (ed->col > 0) {
1275    ed->col--;
1276  } else {
1277    int newpos = prev_line(ed, ed->linepos);
1278    if (newpos < 0) return;
1279
1280    ed->col = line_length(ed, newpos);
1281    ed->linepos = newpos;
1282    ed->line--;
1283    if (ed->line < ed->topline) {
1284      ed->toppos = ed->linepos;
1285      ed->topline = ed->line;
1286      ed->refresh = 1;
1287    }
1288  }
1289
1290  ed->lastcol = ed->col;
1291  adjust(ed);
1292}
1293
1294static void right(struct editor *ed, int select) {
1295  update_selection(ed, select);
1296  if (ed->col < line_length(ed, ed->linepos)) {
1297    ed->col++;
1298  } else {
1299    int newpos = next_line(ed, ed->linepos);
1300    if (newpos < 0) return;
1301
1302    ed->col = 0;
1303    ed->linepos = newpos;
1304    ed->line++;
1305
1306    if (ed->line >= ed->topline + ed->env->lines) {
1307      ed->toppos = next_line(ed, ed->toppos);
1308      ed->topline++;
1309      ed->refresh = 1;
1310    }
1311  }
1312
1313  ed->lastcol = ed->col;
1314  adjust(ed);
1315}
1316
1317static int wordchar(int ch) {
1318  return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9');
1319}
1320
1321static void wordleft(struct editor *ed, int select) {
1322  int pos, phase;
1323
1324  update_selection(ed, select);
1325  pos = ed->linepos + ed->col;
1326  phase = 0;
1327  while (pos > 0) {
1328    int ch = get(ed, pos - 1);
1329    if (phase == 0) {
1330      if (wordchar(ch)) phase = 1;
1331    } else {
1332      if (!wordchar(ch)) break;
1333    }
1334
1335    pos--;
1336    if (pos < ed->linepos) {
1337      ed->linepos = prev_line(ed, ed->linepos);
1338      ed->line--;
1339      ed->refresh = 1;
1340    }
1341  }
1342  ed->col = pos - ed->linepos;
1343  if (ed->line < ed->topline) {
1344    ed->toppos = ed->linepos;
1345    ed->topline = ed->line;
1346  }
1347
1348  ed->lastcol = ed->col;
1349  adjust(ed);
1350}
1351
1352static void wordright(struct editor *ed, int select) {
1353  int pos, end, phase, next;
1354
1355  update_selection(ed, select);
1356  pos = ed->linepos + ed->col;
1357  end = text_length(ed);
1358  next = next_line(ed, ed->linepos);
1359  phase = 0;
1360  while (pos < end) {
1361    int ch = get(ed, pos);
1362    if (phase == 0) {
1363      if (wordchar(ch)) phase = 1;
1364    } else {
1365      if (!wordchar(ch)) break;
1366    }
1367
1368    pos++;
1369    if (pos == next) {
1370      ed->linepos = next;
1371      next = next_line(ed, ed->linepos);
1372      ed->line++;
1373      ed->refresh = 1;
1374    }
1375  }
1376  ed->col = pos - ed->linepos;
1377  if (ed->line >= ed->topline + ed->env->lines) {
1378    ed->toppos = next_line(ed, ed->toppos);
1379    ed->topline++;
1380  }
1381
1382  ed->lastcol = ed->col;
1383  adjust(ed);
1384}
1385
1386static void home(struct editor *ed, int select) {
1387  update_selection(ed, select);
1388  ed->col = ed->lastcol = 0;
1389  adjust(ed);
1390}
1391
1392static void end(struct editor *ed, int select) {
1393  update_selection(ed, select);
1394  ed->col = ed->lastcol = line_length(ed, ed->linepos);
1395  adjust(ed);
1396}
1397
1398static void top(struct editor *ed, int select) {
1399  update_selection(ed, select);
1400  ed->toppos = ed->topline = ed->margin = 0;
1401  ed->linepos = ed->line = ed->col = ed->lastcol = 0;
1402  ed->refresh = 1;
1403}
1404
1405static void bottom(struct editor *ed, int select) {
1406  update_selection(ed, select);
1407  for (;;) {
1408    int newpos = next_line(ed, ed->linepos);
1409    if (newpos < 0) break;
1410
1411    ed->linepos = newpos;
1412    ed->line++;
1413
1414    if (ed->line >= ed->topline + ed->env->lines) {
1415      ed->toppos = next_line(ed, ed->toppos);
1416      ed->topline++;
1417      ed->refresh = 1;
1418    }
1419  }
1420  ed->col = ed->lastcol = line_length(ed, ed->linepos);
1421  adjust(ed);
1422}
1423
1424static void pageup(struct editor *ed, int select) {
1425  int i;
1426
1427  update_selection(ed, select);
1428  if (ed->line < ed->env->lines) {
1429    ed->linepos = ed->toppos = 0;
1430    ed->line = ed->topline = 0;
1431  } else {
1432    for (i = 0; i < ed->env->lines; i++) {
1433      int newpos = prev_line(ed, ed->linepos);
1434      if (newpos < 0) return;
1435
1436      ed->linepos = newpos;
1437      ed->line--;
1438
1439      if (ed->topline > 0) {
1440        ed->toppos = prev_line(ed, ed->toppos);
1441        ed->topline--;
1442      }
1443    }
1444  }
1445
1446  ed->refresh = 1;
1447  adjust(ed);
1448}
1449
1450static void pagedown(struct editor *ed, int select) {
1451  int i;
1452
1453  update_selection(ed, select);
1454  for (i = 0; i < ed->env->lines; i++) {
1455    int newpos = next_line(ed, ed->linepos);
1456    if (newpos < 0) break;
1457
1458    ed->linepos = newpos;
1459    ed->line++;
1460
1461    ed->toppos = next_line(ed, ed->toppos);
1462    ed->topline++;
1463  }
1464
1465  ed->refresh = 1;
1466  adjust(ed);
1467}
1468
1469//
1470// Text editing
1471//
1472
1473static void insert_char(struct editor *ed, unsigned char ch) {
1474  erase_selection(ed);
1475  insert(ed, ed->linepos + ed->col, &ch, 1);
1476  ed->col++;
1477  ed->lastcol = ed->col;
1478  adjust(ed);
1479  if (!ed->refresh) ed->lineupdate = 1;
1480}
1481
1482static void newline(struct editor *ed) {
1483  int p;
1484  unsigned char ch;
1485
1486  erase_selection(ed);
1487#if defined(__linux__) || defined(__rtems__)
1488  insert(ed, ed->linepos + ed->col, (unsigned char*) "\n", 1);
1489#else
1490  insert(ed, ed->linepos + ed->col, "\r\n", 2);
1491#endif
1492  ed->col = ed->lastcol = 0;
1493  ed->line++;
1494  p = ed->linepos;
1495  ed->linepos = next_line(ed, ed->linepos);
1496  for (;;) {
1497    ch = get(ed, p++);
1498    if (ch == ' ' || ch == '\t') {
1499      insert(ed, ed->linepos + ed->col, &ch, 1);
1500      ed->col++;
1501    } else {
1502      break;
1503    }
1504  }
1505  ed->lastcol = ed->col;
1506
1507  ed->refresh = 1;
1508
1509  if (ed->line >= ed->topline + ed->env->lines) {
1510    ed->toppos = next_line(ed, ed->toppos);
1511    ed->topline++;
1512    ed->refresh = 1;
1513  }
1514
1515  adjust(ed);
1516}
1517
1518static void backspace(struct editor *ed) {
1519  if (erase_selection(ed)) return;
1520  if (ed->linepos + ed->col == 0) return;
1521  if (ed->col == 0) {
1522    int pos = ed->linepos;
1523    erase(ed, --pos, 1);
1524    if (get(ed, pos - 1) == '\r') erase(ed, --pos, 1);
1525
1526    ed->line--;
1527    ed->linepos = line_start(ed, pos);
1528    ed->col = pos - ed->linepos;
1529    ed->refresh = 1;
1530
1531    if (ed->line < ed->topline) {
1532      ed->toppos = ed->linepos;
1533      ed->topline = ed->line;
1534    }
1535  } else {
1536    ed->col--;
1537    erase(ed, ed->linepos + ed->col, 1);
1538    ed->lineupdate = 1;
1539  }
1540
1541  ed->lastcol = ed->col;
1542  adjust(ed);
1543}
1544
1545static void del(struct editor *ed) {
1546  int pos, ch;
1547
1548  if (erase_selection(ed)) return;
1549  pos = ed->linepos + ed->col;
1550  ch = get(ed, pos);
1551  if (ch < 0) return;
1552
1553  erase(ed, pos, 1);
1554  if (ch == '\r') {
1555    ch = get(ed, pos);
1556    if (ch == '\n') erase(ed, pos, 1);
1557  }
1558
1559  if (ch == '\n') {
1560    ed->refresh = 1;
1561  } else {
1562    ed->lineupdate = 1;
1563  }
1564}
1565
1566static void indent(struct editor *ed, unsigned char *indentation) {
1567  int start, end, i, lines, toplines, newline, ch;
1568  unsigned char *buffer, *p;
1569  int buflen;
1570  int width = strlen((const char*) indentation);
1571  int pos = ed->linepos + ed->col;
1572
1573  if (!get_selection(ed, &start, &end)) {
1574    insert_char(ed, '\t');
1575    return;
1576  }
1577
1578  lines = 0;
1579  toplines = 0;
1580  newline = 1;
1581  for (i = start; i < end; i++) {
1582    if (i == ed->toppos) toplines = lines;
1583    if (newline) {
1584      lines++;
1585      newline = 0;
1586    }
1587    if (get(ed, i) == '\n') newline = 1;
1588  }
1589  buflen = end - start + lines * width;
1590  buffer = malloc(buflen);
1591  if (!buffer) return;
1592
1593  newline = 1;
1594  p = buffer;
1595  for (i = start; i < end; i++) {
1596    if (newline) {
1597      memcpy(p, indentation, width);
1598      p += width;
1599      newline = 0;
1600    }
1601    ch = get(ed, i);
1602    *p++ = ch;
1603    if (ch == '\n') newline = 1;
1604  }
1605
1606  replace(ed, start, end - start, buffer, buflen, 1);
1607  free(buffer);
1608
1609  if (ed->anchor < pos) {
1610    pos += width * lines;
1611  } else {
1612    ed->anchor += width * lines;
1613  }
1614
1615  ed->toppos += width * toplines;
1616  ed->linepos = line_start(ed, pos);
1617  ed->col = ed->lastcol = pos - ed->linepos;
1618
1619  adjust(ed);
1620  ed->refresh = 1;
1621}
1622
1623static void unindent(struct editor *ed, unsigned char *indentation) {
1624  int start, end, i, newline, ch, shrinkage, topofs;
1625  unsigned char *buffer, *p;
1626  int width = strlen((const char*) indentation);
1627  int pos = ed->linepos + ed->col;
1628
1629  if (!get_selection(ed, &start, &end)) return;
1630
1631  buffer = malloc(end - start);
1632  if (!buffer) return;
1633
1634  newline = 1;
1635  p = buffer;
1636  i = start;
1637  shrinkage = 0;
1638  topofs = 0;
1639  while (i < end) {
1640    if (newline) {
1641      newline = 0;
1642      if (compare(ed, indentation, i, width)) {
1643        i += width;
1644        shrinkage += width;
1645        if (i < ed->toppos) topofs -= width;
1646        continue;
1647      }
1648    }
1649    ch = get(ed, i++);
1650    *p++ = ch;
1651    if (ch == '\n') newline = 1;
1652  }
1653
1654  if (!shrinkage) {
1655    free(buffer);
1656    return;
1657  }
1658
1659  replace(ed, start, end - start, buffer, p - buffer, 1);
1660  free(buffer);
1661
1662  if (ed->anchor < pos) {
1663    pos -= shrinkage;
1664  } else {
1665    ed->anchor -= shrinkage;
1666  }
1667
1668  ed->toppos += topofs;
1669  ed->linepos = line_start(ed, pos);
1670  ed->col = ed->lastcol = pos - ed->linepos;
1671
1672  ed->refresh = 1;
1673  adjust(ed);
1674}
1675
1676static void undo(struct editor *ed) {
1677  if (!ed->undo) return;
1678  moveto(ed, ed->undo->pos, 0);
1679  replace(ed, ed->undo->pos, ed->undo->inserted, ed->undo->undobuf, ed->undo->erased, 0);
1680  ed->undo = ed->undo->prev;
1681  if (!ed->undo) ed->dirty = 0;
1682  ed->anchor = -1;
1683  ed->lastcol = ed->col;
1684  ed->refresh = 1;
1685}
1686
1687static void redo(struct editor *ed) {
1688  if (ed->undo) {
1689    if (!ed->undo->next) return;
1690    ed->undo = ed->undo->next;
1691  } else {
1692    if (!ed->undohead) return;
1693    ed->undo = ed->undohead;
1694  }
1695  replace(ed, ed->undo->pos, ed->undo->erased, ed->undo->redobuf, ed->undo->inserted, 0);
1696  moveto(ed, ed->undo->pos, 0);
1697  ed->dirty = 1;
1698  ed->anchor = -1;
1699  ed->lastcol = ed->col;
1700  ed->refresh = 1;
1701}
1702
1703//
1704// Clipboard
1705//
1706
1707static void copy_selection(struct editor *ed) {
1708  int selstart, selend;
1709
1710  if (!get_selection(ed, &selstart, &selend)) return;
1711  ed->env->clipsize = selend - selstart;
1712  ed->env->clipboard = (unsigned char *) realloc(ed->env->clipboard, ed->env->clipsize);
1713  if (!ed->env->clipboard) return;
1714  copy(ed, ed->env->clipboard, selstart, ed->env->clipsize);
1715  select_toggle(ed);
1716}
1717
1718static void cut_selection(struct editor *ed) {
1719  copy_selection(ed);
1720  erase_selection(ed);
1721  select_toggle(ed);
1722}
1723
1724static void paste_selection(struct editor *ed) {
1725  erase_selection(ed);
1726  insert(ed, ed->linepos + ed->col, ed->env->clipboard, ed->env->clipsize);
1727  moveto(ed, ed->linepos + ed->col + ed->env->clipsize, 0);
1728  ed->refresh = 1;
1729}
1730
1731//
1732// Editor Commands
1733//
1734
1735static void open_editor(struct editor *ed) {
1736  int rc;
1737  char *filename;
1738  struct env *env = ed->env;
1739
1740  if (!prompt(ed, "Open file: ", 1)) {
1741    ed->refresh = 1;
1742    return;
1743  }
1744  filename = (char*) ed->env->linebuf;
1745
1746  ed = find_editor(ed->env, filename);
1747  if (ed) {
1748    env->current = ed;
1749  } else {
1750    ed = create_editor(env);
1751    rc = load_file(ed, filename);
1752    if (rc < 0) {
1753      display_message(ed, "Error %d opening %s (%s)", errno, filename, strerror(errno));
1754      sleep(5);
1755      delete_editor(ed);
1756      ed = env->current;
1757    }
1758  }
1759  ed->refresh = 1;
1760}
1761
1762static void new_editor(struct editor *ed) {
1763  ed = create_editor(ed->env);
1764  new_file(ed, "");
1765  ed->refresh = 1;
1766}
1767
1768static void read_from_stdin(struct editor *ed) {
1769  char buffer[512];
1770  int n, pos;
1771
1772  pos = 0;
1773  while ((n = fread(buffer, 1, sizeof(buffer), stdin)) > 0) {
1774    insert(ed, pos, (unsigned char*) buffer, n);
1775    pos += n;
1776  }
1777  strcpy(ed->filename, "<stdin>");
1778  ed->newfile = 1;
1779  ed->dirty = 0;
1780}
1781
1782static void save_editor(struct editor *ed) {
1783  int rc;
1784
1785  if (!ed->dirty && !ed->newfile) return;
1786
1787  if (ed->newfile) {
1788    if (!prompt(ed, "Save as: ", 1)) {
1789      ed->refresh = 1;
1790      return;
1791    }
1792
1793    if (access((const char*) ed->env->linebuf, F_OK) == 0) {
1794      display_message(ed, "Overwrite %s (y/n)? ", ed->env->linebuf);
1795      if (!ask()) {
1796        ed->refresh = 1;
1797        return;
1798      }
1799    }
1800    strcpy(ed->filename, (const char*) ed->env->linebuf);
1801    ed->newfile = 0;
1802  }
1803
1804  rc = save_file(ed);
1805  if (rc < 0) {
1806    display_message(ed, "Error %d saving document (%s)", errno, strerror(errno));
1807    sleep(5);
1808  }
1809
1810  ed->refresh = 1;
1811}
1812
1813static void close_editor(struct editor *ed) {
1814  struct env *env = ed->env;
1815
1816  if (ed->dirty) {
1817    display_message(ed, "Close %s without saving changes (y/n)? ", ed->filename);
1818    if (!ask()) {
1819      ed->refresh = 1;
1820      return;
1821    }
1822  }
1823
1824  delete_editor(ed);
1825
1826  ed = env->current;
1827  if (!ed) {
1828    ed = create_editor(env);
1829    new_file(ed, "");
1830  }
1831  ed->refresh = 1;
1832}
1833
1834static void pipe_command(struct editor *ed) {
1835#ifdef __rtems__
1836    display_message(ed, "Not supported");
1837    sleep(3);
1838#else
1839  FILE *f;
1840  char buffer[512];
1841  int n;
1842  int pos;
1843
1844  if (!prompt(ed, "Command: ", 1)) {
1845    ed->refresh = 1;
1846    return;
1847  }
1848
1849#ifdef SANOS
1850  f = popen(ed->env->linebuf, "r2");
1851#else
1852  f = popen(ed->env->linebuf, "r");
1853#endif
1854  if (!f) {
1855    display_message(ed, "Error %d running command (%s)", errno, strerror(errno));
1856    sleep(5);
1857  } else {
1858    erase_selection(ed);
1859    pos = ed->linepos + ed->col;
1860    while ((n = fread(buffer, 1, sizeof(buffer), f)) > 0) {
1861      insert(ed, pos, buffer, n);
1862      pos += n;
1863    }
1864    moveto(ed, pos, 0);
1865    pclose(f);
1866  }
1867  ed->refresh = 1;
1868#endif
1869}
1870
1871static void find_text(struct editor *ed, int next) {
1872  int slen;
1873
1874  if (!next) {
1875    if (!prompt(ed, "Find: ", 1)) {
1876      ed->refresh = 1;
1877      return;
1878    }
1879    if (ed->env->search) free(ed->env->search);
1880    ed->env->search = (unsigned char*) strdup((const char*) ed->env->linebuf);
1881  }
1882
1883  if (!ed->env->search) return;
1884  slen = strlen((const char*) ed->env->search);
1885  if (slen > 0) {
1886    unsigned char *match;
1887
1888    close_gap(ed);
1889    match = (unsigned char*) strstr((char*) ed->start + ed->linepos + ed->col, (char*) ed->env->search);
1890    if (match != NULL) {
1891      int pos = match - ed->start;
1892      ed->anchor = pos;
1893      moveto(ed, pos + slen, 1);
1894    } else {
1895      outch('\007');
1896    }
1897  }
1898  ed->refresh = 1;
1899}
1900
1901static void goto_line(struct editor *ed) {
1902  int lineno, l, pos;
1903
1904  ed->anchor = -1;
1905  if (prompt(ed, "Goto line: ", 1)) {
1906    lineno = atoi((char*) ed->env->linebuf);
1907    if (lineno > 0) {
1908      pos = 0;
1909      for (l = 0; l < lineno - 1; l++) {
1910        pos = next_line(ed, pos);
1911        if (pos < 0) break;
1912      }
1913    } else {
1914      pos = -1;
1915    }
1916
1917    if (pos >= 0) {
1918      moveto(ed, pos, 1);
1919    } else {
1920      outch('\007');
1921    }
1922  }
1923  ed->refresh = 1;
1924}
1925
1926static struct editor *next_file(struct editor *ed) {
1927  ed = ed->env->current = ed->next;
1928  ed->refresh = 1;
1929  return ed;
1930}
1931
1932static void jump_to_editor(struct editor *ed) {
1933  struct env *env = ed->env;
1934  char filename[FILENAME_MAX];
1935  int lineno = 0;
1936
1937  if (!get_selected_text(ed, filename, FILENAME_MAX)) {
1938    int pos = ed->linepos + ed->col;
1939    char *p = filename;
1940    int left = FILENAME_MAX - 1;
1941    while (left > 0) {
1942      int ch = get(ed, pos);
1943      if (ch < 0) break;
1944      if (strchr("!@\"'#%&()[]{}*?+:;\r\n\t ", ch)) break;
1945      *p++ = ch;
1946      left--;
1947      pos++;
1948    }
1949    *p = 0;
1950
1951    if (get(ed, pos) == ':') {
1952      pos++;
1953      for (;;) {
1954        int ch = get(ed, pos);
1955        if (ch < 0) break;
1956        if (ch >= '0' && ch <= '9') {
1957          lineno = lineno * 10 + (ch - '0');
1958        } else {
1959          break;
1960        }
1961        pos++;
1962      }
1963    }
1964  }
1965  if (!*filename) return;
1966
1967  ed = find_editor(env, filename);
1968  if (ed) {
1969    env->current = ed;
1970  } else {
1971    ed = create_editor(env);
1972    if (load_file(ed, filename) < 0) {
1973      outch('\007');
1974      delete_editor(ed);
1975      ed = env->current;
1976    }
1977  }
1978
1979  if (lineno > 0) {
1980    int pos = 0;
1981    while (--lineno > 0) {
1982      pos = next_line(ed, pos);
1983      if (pos < 0) break;
1984    }
1985    if (pos >= 0) moveto(ed, pos, 1);
1986  }
1987
1988  ed->refresh = 1;
1989}
1990
1991static void redraw_screen(struct editor *ed) {
1992  get_console_size(ed->env);
1993  draw_screen(ed);
1994}
1995
1996static int quit(struct env *env) {
1997  struct editor *ed = env->current;
1998  struct editor *start = ed;
1999
2000  do {
2001    if (ed->dirty) {
2002      display_message(ed, "Close %s without saving changes (y/n)? ", ed->filename);
2003      if (!ask()) return 0;
2004    }
2005    ed = ed->next;
2006  } while (ed != start);
2007
2008  return 1;
2009}
2010
2011static void help(struct editor *ed) {
2012  gotoxy(0, 0);
2013  clear_screen();
2014  outstr("Editor Command Summary\r\n");
2015  outstr("======================\r\n\r\n");
2016  outstr("<up>         Move one line up (*)         Ctrl+N  New editor\r\n");
2017  outstr("<down>       Move one line down (*)       Ctrl+O  Open file\r\n");
2018  outstr("<left>       Move one character left (*)  Ctrl+S  Save file\r\n");
2019  outstr("<right>      Move one character right (*) Ctrl+W  Close file\r\n");
2020  outstr("<pgup>       Move one page up (*)         Ctrl+Q  Quit\r\n");
2021  outstr("<pgdn>       Move one page down (*)       Ctrl+P  Pipe command\r\n");
2022  outstr("Ctrl+<left>  Move to previous word (*)    Ctrl+A  Select all\r\n");
2023  outstr("Ctrl+<right> Move to next word (*)        Ctrl+C  Copy selection to clipboard\r\n");
2024  outstr("<home>       Move to start of line (*)    Ctrl+X  Cut selection to clipboard\r\n");
2025  outstr("<end>        Move to end of line (*)      Ctrl+V  Paste from clipboard\r\n");
2026  outstr("Ctrl+<home>  Move to start of file (*)    Ctrl+Z  Undo\r\n");
2027  outstr("Ctrl+<end>   Move to end of file (*)      Ctrl+R  Redo\r\n");
2028  outstr("<backspace>  Delete previous character    Ctrl+F  Find text\r\n");
2029  outstr("<delete>     Delete current character     Ctrl+G  Find next\r\n");
2030  outstr("Ctrl+<tab>   Next editor                  Ctrl+L  Goto line\r\n");
2031  outstr("<tab>        Indent selection             F1      Help\r\n");
2032  outstr("Shift+<tab>  Unindent selection           F2      Select toggle\r\n");
2033  outstr(" (*) Extends selection, F2 toggles.       F3      Navigate to file\r\n");
2034  outstr("                                          F4      Copy selection to clipboard\r\n");
2035  outstr("  Ctrl-Q/S may not work over              F5      Redraw screen\r\n");
2036  outstr("  serial links, use funcions keys         F9      Save file\r\n");
2037  outstr("                                          F10     Quit\r\n");
2038  outstr("Press any key to continue...");
2039  fflush(stdout);
2040
2041  getkey();
2042  draw_screen(ed);
2043  draw_full_statusline(ed);
2044}
2045
2046//
2047// Editor
2048//
2049
2050static void edit(struct editor *ed) {
2051  int done = 0;
2052  int key;
2053
2054  ed->refresh = 1;
2055  while (!done) {
2056    if (ed->refresh) {
2057      draw_screen(ed);
2058      draw_full_statusline(ed);
2059      ed->refresh = 0;
2060      ed->lineupdate = 0;
2061    } else if (ed->lineupdate) {
2062      update_line(ed);
2063      ed->lineupdate = 0;
2064      draw_statusline(ed);
2065    } else {
2066      draw_statusline(ed);
2067    }
2068
2069    position_cursor(ed);
2070    fflush(stdout);
2071    key = getkey();
2072
2073    if (key >= ' ' && key <= 0x7F) {
2074#ifdef LESS
2075      switch (key) {
2076        case 'q': done = 1; break;
2077        case '/': find_text(ed, 0); break;
2078      }
2079#else
2080      insert_char(ed, (unsigned char) key);
2081#endif
2082    } else {
2083      switch (key) {
2084        case KEY_F1: help(ed); break;
2085        case KEY_F2: select_toggle(ed); break;
2086        case KEY_F3: jump_to_editor(ed); ed = ed->env->current; break;
2087        case KEY_F4: copy_selection(ed); break;
2088        case KEY_F5: redraw_screen(ed); break;
2089        case KEY_F9: save_editor(ed); break;
2090        case KEY_F10: done = 1; break;
2091
2092#if defined(__linux__) || defined(__rtems__)
2093        case ctrl('y'): help(ed); break;
2094        case ctrl('t'): top(ed, 0); break;
2095        case ctrl('b'): bottom(ed, 0); break;
2096#endif
2097
2098        case KEY_UP: up(ed, ed->selecting); break;
2099        case KEY_DOWN: down(ed, ed->selecting); break;
2100        case KEY_LEFT: left(ed, ed->selecting); break;
2101        case KEY_RIGHT: right(ed, ed->selecting); break;
2102        case KEY_HOME: home(ed, ed->selecting); break;
2103        case KEY_END: end(ed, ed->selecting); break;
2104        case KEY_PGUP: pageup(ed, ed->selecting); break;
2105        case KEY_PGDN: pagedown(ed, ed->selecting); break;
2106
2107        case KEY_CTRL_RIGHT: wordright(ed, ed->selecting); break;
2108        case KEY_CTRL_LEFT: wordleft(ed, ed->selecting); break;
2109        case KEY_CTRL_HOME: top(ed, ed->selecting); break;
2110        case KEY_CTRL_END: bottom(ed, ed->selecting); break;
2111
2112#if SHIFT_SELECT
2113        case KEY_SHIFT_UP: up(ed, 1); break;
2114        case KEY_SHIFT_DOWN: down(ed, 1); break;
2115        case KEY_SHIFT_LEFT: left(ed, 1); break;
2116        case KEY_SHIFT_RIGHT: right(ed, 1); break;
2117        case KEY_SHIFT_PGUP: pageup(ed, 1); break;
2118        case KEY_SHIFT_PGDN: pagedown(ed, 1); break;
2119        case KEY_SHIFT_HOME: home(ed, 1); break;
2120        case KEY_SHIFT_END: end(ed, 1); break;
2121
2122        case KEY_SHIFT_CTRL_RIGHT: wordright(ed, 1); break;
2123        case KEY_SHIFT_CTRL_LEFT: wordleft(ed, 1); break;
2124        case KEY_SHIFT_CTRL_HOME: top(ed, 1); break;
2125        case KEY_SHIFT_CTRL_END: bottom(ed, 1); break;
2126#endif
2127
2128        case KEY_CTRL_TAB: ed = next_file(ed); break;
2129
2130        case ctrl('e'): select_toggle(ed); break;
2131        case ctrl('a'): select_all(ed); break;
2132        case ctrl('c'): copy_selection(ed); break;
2133        case ctrl('f'): find_text(ed, 0); break;
2134        case ctrl('l'): goto_line(ed); break;
2135        case ctrl('g'): find_text(ed, 1); break;
2136        case ctrl('q'): done = 1; break;
2137#ifdef LESS
2138        case KEY_ESC: done = 1; break;
2139#else
2140        case KEY_TAB: indent(ed, (unsigned char*) INDENT); break;
2141        case KEY_SHIFT_TAB: unindent(ed, (unsigned char*) INDENT); break;
2142
2143        case KEY_ENTER: newline(ed); break;
2144        case KEY_BACKSPACE: backspace(ed); break;
2145        case KEY_DEL: del(ed); break;
2146        case ctrl('x'): cut_selection(ed); break;
2147        case ctrl('z'): undo(ed); break;
2148        case ctrl('r'): redo(ed); break;
2149        case ctrl('v'): paste_selection(ed); break;
2150        case ctrl('o'): open_editor(ed); ed = ed->env->current; break;
2151        case ctrl('n'): new_editor(ed); ed = ed->env->current; break;
2152        case ctrl('s'): save_editor(ed); break;
2153        case ctrl('p'): pipe_command(ed); break;
2154#endif
2155#if defined(__rtems__)
2156        /*
2157         * Coverity spotted this as using ed after free() so changing
2158         * the order of the statements.
2159         */
2160        case ctrl('w'): ed = ed->env->current; close_editor(ed); break;
2161#else
2162        case ctrl('w'): close_editor(ed); ed = ed->env->current; break;
2163#endif
2164      }
2165    }
2166  }
2167}
2168
2169//
2170// main
2171//
2172static int rtems_shell_main_edit(int argc, char *argv[])
2173{
2174  struct env env;
2175  int rc;
2176  int i;
2177  sigset_t blocked_sigmask, orig_sigmask;
2178#if defined(__linux__)
2179  struct termios tio;
2180#endif
2181#if defined(__linux__) || defined(__rtems__)
2182  struct termios orig_tio;
2183#endif
2184#ifdef SANOS
2185  struct term *term;
2186#endif
2187
2188  memset(&env, 0, sizeof(env));
2189  for (i = 1; i < argc; i++) {
2190    struct editor *ed = create_editor(&env);
2191    rc = load_file(ed, argv[i]);
2192    if (rc < 0 && errno == ENOENT) rc = new_file(ed, argv[i]);
2193    if (rc < 0) {
2194      perror(argv[i]);
2195      return 0;
2196    }
2197  }
2198  if (env.current == NULL) {
2199    struct editor *ed = create_editor(&env);
2200    if (isatty(fileno(stdin))) {
2201      new_file(ed, "");
2202    } else {
2203      read_from_stdin(ed);
2204    }
2205  }
2206  env.current = env.current->next;
2207
2208#ifdef SANOS
2209  term = gettib()->proc->term;
2210  if (fdin != term->ttyin) dup2(term->ttyin, fdin);
2211  if (fdout != term->ttyout) dup2(term->ttyout, fdout);
2212#elif !defined(__rtems__)
2213  if (!isatty(fileno(stdin))) {
2214    if (!freopen("/dev/tty", "r", stdin)) perror("/dev/tty");
2215  }
2216#endif
2217
2218  setvbuf(stdout, NULL, 0, 8192);
2219
2220#if defined(__linux__) || defined(__rtems__)
2221  (void) tcgetattr(0, &orig_tio);
2222#if !defined(__rtems__)
2223  cfmakeraw(&tio);
2224  tcsetattr(0, TCSANOW, &tio);
2225#endif
2226  if (getenv("TERM") && strcmp(getenv("TERM"), "linux") == 0) {
2227    linux_console = 1;
2228  } else {
2229    outstr(CLRSCR);
2230    outstr("\033[3 q");  // xterm
2231    outstr("\033]50;CursorShape=2\a");  // KDE
2232  }
2233#endif
2234
2235  get_console_size(&env);
2236
2237  sigemptyset(&blocked_sigmask);
2238  sigaddset(&blocked_sigmask, SIGINT);
2239  sigaddset(&blocked_sigmask, SIGTSTP);
2240  sigaddset(&blocked_sigmask, SIGABRT);
2241  sigprocmask(SIG_BLOCK, &blocked_sigmask, &orig_sigmask);
2242
2243  for (;;) {
2244    if (!env.current) break;
2245    edit(env.current);
2246    if (quit(&env)) break;
2247  }
2248
2249  gotoxy(0, env.lines + 1);
2250  outstr(RESET_COLOR CLREOL);
2251#if defined(__linux__) || defined(__rtems__)
2252  tcsetattr(0, TCSANOW, &orig_tio);
2253#endif
2254
2255  while (env.current) delete_editor(env.current);
2256
2257  if (env.clipboard) free(env.clipboard);
2258  if (env.search) free(env.search);
2259  if (env.linebuf) free(env.linebuf);
2260
2261  setbuf(stdout, NULL);
2262  sigprocmask(SIG_SETMASK, &orig_sigmask, NULL);
2263
2264  return 0;
2265}
2266
2267rtems_shell_cmd_t rtems_shell_EDIT_Command = {
2268  "edit",                /* name */
2269  "edit [file ...]",     /* usage */
2270  "files",               /* topic */
2271  rtems_shell_main_edit, /* command */
2272  NULL,                  /* alias */
2273  NULL                   /* next */
2274};
Note: See TracBrowser for help on using the repository browser.