1 /*@ S-nail - a mail user agent derived from Berkeley Mail.
4 * Copyright (c) 2000-2004 Gunnar Ritter, Freiburg i. Br., Germany.
5 * Copyright (c) 2012 - 2015 Steffen (Daode) Nurpmeso <sdaoden@users.sf.net>.
8 * Permission to use, copy, modify, and/or distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Copyright (c) 1980, 1993
22 * The Regents of the University of California. All rights reserved.
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 * 2. Redistributions in binary form must reproduce the above copyright
30 * notice, this list of conditions and the following disclaimer in the
31 * documentation and/or other materials provided with the distribution.
32 * 3. Neither the name of the University nor the names of its contributors
33 * may be used to endorse or promote products derived from this software
34 * without specific prior written permission.
36 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
37 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
40 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
41 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
42 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
43 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
44 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
45 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 #ifndef HAVE_AMALGAMATION
56 # include <readline/readline.h>
58 # include <readline/history.h>
60 #elif defined HAVE_EDITLINE
61 # include <histedit.h>
64 /* Shared history support macros */
66 # define _CL_HISTFILE(S) \
68 char const *__hist_obsolete = ok_vlook(NAIL_HISTFILE);\
69 if (__hist_obsolete != NULL)\
70 OBSOLETE(_("please use *history-file* instead of *NAIL_HISTFILE*"));\
71 S = ok_vlook(history_file);\
73 (S) = __hist_obsolete;\
75 S = fexpand(S, FEXP_LOCAL | FEXP_NSHELL);\
78 # define _CL_HISTSIZE(V) \
80 char const *__hist_obsolete = ok_vlook(NAIL_HISTSIZE);\
81 char const *__sv = ok_vlook(history_size);\
83 if (__hist_obsolete != NULL)\
84 OBSOLETE(_("please use *history-size* instead of *NAIL_HISTSIZE*"));\
86 __sv = __hist_obsolete;\
87 if (__sv == NULL || *__sv == '\0' || (__rv = strtol(__sv, NULL, 10)) == 0)\
95 # define _CL_CHECK_ADDHIST(S,NOACT) \
106 # define C_HISTORY_SHARED \
113 if (argv[1] != NULL)\
115 if (!asccasecmp(*argv, "show"))\
117 if (!asccasecmp(*argv, "clear"))\
119 if ((entry = strtol(*argv, argv, 10)) > 0 && **argv == '\0')\
122 n_err(_("Synopsis: history: %s\n" \
123 "<show> (default), <clear> or select <NO> from editor history"));\
127 return (v == NULL ? !STOP : !OKAY); /* xxx 1:bad 0:good -- do some */
128 #endif /* HAVE_HISTORY */
130 /* fexpand() flags for expand-on-tab */
131 #define _CL_TAB_FEXP_FL (FEXP_FULL | FEXP_SILENT | FEXP_MULTIOK)
134 * Because we have multiple identical implementations, change file layout a bit
135 * and place the implementations one after the other below the other externals
138 static sigjmp_buf __n_tty_actjmp
; /* TODO someday, we won't need it no more */
140 __n_tty_acthdl(int s
) /* TODO someday, we won't need it no more */
142 NYD_X
; /* Signal handler */
143 termios_state_reset();
144 siglongjmp(__n_tty_actjmp
, s
);
148 getapproval(char const * volatile prompt
, bool_t noninteract_default
)
150 sighandler_type
volatile oint
, ohup
;
155 if (!(options
& OPT_INTERACTIVE
)) {
157 rv
= noninteract_default
;
163 char const *quest
= noninteract_default
164 ? _("[yes]/no? ") : _("[no]/yes? ");
167 prompt
= _("Continue");
168 prompt
= savecatsep(prompt
, ' ', quest
);
171 oint
= safe_signal(SIGINT
, SIG_IGN
);
172 ohup
= safe_signal(SIGHUP
, SIG_IGN
);
173 if ((sig
= sigsetjmp(__n_tty_actjmp
, 1)) != 0)
175 safe_signal(SIGINT
, &__n_tty_acthdl
);
176 safe_signal(SIGHUP
, &__n_tty_acthdl
);
178 if (readline_input(prompt
, FAL0
, &termios_state
.ts_linebuf
,
179 &termios_state
.ts_linesize
, NULL
) >= 0)
180 rv
= (boolify(termios_state
.ts_linebuf
, UIZ_MAX
,
181 noninteract_default
) > 0);
183 termios_state_reset();
185 safe_signal(SIGHUP
, ohup
);
186 safe_signal(SIGINT
, oint
);
196 getuser(char const * volatile query
) /* TODO v15-compat obsolete */
198 sighandler_type
volatile oint
, ohup
;
199 char * volatile user
= NULL
;
206 oint
= safe_signal(SIGINT
, SIG_IGN
);
207 ohup
= safe_signal(SIGHUP
, SIG_IGN
);
208 if ((sig
= sigsetjmp(__n_tty_actjmp
, 1)) != 0)
210 safe_signal(SIGINT
, &__n_tty_acthdl
);
211 safe_signal(SIGHUP
, &__n_tty_acthdl
);
213 if (readline_input(query
, FAL0
, &termios_state
.ts_linebuf
,
214 &termios_state
.ts_linesize
, NULL
) >= 0)
215 user
= termios_state
.ts_linebuf
;
217 termios_state_reset();
219 safe_signal(SIGHUP
, ohup
);
220 safe_signal(SIGINT
, oint
);
228 getpassword(char const *query
)
230 sighandler_type
volatile oint
, ohup
;
232 char * volatile pass
= NULL
;
237 query
= _("Password: ");
238 fputs(query
, stdout
);
241 /* FIXME everywhere: tcsetattr() generates SIGTTOU when we're not in
242 * FIXME foreground pgrp, and can fail with EINTR!! also affects
243 * FIXME termios_state_reset() */
244 if (options
& OPT_TTYIN
) {
245 tcgetattr(STDIN_FILENO
, &termios_state
.ts_tios
);
246 memcpy(&tios
, &termios_state
.ts_tios
, sizeof tios
);
247 termios_state
.ts_needs_reset
= TRU1
;
248 tios
.c_iflag
&= ~(ISTRIP
);
249 tios
.c_lflag
&= ~(ECHO
| ECHOE
| ECHOK
| ECHONL
);
252 oint
= safe_signal(SIGINT
, SIG_IGN
);
253 ohup
= safe_signal(SIGHUP
, SIG_IGN
);
254 if ((sig
= sigsetjmp(__n_tty_actjmp
, 1)) != 0)
256 safe_signal(SIGINT
, &__n_tty_acthdl
);
257 safe_signal(SIGHUP
, &__n_tty_acthdl
);
259 if (options
& OPT_TTYIN
)
260 tcsetattr(STDIN_FILENO
, TCSAFLUSH
, &tios
);
262 if (readline_restart(stdin
, &termios_state
.ts_linebuf
,
263 &termios_state
.ts_linesize
, 0) >= 0)
264 pass
= termios_state
.ts_linebuf
;
266 termios_state_reset();
267 if (options
& OPT_TTYIN
)
270 safe_signal(SIGHUP
, ohup
);
271 safe_signal(SIGINT
, oint
);
277 #endif /* HAVE_SOCKETS */
284 static sighandler_type _rl_shup
;
285 static char * _rl_buf
; /* pre_input() hook: initial line */
286 static int _rl_buflen
; /* content, and its length */
288 static int _rl_pre_input(void);
294 /* Handle leftover data from \ escaped former line */
295 rl_extend_line_buffer(_rl_buflen
+ 10);
296 memcpy(rl_line_buffer
, _rl_buf
, _rl_buflen
+ 1);
297 rl_point
= rl_end
= _rl_buflen
;
298 rl_pre_input_hook
= (rl_hook_func_t
*)NULL
;
313 rl_readline_name
= UNCONST(uagent
);
317 stifle_history((int)hs
);
319 rl_read_init_file(NULL
);
321 /* Because rl_read_init_file() may have introduced yet a different
322 * history size limit, simply load and incorporate the history, leave
323 * it up to readline(3) to do the rest */
349 n_tty_signal(int sig
)
352 NYD_X
; /* Signal handler */
360 /* readline(3) doesn't catch it :( */
361 rl_free_line_state();
362 rl_cleanup_after_signal();
363 safe_signal(SIGHUP
, _rl_shup
);
365 sigaddset(&nset
, sig
);
366 sigprocmask(SIG_UNBLOCK
, &nset
, &oset
);
368 /* XXX When we come here we'll continue editing, so reestablish
369 * XXX cannot happen */
370 sigprocmask(SIG_BLOCK
, &oset
, NULL
);
371 _rl_shup
= safe_signal(SIGHUP
, &n_tty_signal
);
372 rl_reset_after_signal();
380 (n_tty_readline
)(char const *prompt
, char **linebuf
, size_t *linesize
, size_t n
390 rl_pre_input_hook
= &_rl_pre_input
;
393 _rl_shup
= safe_signal(SIGHUP
, &n_tty_signal
);
394 line
= readline(prompt
!= NULL
? prompt
: "");
395 safe_signal(SIGHUP
, _rl_shup
);
403 if (n
>= *linesize
) {
404 *linesize
= LINESIZE
+ n
+1;
405 *linebuf
= (srealloc
)(*linebuf
, *linesize SMALLOC_DEBUG_ARGSCALL
);
407 memcpy(*linebuf
, line
, n
);
409 (*linebuf
)[n
] = '\0';
417 n_tty_addhist(char const *s
, bool_t isgabby
)
423 if (isgabby
&& !ok_blook(history_gabby
))
425 _CL_CHECK_ADDHIST(s
, goto jleave
);
426 hold_all_sigs(); /* XXX too heavy */
427 add_history(s
); /* XXX yet we jump away! */
428 rele_all_sigs(); /* XXX remove jumps */
446 if ((fp
= Ftmp(NULL
, "hist", OF_RDWR
| OF_UNLINK
| OF_REGISTER
)) == NULL
) {
447 n_perr(_("tmpfile"), 0);
452 hs
= history_get_history_state();
454 for (i
= (ul_i
)hs
->length
, hl
= hs
->entries
+ i
, b
= 0; i
> 0; --i
) {
455 char *cp
= (*--hl
)->line
;
456 size_t sl
= strlen(cp
);
457 fprintf(fp
, "%4lu. %-50.50s (%4lu+%2lu bytes)\n", i
, cp
, b
, sl
);
461 page_or_print(fp
, (size_t)hs
->length
);
471 HISTORY_STATE
*hs
= history_get_history_state();
473 if (UICMP(z
, entry
, <=, hs
->length
))
474 v
= temporary_arg_v_store
= hs
->entries
[entry
- 1]->line
;
480 # endif /* HAVE_HISTORY */
481 #endif /* HAVE_READLINE */
488 static EditLine
* _el_el
; /* editline(3) handle */
489 static char const * _el_prompt
; /* Current prompt */
491 static History
* _el_hcom
; /* History handle for commline */
494 static char const * _el_getprompt(void);
514 _el_hcom
= history_init();
515 history(_el_hcom
, &he
, H_SETSIZE
, (int)hs
);
516 /* We unroll our own one history(_el_hcom, &he, H_SETUNIQUE, 1);*/
519 _el_el
= el_init(uagent
, stdin
, stdout
, stderr
);
520 el_set(_el_el
, EL_SIGNAL
, 1);
521 el_set(_el_el
, EL_TERMINAL
, NULL
);
522 /* Need to set HIST before EDITOR, otherwise it won't work automatic */
524 el_set(_el_el
, EL_HIST
, &history
, _el_hcom
);
526 el_set(_el_el
, EL_EDITOR
, "emacs");
527 # ifdef EL_PROMPT_ESC
528 el_set(_el_el
, EL_PROMPT_ESC
, &_el_getprompt
, '\1');
530 el_set(_el_el
, EL_PROMPT
, &_el_getprompt
);
533 el_set(_el_el
, EL_ADDFN
, "tab_complete",
534 "editline(3) internal completion function", &_el_file_cpl
);
535 el_set(_el_el
, EL_BIND
, "^I", "tab_complete", NULL
);
538 el_set(_el_el
, EL_BIND
, "^R", "ed-search-prev-history", NULL
);
540 el_source(_el_el
, NULL
); /* Source ~/.editrc */
543 /* Because el_source() may have introduced yet a different history size
544 * limit, simply load and incorporate the history, leave it up to
545 * editline(3) to do the rest */
549 history(_el_hcom
, &he
, H_LOAD
, v
);
569 history(_el_hcom
, &he
, H_SAVE
, v
);
570 history_end(_el_hcom
);
576 n_tty_signal(int sig
)
578 NYD_X
; /* Signal handler */
591 (n_tty_readline
)(char const *prompt
, char **linebuf
, size_t *linesize
, size_t n
598 _el_prompt
= (prompt
!= NULL
) ? prompt
: "";
600 el_push(_el_el
, *linebuf
);
601 line
= el_gets(_el_el
, &nn
);
609 if (n
> 0 && line
[n
- 1] == '\n')
612 if (n
>= *linesize
) {
613 *linesize
= LINESIZE
+ n
+ 1;
614 *linebuf
= (srealloc
)(*linebuf
, *linesize SMALLOC_DEBUG_ARGSCALL
);
616 memcpy(*linebuf
, line
, n
);
617 (*linebuf
)[n
] = '\0';
624 n_tty_addhist(char const *s
, bool_t isgabby
)
627 /* Enlarge meaning of unique .. to something that rocks;
628 * xxx unfortunately this is expensive to do with editline(3)
629 * xxx maybe it would be better to hook the ptfs instead? */
638 if (isgabby
&& !ok_blook(history_gabby
))
640 _CL_CHECK_ADDHIST(s
, goto jleave
);
642 hold_all_sigs(); /* XXX too heavy, yet we jump away! */
643 for (i
= history(_el_hcom
, &he
, H_FIRST
); i
>= 0;
644 i
= history(_el_hcom
, &he
, H_NEXT
))
645 if (!strcmp(he
.str
, s
)) {
646 history(_el_hcom
, &he
, H_DEL
, he
.num
);
649 history(_el_hcom
, &he
, H_ENTER
, s
);
650 rele_all_sigs(); /* XXX remove jumps */
668 if ((fp
= Ftmp(NULL
, "hist", OF_RDWR
| OF_UNLINK
| OF_REGISTER
)) == NULL
) {
669 n_perr(_("tmpfile"), 0);
674 i
= (size_t)((history(_el_hcom
, &he
, H_GETSIZE
) >= 0) ? he
.num
: 0);
676 for (x
= history(_el_hcom
, &he
, H_FIRST
); x
>= 0;
677 x
= history(_el_hcom
, &he
, H_NEXT
)) {
678 size_t sl
= strlen(he
.str
);
679 fprintf(fp
, "%4lu. %-50.50s (%4lu+%2lu bytes)\n",
680 (ul_i
)i
, he
.str
, (ul_i
)b
, (ul_i
)sl
);
685 page_or_print(fp
, i
);
692 history(_el_hcom
, &he
, H_CLEAR
);
701 i
= (size_t)((history(_el_hcom
, &he
, H_GETSIZE
) >= 0) ? he
.num
: 0);
702 if (UICMP(z
, entry
, <=, i
)) {
703 entry
= (long)i
- entry
;
704 for (x
= history(_el_hcom
, &he
, H_FIRST
); x
>= 0;
705 x
= history(_el_hcom
, &he
, H_NEXT
))
707 v
= temporary_arg_v_store
= UNCONST(he
.str
);
715 # endif /* HAVE_HISTORY */
716 #endif /* HAVE_EDITLINE */
719 * NCL: our homebrew version (inspired from NetBSD sh(1) / dash(1)s hetio.c).
721 * Only used in interactive mode, simply use STDIN_FILENO as point of interest.
722 * We do not handle character widths because the terminal must deal with that
723 * anyway on the one hand, and also wcwidth(3) doesn't support zero-width
724 * characters by definition on the other. We're addicted.
726 * To avoid memory leaks etc. with the current codebase that simply longjmp(3)s
727 * we're forced to use the very same buffer--the one that is passed through to
728 * us from the outside--to store anything we need, i.e., a `struct cell[]', and
729 * convert that on-the-fly back to the plain char* result once we're done.
730 * To simplify our live, use savestr() buffers for all other needed memory
735 # define MAX_INPUT 255 /* (_POSIX_MAX_INPUT = 255 as of Issue 7 TC1) */
738 /* Since we simply fputs(3) the prompt, assume each character requires two
739 * visual cells -- and we need to restrict the maximum prompt size because
740 * of MAX_INPUT and our desire to have room for some error message left */
741 # define _PROMPT_VLEN(P) (strlen(P) * 2)
742 # define _PROMPT_MAX ((MAX_INPUT / 2) + (MAX_INPUT / 4))
752 char cbuf
[MB_LEN_MAX
* 2]; /* .. plus reset shift sequence */
756 size_t cursor
; /* Current cursor position */
757 size_t topins
; /* Outermost cursor col set */
759 char *cbuf
; /* *x_buf */
762 struct str defc
; /* Current default content */
763 struct str savec
; /* Saved default content */
765 struct hist
*hist
; /* History cursor */
768 char const *nd
; /* Cursor right */
769 char **x_buf
; /* Caller pointers */
776 struct hist
*younger
;
779 char dat
[VFIELD_SIZE(sizeof(ui32_t
))];
783 static sighandler_type _ncl_oint
;
784 static sighandler_type _ncl_oquit
;
785 static sighandler_type _ncl_oterm
;
786 static sighandler_type _ncl_ohup
;
787 static sighandler_type _ncl_otstp
;
788 static sighandler_type _ncl_ottin
;
789 static sighandler_type _ncl_ottou
;
790 static struct xtios _ncl_tios
;
792 static struct hist
*_ncl_hist
;
793 static struct hist
*_ncl_hist_tail
;
794 static size_t _ncl_hist_size
;
795 static size_t _ncl_hist_size_max
;
796 static bool_t _ncl_hist_load
;
799 static void _ncl_sigs_up(void);
800 static void _ncl_sigs_down(void);
802 static void _ncl_term_mode(bool_t raw
);
804 static void _ncl_check_grow(struct line
*l
, size_t no SMALLOC_DEBUG_ARGS
);
805 static void _ncl_bs_eof_dvup(struct cell
*cap
, size_t i
);
806 static ssize_t
_ncl_wboundary(struct line
*l
, ssize_t dir
);
807 static ssize_t
_ncl_cell2dat(struct line
*l
);
808 # if defined HAVE_HISTORY || defined HAVE_TABEXPAND
809 static void _ncl_cell2save(struct line
*l
);
812 static void _ncl_khome(struct line
*l
, bool_t dobell
);
813 static void _ncl_kend(struct line
*l
);
814 static void _ncl_kbs(struct line
*l
);
815 static void _ncl_kkill(struct line
*l
, bool_t dobell
);
816 static ssize_t
_ncl_keof(struct line
*l
);
817 static void _ncl_kleft(struct line
*l
);
818 static void _ncl_kright(struct line
*l
);
819 static void _ncl_krefresh(struct line
*l
);
820 static void _ncl_kbwddelw(struct line
*l
);
821 static void _ncl_kgow(struct line
*l
, ssize_t dir
);
822 static void _ncl_kother(struct line
*l
, wchar_t wc
);
824 static size_t __ncl_khist_shared(struct line
*l
, struct hist
*hp
);
825 static size_t _ncl_khist(struct line
*l
, bool_t backwd
);
826 static size_t _ncl_krhist(struct line
*l
);
828 # ifdef HAVE_TABEXPAND
829 static size_t _ncl_kht(struct line
*l
);
831 static ssize_t
_ncl_readline(char const *prompt
, char **buf
, size_t *bufsize
,
832 size_t len SMALLOC_DEBUG_ARGS
);
842 sigprocmask(SIG_BLOCK
, &nset
, &oset
);
843 _ncl_oint
= safe_signal(SIGINT
, &n_tty_signal
);
844 _ncl_oquit
= safe_signal(SIGQUIT
, &n_tty_signal
);
845 _ncl_oterm
= safe_signal(SIGTERM
, &n_tty_signal
);
846 _ncl_ohup
= safe_signal(SIGHUP
, &n_tty_signal
);
847 _ncl_otstp
= safe_signal(SIGTSTP
, &n_tty_signal
);
848 _ncl_ottin
= safe_signal(SIGTTIN
, &n_tty_signal
);
849 _ncl_ottou
= safe_signal(SIGTTOU
, &n_tty_signal
);
850 sigprocmask(SIG_SETMASK
, &oset
, (sigset_t
*)NULL
);
862 sigprocmask(SIG_BLOCK
, &nset
, &oset
);
863 safe_signal(SIGINT
, _ncl_oint
);
864 safe_signal(SIGQUIT
, _ncl_oquit
);
865 safe_signal(SIGTERM
, _ncl_oterm
);
866 safe_signal(SIGHUP
, _ncl_ohup
);
867 safe_signal(SIGTSTP
, _ncl_otstp
);
868 safe_signal(SIGTTIN
, _ncl_ottin
);
869 safe_signal(SIGTTOU
, _ncl_ottou
);
870 sigprocmask(SIG_SETMASK
, &oset
, (sigset_t
*)NULL
);
875 _ncl_term_mode(bool_t raw
)
877 struct termios
*tiosp
;
880 tiosp
= &_ncl_tios
.told
;
884 /* Always requery the attributes, in case we've been moved from background
885 * to foreground or however else in between sessions */
886 /* XXX Always enforce ECHO and ICANON in the OLD attributes - do so as long
887 * XXX as we don't properly deal with TTIN and TTOU etc. */
888 tcgetattr(STDIN_FILENO
, tiosp
);
889 tiosp
->c_lflag
|= ECHO
| ICANON
;
891 memcpy(&_ncl_tios
.tnew
, tiosp
, sizeof *tiosp
);
892 tiosp
= &_ncl_tios
.tnew
;
893 tiosp
->c_cc
[VMIN
] = 1;
894 tiosp
->c_cc
[VTIME
] = 0;
895 tiosp
->c_iflag
&= ~(ISTRIP
);
896 tiosp
->c_lflag
&= ~(ECHO
/*| ECHOE | ECHONL */| ICANON
| IEXTEN
);
898 tcsetattr(STDIN_FILENO
, TCSADRAIN
, tiosp
);
903 _ncl_check_grow(struct line
*l
, size_t no SMALLOC_DEBUG_ARGS
)
908 i
= (l
->topins
+ no
) * sizeof(struct cell
) + 2 * sizeof(struct cell
);
909 if (i
>= *l
->x_bufsize
) {
913 *l
->x_buf
= (srealloc
)(*l
->x_buf
, i SMALLOC_DEBUG_ARGSCALL
);
919 _ncl_bs_eof_dvup(struct cell
*cap
, size_t i
)
925 memmove(cap
, cap
+ 1, i
* sizeof(*cap
));
927 /* And.. the (rest of the) visual update */
928 for (j
= 0; j
< i
; ++j
)
929 fwrite(cap
[j
].cbuf
, sizeof *cap
->cbuf
, cap
[j
].count
, stdout
);
930 fputs(" \b", stdout
);
931 for (j
= 0; j
< i
; ++j
)
937 _ncl_wboundary(struct line
*l
, ssize_t dir
)
954 --t
, --c
; /* Unsigned wrapping may occur (twice), then */
956 for (i
= 0, cap
= l
->line
.cells
, anynon
= FAL0
;;) {
957 wchar_t wc
= cap
[c
+ dir
].wc
;
958 if (iswblank(wc
) || iswpunct(wc
)) {
977 _ncl_cell2dat(struct line
*l
)
983 for (i
= 0; i
< l
->topins
; ++i
) {
984 struct cell
*cap
= l
->line
.cells
+ i
;
985 memcpy(l
->line
.cbuf
+ len
, cap
->cbuf
, cap
->count
);
988 l
->line
.cbuf
[len
] = '\0';
993 # if defined HAVE_HISTORY || defined HAVE_TABEXPAND
995 _ncl_cell2save(struct line
*l
)
1001 l
->savec
.s
= NULL
, l
->savec
.l
= 0;
1005 for (cap
= l
->line
.cells
, len
= i
= 0; i
< l
->topins
; ++cap
, ++i
)
1009 l
->savec
.s
= salloc(len
+ 1);
1011 for (cap
= l
->line
.cells
, len
= i
= 0; i
< l
->topins
; ++cap
, ++i
) {
1012 memcpy(l
->savec
.s
+ len
, cap
->cbuf
, cap
->count
);
1015 l
->savec
.s
[len
] = '\0';
1022 _ncl_khome(struct line
*l
, bool_t dobell
)
1038 _ncl_kend(struct line
*l
)
1043 i
= (ssize_t
)(l
->topins
- l
->cursor
);
1046 l
->cursor
= l
->topins
;
1048 fputs(l
->nd
, stdout
);
1055 _ncl_kbs(struct line
*l
)
1068 _ncl_bs_eof_dvup(l
->line
.cells
+ c
, t
);
1075 _ncl_kkill(struct line
*l
, bool_t dobell
)
1081 i
= (size_t)(l
->topins
- c
);
1085 for (j
= i
; j
!= 0; --j
)
1087 for (j
= i
; j
!= 0; --j
)
1095 _ncl_keof(struct line
*l
)
1103 i
= (ssize_t
)(t
- c
);
1107 _ncl_bs_eof_dvup(l
->line
.cells
+ c
, --i
);
1108 } else if (t
== 0 /*&& !ok_blook(ignoreeof)*/) {
1109 /*fputs("^D", stdout);
1121 _ncl_kleft(struct line
*l
)
1124 if (l
->cursor
> 0) {
1133 _ncl_kright(struct line
*l
)
1136 if (l
->cursor
< l
->topins
) {
1138 fputs(l
->nd
, stdout
);
1145 _ncl_krefresh(struct line
*l
)
1152 if (l
->prompt
!= NULL
&& *l
->prompt
!= '\0')
1153 fputs(l
->prompt
, stdout
);
1154 for (cap
= l
->line
.cells
, i
= l
->topins
; i
> 0; ++cap
, --i
)
1155 fwrite(cap
->cbuf
, sizeof *cap
->cbuf
, cap
->count
, stdout
);
1156 for (i
= l
->topins
- l
->cursor
; i
> 0; --i
)
1162 _ncl_kbwddelw(struct line
*l
)
1169 i
= _ncl_wboundary(l
, -1);
1180 cap
= l
->line
.cells
+ c
;
1182 if (t
!= l
->cursor
) {
1184 memmove(cap
, cap
+ i
, j
* sizeof(*cap
));
1187 for (j
= i
; j
> 0; --j
)
1189 for (j
= l
->topins
- c
; j
> 0; ++cap
, --j
)
1190 fwrite(cap
[0].cbuf
, sizeof *cap
->cbuf
, cap
[0].count
, stdout
);
1191 for (j
= i
; j
> 0; --j
)
1193 for (j
= t
- c
; j
> 0; --j
)
1200 _ncl_kgow(struct line
*l
, ssize_t dir
)
1205 i
= _ncl_wboundary(l
, dir
);
1219 fputs(l
->nd
, stdout
);
1226 _ncl_kother(struct line
*l
, wchar_t wc
)
1228 /* Append if at EOL, insert otherwise;
1229 * since we may move around character-wise, always use a fresh ps */
1231 struct cell cell
, *cap
;
1235 /* First init a cell and see wether we'll really handle this wc */
1237 memset(&ps
, 0, sizeof ps
);
1238 i
= wcrtomb(cell
.cbuf
, wc
, &ps
);
1241 cell
.count
= (ui32_t
)i
;
1242 if (options
& OPT_ENC_MBSTATE
) {
1243 i
= wcrtomb(cell
.cbuf
+ i
, L
'\0', &ps
);
1246 else if (--i
< MB_LEN_MAX
)
1247 cell
.count
+= (ui32_t
)i
;
1252 /* Yes, we will! Place it in the array */
1254 i
= l
->topins
++ - c
;
1255 cap
= l
->line
.cells
+ c
;
1257 memmove(cap
+ 1, cap
, i
* sizeof(cell
));
1258 memcpy(cap
, &cell
, sizeof cell
);
1260 /* And update visual */
1263 fwrite(cap
->cbuf
, sizeof *cap
->cbuf
, cap
->count
, stdout
);
1264 while ((++cap
, i
-- != 0));
1271 # ifdef HAVE_HISTORY
1273 __ncl_khist_shared(struct line
*l
, struct hist
*hp
)
1278 if ((l
->hist
= hp
) != NULL
) {
1279 l
->defc
.s
= savestrbuf(hp
->dat
, hp
->len
);
1281 l
->defc
.l
= hp
->len
;
1282 if (l
->topins
> 0) {
1283 _ncl_khome(l
, FAL0
);
1284 _ncl_kkill(l
, FAL0
);
1295 _ncl_khist(struct line
*l
, bool_t backwd
)
1301 /* If we're not in history mode yet, save line content;
1302 * also, disallow forward search, then, and, of course, bail unless we
1303 * do have any history at all */
1304 if ((hp
= l
->hist
) == NULL
) {
1307 if ((hp
= _ncl_hist
) == NULL
)
1313 hp
= backwd
? hp
->older
: hp
->younger
;
1315 rv
= __ncl_khist_shared(l
, hp
);
1321 _ncl_krhist(struct line
*l
)
1323 struct str orig_savec
;
1324 struct hist
*hp
= NULL
;
1328 /* We cannot complete an empty line */
1329 if (l
->topins
== 0) {
1330 /* XXX The upcoming hard reset would restore a set savec buffer,
1331 * XXX so forcefully reset that. A cleaner solution would be to
1332 * XXX reset it whenever a restore is no longer desired */
1333 l
->savec
.s
= NULL
, l
->savec
.l
= 0;
1336 if ((hp
= l
->hist
) == NULL
) {
1337 if ((hp
= _ncl_hist
) == NULL
)
1339 orig_savec
.s
= NULL
;
1340 orig_savec
.l
= 0; /* silence CC */
1341 } else if ((hp
= hp
->older
) == NULL
)
1344 orig_savec
= l
->savec
;
1346 if (orig_savec
.s
== NULL
)
1348 for (; hp
!= NULL
; hp
= hp
->older
)
1349 if (is_prefix(l
->savec
.s
, hp
->dat
))
1351 if (orig_savec
.s
!= NULL
)
1352 l
->savec
= orig_savec
;
1354 rv
= __ncl_khist_shared(l
, hp
);
1360 # ifdef HAVE_TABEXPAND
1362 _ncl_kht(struct line
*l
)
1364 struct str orig
, bot
, topp
, sub
, exp
;
1365 struct cell
*cword
, *ctop
, *cx
;
1366 bool_t set_savec
= FAL0
;
1370 /* We cannot expand an empty line */
1374 /* Get plain line data; if this is the first expansion/xy, update the
1375 * very original content so that ^G gets the origin back */
1385 cword
= l
->line
.cells
;
1386 ctop
= cword
+ l
->cursor
;
1388 /* topp: separate data right of cursor */
1389 if ((cx
= cword
+ l
->topins
) != ctop
) {
1390 for (rv
= 0; cx
> ctop
; --cx
)
1393 topp
.s
= orig
.s
+ orig
.l
- rv
;
1395 topp
.s
= NULL
, topp
.l
= 0;
1397 /* bot, sub: we cannot expand the entire data left of cursor, but only
1398 * the last "word", so separate them */
1399 while (cx
> cword
&& !iswspace(cx
[-1].wc
))
1401 for (rv
= 0; cword
< cx
; ++cword
)
1410 /* Leave room for "implicit asterisk" expansion, as below */
1412 sub
.s
= UNCONST("*");
1415 exp
.s
= salloc(sub
.l
+ 1 +1);
1416 memcpy(exp
.s
, sub
.s
, sub
.l
);
1417 exp
.s
[sub
.l
] = '\0';
1421 /* TODO there is a TODO note upon fexpand() with multi-return;
1422 * TODO if that will change, the if() below can be simplified */
1423 /* Super-Heavy-Metal: block all sigs, avoid leaks on jump */
1426 exp
.s
= fexpand(sub
.s
, _CL_TAB_FEXP_FL
);
1429 if (exp
.s
== NULL
|| (exp
.l
= strlen(exp
.s
)) == 0)
1431 /* If the expansion equals the original string, assume the user wants what
1432 * is usually known as tab completion, append `*' and restart */
1433 if (exp
.l
== sub
.l
&& !strcmp(exp
.s
, sub
.s
)) {
1434 if (sub
.s
[sub
.l
- 1] == '*')
1436 sub
.s
[sub
.l
++] = '*';
1437 sub
.s
[sub
.l
] = '\0';
1441 /* Cramp expansion length to MAX_INPUT, or 255 if not defined.
1442 * Take care to take *prompt* into account, since we don't know
1443 * anything about it's visual length (fputs(3) is used), simply
1444 * assume each character requires two columns */
1445 /* TODO the problem is that we loose control otherwise; in the best
1446 * TODO case the user can control via ^A and ^K etc., but be safe;
1447 * TODO we cannot simply adjust fexpand() because we don't know how
1448 * TODO that is implemented... The real solution would be to check
1449 * TODO wether we fit on a line, and start a pager if not.
1450 * TODO However, that should be part of a real tab-COMPLETION, then,
1451 * TODO i.e., don't EXPAND, but SHOW COMPLETIONS, page-wise if needed.
1452 * TODO And: MAX_INPUT is dynamic: pathconf(2), _SC_MAX_INPUT */
1453 rv
= (l
->prompt
!= NULL
) ? _PROMPT_VLEN(l
->prompt
) : 0;
1454 if (rv
+ bot
.l
+ exp
.l
+ topp
.l
>= MAX_INPUT
) {
1455 exp
.s
= UNCONST("[ERR_TOO_LONG]");
1456 exp
.l
= sizeof("[ERR_TOO_LONG]") - 1;
1458 if (rv
+ bot
.l
+ exp
.l
>= MAX_INPUT
)
1460 if (rv
+ exp
.l
>= MAX_INPUT
) {
1461 exp
.s
= UNCONST("[ERR]");
1462 exp
.l
= sizeof("[ERR]") - 1;
1466 orig
.l
= bot
.l
+ exp
.l
+ topp
.l
;
1467 orig
.s
= salloc(orig
.l
+ 5 +1);
1468 if ((rv
= bot
.l
) > 0)
1469 memcpy(orig
.s
, bot
.s
, rv
);
1470 memcpy(orig
.s
+ rv
, exp
.s
, exp
.l
);
1473 memcpy(orig
.s
+ rv
, topp
.s
, topp
.l
);
1479 _ncl_khome(l
, FAL0
);
1480 _ncl_kkill(l
, FAL0
);
1485 /* If we've provided a default content, but failed to expand, there is
1486 * nothing we can "revert to": drop that default again */
1488 l
->savec
.s
= NULL
, l
->savec
.l
= 0;
1492 # endif /* HAVE_TABEXPAND */
1495 _ncl_readline(char const *prompt
, char **buf
, size_t *bufsize
, size_t len
1498 /* We want to save code, yet we may have to incorporate a lines'
1499 * default content and / or default input to switch back to after some
1500 * history movement; let "len > 0" mean "have to display some data
1501 * buffer", and only otherwise read(2) it */
1504 char cbuf_base
[MB_LEN_MAX
* 2], *cbuf
, *cbufp
, cursor_maybe
, cursor_store
;
1509 memset(&l
, 0, sizeof l
);
1512 l
.defc
.s
= savestrbuf(*buf
, len
);
1515 if ((l
.prompt
= prompt
) != NULL
&& _PROMPT_VLEN(prompt
) > _PROMPT_MAX
)
1516 l
.prompt
= prompt
= "?ERR?";
1517 /* TODO *l.nd=='\0' : instead adjust accmacvar.c to disallow empty vals */
1518 if ((l
.nd
= ok_vlook(line_editor_cursor_right
)) == NULL
|| *l
.nd
== '\0')
1519 l
.nd
= "\033[C"; /* XXX no "magic" constant */
1521 l
.x_bufsize
= bufsize
;
1523 if (prompt
!= NULL
&& *prompt
!= '\0')
1524 fputs(prompt
, stdout
);
1528 memset(ps
, 0, sizeof ps
);
1529 cursor_maybe
= cursor_store
= 0;
1530 /* TODO: NCL: we should output the reset sequence when we jrestart:
1531 * TODO: NCL: if we are using a stateful encoding? !
1532 * TODO: NCL: in short: this is not yet well understood */
1534 _ncl_check_grow(&l
, len SMALLOC_DEBUG_ARGSCALL
);
1536 /* Normal read(2)? Else buffer-takeover: speed this one up */
1541 assert(l
.defc
.l
> 0 && l
.defc
.s
!= NULL
);
1543 cbuf
= l
.defc
.s
+ (l
.defc
.l
- len
);
1547 /* Read in the next complete multibyte character */
1550 if ((rv
= read(STDIN_FILENO
, cbufp
, 1)) < 1) {
1551 if (errno
== EINTR
) /* xxx #if !SA_RESTART ? */
1558 /* Ach! the ISO C multibyte handling!
1559 * Encodings with locking shift states cannot really be helped, since
1560 * it is impossible to only query the shift state, as opposed to the
1561 * entire shift state + character pair (via ISO C functions) */
1562 rv
= (ssize_t
)mbrtowc(&wc
, cbuf
, PTR2SIZE(cbufp
- cbuf
), ps
+ 0);
1564 /* Any error during take-over can only result in a hard reset;
1565 * Otherwise, if it's a hard error, or if too many redundant shift
1566 * sequences overflow our buffer, also perform a hard reset */
1567 if (len
!= 0 || rv
== -1 ||
1568 sizeof cbuf_base
== PTR2SIZE(cbufp
- cbuf
)) {
1569 l
.savec
.s
= l
.defc
.s
= NULL
,
1570 l
.savec
.l
= l
.defc
.l
= len
= 0;
1575 /* Otherwise, due to the way we deal with the buffer, we need to
1576 * restore the mbstate_t from before this conversion */
1581 if (len
!= 0 && (len
-= (size_t)rv
) == 0)
1582 l
.defc
.s
= NULL
, l
.defc
.l
= 0;
1587 /* Don't interpret control bytes during buffer take-over */
1588 if (cbuf
!= cbuf_base
)
1591 case 'A' ^ 0x40: /* cursor home */
1592 _ncl_khome(&l
, TRU1
);
1594 case 'B' ^ 0x40: /* backward character */
1598 /* 'C': interrupt (CTRL-C) */
1599 case 'D' ^ 0x40: /* delete char forward if any, else EOF */
1600 if ((rv
= _ncl_keof(&l
)) < 0)
1603 case 'E' ^ 0x40: /* end of line */
1606 case 'F' ^ 0x40: /* forward character */
1611 case 'H' ^ 0x40: /* backspace */
1615 case 'I' ^ 0x40: /* horizontal tab */
1616 # ifdef HAVE_TABEXPAND
1617 if ((len
= _ncl_kht(&l
)) > 0)
1621 case 'J' ^ 0x40: /* NL (\n) */
1623 case 'G' ^ 0x40: /* full reset */
1626 case 'U' ^ 0x40: /* ^U: ^A + ^K */
1627 _ncl_khome(&l
, FAL0
);
1629 case 'K' ^ 0x40: /* kill from cursor to end of line */
1630 _ncl_kkill(&l
, (wc
== ('K' ^ 0x40) || l
.topins
== 0));
1631 /* (Handle full reset?) */
1632 if (wc
== ('G' ^ 0x40)) {
1633 # ifdef HAVE_HISTORY
1636 if ((len
= l
.savec
.l
) != 0) {
1638 l
.savec
.s
= NULL
, l
.savec
.l
= 0;
1644 case 'L' ^ 0x40: /* repaint line */
1649 case 'N' ^ 0x40: /* history next */
1651 # ifdef HAVE_HISTORY
1654 if ((len
= _ncl_khist(&l
, FAL0
)) > 0)
1662 case 'O' ^ 0x40: /* `dp' */
1666 cbuf_base
[2] = '\0';
1667 pstate
&= ~PS_HOOK_MASK
;
1668 execute(cbuf_base
, 2);
1670 case 'P' ^ 0x40: /* history previous */
1672 # ifdef HAVE_HISTORY
1673 if ((len
= _ncl_khist(&l
, TRU1
)) > 0)
1681 case 'R' ^ 0x40: /* reverse history search */
1682 # ifdef HAVE_HISTORY
1683 if ((len
= _ncl_krhist(&l
)) > 0)
1692 /*case 'V' ^ 0x40: TODO*/ /* forward delete "word" */
1693 case 'W' ^ 0x40: /* backward delete "word" */
1696 case 'X' ^ 0x40: /* move cursor forward "word" */
1699 case 'Y' ^ 0x40: /* move cursor backward "word" */
1702 /* 'Z': suspend (CTRL-Z) */
1704 if (cursor_maybe
++ != 0)
1708 /* XXX Handle usual ^[[[ABCD1456] cursor keys: UGLY,"MAGIC",INFLEX */
1709 if (cursor_maybe
> 0) {
1710 if (++cursor_maybe
== 2) {
1714 } else if (cursor_maybe
== 3) {
1718 case L
'A': goto j_p
;
1719 case L
'B': goto j_n
;
1720 case L
'C': goto j_f
;
1721 case L
'D': goto j_b
;
1732 cursor_store
= ((wc
== L
'1') ? '0' :
1733 (wc
== L
'4' ? '$' : (wc
== L
'5' ? '-' : '+')));
1737 _ncl_kother(&l
, L
'[');
1743 x
[0] = cursor_store
;
1749 } else if (cursor_store
== '-' && (wc
== L
'A' || wc
== L
'B')) {
1751 x
[0] = (wc
!= L
'A') ? '+' : cursor_store
;
1758 _ncl_kother(&l
, L
'[');
1759 _ncl_kother(&l
, (wchar_t)cursor_store
);
1765 _ncl_kother(&l
, wc
);
1766 /* Don't clear the history during takeover..
1767 * ..and also avoid fflush()ing unless we've worked entire buffer */
1770 # ifdef HAVE_HISTORY
1771 if (cbuf
== cbuf_base
)
1783 /* We have a completed input line, convert the struct cell data to its
1784 * plain character equivalent */
1788 len
= _ncl_cell2dat(&l
);
1798 # ifdef HAVE_HISTORY
1803 size_t lsize
, cnt
, llen
;
1807 # ifdef HAVE_HISTORY
1810 _ncl_hist_size_max
= hs
;
1818 hold_all_sigs(); /* TODO too heavy, yet we may jump even here!? */
1819 f
= fopen(v
, "r"); /* TODO HISTFILE LOAD: use linebuf pool */
1822 (void)file_lock(fileno(f
), FLT_READ
, 0,0, 500);
1827 while (fgetline(&lbuf
, &lsize
, &cnt
, &llen
, f
, FAL0
) != NULL
) {
1828 if (llen
> 0 && lbuf
[llen
- 1] == '\n')
1829 lbuf
[--llen
] = '\0';
1830 if (llen
== 0 || lbuf
[0] == '#') /* xxx comments? noone! */
1833 bool_t isgabby
= (lbuf
[0] == '*');
1834 _ncl_hist_load
= TRU1
;
1835 n_tty_addhist(lbuf
+ isgabby
, isgabby
);
1836 _ncl_hist_load
= FAL0
;
1844 rele_all_sigs(); /* XXX remove jumps */
1846 # endif /* HAVE_HISTORY */
1853 # ifdef HAVE_HISTORY
1862 # ifdef HAVE_HISTORY
1870 dogabby
= ok_blook(history_gabby_persist
);
1872 if ((hp
= _ncl_hist
) != NULL
)
1873 for (; hp
->older
!= NULL
; hp
= hp
->older
)
1874 if ((dogabby
|| !hp
->isgabby
) && --hs
== 0)
1877 hold_all_sigs(); /* TODO too heavy, yet we may jump even here!? */
1878 f
= fopen(v
, "w"); /* TODO temporary + rename?! */
1881 (void)file_lock(fileno(f
), FLT_WRITE
, 0,0, 500);
1882 if (fchmod(fileno(f
), S_IRUSR
| S_IWUSR
) != 0)
1885 for (; hp
!= NULL
; hp
= hp
->younger
) {
1886 if (!hp
->isgabby
|| dogabby
) {
1889 fwrite(hp
->dat
, sizeof *hp
->dat
, hp
->len
, f
);
1896 rele_all_sigs(); /* XXX remove jumps */
1898 # endif /* HAVE_HISTORY */
1903 n_tty_signal(int sig
)
1905 sigset_t nset
, oset
;
1906 NYD_X
; /* Signal handler */
1910 /* We don't deal with SIGWINCH, yet get called from main.c */
1913 _ncl_term_mode(FAL0
);
1916 sigaddset(&nset
, sig
);
1917 sigprocmask(SIG_UNBLOCK
, &nset
, &oset
);
1919 /* When we come here we'll continue editing, so reestablish */
1920 sigprocmask(SIG_BLOCK
, &oset
, (sigset_t
*)NULL
);
1922 _ncl_term_mode(TRU1
);
1928 (n_tty_readline
)(char const *prompt
, char **linebuf
, size_t *linesize
, size_t n
1934 /* Of course we have races here, but they cannot be avoided on POSIX
1935 * (except by even *more* actions) */
1937 _ncl_term_mode(TRU1
);
1938 nn
= _ncl_readline(prompt
, linebuf
, linesize
, n SMALLOC_DEBUG_ARGSCALL
);
1939 _ncl_term_mode(FAL0
);
1946 n_tty_addhist(char const *s
, bool_t isgabby
)
1948 # ifdef HAVE_HISTORY
1949 /* Super-Heavy-Metal: block all sigs, avoid leaks+ on jump */
1951 struct hist
*h
, *o
, *y
;
1957 # ifdef HAVE_HISTORY
1958 if (isgabby
&& !ok_blook(history_gabby
))
1960 if (_ncl_hist_size_max
== 0)
1962 _CL_CHECK_ADDHIST(s
, goto j_leave
);
1964 l
= (ui32_t
)strlen(s
);
1966 /* Eliminating duplicates is expensive, but simply inacceptable so
1967 * during the load of a potentially large history file! */
1968 if (!_ncl_hist_load
)
1969 for (h
= _ncl_hist
; h
!= NULL
; h
= h
->older
)
1970 if (h
->len
== l
&& !strcmp(h
->dat
, s
)) {
1971 hold_all_sigs(); /* TODO */
1973 h
->isgabby
= !!isgabby
;
1989 if (!_ncl_hist_load
&& _ncl_hist_size
> _ncl_hist_size_max
) {
1991 if ((h
= _ncl_hist_tail
) != NULL
) {
1992 if ((_ncl_hist_tail
= h
->younger
) == NULL
)
1995 _ncl_hist_tail
->older
= NULL
;
2000 h
= smalloc((sizeof(struct hist
) - VFIELD_SIZEOF(struct hist
, dat
)) + l
+1);
2001 h
->isgabby
= !!isgabby
;
2003 memcpy(h
->dat
, s
, l
+1);
2005 if ((h
->older
= _ncl_hist
) != NULL
)
2006 _ncl_hist
->younger
= h
;
2018 # ifdef HAVE_HISTORY
2029 if (_ncl_hist
== NULL
)
2032 if ((fp
= Ftmp(NULL
, "hist", OF_RDWR
| OF_UNLINK
| OF_REGISTER
)) == NULL
) {
2033 n_perr(_("tmpfile"), 0);
2040 for (h
= _ncl_hist
; h
!= NULL
; --i
, b
+= h
->len
, h
= h
->older
)
2042 "%c%4" PRIuZ
". %-50.50s (%4" PRIuZ
"+%2" PRIu32
" bytes)\n",
2043 (h
->isgabby
? '*' : ' '), i
, h
->dat
, b
, h
->len
);
2045 page_or_print(fp
, i
);
2053 while ((h
= _ncl_hist
) != NULL
) {
2054 _ncl_hist
= h
->older
;
2057 _ncl_hist_tail
= NULL
;
2065 if (UICMP(z
, entry
, <=, _ncl_hist_size
)) {
2066 entry
= (long)_ncl_hist_size
- entry
;
2067 for (h
= _ncl_hist
;; h
= h
->older
)
2070 else if (entry
-- != 0)
2073 v
= temporary_arg_v_store
= h
->dat
;
2081 # endif /* HAVE_HISTORY */
2082 #endif /* HAVE_NCL */
2085 * The really-nothing-at-all implementation
2088 #if !defined HAVE_READLINE && !defined HAVE_EDITLINE && !defined HAVE_NCL
2104 n_tty_signal(int sig
)
2106 NYD_X
; /* Signal handler */
2111 (n_tty_readline
)(char const *prompt
, char **linebuf
, size_t *linesize
, size_t n
2117 if (prompt
!= NULL
) {
2118 if (*prompt
!= '\0')
2119 fputs(prompt
, stdout
);
2122 rv
= (readline_restart
)(stdin
, linebuf
, linesize
,n SMALLOC_DEBUG_ARGSCALL
);
2128 n_tty_addhist(char const *s
, bool_t isgabby
)
2135 #endif /* nothing at all */