Coverage Report

Created: 2022-12-08 06:09

/src/gnupg/common/ttyio.c
Line
Count
Source (jump to first uncovered line)
1
/* ttyio.c -  tty i/O functions
2
 * Copyright (C) 1997-2019 Werner Koch
3
 * Copyright (C) 1998-2020 Free Software Foundation, Inc.
4
 * Copyright (C) 2015-2020 g10 Code GmbH
5
 *
6
 * This file is part of GnuPG.
7
 *
8
 * This file is free software; you can redistribute it and/or modify
9
 * it under the terms of either
10
 *
11
 *   - the GNU Lesser General Public License as published by the Free
12
 *     Software Foundation; either version 3 of the License, or (at
13
 *     your option) any later version.
14
 *
15
 * or
16
 *
17
 *   - the GNU General Public License as published by the Free
18
 *     Software Foundation; either version 2 of the License, or (at
19
 *     your option) any later version.
20
 *
21
 * or both in parallel, as here.
22
 *
23
 * This file is distributed in the hope that it will be useful,
24
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26
 * GNU General Public License for more details.
27
 *
28
 * You should have received a copy of the GNU General Public License
29
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
30
 * SPDX-License-Identifier: (LGPL-3.0-or-later OR GPL-2.0-or-later)
31
 */
32
33
#include <config.h>
34
#include <stdio.h>
35
#include <stdlib.h>
36
#include <string.h>
37
#include <stdarg.h>
38
#include <unistd.h>
39
40
#ifdef HAVE_TCGETATTR
41
# include <termios.h>
42
#else
43
# ifdef HAVE_TERMIO_H
44
/* simulate termios with termio */
45
#  include <termio.h>
46
#  define termios termio
47
#  define tcsetattr ioctl
48
#  define TCSAFLUSH TCSETAF
49
#  define tcgetattr(A,B) ioctl(A,TCGETA,B)
50
#  define HAVE_TCGETATTR
51
# endif
52
#endif
53
#ifdef HAVE_W32_SYSTEM
54
# ifdef HAVE_WINSOCK2_H
55
#  include <winsock2.h>
56
# endif
57
# include <windows.h>
58
# ifdef HAVE_TCGETATTR
59
#  error mingw32 and termios
60
# endif
61
#endif
62
#include <errno.h>
63
#include <ctype.h>
64
65
#include "util.h"
66
#include "ttyio.h"
67
#include "i18n.h"
68
#include "common-defs.h"
69
70
0
#define CONTROL_D ('D' - 'A' + 1)
71
72
73
#ifdef HAVE_W32_SYSTEM
74
static struct {
75
    HANDLE in, out;
76
} con;
77
#define DEF_INPMODE  (ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT    \
78
                                       |ENABLE_PROCESSED_INPUT )
79
#define HID_INPMODE  (ENABLE_LINE_INPUT|ENABLE_PROCESSED_INPUT )
80
#define DEF_OUTMODE  (ENABLE_WRAP_AT_EOL_OUTPUT|ENABLE_PROCESSED_OUTPUT)
81
82
#else /* Unix */
83
static FILE *ttyfp = NULL;
84
#endif /* Unix */
85
86
static int initialized;
87
static int last_prompt_len;
88
static int batchmode;
89
static int no_terminal;
90
91
#ifdef HAVE_TCGETATTR
92
    static struct termios termsave;
93
    static int restore_termios;
94
#endif
95
96
/* Hooks set by gpgrlhelp.c if required. */
97
static void (*my_rl_set_completer) (rl_completion_func_t *);
98
static void (*my_rl_inhibit_completion) (int);
99
static void (*my_rl_cleanup_after_signal) (void);
100
static void (*my_rl_init_stream) (FILE *);
101
static char *(*my_rl_readline) (const char*);
102
static void (*my_rl_add_history) (const char*);
103
static int (*my_rl_rw_history)(const char *, int, int);
104
105
/* This is a wrapper around ttyname so that we can use it even when
106
   the standard streams are redirected.  It figures the name out the
107
   first time and returns it in a statically allocated buffer. */
108
const char *
109
tty_get_ttyname (void)
110
0
{
111
0
  static char *name;
112
113
  /* On a GNU system ctermid() always return /dev/tty, so this does
114
     not make much sense - however if it is ever changed we do the
115
     Right Thing now. */
116
0
#ifdef HAVE_CTERMID
117
0
  static int got_name;
118
119
0
  if (!got_name)
120
0
    {
121
0
      const char *s;
122
      /* Note that despite our checks for these macros the function is
123
         not necessarily thread save.  We mainly do this for
124
         portability reasons, in case L_ctermid is not defined. */
125
0
# if defined(_POSIX_THREAD_SAFE_FUNCTIONS) || defined(_POSIX_TRHEADS)
126
0
      char buffer[L_ctermid];
127
0
      s = ctermid (buffer);
128
# else
129
      s = ctermid (NULL);
130
# endif
131
0
      if (s)
132
0
        name = strdup (s);
133
0
      got_name = 1;
134
0
    }
135
0
#endif /*HAVE_CTERMID*/
136
  /* Assume the standard tty on memory error or when there is no
137
     ctermid. */
138
0
  return name? name : "/dev/tty";
139
0
}
140
141
142
143
#ifdef HAVE_TCGETATTR
144
static void
145
cleanup(void)
146
0
{
147
0
  if (restore_termios)
148
0
    {
149
0
      restore_termios = 0; /* do it prior in case it is interrupted again */
150
0
      if (tcsetattr(fileno(ttyfp), TCSAFLUSH, &termsave))
151
0
        log_error ("tcsetattr() failed: %s\n", strerror (errno));
152
0
    }
153
0
}
154
#endif /*HAVE_TCGETATTR*/
155
156
157
static void
158
init_ttyfp(void)
159
0
{
160
0
  if (initialized)
161
0
    return;
162
163
#ifdef HAVE_W32_SYSTEM
164
  {
165
    SECURITY_ATTRIBUTES sa;
166
167
    memset (&sa, 0, sizeof(sa));
168
    sa.nLength = sizeof(sa);
169
    sa.bInheritHandle = TRUE;
170
    con.out = CreateFileA ("CONOUT$", GENERIC_READ|GENERIC_WRITE,
171
                           FILE_SHARE_READ|FILE_SHARE_WRITE,
172
                           &sa, OPEN_EXISTING, 0, 0 );
173
    if (con.out == INVALID_HANDLE_VALUE)
174
      log_fatal ("open(CONOUT$) failed: %s\n", w32_strerror (-1));
175
176
    memset (&sa, 0, sizeof(sa));
177
    sa.nLength = sizeof(sa);
178
    sa.bInheritHandle = TRUE;
179
    con.in = CreateFileA ("CONIN$", GENERIC_READ|GENERIC_WRITE,
180
                          FILE_SHARE_READ|FILE_SHARE_WRITE,
181
                          &sa, OPEN_EXISTING, 0, 0 );
182
    if (con.in == INVALID_HANDLE_VALUE)
183
      log_fatal ("open(CONIN$) failed: %s\n", w32_strerror (-1));
184
  }
185
  SetConsoleMode (con.in, DEF_INPMODE);
186
  SetConsoleMode (con.out, DEF_OUTMODE);
187
188
#else /* Unix */
189
0
  ttyfp = batchmode? stderr : fopen (tty_get_ttyname (), "r+");
190
0
  if (!ttyfp)
191
0
    {
192
0
      log_error ("cannot open '%s': %s\n", tty_get_ttyname (), strerror(errno));
193
0
      exit (2);
194
0
    }
195
0
  if (my_rl_init_stream)
196
0
    my_rl_init_stream (ttyfp);
197
0
#endif /* Unix */
198
199
0
#ifdef HAVE_TCGETATTR
200
0
  atexit (cleanup);
201
0
#endif
202
203
0
  initialized = 1;
204
0
}
205
206
207
int
208
tty_batchmode( int onoff )
209
0
{
210
0
  int old = batchmode;
211
0
  if (onoff != -1)
212
0
    batchmode = onoff;
213
0
  return old;
214
0
}
215
216
int
217
tty_no_terminal(int onoff)
218
0
{
219
0
  int old = no_terminal;
220
0
  no_terminal = onoff ? 1 : 0;
221
0
  return old;
222
0
}
223
224
225
#ifdef HAVE_W32_SYSTEM
226
/* Write the UTF-8 encoded STRING to the console.  */
227
static void
228
w32_write_console (const char *string)
229
{
230
  wchar_t *wstring;
231
  DWORD n, nwritten;
232
233
  wstring = utf8_to_wchar (string);
234
  if (!wstring)
235
    log_fatal ("w32_write_console failed: %s", strerror (errno));
236
  n = wcslen (wstring);
237
238
  if (!WriteConsoleW (con.out, wstring, n, &nwritten, NULL))
239
    {
240
      static int shown;
241
      if (!shown)
242
        {
243
          shown = 1;
244
          log_info ("WriteConsole failed: %s", w32_strerror (-1));
245
          log_info ("Please configure a suitable font for the console\n");
246
        }
247
      n = strlen (string);
248
      if (!WriteConsoleA (con.out, string, n , &nwritten, NULL))
249
        log_fatal ("WriteConsole fallback failed: %s", w32_strerror (-1));
250
    }
251
  else
252
    {
253
      if (n != nwritten)
254
        log_fatal ("WriteConsole failed: %lu != %lu\n",
255
                   (unsigned long)n, (unsigned long)nwritten);
256
    }
257
  last_prompt_len += n;
258
  xfree (wstring);
259
}
260
#endif /*HAVE_W32_SYSTEM*/
261
262
263
void
264
tty_printf (const char *fmt, ... )
265
0
{
266
0
  va_list arg_ptr;
267
268
0
  if (no_terminal)
269
0
    return;
270
271
0
  if (!initialized)
272
0
    init_ttyfp ();
273
274
0
  va_start (arg_ptr, fmt);
275
276
#ifdef HAVE_W32_SYSTEM
277
  {
278
    char *buf = NULL;
279
280
    vasprintf(&buf, fmt, arg_ptr);
281
    if (!buf)
282
      log_bug ("vasprintf() failed\n");
283
    w32_write_console (buf);
284
    xfree (buf);
285
  }
286
#else /* Unix */
287
0
  last_prompt_len += vfprintf (ttyfp, fmt, arg_ptr) ;
288
0
  fflush (ttyfp);
289
0
#endif /* Unix */
290
0
  va_end(arg_ptr);
291
0
}
292
293
294
/* Same as tty_printf but if FP is not NULL, behave like a regular
295
   fprintf. */
296
void
297
tty_fprintf (estream_t fp, const char *fmt, ... )
298
0
{
299
0
  va_list arg_ptr;
300
301
0
  if (fp)
302
0
    {
303
0
      va_start (arg_ptr, fmt) ;
304
0
      es_vfprintf (fp, fmt, arg_ptr );
305
0
      va_end (arg_ptr);
306
0
      return;
307
0
    }
308
309
0
  if (no_terminal)
310
0
    return;
311
312
0
  if (!initialized)
313
0
    init_ttyfp ();
314
315
0
  va_start (arg_ptr, fmt);
316
317
#ifdef HAVE_W32_SYSTEM
318
  {
319
    char *buf = NULL;
320
321
    vasprintf (&buf, fmt, arg_ptr);
322
    if (!buf)
323
      log_bug ("vasprintf() failed\n");
324
    w32_write_console (buf);
325
    xfree (buf);
326
  }
327
#else /* Unix */
328
0
  last_prompt_len += vfprintf(ttyfp,fmt,arg_ptr) ;
329
0
  fflush(ttyfp);
330
0
#endif /* Unix */
331
332
0
  va_end(arg_ptr);
333
0
}
334
335
336
/* Print a string, but filter all control characters out.  If FP is
337
 * not NULL print to that stream instead to the tty.  */
338
static void
339
do_print_string (estream_t fp, const byte *p, size_t n )
340
0
{
341
0
  if (no_terminal && !fp)
342
0
    return;
343
344
0
  if (!initialized && !fp)
345
0
    init_ttyfp();
346
347
0
  if (fp)
348
0
    {
349
0
      print_utf8_buffer (fp, p, n);
350
0
      return;
351
0
    }
352
353
#ifdef HAVE_W32_SYSTEM
354
  /* Not so effective, change it if you want */
355
  for (; n; n--, p++)
356
    {
357
      if (iscntrl (*p))
358
        {
359
          if( *p == '\n' )
360
            tty_printf ("\\n");
361
          else if( !*p )
362
            tty_printf ("\\0");
363
          else
364
            tty_printf ("\\x%02x", *p);
365
        }
366
      else
367
        tty_printf ("%c", *p);
368
    }
369
#else /* Unix */
370
0
  for (; n; n--, p++)
371
0
    {
372
0
      if (iscntrl (*p))
373
0
        {
374
0
          putc ('\\', ttyfp);
375
0
          if ( *p == '\n' )
376
0
            putc ('n', ttyfp);
377
0
          else if ( !*p )
378
0
            putc ('0', ttyfp);
379
0
          else
380
0
            fprintf (ttyfp, "x%02x", *p );
381
0
        }
382
0
      else
383
0
        putc (*p, ttyfp);
384
0
    }
385
0
#endif /* Unix */
386
0
}
387
388
389
void
390
tty_print_utf8_string2 (estream_t fp, const byte *p, size_t n, size_t max_n)
391
0
{
392
0
  size_t i;
393
0
  char *buf;
394
395
0
  if (no_terminal && !fp)
396
0
    return;
397
398
  /* We can handle plain ascii simpler, so check for it first. */
399
0
  for(i=0; i < n; i++ )
400
0
    {
401
0
      if (p[i] & 0x80)
402
0
        break;
403
0
    }
404
0
  if (i < n)
405
0
    {
406
0
      buf = utf8_to_native ((const char *)p, n, 0);
407
0
      if (max_n && (strlen (buf) > max_n))
408
0
        buf[max_n] = 0;
409
      /* (utf8_to_native already did  the control character quoting) */
410
0
      tty_fprintf (fp, "%s", buf);
411
0
      xfree (buf);
412
0
    }
413
0
  else
414
0
    {
415
0
      if (max_n && (n > max_n))
416
0
        n = max_n;
417
0
      do_print_string (fp, p, n );
418
0
    }
419
0
}
420
421
422
void
423
tty_print_utf8_string (const byte *p, size_t n)
424
0
{
425
0
  tty_print_utf8_string2 (NULL, p, n, 0);
426
0
}
427
428
429
/* Read a string from the tty using PROMPT.  If HIDDEN is set the
430
 * input is not echoed.  */
431
static char *
432
do_get (const char *prompt, int hidden)
433
0
{
434
0
  char *buf;
435
0
  int  n;  /* Allocated size of BUF.  */
436
0
  int  i;  /* Number of bytes in BUF. */
437
0
  int  c;
438
#ifdef HAVE_W32_SYSTEM
439
  char *utf8buf;
440
  int errcount = 0;
441
#else
442
0
  byte cbuf[1];
443
0
#endif
444
445
0
  if (batchmode)
446
0
    {
447
0
      log_error (_("Sorry, we are in batchmode - can't get input\n"));
448
0
      exit (2);
449
0
    }
450
451
0
  if (no_terminal)
452
0
    {
453
0
      log_error (_("Sorry, no terminal at all requested - can't get input\n"));
454
0
      exit (2);
455
0
    }
456
457
0
  if (!initialized)
458
0
    init_ttyfp ();
459
460
0
  last_prompt_len = 0;
461
0
  tty_printf ("%s", prompt);
462
0
  buf = xmalloc ((n=50));
463
0
  i = 0;
464
465
#ifdef HAVE_W32_SYSTEM
466
  if (hidden)
467
    SetConsoleMode(con.in, HID_INPMODE );
468
469
  utf8buf = NULL;
470
  for (;;)
471
    {
472
      DWORD nread;
473
      wchar_t wbuf[2];
474
      const unsigned char *s;
475
476
      if (!ReadConsoleW (con.in, wbuf, 1, &nread, NULL))
477
        log_fatal ("ReadConsole failed: %s", w32_strerror (-1));
478
      if (!nread)
479
        continue;
480
481
      wbuf[1] = 0;
482
      xfree (utf8buf);
483
      utf8buf = wchar_to_utf8 (wbuf);
484
      if (!utf8buf)
485
        {
486
          log_info ("wchar_to_utf8 failed: %s\n", strerror (errno));
487
          if (++errcount > 10)
488
            log_fatal (_("too many errors; giving up\n"));
489
          continue;
490
        }
491
      if (*utf8buf == '\n')
492
        {
493
          if (utf8buf[1])
494
            {
495
              log_info ("ReadConsole returned more than requested"
496
                        " (0x0a,0x%02x)\n", utf8buf[1]);
497
              if (++errcount > 10)
498
                log_fatal (_("too many errors; giving up\n"));
499
            }
500
          break;
501
        }
502
      if (!hidden)
503
        last_prompt_len++;
504
505
      for (s=utf8buf; *s; s++)
506
        {
507
          c = *s;
508
          if (c == '\t')
509
            c = ' ';  /* Map tab to a space.  */
510
          else if ((c >= 0 && c <= 0x1f) || c == 0x7f)
511
            continue; /* Remove control characters.  */
512
          if (!(i < n-1))
513
            {
514
              n += 50;
515
              buf = xrealloc (buf, n);
516
            }
517
          buf[i++] = c;
518
        }
519
    }
520
  xfree (utf8buf);
521
522
  if (hidden)
523
    SetConsoleMode(con.in, DEF_INPMODE );
524
525
#else /* Unix */
526
527
0
  if (hidden)
528
0
    {
529
0
#ifdef HAVE_TCGETATTR
530
0
      struct termios term;
531
532
0
      if (tcgetattr(fileno(ttyfp), &termsave))
533
0
        log_fatal ("tcgetattr() failed: %s\n", strerror(errno));
534
0
      restore_termios = 1;
535
0
      term = termsave;
536
0
      term.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
537
0
      if (tcsetattr( fileno(ttyfp), TCSAFLUSH, &term ) )
538
0
        log_fatal("tcsetattr() failed: %s\n", strerror(errno));
539
0
#endif /*HAVE_TCGETATTR*/
540
0
    }
541
542
  /* fixme: How can we avoid that the \n is echoed w/o disabling
543
   * canonical mode - w/o this kill_prompt can't work */
544
0
  while (read(fileno(ttyfp), cbuf, 1) == 1 && *cbuf != '\n')
545
0
    {
546
0
      if (!hidden)
547
0
        last_prompt_len++;
548
0
      c = *cbuf;
549
0
      if (c == CONTROL_D)
550
0
        log_info (_("Control-D detected\n"));
551
552
0
      if (c == '\t') /* Map tab to a space.  */
553
0
        c = ' ';
554
0
      else if ( (c >= 0 && c <= 0x1f) || c == 0x7f)
555
0
        continue; /* Skip all other ASCII control characters.  */
556
0
      if (!(i < n-1))
557
0
        {
558
0
          n += 50;
559
0
          buf = xrealloc (buf, n);
560
0
        }
561
0
      buf[i++] = c;
562
0
    }
563
0
  if (*cbuf != '\n')
564
0
    {
565
0
      buf[0] = CONTROL_D;
566
0
      i = 1;
567
0
    }
568
569
0
  if (hidden)
570
0
    {
571
0
#ifdef HAVE_TCGETATTR
572
0
      if (tcsetattr (fileno(ttyfp), TCSAFLUSH, &termsave))
573
0
        log_error ("tcsetattr() failed: %s\n", strerror(errno));
574
0
      restore_termios = 0;
575
0
#endif /*HAVE_TCGETATTR*/
576
0
    }
577
0
#endif /* Unix */
578
579
0
  buf[i] = 0;
580
0
  return buf;
581
0
}
582
583
584
585
/* Note: This function never returns NULL. */
586
char *
587
tty_get( const char *prompt )
588
0
{
589
0
  if (!batchmode && !no_terminal && my_rl_readline && my_rl_add_history)
590
0
    {
591
0
      char *line;
592
0
      char *buf;
593
594
0
      if (!initialized)
595
0
  init_ttyfp();
596
597
0
      last_prompt_len = 0;
598
599
0
      line = my_rl_readline (prompt?prompt:"");
600
601
      /* We need to copy it to memory controlled by our malloc
602
         implementations; further we need to convert an EOF to our
603
         convention. */
604
0
      buf = xmalloc(line? strlen(line)+1:2);
605
0
      if (line)
606
0
        {
607
0
          strcpy (buf, line);
608
0
          trim_spaces (buf);
609
0
          if (strlen (buf) > 2 )
610
0
            my_rl_add_history (line); /* Note that we test BUF but add LINE. */
611
0
          free (line);
612
0
        }
613
0
      else
614
0
        {
615
0
          buf[0] = CONTROL_D;
616
0
          buf[1] = 0;
617
0
        }
618
0
      return buf;
619
0
    }
620
0
  else
621
0
    return do_get ( prompt, 0 );
622
0
}
623
624
625
/* Variable argument version of tty_get.  The prompt is actually a
626
 * format string with arguments.  */
627
char *
628
tty_getf (const char *promptfmt, ... )
629
0
{
630
0
  va_list arg_ptr;
631
0
  char *prompt;
632
0
  char *answer;
633
634
0
  va_start (arg_ptr, promptfmt);
635
0
  if (gpgrt_vasprintf (&prompt, promptfmt, arg_ptr) < 0)
636
0
    log_fatal ("estream_vasprintf failed: %s\n", strerror (errno));
637
0
  va_end (arg_ptr);
638
0
  answer = tty_get (prompt);
639
0
  xfree (prompt);
640
0
  return answer;
641
0
}
642
643
644
char *
645
tty_get_hidden( const char *prompt )
646
0
{
647
0
  return do_get (prompt, 1);
648
0
}
649
650
651
void
652
tty_kill_prompt (void)
653
0
{
654
0
  if (no_terminal)
655
0
    return;
656
657
0
  if (!initialized)
658
0
    init_ttyfp ();
659
660
0
  if (batchmode)
661
0
    last_prompt_len = 0;
662
0
  if (!last_prompt_len)
663
0
    return;
664
#ifdef HAVE_W32_SYSTEM
665
  tty_printf ("\r%*s\r", last_prompt_len, "");
666
#else /* Unix */
667
0
  {
668
0
    int i;
669
0
    putc ('\r', ttyfp);
670
0
    for (i=0; i < last_prompt_len; i ++ )
671
0
      putc (' ', ttyfp);
672
0
    putc ('\r', ttyfp);
673
0
    fflush (ttyfp);
674
0
  }
675
0
#endif /* Unix */
676
0
  last_prompt_len = 0;
677
0
}
678
679
680
int
681
tty_get_answer_is_yes( const char *prompt )
682
0
{
683
0
  int yes;
684
0
  char *p;
685
686
0
  p = tty_get (prompt);
687
0
  tty_kill_prompt ();
688
0
  yes = answer_is_yes (p);
689
0
  xfree (p);
690
691
0
  return yes;
692
0
}
693
694
695
/* Called by gnupg_rl_initialize to setup the readline support. */
696
void
697
tty_private_set_rl_hooks (void (*init_stream) (FILE *),
698
                          void (*set_completer) (rl_completion_func_t*),
699
                          void (*inhibit_completion) (int),
700
                          void (*cleanup_after_signal) (void),
701
                          char *(*readline_fun) (const char*),
702
                          void (*add_history_fun) (const char*),
703
                          int (*rw_history_fun)(const char *, int, int))
704
0
{
705
0
  my_rl_init_stream = init_stream;
706
0
  my_rl_set_completer = set_completer;
707
0
  my_rl_inhibit_completion = inhibit_completion;
708
0
  my_rl_cleanup_after_signal = cleanup_after_signal;
709
0
  my_rl_readline = readline_fun;
710
0
  my_rl_add_history = add_history_fun;
711
0
  my_rl_rw_history = rw_history_fun;
712
0
}
713
714
715
/* Read the history from FILENAME or limit the size of the history.
716
 * If FILENAME is NULL and NLINES is zero the current history is
717
 * cleared.  Returns 0 on success or -1 on error and sets ERRNO.  No
718
 * error is return if readline support is not available.  */
719
int
720
tty_read_history (const char *filename, int nlines)
721
0
{
722
0
  int rc;
723
724
0
  if (!my_rl_rw_history)
725
0
    return 0;
726
727
0
  rc = my_rl_rw_history (filename, 0, nlines);
728
0
  if (rc && gpg_err_code_from_syserror () == GPG_ERR_ENOENT)
729
0
    rc = 0;
730
731
0
  return rc;
732
0
}
733
734
735
/* Write the current history to the file FILENAME.  Returns 0 on
736
 * success or -1 on error and sets ERRNO.  No error is return if
737
 * readline support is not available.  */
738
int
739
tty_write_history (const char *filename)
740
0
{
741
0
  if (!my_rl_rw_history)
742
0
    return 0;
743
744
0
  return my_rl_rw_history (filename, 1, 0);
745
0
}
746
747
748
#ifdef HAVE_LIBREADLINE
749
void
750
tty_enable_completion (rl_completion_func_t *completer)
751
{
752
  if (no_terminal || !my_rl_set_completer )
753
    return;
754
755
  if (!initialized)
756
    init_ttyfp();
757
758
  my_rl_set_completer (completer);
759
}
760
761
void
762
tty_disable_completion (void)
763
{
764
  if (no_terminal || !my_rl_inhibit_completion)
765
    return;
766
767
  if (!initialized)
768
    init_ttyfp();
769
770
  my_rl_inhibit_completion (1);
771
}
772
#endif /* HAVE_LIBREADLINE */
773
774
void
775
tty_cleanup_after_signal (void)
776
0
{
777
0
#ifdef HAVE_TCGETATTR
778
0
  cleanup ();
779
0
#endif
780
0
}
781
782
void
783
tty_cleanup_rl_after_signal (void)
784
0
{
785
0
  if (my_rl_cleanup_after_signal)
786
0
    my_rl_cleanup_after_signal ();
787
0
}