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

4.115
Last change on this file since d006b46d was fdd1e20, checked in by Sebastian Huber <sebastian.huber@…>, on 11/26/14 at 08:57:57

shell: Include missing header

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