tizen 2.3.1 release
[framework/connectivity/bluez.git] / android / client / terminal.c
1 /*
2  * Copyright (C) 2013 Intel Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 #include <stdio.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include <stdbool.h>
22 #include <termios.h>
23 #include <stdlib.h>
24
25 #include "terminal.h"
26 #include "history.h"
27
28 /*
29  * Character sequences recognized by code in this file
30  * Leading ESC 0x1B is not included
31  */
32 #define SEQ_INSERT "[2~"
33 #define SEQ_DELETE "[3~"
34 #define SEQ_HOME   "OH"
35 #define SEQ_END    "OF"
36 #define SEQ_PGUP   "[5~"
37 #define SEQ_PGDOWN "[6~"
38 #define SEQ_LEFT   "[D"
39 #define SEQ_RIGHT  "[C"
40 #define SEQ_UP     "[A"
41 #define SEQ_DOWN   "[B"
42 #define SEQ_STAB   "[Z"
43 #define SEQ_M_n    "n"
44 #define SEQ_M_p    "p"
45 #define SEQ_CLEFT  "[1;5D"
46 #define SEQ_CRIGHT "[1;5C"
47 #define SEQ_CUP    "[1;5A"
48 #define SEQ_CDOWN  "[1;5B"
49 #define SEQ_SLEFT  "[1;2D"
50 #define SEQ_SRIGHT "[1;2C"
51 #define SEQ_SUP    "[1;2A"
52 #define SEQ_SDOWN  "[1;2B"
53 #define SEQ_MLEFT  "[1;3D"
54 #define SEQ_MRIGHT "[1;3C"
55 #define SEQ_MUP    "[1;3A"
56 #define SEQ_MDOWN  "[1;3B"
57
58 #define KEY_SEQUENCE(k) { KEY_##k, SEQ_##k }
59 struct ansii_sequence {
60         int code;
61         const char *sequence;
62 };
63
64 /* Table connects single int key codes with character sequences */
65 static const struct ansii_sequence ansii_sequnces[] = {
66         KEY_SEQUENCE(INSERT),
67         KEY_SEQUENCE(DELETE),
68         KEY_SEQUENCE(HOME),
69         KEY_SEQUENCE(END),
70         KEY_SEQUENCE(PGUP),
71         KEY_SEQUENCE(PGDOWN),
72         KEY_SEQUENCE(LEFT),
73         KEY_SEQUENCE(RIGHT),
74         KEY_SEQUENCE(UP),
75         KEY_SEQUENCE(DOWN),
76         KEY_SEQUENCE(CLEFT),
77         KEY_SEQUENCE(CRIGHT),
78         KEY_SEQUENCE(CUP),
79         KEY_SEQUENCE(CDOWN),
80         KEY_SEQUENCE(SLEFT),
81         KEY_SEQUENCE(SRIGHT),
82         KEY_SEQUENCE(SUP),
83         KEY_SEQUENCE(SDOWN),
84         KEY_SEQUENCE(MLEFT),
85         KEY_SEQUENCE(MRIGHT),
86         KEY_SEQUENCE(MUP),
87         KEY_SEQUENCE(MDOWN),
88         KEY_SEQUENCE(STAB),
89         KEY_SEQUENCE(M_p),
90         KEY_SEQUENCE(M_n),
91         { 0, NULL }
92 };
93
94 #define KEY_SEQUNCE_NOT_FINISHED -1
95 #define KEY_C_C 3
96 #define KEY_C_D 4
97 #define KEY_C_L 12
98
99 #define isseqence(c) ((c) == 0x1B)
100
101 /*
102  * Number of characters that consist of ANSI sequence
103  * Should not be less then longest string in ansi_sequences
104  */
105 #define MAX_ASCII_SEQUENCE 10
106
107 static char current_sequence[MAX_ASCII_SEQUENCE];
108 static int current_sequence_len = -1;
109
110 /* single line typed by user goes here */
111 static char line_buf[LINE_BUF_MAX];
112 /* index of cursor in input line */
113 static int line_buf_ix = 0;
114 /* current length of input line */
115 static int line_len = 0;
116
117 /* line index used for fetching lines from history */
118 static int line_index = 0;
119
120 static char prompt_buf[10] = "> ";
121 static const char *const noprompt = "";
122 static const char *current_prompt = prompt_buf;
123 static const char *prompt = prompt_buf;
124 /*
125  * Moves cursor to right or left
126  *
127  * n - positive - moves cursor right
128  * n - negative - moves cursor left
129  */
130 static void terminal_move_cursor(int n)
131 {
132         if (n < 0) {
133                 for (; n < 0; n++)
134                         putchar('\b');
135         } else if (n > 0) {
136                 printf("%*s", n, line_buf + line_buf_ix);
137         }
138 }
139
140 /* Draw command line */
141 void terminal_draw_command_line(void)
142 {
143         /*
144          * this needs to be checked here since line_buf is not cleared
145          * before parsing event though line_len and line_buf_ix are
146          */
147         if (line_len > 0)
148                 printf("%s%s", prompt, line_buf);
149         else
150                 printf("%s", prompt);
151
152         /* move cursor to it's place */
153         terminal_move_cursor(line_buf_ix - line_len);
154 }
155
156 /* inserts string into command line at cursor position */
157 void terminal_insert_into_command_line(const char *p)
158 {
159         int len = strlen(p);
160
161         if (line_len == line_buf_ix) {
162                 strcat(line_buf, p);
163                 printf("%s", p);
164                 line_len = line_len + len;
165                 line_buf_ix = line_len;
166         } else {
167                 memmove(line_buf + line_buf_ix + len,
168                         line_buf + line_buf_ix, line_len - line_buf_ix + 1);
169                 memmove(line_buf + line_buf_ix, p, len);
170                 printf("%s", line_buf + line_buf_ix);
171                 line_buf_ix += len;
172                 line_len += len;
173                 terminal_move_cursor(line_buf_ix - line_len);
174         }
175 }
176
177 /* Prints string and redraws command line */
178 int terminal_print(const char *format, ...)
179 {
180         va_list args;
181         int ret;
182
183         va_start(args, format);
184
185         ret = terminal_vprint(format, args);
186
187         va_end(args);
188         return ret;
189 }
190
191 /* Prints string and redraws command line */
192 int terminal_vprint(const char *format, va_list args)
193 {
194         int ret;
195
196         printf("\r%*s\r", (int) line_len + 1, " ");
197
198         ret = vprintf(format, args);
199
200         terminal_draw_command_line();
201
202         fflush(stdout);
203
204         return ret;
205 }
206
207 /*
208  * Call this when text in line_buf was changed
209  * and line needs to be redrawn
210  */
211 static void terminal_line_replaced(void)
212 {
213         int len = strlen(line_buf);
214
215         /* line is shorter that previous */
216         if (len < line_len) {
217                 /* if new line is shorter move cursor to end of new end */
218                 while (line_buf_ix > len) {
219                         putchar('\b');
220                         line_buf_ix--;
221                 }
222
223                 /* If cursor was not at the end, move it to the end */
224                 if (line_buf_ix < line_len)
225                         printf("%.*s", line_len - line_buf_ix,
226                                         line_buf + line_buf_ix);
227                 /* over write end of previous line */
228                 while (line_len >= len++)
229                         putchar(' ');
230         }
231
232         /* draw new line */
233         printf("\r%s%s", prompt, line_buf);
234         /* set up indexes to new line */
235         line_len = strlen(line_buf);
236         line_buf_ix = line_len;
237         fflush(stdout);
238 }
239
240 static void terminal_clear_line(void)
241 {
242         line_buf[0] = '\0';
243         terminal_line_replaced();
244 }
245
246 static void terminal_clear_screen(void)
247 {
248         line_buf[0] = '\0';
249         line_buf_ix = 0;
250         line_len = 0;
251
252         printf("\x1b[2J\x1b[1;1H%s", prompt);
253 }
254
255 static void terminal_delete_char(void)
256 {
257         /* delete character under cursor if not at the very end */
258         if (line_buf_ix >= line_len)
259                 return;
260         /*
261          * Prepare buffer with one character missing
262          * trailing 0 is moved
263          */
264         line_len--;
265         memmove(line_buf + line_buf_ix, line_buf + line_buf_ix + 1,
266                                                 line_len - line_buf_ix + 1);
267         /* print rest of line from current cursor position */
268         printf("%s \b", line_buf + line_buf_ix);
269         /* move back cursor */
270         terminal_move_cursor(line_buf_ix - line_len);
271 }
272
273 /*
274  * Function tries to replace current line with specified line in history
275  * new_line_index - new line to show, -1 to show oldest
276  */
277 static void terminal_get_line_from_history(int new_line_index)
278 {
279         new_line_index = history_get_line(new_line_index,
280                                                 line_buf, LINE_BUF_MAX);
281
282         if (new_line_index >= 0) {
283                 terminal_line_replaced();
284                 line_index = new_line_index;
285         }
286 }
287
288 /*
289  * Function searches history back or forward for command line that starts
290  * with characters up to cursor position
291  *
292  * back - true - searches backward
293  * back - false - searches forward (more recent commands)
294  */
295 static void terminal_match_hitory(bool back)
296 {
297         char buf[line_buf_ix + 1];
298         int line;
299         int matching_line = -1;
300         int dir = back ? 1 : -1;
301
302         line = line_index + dir;
303         while (matching_line == -1 && line >= 0) {
304                 int new_line_index;
305
306                 new_line_index = history_get_line(line, buf, line_buf_ix + 1);
307                 if (new_line_index < 0)
308                         break;
309
310                 if (0 == strncmp(line_buf, buf, line_buf_ix))
311                         matching_line = line;
312                 line += dir;
313         }
314
315         if (matching_line >= 0) {
316                 int pos = line_buf_ix;
317                 terminal_get_line_from_history(matching_line);
318                 /* move back to cursor position to original place */
319                 line_buf_ix = pos;
320                 terminal_move_cursor(pos - line_len);
321         }
322 }
323
324 /*
325  * Converts terminal character sequences to single value representing
326  * keyboard keys
327  */
328 static int terminal_convert_sequence(int c)
329 {
330         int i;
331
332         /* Not in sequence yet? */
333         if (current_sequence_len == -1) {
334                 /* Is ansi sequence detected by 0x1B ? */
335                 if (isseqence(c)) {
336                         current_sequence_len++;
337                         return KEY_SEQUNCE_NOT_FINISHED;
338                 }
339
340                 return c;
341         }
342
343         /* Inside sequence */
344         current_sequence[current_sequence_len++] = c;
345         current_sequence[current_sequence_len] = '\0';
346         for (i = 0; ansii_sequnces[i].code; ++i) {
347                 /* Matches so far? */
348                 if (0 != strncmp(current_sequence, ansii_sequnces[i].sequence,
349                                                         current_sequence_len))
350                         continue;
351
352                 /* Matches as a whole? */
353                 if (ansii_sequnces[i].sequence[current_sequence_len] == 0) {
354                         current_sequence_len = -1;
355                         return ansii_sequnces[i].code;
356                 }
357
358                 /* partial match (not whole sequence yet) */
359                 return KEY_SEQUNCE_NOT_FINISHED;
360         }
361
362         terminal_print("ansi char 0x%X %c\n", c);
363         /*
364          * Sequence does not match
365          * mark that no in sequence any more, return char
366          */
367         current_sequence_len = -1;
368         return c;
369 }
370
371 typedef void (*terminal_action)(int c, line_callback process_line);
372
373 #define TERMINAL_ACTION(n) \
374         static void n(int c, void (*process_line)(char *line))
375
376 TERMINAL_ACTION(terminal_action_null)
377 {
378 }
379
380 /* Mapping between keys and function */
381 typedef struct {
382         int key;
383         terminal_action func;
384 } KeyAction;
385
386 int action_keys[] = {
387         KEY_SEQUNCE_NOT_FINISHED,
388         KEY_LEFT,
389         KEY_RIGHT,
390         KEY_HOME,
391         KEY_END,
392         KEY_DELETE,
393         KEY_CLEFT,
394         KEY_CRIGHT,
395         KEY_SUP,
396         KEY_SDOWN,
397         KEY_UP,
398         KEY_DOWN,
399         KEY_BACKSPACE,
400         KEY_INSERT,
401         KEY_PGUP,
402         KEY_PGDOWN,
403         KEY_CUP,
404         KEY_CDOWN,
405         KEY_SLEFT,
406         KEY_SRIGHT,
407         KEY_MLEFT,
408         KEY_MRIGHT,
409         KEY_MUP,
410         KEY_MDOWN,
411         KEY_STAB,
412         KEY_M_n,
413         KEY_M_p,
414         KEY_C_C,
415         KEY_C_D,
416         KEY_C_L,
417         '\t',
418         '\r',
419         '\n',
420 };
421
422 #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
423
424 /*
425  * current_actions holds all recognizable kes and actions for them
426  * additional element (index 0) is used for default action
427  */
428 static KeyAction current_actions[NELEM(action_keys) + 1];
429
430 /* KeyAction comparator by key, for qsort and bsearch */
431 static int KeyActionKeyCompare(const void *a, const void *b)
432 {
433         return ((const KeyAction *) a)->key - ((const KeyAction *) b)->key;
434 }
435
436 /* Find action by key, NULL if no action for this key */
437 static KeyAction *terminal_get_action(int key)
438 {
439         KeyAction a = { .key = key };
440
441         return bsearch(&a, current_actions + 1, NELEM(action_keys), sizeof(a),
442                                                         KeyActionKeyCompare);
443 }
444
445 /* Sets new set of actions to use */
446 static void terminal_set_actions(const KeyAction *actions)
447 {
448         int i;
449
450         /* Make map with empty function for every key */
451         for (i = 0; i < NELEM(action_keys); ++i) {
452                 /*
453                  * + 1 due to 0 index reserved for default action that is
454                  * called for non mapped key
455                  */
456                 current_actions[i + 1].key = action_keys[i];
457                 current_actions[i + 1].func = terminal_action_null;
458         }
459
460         /* Sort action from 1 (index 0 - default action) */
461         qsort(current_actions + 1, NELEM(action_keys), sizeof(KeyAction),
462                                                         KeyActionKeyCompare);
463         /* Set default action (first in array) */
464         current_actions[0] = *actions++;
465
466         /* Copy rest of actions into their places */
467         for (; actions->key; ++actions) {
468                 KeyAction *place = terminal_get_action(actions->key);
469
470                 if (place)
471                         place->func = actions->func;
472         }
473 }
474
475 TERMINAL_ACTION(terminal_action_left)
476 {
477         /* if not at the beginning move to previous character */
478         if (line_buf_ix <= 0)
479                 return;
480         line_buf_ix--;
481         terminal_move_cursor(-1);
482 }
483
484 TERMINAL_ACTION(terminal_action_right)
485 {
486         /*
487          * If not at the end, just print current character
488          * and modify position
489          */
490         if (line_buf_ix < line_len)
491                 putchar(line_buf[line_buf_ix++]);
492 }
493
494 TERMINAL_ACTION(terminal_action_home)
495 {
496         /* move to beginning of line and update position */
497         printf("\r%s", prompt);
498         line_buf_ix = 0;
499 }
500
501 TERMINAL_ACTION(terminal_action_end)
502 {
503         /* if not at the end of line */
504         if (line_buf_ix < line_len) {
505                 /* print everything from cursor */
506                 printf("%s", line_buf + line_buf_ix);
507                 /* just modify current position */
508                 line_buf_ix = line_len;
509         }
510 }
511
512 TERMINAL_ACTION(terminal_action_del)
513 {
514         terminal_delete_char();
515 }
516
517 TERMINAL_ACTION(terminal_action_word_left)
518 {
519         int old_pos;
520         /*
521          * Move by word left
522          *
523          * Are we at the beginning of line?
524          */
525         if (line_buf_ix <= 0)
526                 return;
527
528         old_pos = line_buf_ix;
529         line_buf_ix--;
530         /* skip spaces left */
531         while (line_buf_ix && isspace(line_buf[line_buf_ix]))
532                 line_buf_ix--;
533
534         /* skip all non spaces to the left */
535         while (line_buf_ix > 0 &&
536                         !isspace(line_buf[line_buf_ix - 1]))
537                 line_buf_ix--;
538
539         /* move cursor to new position */
540         terminal_move_cursor(line_buf_ix - old_pos);
541 }
542
543 TERMINAL_ACTION(terminal_action_word_right)
544 {
545         int old_pos;
546         /*
547          * Move by word right
548          *
549          * are we at the end of line?
550          */
551         if (line_buf_ix >= line_len)
552                 return;
553
554         old_pos = line_buf_ix;
555         /* skip all spaces */
556         while (line_buf_ix < line_len && isspace(line_buf[line_buf_ix]))
557                 line_buf_ix++;
558
559         /* skip all non spaces */
560         while (line_buf_ix < line_len && !isspace(line_buf[line_buf_ix]))
561                 line_buf_ix++;
562         /*
563          * Move cursor to right by printing text
564          * between old cursor and new
565          */
566         if (line_buf_ix > old_pos)
567                 printf("%.*s", (int) (line_buf_ix - old_pos),
568                                                         line_buf + old_pos);
569 }
570
571 TERMINAL_ACTION(terminal_action_history_begin)
572 {
573         terminal_get_line_from_history(-1);
574 }
575
576 TERMINAL_ACTION(terminal_action_history_end)
577 {
578         if (line_index > 0)
579                 terminal_get_line_from_history(0);
580 }
581
582 TERMINAL_ACTION(terminal_action_history_up)
583 {
584         terminal_get_line_from_history(line_index + 1);
585 }
586
587 TERMINAL_ACTION(terminal_action_history_down)
588 {
589         if (line_index > 0)
590                 terminal_get_line_from_history(line_index - 1);
591 }
592
593 TERMINAL_ACTION(terminal_action_tab)
594 {
595         /* tab processing */
596         process_tab(line_buf, line_buf_ix);
597 }
598
599
600 TERMINAL_ACTION(terminal_action_backspace)
601 {
602         if (line_buf_ix <= 0)
603                 return;
604
605         if (line_buf_ix == line_len) {
606                 printf("\b \b");
607                 line_len = --line_buf_ix;
608                 line_buf[line_len] = 0;
609         } else {
610                 putchar('\b');
611                 line_buf_ix--;
612                 line_len--;
613                 memmove(line_buf + line_buf_ix,
614                                 line_buf + line_buf_ix + 1,
615                                 line_len - line_buf_ix + 1);
616                 printf("%s \b", line_buf + line_buf_ix);
617                 terminal_move_cursor(line_buf_ix - line_len);
618         }
619 }
620
621 TERMINAL_ACTION(terminal_action_find_history_forward)
622 {
623         /* Search history forward */
624         terminal_match_hitory(false);
625 }
626
627 TERMINAL_ACTION(terminal_action_find_history_backward)
628 {
629         /* Search history forward */
630         terminal_match_hitory(true);
631 }
632
633 TERMINAL_ACTION(terminal_action_ctrl_c)
634 {
635         terminal_clear_line();
636 }
637
638 TERMINAL_ACTION(terminal_action_ctrl_d)
639 {
640         if (line_len > 0) {
641                 terminal_delete_char();
642         } else  {
643                 puts("");
644                 exit(0);
645         }
646 }
647
648 TERMINAL_ACTION(terminal_action_clear_screen)
649 {
650         terminal_clear_screen();
651 }
652
653 TERMINAL_ACTION(terminal_action_enter)
654 {
655         /*
656          * On new line add line to history
657          * forget history position
658          */
659         history_add_line(line_buf);
660         line_len = 0;
661         line_buf_ix = 0;
662         line_index = -1;
663         /* print new line */
664         putchar(c);
665         prompt = noprompt;
666         process_line(line_buf);
667         /* clear current line */
668         line_buf[0] = '\0';
669         prompt = current_prompt;
670         printf("%s", prompt);
671 }
672
673 TERMINAL_ACTION(terminal_action_default)
674 {
675         char str[2] = { c, 0 };
676
677         if (!isprint(c))
678                 /*
679                  * TODO: remove this print once all meaningful sequences
680                  * are identified
681                  */
682                 printf("char-0x%02x\n", c);
683         else if (line_buf_ix < LINE_BUF_MAX - 1)
684                 terminal_insert_into_command_line(str);
685 }
686
687 /* Callback to call when user hit enter during prompt for */
688 static line_callback prompt_callback;
689
690 static KeyAction normal_actions[] = {
691         { 0, terminal_action_default },
692         { KEY_LEFT, terminal_action_left },
693         { KEY_RIGHT, terminal_action_right },
694         { KEY_HOME, terminal_action_home },
695         { KEY_END, terminal_action_end },
696         { KEY_DELETE, terminal_action_del },
697         { KEY_CLEFT, terminal_action_word_left },
698         { KEY_CRIGHT, terminal_action_word_right },
699         { KEY_SUP, terminal_action_history_begin },
700         { KEY_SDOWN, terminal_action_history_end },
701         { KEY_UP, terminal_action_history_up },
702         { KEY_DOWN, terminal_action_history_down },
703         { '\t', terminal_action_tab },
704         { KEY_BACKSPACE, terminal_action_backspace },
705         { KEY_M_n, terminal_action_find_history_forward },
706         { KEY_M_p, terminal_action_find_history_backward },
707         { KEY_C_C, terminal_action_ctrl_c },
708         { KEY_C_D, terminal_action_ctrl_d },
709         { KEY_C_L, terminal_action_clear_screen },
710         { '\r', terminal_action_enter },
711         { '\n', terminal_action_enter },
712         { 0, NULL },
713 };
714
715 TERMINAL_ACTION(terminal_action_answer)
716 {
717         putchar(c);
718
719         terminal_set_actions(normal_actions);
720         /* Restore default prompt */
721         current_prompt = prompt_buf;
722
723         /* No prompt for prints */
724         prompt = noprompt;
725         line_buf_ix = 0;
726         line_len = 0;
727         /* Call user function with what was typed */
728         prompt_callback(line_buf);
729
730         line_buf[0] = 0;
731         /* promot_callback could change current_prompt */
732         prompt = current_prompt;
733
734         printf("%s", prompt);
735 }
736
737 TERMINAL_ACTION(terminal_action_prompt_ctrl_c)
738 {
739         printf("^C\n");
740         line_buf_ix = 0;
741         line_len = 0;
742         line_buf[0] = 0;
743
744         current_prompt = prompt_buf;
745         prompt = current_prompt;
746         terminal_set_actions(normal_actions);
747
748         printf("%s", prompt);
749 }
750
751 static KeyAction prompt_actions[] = {
752         { 0, terminal_action_default },
753         { KEY_LEFT, terminal_action_left },
754         { KEY_RIGHT, terminal_action_right },
755         { KEY_HOME, terminal_action_home },
756         { KEY_END, terminal_action_end },
757         { KEY_DELETE, terminal_action_del },
758         { KEY_CLEFT, terminal_action_word_left },
759         { KEY_CRIGHT, terminal_action_word_right },
760         { KEY_BACKSPACE, terminal_action_backspace },
761         { KEY_C_C, terminal_action_prompt_ctrl_c },
762         { KEY_C_D, terminal_action_ctrl_d },
763         { '\r', terminal_action_answer },
764         { '\n', terminal_action_answer },
765         { 0, NULL },
766 };
767
768 void terminal_process_char(int c, line_callback process_line)
769 {
770         KeyAction *a;
771
772         c = terminal_convert_sequence(c);
773
774         /* Get action for this key */
775         a = terminal_get_action(c);
776
777         /* No action found, get default one */
778         if (a == NULL)
779                 a = &current_actions[0];
780
781         a->func(c, process_line);
782         fflush(stdout);
783 }
784
785 void terminal_prompt_for(const char *s, line_callback process_line)
786 {
787         current_prompt = s;
788         if (prompt != noprompt) {
789                 prompt = s;
790                 terminal_clear_line();
791         }
792         prompt_callback = process_line;
793         terminal_set_actions(prompt_actions);
794 }
795
796 static struct termios origianl_tios;
797
798 static void terminal_cleanup(void)
799 {
800         tcsetattr(0, TCSANOW, &origianl_tios);
801 }
802
803 void terminal_setup(void)
804 {
805         struct termios tios;
806
807         terminal_set_actions(normal_actions);
808
809         tcgetattr(0, &origianl_tios);
810         tios = origianl_tios;
811
812         /*
813          * Turn off echo since all editing is done by hand,
814          * Ctrl-c handled internally
815          */
816         tios.c_lflag &= ~(ICANON | ECHO | BRKINT | IGNBRK);
817         tcsetattr(0, TCSANOW, &tios);
818
819         /* Restore terminal at exit */
820         atexit(terminal_cleanup);
821
822         printf("%s", prompt);
823         fflush(stdout);
824 }